1use super::*;
2
3#[derive(Clone, Copy, Debug, Eq, PartialEq)]
5pub enum McpSchemaType {
6 Null,
7 Boolean,
8 Integer,
9 Number,
10 String,
11 Array,
12 Object,
13}
14
15impl McpSchemaType {
16 pub const fn as_str(self) -> &'static str {
18 match self {
19 Self::Null => "null",
20 Self::Boolean => "boolean",
21 Self::Integer => "integer",
22 Self::Number => "number",
23 Self::String => "string",
24 Self::Array => "array",
25 Self::Object => "object",
26 }
27 }
28}
29
30#[derive(Clone, Copy, Debug, Eq, PartialEq)]
32pub enum McpStringFormat {
33 Date,
34 DateTime,
35}
36
37impl McpStringFormat {
38 pub const fn as_str(self) -> &'static str {
40 match self {
41 Self::Date => "date",
42 Self::DateTime => "date-time",
43 }
44 }
45}
46
47#[derive(Clone, Debug, Eq, PartialEq)]
49pub struct McpSchemaNumber(Number);
50
51impl McpSchemaNumber {
52 pub fn from_f64(value: f64) -> Option<Self> {
54 Number::from_f64(value).map(Self)
55 }
56
57 pub fn into_value(self) -> Value {
59 Value::Number(self.0)
60 }
61}
62
63macro_rules! impl_schema_number {
64 ($($ty:ty),* $(,)?) => {
65 $(
66 impl From<$ty> for McpSchemaNumber {
67 fn from(value: $ty) -> Self {
68 Self(Number::from(value))
69 }
70 }
71 )*
72 };
73}
74
75impl_schema_number!(i8, i16, i32, i64, u8, u16, u32, u64);
76
77impl From<isize> for McpSchemaNumber {
78 fn from(value: isize) -> Self {
79 Self(Number::from(value as i64))
80 }
81}
82
83impl From<usize> for McpSchemaNumber {
84 fn from(value: usize) -> Self {
85 Self(Number::from(value as u64))
86 }
87}
88
89pub enum McpAdditionalProperties {
91 Allowed(bool),
93 Schema(McpSchema),
95}
96
97impl From<bool> for McpAdditionalProperties {
98 fn from(value: bool) -> Self {
99 Self::Allowed(value)
100 }
101}
102
103impl From<McpSchema> for McpAdditionalProperties {
104 fn from(schema: McpSchema) -> Self {
105 Self::Schema(schema)
106 }
107}
108
109#[derive(Clone, Debug, Eq, PartialEq)]
115pub struct McpSchema(Value);
116
117impl McpSchema {
118 pub fn new(schema: Value) -> Self {
119 Self(schema)
120 }
121
122 pub fn any() -> Self {
123 Self(Value::Object(Map::new()))
124 }
125
126 pub fn impossible() -> Self {
127 Self::any().with_not(Self::any())
128 }
129
130 pub fn typed(schema_type: McpSchemaType) -> Self {
131 let mut object = Map::new();
132 object.insert(
133 "type".to_string(),
134 Value::String(schema_type.as_str().to_string()),
135 );
136 Self(Value::Object(object))
137 }
138
139 pub fn null() -> Self {
140 Self::typed(McpSchemaType::Null)
141 }
142
143 pub fn boolean() -> Self {
144 Self::typed(McpSchemaType::Boolean)
145 }
146
147 pub fn integer() -> Self {
148 Self::typed(McpSchemaType::Integer)
149 }
150
151 pub fn number() -> Self {
152 Self::typed(McpSchemaType::Number)
153 }
154
155 pub fn string() -> Self {
156 Self::typed(McpSchemaType::String)
157 }
158
159 pub fn array(item_schema: McpSchema) -> Self {
160 Self::typed(McpSchemaType::Array).with_items(item_schema)
161 }
162
163 pub fn object() -> Self {
164 Self::typed(McpSchemaType::Object)
165 }
166
167 pub fn any_of<I>(schemas: I) -> Self
168 where
169 I: IntoIterator<Item = McpSchema>,
170 {
171 let mut schema = Self::any();
172 schema.set_any_of(schemas);
173 schema
174 }
175
176 pub fn one_of<I>(schemas: I) -> Self
177 where
178 I: IntoIterator<Item = McpSchema>,
179 {
180 let mut schema = Self::any();
181 schema.set_one_of(schemas);
182 schema
183 }
184
185 pub fn with_description(mut self, description: impl Into<String>) -> Self {
186 self.set_description(description);
187 self
188 }
189
190 pub fn with_extension(mut self, key: impl Into<String>, value: Value) -> Self {
191 self.set_extension(key, value);
192 self
193 }
194
195 pub fn with_format(mut self, format: McpStringFormat) -> Self {
196 self.set_format(format);
197 self
198 }
199
200 pub fn with_minimum(mut self, minimum: impl Into<McpSchemaNumber>) -> Self {
201 self.set_minimum(minimum);
202 self
203 }
204
205 pub fn with_min_items(mut self, min_items: usize) -> Self {
206 self.set_min_items(min_items);
207 self
208 }
209
210 pub fn with_max_items(mut self, max_items: usize) -> Self {
211 self.set_max_items(max_items);
212 self
213 }
214
215 pub fn with_unique_items(mut self, unique_items: bool) -> Self {
216 self.set_unique_items(unique_items);
217 self
218 }
219
220 pub fn with_default(mut self, value: impl Into<Value>) -> Self {
221 self.set_default(value);
222 self
223 }
224
225 pub fn with_const(mut self, value: impl Into<Value>) -> Self {
226 self.set_const(value);
227 self
228 }
229
230 pub fn with_enum_values<I, V>(mut self, values: I) -> Self
231 where
232 I: IntoIterator<Item = V>,
233 V: Into<Value>,
234 {
235 self.set_enum_values(values);
236 self
237 }
238
239 pub fn with_items(mut self, item_schema: McpSchema) -> Self {
240 self.set_items(item_schema);
241 self
242 }
243
244 pub fn with_prefix_items<I>(mut self, item_schemas: I) -> Self
245 where
246 I: IntoIterator<Item = McpSchema>,
247 {
248 self.set_prefix_items(item_schemas);
249 self
250 }
251
252 pub fn with_properties(mut self, properties: McpSchemaProperties) -> Self {
253 self.set_properties(properties);
254 self
255 }
256
257 pub fn with_required<I, S>(mut self, required: I) -> Self
258 where
259 I: IntoIterator<Item = S>,
260 S: Into<String>,
261 {
262 self.set_required(required);
263 self
264 }
265
266 pub fn with_additional_properties(
267 mut self,
268 additional_properties: impl Into<McpAdditionalProperties>,
269 ) -> Self {
270 self.set_additional_properties(additional_properties);
271 self
272 }
273
274 pub fn with_not(mut self, schema: McpSchema) -> Self {
275 self.set_not(schema);
276 self
277 }
278
279 pub fn set_description(&mut self, description: impl Into<String>) {
280 self.set_extension("description", Value::String(description.into()));
281 }
282
283 pub fn set_extension(&mut self, key: impl Into<String>, value: Value) {
284 if let Some(object) = self.as_object_mut() {
285 object.insert(key.into(), value);
286 }
287 }
288
289 pub fn set_format(&mut self, format: McpStringFormat) {
290 self.set_extension("format", Value::String(format.as_str().to_string()));
291 }
292
293 pub fn set_minimum(&mut self, minimum: impl Into<McpSchemaNumber>) {
294 self.set_extension("minimum", minimum.into().into_value());
295 }
296
297 pub fn set_min_items(&mut self, min_items: usize) {
298 self.set_extension("minItems", Value::Number(Number::from(min_items as u64)));
299 }
300
301 pub fn set_max_items(&mut self, max_items: usize) {
302 self.set_extension("maxItems", Value::Number(Number::from(max_items as u64)));
303 }
304
305 pub fn set_unique_items(&mut self, unique_items: bool) {
306 self.set_extension("uniqueItems", Value::Bool(unique_items));
307 }
308
309 pub fn set_default(&mut self, value: impl Into<Value>) {
310 self.set_extension("default", value.into());
311 }
312
313 pub fn set_const(&mut self, value: impl Into<Value>) {
314 self.set_extension("const", value.into());
315 }
316
317 pub fn set_enum_values<I, V>(&mut self, values: I)
318 where
319 I: IntoIterator<Item = V>,
320 V: Into<Value>,
321 {
322 self.set_extension(
323 "enum",
324 Value::Array(values.into_iter().map(Into::into).collect()),
325 );
326 }
327
328 pub fn set_items(&mut self, item_schema: McpSchema) {
329 self.set_extension("items", item_schema.into_value());
330 }
331
332 pub fn set_prefix_items<I>(&mut self, item_schemas: I)
333 where
334 I: IntoIterator<Item = McpSchema>,
335 {
336 self.set_extension(
337 "prefixItems",
338 Value::Array(
339 item_schemas
340 .into_iter()
341 .map(McpSchema::into_value)
342 .collect(),
343 ),
344 );
345 }
346
347 pub fn set_properties(&mut self, properties: McpSchemaProperties) {
348 self.set_extension(
349 "properties",
350 Value::Object(
351 properties
352 .into_iter()
353 .map(|(name, schema)| (name, schema.into_value()))
354 .collect(),
355 ),
356 );
357 }
358
359 pub fn set_required<I, S>(&mut self, required: I)
360 where
361 I: IntoIterator<Item = S>,
362 S: Into<String>,
363 {
364 self.set_extension(
365 "required",
366 Value::Array(
367 required
368 .into_iter()
369 .map(|field| Value::String(field.into()))
370 .collect(),
371 ),
372 );
373 }
374
375 pub fn set_additional_properties(
376 &mut self,
377 additional_properties: impl Into<McpAdditionalProperties>,
378 ) {
379 let value = match additional_properties.into() {
380 McpAdditionalProperties::Allowed(value) => Value::Bool(value),
381 McpAdditionalProperties::Schema(schema) => schema.into_value(),
382 };
383 self.set_extension("additionalProperties", value);
384 }
385
386 pub fn set_any_of<I>(&mut self, schemas: I)
387 where
388 I: IntoIterator<Item = McpSchema>,
389 {
390 self.set_extension(
391 "anyOf",
392 Value::Array(schemas.into_iter().map(McpSchema::into_value).collect()),
393 );
394 }
395
396 pub fn set_one_of<I>(&mut self, schemas: I)
397 where
398 I: IntoIterator<Item = McpSchema>,
399 {
400 self.set_extension(
401 "oneOf",
402 Value::Array(schemas.into_iter().map(McpSchema::into_value).collect()),
403 );
404 }
405
406 pub fn set_not(&mut self, schema: McpSchema) {
407 self.set_extension("not", schema.into_value());
408 }
409
410 pub fn as_value(&self) -> &Value {
411 &self.0
412 }
413
414 pub fn as_object_mut(&mut self) -> Option<&mut Map<String, Value>> {
415 self.0.as_object_mut()
416 }
417
418 pub fn into_value(self) -> Value {
419 self.0
420 }
421}
422
423impl<I> Index<I> for McpSchema
424where
425 Value: Index<I>,
426{
427 type Output = <Value as Index<I>>::Output;
428
429 fn index(&self, index: I) -> &Self::Output {
430 &self.0[index]
431 }
432}
433
434pub trait McpJsonSchema {
443 fn json_schema() -> McpSchema;
445}
446
447#[derive(Clone, Debug, Default, Deserialize, Eq, PartialEq, Serialize)]
453#[serde(transparent)]
454pub struct McpAny(Value);
455
456impl McpAny {
457 pub fn new(value: Value) -> Self {
459 Self(value)
460 }
461
462 pub fn as_value(&self) -> &Value {
464 &self.0
465 }
466
467 pub fn into_value(self) -> Value {
469 self.0
470 }
471}
472
473impl From<Value> for McpAny {
474 fn from(value: Value) -> Self {
475 Self::new(value)
476 }
477}
478
479impl From<McpAny> for Value {
480 fn from(value: McpAny) -> Self {
481 value.into_value()
482 }
483}
484
485impl std::ops::Deref for McpAny {
486 type Target = Value;
487
488 fn deref(&self) -> &Self::Target {
489 self.as_value()
490 }
491}
492
493impl McpJsonSchema for McpAny {
494 fn json_schema() -> McpSchema {
495 McpSchema::any()
496 }
497}
498
499impl McpJsonSchema for Value {
500 fn json_schema() -> McpSchema {
501 McpSchema::any()
502 }
503}
504
505pub trait McpToolInput: Sized {
514 fn input_schema() -> McpSchema;
516
517 fn from_tool_call(call: McpToolCall) -> Result<Self, McpToolError>;
524}
525
526impl McpToolInput for () {
527 fn input_schema() -> McpSchema {
528 object_schema(McpSchemaProperties::new(), std::iter::empty::<&str>())
529 }
530
531 fn from_tool_call(call: McpToolCall) -> Result<Self, McpToolError> {
532 call.into_arguments().finish()
533 }
534}
535
536#[derive(Clone)]
541pub struct McpTypedTool<Input> {
542 definition: ToolDefinition,
543 _input: PhantomData<fn() -> Input>,
544}
545
546impl<Input> McpTypedTool<Input> {
547 pub(crate) fn from_definition_unchecked(definition: ToolDefinition) -> Self {
548 Self {
549 definition,
550 _input: PhantomData,
551 }
552 }
553
554 pub fn definition(&self) -> &ToolDefinition {
556 &self.definition
557 }
558
559 pub fn definition_mut(&mut self) -> &mut ToolDefinition {
561 &mut self.definition
562 }
563
564 pub fn into_definition(self) -> ToolDefinition {
566 self.definition
567 }
568}
569
570impl<Input> AsRef<ToolDefinition> for McpTypedTool<Input> {
571 fn as_ref(&self) -> &ToolDefinition {
572 self.definition()
573 }
574}
575
576impl<Input> std::ops::Deref for McpTypedTool<Input> {
577 type Target = ToolDefinition;
578
579 fn deref(&self) -> &Self::Target {
580 self.definition()
581 }
582}
583
584pub trait McpToolValue: Sized {
593 fn tool_value_schema() -> McpSchema;
595
596 fn from_tool_value(field: &str, value: Value) -> Result<Self, McpToolError>;
603}
604
605impl<T> McpToolValue for T
606where
607 T: McpJsonSchema + DeserializeOwned,
608{
609 fn tool_value_schema() -> McpSchema {
610 T::json_schema()
611 }
612
613 fn from_tool_value(field: &str, value: Value) -> Result<Self, McpToolError> {
614 let schema = T::json_schema();
615 if value.is_null() && !schema_allows_null(&schema) {
616 return Err(McpToolError::UnexpectedNull {
617 field: field.to_string(),
618 });
619 }
620 validate_value_against_closed_schema(field, schema.as_value(), &value)?;
621 let value = normalize_value_against_schema(schema.as_value(), value);
622
623 serde_json::from_value(value).map_err(|error| McpToolError::DecodeField {
624 field: field.to_string(),
625 message: error.to_string(),
626 })
627 }
628}
629
630#[derive(Clone, Debug, Default, Deserialize, Eq, PartialEq, Serialize)]
635#[serde(deny_unknown_fields)]
636pub struct McpRange<T> {
637 pub min: Option<T>,
639 pub max: Option<T>,
641}
642
643impl<T> McpRange<T> {
644 pub fn new(min: Option<T>, max: Option<T>) -> Self {
646 Self { min, max }
647 }
648
649 pub fn into_tuple(self) -> (Option<T>, Option<T>) {
651 (self.min, self.max)
652 }
653}
654
655impl<T> From<(Option<T>, Option<T>)> for McpRange<T> {
656 fn from((min, max): (Option<T>, Option<T>)) -> Self {
657 Self::new(min, max)
658 }
659}
660
661impl<T> From<McpRange<T>> for (Option<T>, Option<T>) {
662 fn from(value: McpRange<T>) -> Self {
663 value.into_tuple()
664 }
665}
666
667impl<T> McpJsonSchema for McpRange<T>
668where
669 T: McpJsonSchema,
670{
671 fn json_schema() -> McpSchema {
672 range_schema(T::json_schema())
673 }
674}
675
676impl McpJsonSchema for bool {
677 fn json_schema() -> McpSchema {
678 schema_for_primitive(McpPrimitiveKind::Boolean)
679 }
680}
681
682macro_rules! impl_integer_schema {
683 ($($ty:ty),* $(,)?) => {
684 $(
685 impl McpJsonSchema for $ty {
686 fn json_schema() -> McpSchema {
687 schema_for_primitive(McpPrimitiveKind::Integer)
688 }
689 }
690 )*
691 };
692}
693
694impl_integer_schema!(
695 i8, i16, i32, i64, i128, isize, u8, u16, u32, u64, u128, usize,
696);
697
698macro_rules! impl_number_schema {
699 ($($ty:ty),* $(,)?) => {
700 $(
701 impl McpJsonSchema for $ty {
702 fn json_schema() -> McpSchema {
703 schema_for_primitive(McpPrimitiveKind::Number)
704 }
705 }
706 )*
707 };
708}
709
710impl_number_schema!(f32, f64);
711
712#[cfg(feature = "rust_decimal")]
713impl McpJsonSchema for rust_decimal::Decimal {
714 fn json_schema() -> McpSchema {
715 schema_for_primitive(McpPrimitiveKind::Decimal)
716 }
717}
718
719impl McpJsonSchema for String {
720 fn json_schema() -> McpSchema {
721 schema_for_primitive(McpPrimitiveKind::String)
722 }
723}
724
725impl McpJsonSchema for str {
726 fn json_schema() -> McpSchema {
727 schema_for_primitive(McpPrimitiveKind::String)
728 }
729}
730
731impl McpJsonSchema for char {
732 fn json_schema() -> McpSchema {
733 schema_for_primitive(McpPrimitiveKind::String)
734 }
735}
736
737impl McpJsonSchema for PathBuf {
738 fn json_schema() -> McpSchema {
739 schema_for_primitive(McpPrimitiveKind::String)
740 }
741}
742
743impl McpJsonSchema for Path {
744 fn json_schema() -> McpSchema {
745 schema_for_primitive(McpPrimitiveKind::String)
746 }
747}
748
749#[cfg(feature = "chrono")]
750impl McpJsonSchema for chrono::NaiveDate {
751 fn json_schema() -> McpSchema {
752 schema_for_primitive(McpPrimitiveKind::Date)
753 }
754}
755
756#[cfg(feature = "chrono")]
757impl McpJsonSchema for chrono::NaiveDateTime {
758 fn json_schema() -> McpSchema {
759 schema_for_primitive(McpPrimitiveKind::DateTime)
760 }
761}
762
763#[cfg(feature = "chrono")]
764impl<Tz> McpJsonSchema for chrono::DateTime<Tz>
765where
766 Tz: chrono::TimeZone,
767{
768 fn json_schema() -> McpSchema {
769 schema_for_primitive(McpPrimitiveKind::DateTime)
770 }
771}
772
773impl<T> McpJsonSchema for Option<T>
774where
775 T: McpJsonSchema,
776{
777 fn json_schema() -> McpSchema {
778 nullable_schema(T::json_schema())
779 }
780}
781
782impl<T> McpJsonSchema for Vec<T>
783where
784 T: McpJsonSchema,
785{
786 fn json_schema() -> McpSchema {
787 array_schema(T::json_schema())
788 }
789}
790
791impl<T> McpJsonSchema for [T]
792where
793 T: McpJsonSchema,
794{
795 fn json_schema() -> McpSchema {
796 array_schema(T::json_schema())
797 }
798}
799
800impl<T, const N: usize> McpJsonSchema for [T; N]
801where
802 T: McpJsonSchema,
803{
804 fn json_schema() -> McpSchema {
805 let mut schema = array_schema(T::json_schema());
806 if let Some(object) = schema.as_object_mut() {
807 object.insert("minItems".to_string(), Value::Number((N as u64).into()));
808 object.insert("maxItems".to_string(), Value::Number((N as u64).into()));
809 }
810 schema
811 }
812}
813
814macro_rules! impl_tuple_schema {
815 ($($name:ident),+ $(,)?) => {
816 impl<$($name),+> McpJsonSchema for ($($name,)+)
817 where
818 $($name: McpJsonSchema,)+
819 {
820 fn json_schema() -> McpSchema {
821 tuple_schema([
822 $(<$name as McpJsonSchema>::json_schema(),)+
823 ])
824 }
825 }
826 };
827}
828
829impl_tuple_schema!(A);
830impl_tuple_schema!(A, B);
831impl_tuple_schema!(A, B, C);
832impl_tuple_schema!(A, B, C, D);
833
834impl<T> McpJsonSchema for BTreeSet<T>
835where
836 T: McpJsonSchema,
837{
838 fn json_schema() -> McpSchema {
839 unique_array_schema(T::json_schema())
840 }
841}
842
843impl<T> McpJsonSchema for HashSet<T>
844where
845 T: Eq + Hash + McpJsonSchema,
846{
847 fn json_schema() -> McpSchema {
848 unique_array_schema(T::json_schema())
849 }
850}
851
852impl<T> McpJsonSchema for BTreeMap<String, T>
853where
854 T: McpJsonSchema,
855{
856 fn json_schema() -> McpSchema {
857 string_keyed_object_schema(T::json_schema())
858 }
859}
860
861impl<T> McpJsonSchema for HashMap<String, T>
862where
863 T: McpJsonSchema,
864{
865 fn json_schema() -> McpSchema {
866 string_keyed_object_schema(T::json_schema())
867 }
868}
869
870impl<T> McpJsonSchema for Map<String, T>
871where
872 T: McpJsonSchema,
873{
874 fn json_schema() -> McpSchema {
875 string_keyed_object_schema(T::json_schema())
876 }
877}
878
879impl<T> McpJsonSchema for &T
880where
881 T: ?Sized + McpJsonSchema,
882{
883 fn json_schema() -> McpSchema {
884 T::json_schema()
885 }
886}
887
888impl<'a, T> McpJsonSchema for Cow<'a, T>
889where
890 T: ?Sized + ToOwned + McpJsonSchema,
891{
892 fn json_schema() -> McpSchema {
893 T::json_schema()
894 }
895}
896
897pub fn array_schema(item_schema: McpSchema) -> McpSchema {
899 McpSchema::array(item_schema)
900}
901
902pub fn unique_array_schema(item_schema: McpSchema) -> McpSchema {
904 array_schema(item_schema).with_unique_items(true)
905}
906
907pub fn tuple_schema<I>(item_schemas: I) -> McpSchema
909where
910 I: IntoIterator<Item = McpSchema>,
911{
912 let prefix_items = item_schemas.into_iter().collect::<Vec<_>>();
913 let len = prefix_items.len();
914
915 McpSchema::typed(McpSchemaType::Array)
916 .with_prefix_items(prefix_items)
917 .with_min_items(len)
918 .with_max_items(len)
919}
920
921pub fn string_keyed_object_schema(value_schema: McpSchema) -> McpSchema {
923 McpSchema::object().with_additional_properties(value_schema)
924}
925
926pub fn object_schema<I, S>(properties: McpSchemaProperties, required: I) -> McpSchema
928where
929 I: IntoIterator<Item = S>,
930 S: Into<String>,
931{
932 McpSchema::object()
933 .with_properties(properties)
934 .with_required(required)
935 .with_additional_properties(false)
936}
937
938impl<T> McpJsonSchema for Box<T>
939where
940 T: McpJsonSchema,
941{
942 fn json_schema() -> McpSchema {
943 T::json_schema()
944 }
945}
946
947impl McpJsonSchema for () {
948 fn json_schema() -> McpSchema {
949 McpSchema::null()
950 }
951}