1#![expect(deprecated)]
4use std::{
5 borrow::Cow,
6 collections::hash_map::RandomState,
7 hash::{BuildHasher, Hasher},
8 ops::{Deref, DerefMut},
9 sync::{Arc, OnceLock},
10};
11mod annotated;
12mod capabilities;
13mod content;
14mod elicitation_schema;
15mod extension;
16mod meta;
17mod mrtr;
18mod prompt;
19#[cfg(feature = "request-state")]
20mod request_state;
21mod resource;
22mod serde_impl;
23mod task;
24mod tool;
25pub use annotated::*;
26pub use capabilities::*;
27pub use content::*;
28pub use elicitation_schema::*;
29pub use extension::*;
30pub use meta::*;
31pub use mrtr::*;
32pub use prompt::*;
33#[cfg(feature = "request-state")]
34pub use request_state::*;
35pub use resource::*;
36use serde::{Deserialize, Serialize, de::DeserializeOwned};
37use serde_json::Value;
38pub use task::*;
39pub use tool::*;
40
41pub type JsonObject<F = Value> = serde_json::Map<String, F>;
46
47pub fn object(value: serde_json::Value) -> JsonObject {
52 debug_assert!(value.is_object());
53 match value {
54 serde_json::Value::Object(map) => map,
55 _ => JsonObject::default(),
56 }
57}
58
59#[macro_export]
61macro_rules! object {
62 ({$($tt:tt)*}) => {
63 $crate::model::object(serde_json::json! {
64 {$($tt)*}
65 })
66 };
67}
68
69#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Copy, Eq)]
73#[serde(deny_unknown_fields)]
74#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
75#[expect(clippy::exhaustive_structs, reason = "intentionally exhaustive")]
76pub struct EmptyObject {}
77
78pub trait ConstString: Default {
79 const VALUE: &str;
80 fn as_str(&self) -> &'static str {
81 Self::VALUE
82 }
83}
84#[macro_export]
85macro_rules! const_string {
86 ($name:ident = $value:literal) => {
87 #[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
88 #[expect(clippy::exhaustive_structs, reason = "intentionally exhaustive")]
89 pub struct $name;
90
91 impl ConstString for $name {
92 const VALUE: &str = $value;
93 }
94
95 impl serde::Serialize for $name {
96 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
97 where
98 S: serde::Serializer,
99 {
100 $value.serialize(serializer)
101 }
102 }
103
104 impl<'de> serde::Deserialize<'de> for $name {
105 fn deserialize<D>(deserializer: D) -> Result<$name, D::Error>
106 where
107 D: serde::Deserializer<'de>,
108 {
109 let s: String = serde::Deserialize::deserialize(deserializer)?;
110 if s == $value {
111 Ok($name)
112 } else {
113 Err(serde::de::Error::custom(format!(concat!(
114 "expect const string value \"",
115 $value,
116 "\""
117 ))))
118 }
119 }
120 }
121
122 #[cfg(feature = "schemars")]
123 impl schemars::JsonSchema for $name {
124 fn schema_name() -> Cow<'static, str> {
125 Cow::Borrowed(stringify!($name))
126 }
127
128 fn json_schema(_: &mut schemars::SchemaGenerator) -> schemars::Schema {
129 use serde_json::{Map, json};
130
131 let mut schema_map = Map::new();
132 schema_map.insert("type".to_string(), json!("string"));
133 schema_map.insert("format".to_string(), json!("const"));
134 schema_map.insert("const".to_string(), json!($value));
135
136 schemars::Schema::from(schema_map)
137 }
138 }
139 };
140}
141
142const_string!(JsonRpcVersion2_0 = "2.0");
143
144#[derive(Debug, Clone, Eq, PartialEq, Hash, PartialOrd)]
153#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
154pub struct ProtocolVersion(Cow<'static, str>);
155
156impl Default for ProtocolVersion {
157 fn default() -> Self {
158 Self::LATEST
159 }
160}
161
162impl std::fmt::Display for ProtocolVersion {
163 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
164 self.0.fmt(f)
165 }
166}
167
168impl ProtocolVersion {
169 pub const V_2026_07_28: Self = Self(Cow::Borrowed("2026-07-28"));
170 pub const V_2025_11_25: Self = Self(Cow::Borrowed("2025-11-25"));
171 pub const V_2025_06_18: Self = Self(Cow::Borrowed("2025-06-18"));
172 pub const V_2025_03_26: Self = Self(Cow::Borrowed("2025-03-26"));
173 pub const V_2024_11_05: Self = Self(Cow::Borrowed("2024-11-05"));
174
175 pub const LATEST: Self = Self::V_2026_07_28;
177
178 pub const STANDARD_HEADERS: Self = Self::V_2026_07_28;
180
181 pub const NO_INITIALIZE: Self = Self::V_2026_07_28;
184
185 pub const LATEST_WITH_INITIALIZE: Self = Self::V_2025_11_25;
202
203 pub const KNOWN_VERSIONS: &[Self] = &[
205 Self::V_2024_11_05,
206 Self::V_2025_03_26,
207 Self::V_2025_06_18,
208 Self::V_2025_11_25,
209 Self::V_2026_07_28,
210 ];
211
212 pub fn as_str(&self) -> &str {
214 &self.0
215 }
216
217 pub fn has_initialize(&self) -> bool {
231 self.as_str() < Self::NO_INITIALIZE.as_str()
232 }
233
234 pub fn known_up_to(max: &Self) -> &'static [Self] {
264 let count = Self::KNOWN_VERSIONS
265 .iter()
266 .take_while(|version| version.as_str() <= max.as_str())
267 .count();
268 &Self::KNOWN_VERSIONS[..count]
269 }
270}
271
272impl Serialize for ProtocolVersion {
273 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
274 where
275 S: serde::Serializer,
276 {
277 self.0.serialize(serializer)
278 }
279}
280
281impl<'de> Deserialize<'de> for ProtocolVersion {
282 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
283 where
284 D: serde::Deserializer<'de>,
285 {
286 let s: String = Deserialize::deserialize(deserializer)?;
287 #[allow(clippy::single_match)]
288 match s.as_str() {
289 "2024-11-05" => return Ok(ProtocolVersion::V_2024_11_05),
290 "2025-03-26" => return Ok(ProtocolVersion::V_2025_03_26),
291 "2025-06-18" => return Ok(ProtocolVersion::V_2025_06_18),
292 "2025-11-25" => return Ok(ProtocolVersion::V_2025_11_25),
293 "2026-07-28" => return Ok(ProtocolVersion::V_2026_07_28),
294 _ => {}
295 }
296 Ok(ProtocolVersion(Cow::Owned(s)))
297 }
298}
299
300#[derive(Debug, Clone, Eq, PartialEq, Hash)]
305#[expect(clippy::exhaustive_enums, reason = "intentionally exhaustive")]
306pub enum NumberOrString {
307 Number(i64),
309 String(Arc<str>),
311}
312
313impl NumberOrString {
314 pub fn into_json_value(self) -> Value {
315 match self {
316 NumberOrString::Number(n) => Value::Number(serde_json::Number::from(n)),
317 NumberOrString::String(s) => Value::String(s.to_string()),
318 }
319 }
320
321 pub(crate) fn numeric_string_value(&self) -> Option<i64> {
322 match self {
323 Self::String(id) => id.parse().ok(),
324 Self::Number(_) => None,
325 }
326 }
327
328 pub(crate) fn matches_response_id(&self, response_id: &Self) -> bool {
329 self == response_id
330 || matches!(
331 self,
332 Self::Number(request_id)
333 if response_id.numeric_string_value() == Some(*request_id)
334 )
335 }
336}
337
338impl std::fmt::Display for NumberOrString {
339 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
340 match self {
341 NumberOrString::Number(n) => n.fmt(f),
342 NumberOrString::String(s) => s.fmt(f),
343 }
344 }
345}
346
347impl Serialize for NumberOrString {
348 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
349 where
350 S: serde::Serializer,
351 {
352 match self {
353 NumberOrString::Number(n) => n.serialize(serializer),
354 NumberOrString::String(s) => s.serialize(serializer),
355 }
356 }
357}
358
359impl<'de> Deserialize<'de> for NumberOrString {
360 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
361 where
362 D: serde::Deserializer<'de>,
363 {
364 let value: Value = Deserialize::deserialize(deserializer)?;
365 match value {
366 Value::Number(n) => {
367 if let Some(i) = n.as_i64() {
368 Ok(NumberOrString::Number(i))
369 } else if let Some(u) = n.as_u64() {
370 if u <= i64::MAX as u64 {
372 Ok(NumberOrString::Number(u as i64))
373 } else {
374 Err(serde::de::Error::custom("Number too large for i64"))
375 }
376 } else {
377 Err(serde::de::Error::custom("Expected an integer"))
378 }
379 }
380 Value::String(s) => Ok(NumberOrString::String(s.into())),
381 _ => Err(serde::de::Error::custom("Expect number or string")),
382 }
383 }
384}
385
386#[cfg(feature = "schemars")]
387impl schemars::JsonSchema for NumberOrString {
388 fn schema_name() -> Cow<'static, str> {
389 Cow::Borrowed("NumberOrString")
390 }
391
392 fn json_schema(_: &mut schemars::SchemaGenerator) -> schemars::Schema {
393 use serde_json::{Map, json};
394
395 let mut number_schema = Map::new();
396 number_schema.insert("type".to_string(), json!("number"));
397
398 let mut string_schema = Map::new();
399 string_schema.insert("type".to_string(), json!("string"));
400
401 let mut schema_map = Map::new();
402 schema_map.insert("oneOf".to_string(), json!([number_schema, string_schema]));
403
404 schemars::Schema::from(schema_map)
405 }
406}
407
408pub type RequestId = NumberOrString;
410
411#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Hash, Eq)]
416#[serde(transparent)]
417#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
418#[expect(clippy::exhaustive_structs, reason = "intentionally exhaustive")]
419pub struct ProgressToken(pub NumberOrString);
420
421#[derive(Debug, Clone, Default)]
432#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
433#[non_exhaustive]
434pub struct Request<M = String, P = JsonObject> {
435 pub method: M,
436 pub params: P,
437 #[cfg_attr(feature = "schemars", schemars(skip))]
442 pub extensions: Extensions,
443}
444
445impl<M: Default, P> Request<M, P> {
446 pub fn new(params: P) -> Self {
447 Self {
448 method: Default::default(),
449 params,
450 extensions: Extensions::default(),
451 }
452 }
453}
454
455impl<M, P> GetExtensions for Request<M, P> {
456 fn extensions(&self) -> &Extensions {
457 &self.extensions
458 }
459 fn extensions_mut(&mut self) -> &mut Extensions {
460 &mut self.extensions
461 }
462}
463
464#[derive(Debug, Clone, Default)]
465#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
466#[expect(clippy::exhaustive_structs, reason = "intentionally exhaustive")]
467pub struct RequestOptionalParam<M = String, P = JsonObject> {
468 pub method: M,
469 pub params: Option<P>,
471 #[cfg_attr(feature = "schemars", schemars(skip))]
476 pub extensions: Extensions,
477}
478
479impl<M: Default, P> RequestOptionalParam<M, P> {
480 pub fn with_param(params: P) -> Self {
481 Self {
482 method: Default::default(),
483 params: Some(params),
484 extensions: Extensions::default(),
485 }
486 }
487}
488
489#[derive(Debug, Clone, Default)]
490#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
491#[expect(clippy::exhaustive_structs, reason = "intentionally exhaustive")]
492pub struct RequestNoParam<M = String> {
493 pub method: M,
494 #[cfg_attr(feature = "schemars", schemars(skip))]
499 pub extensions: Extensions,
500}
501
502impl<M> GetExtensions for RequestNoParam<M> {
503 fn extensions(&self) -> &Extensions {
504 &self.extensions
505 }
506 fn extensions_mut(&mut self) -> &mut Extensions {
507 &mut self.extensions
508 }
509}
510#[derive(Debug, Clone, Default)]
511#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
512#[non_exhaustive]
513pub struct Notification<M = String, P = JsonObject> {
514 pub method: M,
515 pub params: P,
516 #[cfg_attr(feature = "schemars", schemars(skip))]
521 pub extensions: Extensions,
522}
523
524impl<M: Default, P> Notification<M, P> {
525 pub fn new(params: P) -> Self {
526 Self {
527 method: Default::default(),
528 params,
529 extensions: Extensions::default(),
530 }
531 }
532}
533
534#[derive(Debug, Clone, Default)]
535#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
536#[expect(clippy::exhaustive_structs, reason = "intentionally exhaustive")]
537pub struct NotificationNoParam<M = String> {
538 pub method: M,
539 #[cfg_attr(feature = "schemars", schemars(skip))]
544 pub extensions: Extensions,
545}
546
547#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
548#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
549#[expect(clippy::exhaustive_structs, reason = "intentionally exhaustive")]
550pub struct JsonRpcRequest<R = Request> {
551 pub jsonrpc: JsonRpcVersion2_0,
552 pub id: RequestId,
553 #[serde(flatten)]
554 pub request: R,
555}
556
557impl<R> JsonRpcRequest<R> {
558 pub fn new(id: RequestId, request: R) -> Self {
560 Self {
561 jsonrpc: JsonRpcVersion2_0,
562 id,
563 request,
564 }
565 }
566}
567
568type DefaultResponse = JsonObject;
569#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
570#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
571#[expect(clippy::exhaustive_structs, reason = "intentionally exhaustive")]
572pub struct JsonRpcResponse<R = JsonObject> {
573 pub jsonrpc: JsonRpcVersion2_0,
574 pub id: RequestId,
575 pub result: R,
576}
577
578#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
579#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
580#[expect(clippy::exhaustive_structs, reason = "intentionally exhaustive")]
581pub struct JsonRpcError {
582 pub jsonrpc: JsonRpcVersion2_0,
583 #[serde(default, skip_serializing_if = "Option::is_none")]
587 pub id: Option<RequestId>,
588 pub error: ErrorData,
589}
590
591impl JsonRpcError {
592 pub fn new(id: Option<RequestId>, error: ErrorData) -> Self {
594 Self {
595 jsonrpc: JsonRpcVersion2_0,
596 id,
597 error,
598 }
599 }
600}
601
602#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
603#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
604#[expect(clippy::exhaustive_structs, reason = "intentionally exhaustive")]
605pub struct JsonRpcNotification<N = Notification> {
606 pub jsonrpc: JsonRpcVersion2_0,
607 #[serde(flatten)]
608 pub notification: N,
609}
610
611#[derive(Debug, Clone, Copy, Default, Serialize, Deserialize, PartialEq, Eq)]
616#[serde(transparent)]
617#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
618#[expect(clippy::exhaustive_structs, reason = "intentionally exhaustive")]
619pub struct ErrorCode(pub i32);
620
621impl ErrorCode {
622 pub const UNSUPPORTED_PROTOCOL_VERSION: Self = Self(-32022);
624 pub const MISSING_REQUIRED_CLIENT_CAPABILITY: Self = Self(-32021);
626 pub const HEADER_MISMATCH: Self = Self(-32020);
627 pub const RESOURCE_NOT_FOUND: Self = Self(-32002);
628 pub const INVALID_REQUEST: Self = Self(-32600);
629 pub const METHOD_NOT_FOUND: Self = Self(-32601);
630 pub const INVALID_PARAMS: Self = Self(-32602);
631 pub const INTERNAL_ERROR: Self = Self(-32603);
632 pub const PARSE_ERROR: Self = Self(-32700);
633}
634
635#[derive(Default, Debug, Serialize, Deserialize, Clone, PartialEq)]
640#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
641#[expect(clippy::exhaustive_structs, reason = "intentionally exhaustive")]
642pub struct ErrorData {
643 pub code: ErrorCode,
645
646 pub message: Cow<'static, str>,
648
649 #[serde(skip_serializing_if = "Option::is_none")]
652 pub data: Option<Value>,
653}
654
655impl ErrorData {
656 const TRANSPORT_CLOSED_MARKER: &str = "io.modelcontextprotocol/transportClosed";
657
658 pub fn new(
659 code: ErrorCode,
660 message: impl Into<Cow<'static, str>>,
661 data: Option<Value>,
662 ) -> Self {
663 Self {
664 code,
665 message: message.into(),
666 data,
667 }
668 }
669 pub fn resource_not_found(message: impl Into<Cow<'static, str>>, data: Option<Value>) -> Self {
672 Self::new(ErrorCode::RESOURCE_NOT_FOUND, message, data)
673 }
674 pub fn header_mismatch(message: impl Into<Cow<'static, str>>, data: Option<Value>) -> Self {
675 Self::new(ErrorCode::HEADER_MISMATCH, message, data)
676 }
677 pub fn unsupported_protocol_version(
679 requested: ProtocolVersion,
680 supported: &[ProtocolVersion],
681 ) -> Self {
682 Self::new(
683 ErrorCode::UNSUPPORTED_PROTOCOL_VERSION,
684 "Unsupported protocol version",
685 Some(serde_json::json!({
686 "requested": requested,
687 "supported": supported,
688 })),
689 )
690 }
691 pub fn missing_required_client_capability(required: ClientCapabilities) -> Self {
693 Self::new(
694 ErrorCode::MISSING_REQUIRED_CLIENT_CAPABILITY,
695 "Missing required client capability",
696 Some(serde_json::json!({
697 "requiredCapabilities": required,
698 })),
699 )
700 }
701 pub fn parse_error(message: impl Into<Cow<'static, str>>, data: Option<Value>) -> Self {
702 Self::new(ErrorCode::PARSE_ERROR, message, data)
703 }
704 pub fn invalid_request(message: impl Into<Cow<'static, str>>, data: Option<Value>) -> Self {
705 Self::new(ErrorCode::INVALID_REQUEST, message, data)
706 }
707 pub fn method_not_found<M: ConstString>() -> Self {
708 Self::new(ErrorCode::METHOD_NOT_FOUND, M::VALUE, None)
709 }
710 pub fn invalid_params(message: impl Into<Cow<'static, str>>, data: Option<Value>) -> Self {
711 Self::new(ErrorCode::INVALID_PARAMS, message, data)
712 }
713 pub fn internal_error(message: impl Into<Cow<'static, str>>, data: Option<Value>) -> Self {
714 Self::new(ErrorCode::INTERNAL_ERROR, message, data)
715 }
716
717 #[cfg(feature = "transport-streamable-http-client")]
718 pub(crate) fn transport_closed(message: impl Into<Cow<'static, str>>) -> Self {
719 let mut data = JsonObject::new();
720 data.insert(
721 Self::TRANSPORT_CLOSED_MARKER.to_owned(),
722 Value::from(Self::transport_closed_token()),
723 );
724 Self::internal_error(message, Some(Value::Object(data)))
725 }
726
727 pub(crate) fn is_transport_closed(&self) -> bool {
728 self.data
729 .as_ref()
730 .and_then(|data| data.get(Self::TRANSPORT_CLOSED_MARKER))
731 .and_then(Value::as_u64)
732 == Some(Self::transport_closed_token())
733 }
734
735 fn transport_closed_token() -> u64 {
736 static TOKEN: OnceLock<u64> = OnceLock::new();
737 *TOKEN.get_or_init(|| {
738 let mut hasher = RandomState::new().build_hasher();
739 hasher.write(b"rmcp transport-closed marker");
740 hasher.finish()
741 })
742 }
743}
744
745#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
751#[serde(untagged)]
752#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
753#[expect(clippy::exhaustive_enums, reason = "intentionally exhaustive")]
754pub enum JsonRpcMessage<Req = Request, Resp = DefaultResponse, Noti = Notification> {
755 Request(JsonRpcRequest<Req>),
757 Response(JsonRpcResponse<Resp>),
759 Notification(JsonRpcNotification<Noti>),
761 Error(JsonRpcError),
763}
764
765impl<Req, Resp, Not> JsonRpcMessage<Req, Resp, Not> {
766 #[inline]
767 pub const fn request(request: Req, id: RequestId) -> Self {
768 JsonRpcMessage::Request(JsonRpcRequest {
769 jsonrpc: JsonRpcVersion2_0,
770 id,
771 request,
772 })
773 }
774 #[inline]
775 pub const fn response(response: Resp, id: RequestId) -> Self {
776 JsonRpcMessage::Response(JsonRpcResponse {
777 jsonrpc: JsonRpcVersion2_0,
778 id,
779 result: response,
780 })
781 }
782 #[inline]
783 pub const fn error(error: ErrorData, id: Option<RequestId>) -> Self {
784 JsonRpcMessage::Error(JsonRpcError {
785 jsonrpc: JsonRpcVersion2_0,
786 id,
787 error,
788 })
789 }
790 #[inline]
791 pub const fn notification(notification: Not) -> Self {
792 JsonRpcMessage::Notification(JsonRpcNotification {
793 jsonrpc: JsonRpcVersion2_0,
794 notification,
795 })
796 }
797 pub fn into_request(self) -> Option<(Req, RequestId)> {
798 match self {
799 JsonRpcMessage::Request(r) => Some((r.request, r.id)),
800 _ => None,
801 }
802 }
803 pub fn into_response(self) -> Option<(Resp, RequestId)> {
804 match self {
805 JsonRpcMessage::Response(r) => Some((r.result, r.id)),
806 _ => None,
807 }
808 }
809 pub fn into_notification(self) -> Option<Not> {
810 match self {
811 JsonRpcMessage::Notification(n) => Some(n.notification),
812 _ => None,
813 }
814 }
815 pub fn into_error(self) -> Option<(ErrorData, Option<RequestId>)> {
816 match self {
817 JsonRpcMessage::Error(e) => Some((e.error, e.id)),
818 _ => None,
819 }
820 }
821 pub fn into_result(self) -> Option<(Result<Resp, ErrorData>, Option<RequestId>)> {
822 match self {
823 JsonRpcMessage::Response(r) => Some((Ok(r.result), Some(r.id))),
824 JsonRpcMessage::Error(e) => Some((Err(e.error), e.id)),
825
826 _ => None,
827 }
828 }
829}
830
831pub type EmptyResult = EmptyObject;
838
839impl From<()> for EmptyResult {
840 fn from(_value: ()) -> Self {
841 EmptyResult {}
842 }
843}
844
845impl From<EmptyResult> for () {
846 fn from(_value: EmptyResult) {}
847}
848
849#[derive(Debug, Clone, PartialEq, Eq)]
864#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
865pub struct ResultType(Cow<'static, str>);
866
867impl ResultType {
868 pub const COMPLETE: Self = Self(Cow::Borrowed("complete"));
869 pub const INPUT_REQUIRED: Self = Self(Cow::Borrowed("input_required"));
870 pub const TASK: Self = Self(Cow::Borrowed("task"));
872
873 pub fn as_str(&self) -> &str {
874 &self.0
875 }
876
877 pub fn is_input_required(&self) -> bool {
879 self.0 == "input_required"
880 }
881
882 pub fn is_complete(&self) -> bool {
884 self.0 == "complete"
885 }
886
887 pub fn is_task(&self) -> bool {
889 self.0 == "task"
890 }
891}
892
893impl Default for ResultType {
894 fn default() -> Self {
895 Self::COMPLETE
896 }
897}
898
899impl Serialize for ResultType {
900 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
901 where
902 S: serde::Serializer,
903 {
904 self.0.serialize(serializer)
905 }
906}
907
908impl<'de> Deserialize<'de> for ResultType {
909 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
910 where
911 D: serde::Deserializer<'de>,
912 {
913 let s: String = Deserialize::deserialize(deserializer)?;
914 match s.as_str() {
915 "complete" => Ok(Self::COMPLETE),
916 "input_required" => Ok(Self::INPUT_REQUIRED),
917 _ => Ok(Self(Cow::Owned(s))),
918 }
919 }
920}
921
922impl std::fmt::Display for ResultType {
923 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
924 self.0.fmt(f)
925 }
926}
927
928#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
930#[serde(transparent)]
931#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
932#[expect(clippy::exhaustive_structs, reason = "intentionally exhaustive")]
933pub struct CustomResult(pub Value);
934
935impl CustomResult {
936 pub fn new(result: Value) -> Self {
937 Self(result)
938 }
939
940 pub fn result_as<T: DeserializeOwned>(&self) -> Result<T, serde_json::Error> {
942 serde_json::from_value(self.0.clone())
943 }
944}
945
946#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
947#[serde(rename_all = "camelCase")]
948#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
949#[non_exhaustive]
950pub struct CancelledNotificationParam {
951 #[serde(skip_serializing_if = "Option::is_none")]
952 pub request_id: Option<RequestId>,
953 #[serde(skip_serializing_if = "Option::is_none")]
954 pub reason: Option<String>,
955 #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
956 pub meta: Option<NotificationMetaObject>,
957}
958
959impl CancelledNotificationParam {
960 pub fn new(request_id: Option<RequestId>, reason: Option<String>) -> Self {
961 Self {
962 request_id,
963 reason,
964 meta: None,
965 }
966 }
967}
968
969const_string!(CancelledNotificationMethod = "notifications/cancelled");
970
971pub type CancelledNotification =
980 Notification<CancelledNotificationMethod, CancelledNotificationParam>;
981
982#[derive(Debug, Clone)]
987#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
988#[expect(clippy::exhaustive_structs, reason = "intentionally exhaustive")]
989pub struct CustomNotification {
990 pub method: String,
991 pub params: Option<Value>,
992 #[cfg_attr(feature = "schemars", schemars(skip))]
997 pub extensions: Extensions,
998}
999
1000impl CustomNotification {
1001 pub fn new(method: impl Into<String>, params: Option<Value>) -> Self {
1002 Self {
1003 method: method.into(),
1004 params,
1005 extensions: Extensions::default(),
1006 }
1007 }
1008
1009 pub fn params_as<T: DeserializeOwned>(&self) -> Result<Option<T>, serde_json::Error> {
1011 self.params
1012 .as_ref()
1013 .map(|params| serde_json::from_value(params.clone()))
1014 .transpose()
1015 }
1016}
1017
1018#[derive(Debug, Clone)]
1023#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
1024#[expect(clippy::exhaustive_structs, reason = "intentionally exhaustive")]
1025pub struct CustomRequest {
1026 pub method: String,
1027 pub params: Option<Value>,
1028 #[cfg_attr(feature = "schemars", schemars(skip))]
1033 pub extensions: Extensions,
1034}
1035
1036impl CustomRequest {
1037 pub fn new(method: impl Into<String>, params: Option<Value>) -> Self {
1038 Self {
1039 method: method.into(),
1040 params,
1041 extensions: Extensions::default(),
1042 }
1043 }
1044
1045 pub fn params_as<T: DeserializeOwned>(&self) -> Result<Option<T>, serde_json::Error> {
1047 self.params
1048 .as_ref()
1049 .map(|params| serde_json::from_value(params.clone()))
1050 .transpose()
1051 }
1052}
1053
1054const_string!(InitializeResultMethod = "initialize");
1055pub type InitializeRequest = Request<InitializeResultMethod, InitializeRequestParams>;
1058
1059const_string!(InitializedNotificationMethod = "notifications/initialized");
1060pub type InitializedNotification = NotificationNoParam<InitializedNotificationMethod>;
1062
1063#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
1068#[serde(rename_all = "camelCase")]
1069#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
1070#[non_exhaustive]
1071pub struct InitializeRequestParams {
1072 #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
1074 pub meta: Option<RequestMetaObject>,
1075 pub protocol_version: ProtocolVersion,
1077 pub capabilities: ClientCapabilities,
1079 pub client_info: Implementation,
1081}
1082
1083impl InitializeRequestParams {
1084 pub fn new(capabilities: ClientCapabilities, client_info: Implementation) -> Self {
1086 Self {
1087 meta: None,
1088 protocol_version: ProtocolVersion::default(),
1089 capabilities,
1090 client_info,
1091 }
1092 }
1093
1094 pub fn with_protocol_version(mut self, protocol_version: ProtocolVersion) -> Self {
1095 self.protocol_version = protocol_version;
1096 self
1097 }
1098}
1099
1100impl RequestParamsMeta for InitializeRequestParams {
1101 fn meta(&self) -> Option<&RequestMetaObject> {
1102 self.meta.as_ref()
1103 }
1104 fn meta_mut(&mut self) -> &mut Option<RequestMetaObject> {
1105 &mut self.meta
1106 }
1107}
1108
1109#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
1114#[serde(rename_all = "camelCase")]
1115#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
1116#[non_exhaustive]
1117pub struct InitializeResult {
1118 pub protocol_version: ProtocolVersion,
1120 pub capabilities: ServerCapabilities,
1122 pub server_info: Implementation,
1124 #[serde(skip_serializing_if = "Option::is_none")]
1126 pub instructions: Option<String>,
1127 #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
1128 pub meta: Option<MetaObject>,
1129}
1130
1131impl InitializeResult {
1132 pub fn new(capabilities: ServerCapabilities) -> Self {
1134 Self {
1135 protocol_version: ProtocolVersion::default(),
1136 capabilities,
1137 server_info: Implementation::from_build_env(),
1138 instructions: None,
1139 meta: None,
1140 }
1141 }
1142
1143 pub fn with_instructions(mut self, instructions: impl Into<String>) -> Self {
1145 self.instructions = Some(instructions.into());
1146 self
1147 }
1148
1149 pub fn with_server_info(mut self, server_info: Implementation) -> Self {
1151 self.server_info = server_info;
1152 self
1153 }
1154
1155 pub fn with_protocol_version(mut self, protocol_version: ProtocolVersion) -> Self {
1157 self.protocol_version = protocol_version;
1158 self
1159 }
1160}
1161
1162pub type ServerConfig = InitializeResult;
1179
1180pub type ClientConfig = InitializeRequestParams;
1199
1200#[deprecated(note = "use `ServerConfig` instead")]
1206pub type ServerInfo = InitializeResult;
1207
1208#[deprecated(note = "use `ClientConfig` instead")]
1214pub type ClientInfo = InitializeRequestParams;
1215
1216#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
1221#[serde(rename_all = "camelCase")]
1222#[non_exhaustive]
1223pub struct ServerPeerInfo {
1224 pub protocol_version: ProtocolVersion,
1226 pub capabilities: ServerCapabilities,
1228 #[serde(skip_serializing_if = "Option::is_none")]
1230 pub server_info: Option<Implementation>,
1231 #[serde(skip_serializing_if = "Option::is_none")]
1233 pub instructions: Option<String>,
1234 #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
1236 pub meta: Option<MetaObject>,
1237}
1238
1239impl ServerPeerInfo {
1240 pub fn new(protocol_version: ProtocolVersion, capabilities: ServerCapabilities) -> Self {
1242 Self {
1243 protocol_version,
1244 capabilities,
1245 server_info: None,
1246 instructions: None,
1247 meta: None,
1248 }
1249 }
1250
1251 pub fn with_server_info(mut self, server_info: Implementation) -> Self {
1253 self.server_info = Some(server_info);
1254 self
1255 }
1256
1257 pub fn with_instructions(mut self, instructions: impl Into<String>) -> Self {
1259 self.instructions = Some(instructions.into());
1260 self
1261 }
1262}
1263
1264impl From<InitializeResult> for ServerPeerInfo {
1265 fn from(result: InitializeResult) -> Self {
1266 Self {
1267 protocol_version: result.protocol_version,
1268 capabilities: result.capabilities,
1269 server_info: Some(result.server_info),
1270 instructions: result.instructions,
1271 meta: result.meta,
1272 }
1273 }
1274}
1275
1276const_string!(DiscoverRequestMethod = "server/discover");
1277
1278#[derive(Debug, Serialize, Deserialize, Clone, Copy, PartialEq, Eq, Default)]
1280#[serde(deny_unknown_fields)]
1281#[expect(clippy::exhaustive_structs, reason = "intentionally exhaustive")]
1282pub struct DiscoverRequestParams {}
1283
1284#[cfg(feature = "schemars")]
1285#[derive(schemars::JsonSchema)]
1286#[expect(dead_code, reason = "schema-only representation of request parameters")]
1287struct DiscoverRequestParamsSchema {
1288 #[schemars(rename = "_meta")]
1289 meta: RequestMetaObject,
1290}
1291
1292#[cfg(feature = "schemars")]
1293impl schemars::JsonSchema for DiscoverRequestParams {
1294 fn schema_name() -> Cow<'static, str> {
1295 Cow::Borrowed("DiscoverRequestParams")
1296 }
1297
1298 fn json_schema(generator: &mut schemars::SchemaGenerator) -> schemars::Schema {
1299 DiscoverRequestParamsSchema::json_schema(generator)
1300 }
1301}
1302
1303pub type DiscoverRequest = Request<DiscoverRequestMethod, DiscoverRequestParams>;
1305
1306#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
1308#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
1309#[serde(rename_all = "camelCase")]
1310#[non_exhaustive]
1311pub struct DiscoverResult {
1312 pub result_type: ResultType,
1314 pub supported_versions: Vec<ProtocolVersion>,
1316 pub capabilities: ServerCapabilities,
1318 #[serde(skip_serializing_if = "Option::is_none")]
1320 pub instructions: Option<String>,
1321 pub ttl_ms: u64,
1323 pub cache_scope: CacheScope,
1325 #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
1327 pub meta: Option<MetaObject>,
1328}
1329
1330const SERVER_INFO_META_KEY: &str = "io.modelcontextprotocol/serverInfo";
1331
1332fn server_info_from_meta(meta: &MetaObject) -> Option<Implementation> {
1333 meta.get(SERVER_INFO_META_KEY)
1334 .and_then(|value| serde_json::from_value(value.clone()).ok())
1335}
1336
1337fn set_server_info_on_meta(meta: &mut MetaObject, server_info: Implementation) {
1338 let server_info =
1339 serde_json::to_value(server_info).expect("Implementation serialization cannot fail");
1340 meta.insert(SERVER_INFO_META_KEY.to_owned(), server_info);
1341}
1342
1343impl DiscoverResult {
1344 pub fn new(supported_versions: Vec<ProtocolVersion>, capabilities: ServerCapabilities) -> Self {
1346 Self {
1347 result_type: ResultType::COMPLETE,
1348 supported_versions,
1349 capabilities,
1350 instructions: None,
1351 ttl_ms: 0,
1352 cache_scope: CacheScope::Private,
1353 meta: None,
1354 }
1355 }
1356
1357 pub fn server_info(&self) -> Option<Implementation> {
1359 server_info_from_meta(self.meta.as_ref()?)
1360 }
1361
1362 pub fn set_server_info(&mut self, server_info: Implementation) {
1364 set_server_info_on_meta(self.meta.get_or_insert_default(), server_info);
1365 }
1366
1367 pub fn with_server_info(mut self, server_info: Implementation) -> Self {
1369 self.set_server_info(server_info);
1370 self
1371 }
1372
1373 pub fn from_server_info(
1375 supported_versions: Vec<ProtocolVersion>,
1376 server_config: ServerConfig,
1377 ) -> Self {
1378 let ServerConfig {
1379 capabilities,
1380 server_info,
1381 instructions,
1382 meta,
1383 ..
1384 } = server_config;
1385 let mut result = Self {
1386 result_type: ResultType::COMPLETE,
1387 supported_versions,
1388 capabilities,
1389 instructions,
1390 ttl_ms: 0,
1391 cache_scope: CacheScope::Private,
1392 meta,
1393 };
1394 result.set_server_info(server_info);
1395 result
1396 }
1397
1398 pub fn with_ttl_ms(mut self, ttl_ms: u64) -> Self {
1400 self.ttl_ms = ttl_ms;
1401 self
1402 }
1403
1404 pub fn with_cache_scope(mut self, cache_scope: CacheScope) -> Self {
1406 self.cache_scope = cache_scope;
1407 self
1408 }
1409}
1410
1411impl ServerPeerInfo {
1412 pub fn from_discover_result(protocol_version: ProtocolVersion, result: DiscoverResult) -> Self {
1414 let server_info = result.server_info();
1415 Self {
1416 protocol_version,
1417 capabilities: result.capabilities,
1418 server_info,
1419 instructions: result.instructions,
1420 meta: result.meta,
1421 }
1422 }
1423}
1424
1425#[allow(clippy::derivable_impls)]
1426impl Default for InitializeResult {
1427 fn default() -> Self {
1428 InitializeResult {
1429 protocol_version: ProtocolVersion::default(),
1430 capabilities: ServerCapabilities::default(),
1431 server_info: Implementation::from_build_env(),
1432 instructions: None,
1433 meta: None,
1434 }
1435 }
1436}
1437
1438#[allow(clippy::derivable_impls)]
1439impl Default for InitializeRequestParams {
1440 fn default() -> Self {
1441 InitializeRequestParams {
1442 meta: None,
1443 protocol_version: ProtocolVersion::default(),
1444 capabilities: ClientCapabilities::default(),
1445 client_info: Implementation::from_build_env(),
1446 }
1447 }
1448}
1449
1450#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq, Hash, Copy)]
1452#[serde(rename_all = "lowercase")] #[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
1454#[non_exhaustive]
1455pub enum IconTheme {
1456 Light,
1458 Dark,
1460}
1461
1462#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
1472#[serde(rename_all = "camelCase")]
1473#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
1474#[non_exhaustive]
1475pub struct Icon {
1476 pub src: String,
1478 #[serde(skip_serializing_if = "Option::is_none")]
1480 pub mime_type: Option<String>,
1481 #[serde(skip_serializing_if = "Option::is_none")]
1483 pub sizes: Option<Vec<String>>,
1484 #[serde(skip_serializing_if = "Option::is_none")]
1487 pub theme: Option<IconTheme>,
1488}
1489
1490impl Icon {
1491 pub fn new(src: impl Into<String>) -> Self {
1493 Self {
1494 src: src.into(),
1495 mime_type: None,
1496 sizes: None,
1497 theme: None,
1498 }
1499 }
1500
1501 pub fn with_mime_type(mut self, mime_type: impl Into<String>) -> Self {
1503 self.mime_type = Some(mime_type.into());
1504 self
1505 }
1506
1507 pub fn with_sizes(mut self, sizes: Vec<String>) -> Self {
1509 self.sizes = Some(sizes);
1510 self
1511 }
1512
1513 pub fn with_theme(mut self, theme: IconTheme) -> Self {
1515 self.theme = Some(theme);
1516 self
1517 }
1518}
1519
1520#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
1521#[serde(rename_all = "camelCase")]
1522#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
1523#[non_exhaustive]
1524pub struct Implementation {
1525 pub name: String,
1526 #[serde(skip_serializing_if = "Option::is_none")]
1527 pub title: Option<String>,
1528 pub version: String,
1529 #[serde(skip_serializing_if = "Option::is_none")]
1530 pub description: Option<String>,
1531 #[serde(skip_serializing_if = "Option::is_none")]
1532 pub icons: Option<Vec<Icon>>,
1533 #[serde(skip_serializing_if = "Option::is_none")]
1534 pub website_url: Option<String>,
1535}
1536
1537impl Default for Implementation {
1538 fn default() -> Self {
1539 Self::from_build_env()
1540 }
1541}
1542
1543impl Implementation {
1544 pub fn new(name: impl Into<String>, version: impl Into<String>) -> Self {
1546 Self {
1547 name: name.into(),
1548 title: None,
1549 version: version.into(),
1550 description: None,
1551 icons: None,
1552 website_url: None,
1553 }
1554 }
1555
1556 pub fn from_build_env() -> Self {
1557 Implementation {
1558 name: env!("CARGO_CRATE_NAME").to_owned(),
1559 title: None,
1560 version: env!("CARGO_PKG_VERSION").to_owned(),
1561 description: None,
1562 icons: None,
1563 website_url: None,
1564 }
1565 }
1566
1567 pub fn with_title(mut self, title: impl Into<String>) -> Self {
1569 self.title = Some(title.into());
1570 self
1571 }
1572
1573 pub fn with_description(mut self, description: impl Into<String>) -> Self {
1575 self.description = Some(description.into());
1576 self
1577 }
1578
1579 pub fn with_icons(mut self, icons: Vec<Icon>) -> Self {
1581 self.icons = Some(icons);
1582 self
1583 }
1584
1585 pub fn with_website_url(mut self, website_url: impl Into<String>) -> Self {
1587 self.website_url = Some(website_url.into());
1588 self
1589 }
1590}
1591
1592#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Default)]
1593#[serde(rename_all = "camelCase")]
1594#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
1595#[non_exhaustive]
1596pub struct PaginatedRequestParams {
1597 #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
1599 pub meta: Option<RequestMetaObject>,
1600 #[serde(skip_serializing_if = "Option::is_none")]
1601 pub cursor: Option<String>,
1602}
1603
1604impl PaginatedRequestParams {
1605 pub fn with_cursor(mut self, cursor: Option<String>) -> Self {
1606 self.cursor = cursor;
1607 self
1608 }
1609}
1610
1611impl RequestParamsMeta for PaginatedRequestParams {
1612 fn meta(&self) -> Option<&RequestMetaObject> {
1613 self.meta.as_ref()
1614 }
1615 fn meta_mut(&mut self) -> &mut Option<RequestMetaObject> {
1616 &mut self.meta
1617 }
1618}
1619
1620const_string!(PingRequestMethod = "ping");
1625pub type PingRequest = RequestNoParam<PingRequestMethod>;
1626
1627const_string!(ProgressNotificationMethod = "notifications/progress");
1628#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
1629#[serde(rename_all = "camelCase")]
1630#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
1631#[non_exhaustive]
1632pub struct ProgressNotificationParam {
1633 pub progress_token: ProgressToken,
1634 #[serde(deserialize_with = "serde_impl::json_float::f64")]
1636 pub progress: f64,
1637 #[serde(
1639 default,
1640 deserialize_with = "serde_impl::json_float::option_f64",
1641 skip_serializing_if = "Option::is_none"
1642 )]
1643 pub total: Option<f64>,
1644 #[serde(skip_serializing_if = "Option::is_none")]
1646 pub message: Option<String>,
1647 #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
1648 pub meta: Option<NotificationMetaObject>,
1649}
1650
1651impl ProgressNotificationParam {
1652 pub fn new(progress_token: ProgressToken, progress: f64) -> Self {
1654 Self {
1655 progress_token,
1656 progress,
1657 total: None,
1658 message: None,
1659 meta: None,
1660 }
1661 }
1662
1663 pub fn with_total(mut self, total: f64) -> Self {
1665 self.total = Some(total);
1666 self
1667 }
1668
1669 pub fn with_message(mut self, message: impl Into<String>) -> Self {
1671 self.message = Some(message.into());
1672 self
1673 }
1674}
1675
1676pub type ProgressNotification = Notification<ProgressNotificationMethod, ProgressNotificationParam>;
1677
1678pub type Cursor = String;
1679
1680#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
1684#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
1685#[serde(rename_all = "lowercase")]
1686#[non_exhaustive]
1687pub enum CacheScope {
1688 #[default]
1690 Public,
1691 Private,
1693}
1694
1695fn deserialize_ttl_ms<'de, D>(deserializer: D) -> Result<Option<u64>, D::Error>
1701where
1702 D: serde::Deserializer<'de>,
1703{
1704 let value = Option::<i64>::deserialize(deserializer)?;
1705 Ok(value.map(|ttl_ms| ttl_ms.max(0) as u64))
1706}
1707
1708fn deserialize_cache_scope<'de, D>(deserializer: D) -> Result<Option<CacheScope>, D::Error>
1716where
1717 D: serde::Deserializer<'de>,
1718{
1719 let value = Option::<Value>::deserialize(deserializer)?;
1720 match value {
1721 None | Some(Value::Null) => Ok(None),
1722 Some(Value::String(s)) if s.is_empty() => Ok(None),
1723 Some(value) => CacheScope::deserialize(value)
1724 .map(Some)
1725 .map_err(serde::de::Error::custom),
1726 }
1727}
1728
1729macro_rules! paginated_result {
1730 ($t:ident {
1731 $i_item: ident: $t_item: ty
1732 }) => {
1733 #[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
1734 #[serde(rename_all = "camelCase")]
1735 #[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
1736 #[expect(clippy::exhaustive_structs, reason = "intentionally exhaustive")]
1737 pub struct $t {
1738 #[serde(default, skip_serializing_if = "Option::is_none")]
1749 pub result_type: Option<ResultType>,
1750 #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
1751 pub meta: Option<MetaObject>,
1752 #[serde(default, skip_serializing_if = "Option::is_none")]
1753 pub next_cursor: Option<Cursor>,
1754 #[serde(
1758 default,
1759 deserialize_with = "deserialize_ttl_ms",
1760 skip_serializing_if = "Option::is_none"
1761 )]
1762 pub ttl_ms: Option<u64>,
1763 #[serde(
1767 default,
1768 deserialize_with = "deserialize_cache_scope",
1769 skip_serializing_if = "Option::is_none"
1770 )]
1771 pub cache_scope: Option<CacheScope>,
1772 pub $i_item: $t_item,
1773 }
1774
1775 impl Default for $t {
1776 fn default() -> Self {
1777 Self::with_all_items(Default::default())
1778 }
1779 }
1780
1781 impl $t {
1782 pub fn with_all_items(items: $t_item) -> Self {
1783 Self {
1784 result_type: Some(ResultType::COMPLETE),
1785 meta: None,
1786 next_cursor: None,
1787 ttl_ms: None,
1788 cache_scope: None,
1789 $i_item: items,
1790 }
1791 }
1792
1793 pub fn with_ttl_ms(mut self, ttl_ms: u64) -> Self {
1795 self.ttl_ms = Some(ttl_ms);
1796 self
1797 }
1798
1799 pub fn with_cache_scope(mut self, cache_scope: CacheScope) -> Self {
1801 self.cache_scope = Some(cache_scope);
1802 self
1803 }
1804 }
1805 };
1806}
1807
1808const_string!(ListResourcesRequestMethod = "resources/list");
1813pub type ListResourcesRequest =
1815 RequestOptionalParam<ListResourcesRequestMethod, PaginatedRequestParams>;
1816
1817paginated_result!(ListResourcesResult {
1818 resources: Vec<Resource>
1819});
1820
1821const_string!(ListResourceTemplatesRequestMethod = "resources/templates/list");
1822pub type ListResourceTemplatesRequest =
1824 RequestOptionalParam<ListResourceTemplatesRequestMethod, PaginatedRequestParams>;
1825
1826paginated_result!(ListResourceTemplatesResult {
1827 resource_templates: Vec<ResourceTemplate>
1828});
1829
1830const_string!(ReadResourceRequestMethod = "resources/read");
1831#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
1833#[serde(rename_all = "camelCase")]
1834#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
1835#[non_exhaustive]
1836pub struct ReadResourceRequestParams {
1837 #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
1839 pub meta: Option<RequestMetaObject>,
1840 pub uri: String,
1842 #[serde(skip_serializing_if = "Option::is_none")]
1845 pub input_responses: Option<InputResponses>,
1846 #[serde(skip_serializing_if = "Option::is_none")]
1848 pub request_state: Option<String>,
1849}
1850
1851impl ReadResourceRequestParams {
1852 pub fn new(uri: impl Into<String>) -> Self {
1854 Self {
1855 meta: None,
1856 uri: uri.into(),
1857 input_responses: None,
1858 request_state: None,
1859 }
1860 }
1861
1862 pub fn with_meta(mut self, meta: RequestMetaObject) -> Self {
1864 self.meta = Some(meta);
1865 self
1866 }
1867
1868 pub fn with_input_responses(mut self, input_responses: InputResponses) -> Self {
1870 self.input_responses = Some(input_responses);
1871 self
1872 }
1873
1874 pub fn with_request_state(mut self, request_state: impl Into<String>) -> Self {
1876 self.request_state = Some(request_state.into());
1877 self
1878 }
1879}
1880
1881impl RequestParamsMeta for ReadResourceRequestParams {
1882 fn meta(&self) -> Option<&RequestMetaObject> {
1883 self.meta.as_ref()
1884 }
1885 fn meta_mut(&mut self) -> &mut Option<RequestMetaObject> {
1886 &mut self.meta
1887 }
1888}
1889
1890#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
1892#[serde(rename_all = "camelCase")]
1893#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
1894#[non_exhaustive]
1895pub struct ReadResourceResult {
1896 #[serde(default, skip_serializing_if = "Option::is_none")]
1907 pub result_type: Option<ResultType>,
1908 #[serde(
1912 default,
1913 deserialize_with = "deserialize_ttl_ms",
1914 skip_serializing_if = "Option::is_none"
1915 )]
1916 pub ttl_ms: Option<u64>,
1917 #[serde(
1921 default,
1922 deserialize_with = "deserialize_cache_scope",
1923 skip_serializing_if = "Option::is_none"
1924 )]
1925 pub cache_scope: Option<CacheScope>,
1926 pub contents: Vec<ResourceContents>,
1928 #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
1929 pub meta: Option<MetaObject>,
1930}
1931
1932impl ReadResourceResult {
1933 pub fn new(contents: Vec<ResourceContents>) -> Self {
1935 Self {
1936 result_type: Some(ResultType::COMPLETE),
1937 ttl_ms: None,
1938 cache_scope: None,
1939 contents,
1940 meta: None,
1941 }
1942 }
1943
1944 pub fn with_ttl_ms(mut self, ttl_ms: u64) -> Self {
1946 self.ttl_ms = Some(ttl_ms);
1947 self
1948 }
1949
1950 pub fn with_cache_scope(mut self, cache_scope: CacheScope) -> Self {
1952 self.cache_scope = Some(cache_scope);
1953 self
1954 }
1955}
1956
1957pub type ReadResourceRequest = Request<ReadResourceRequestMethod, ReadResourceRequestParams>;
1959
1960const_string!(ResourceListChangedNotificationMethod = "notifications/resources/list_changed");
1961pub type ResourceListChangedNotification =
1963 NotificationNoParam<ResourceListChangedNotificationMethod>;
1964
1965const_string!(SubscribeRequestMethod = "resources/subscribe");
1966#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
1968#[serde(rename_all = "camelCase")]
1969#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
1970#[non_exhaustive]
1971pub struct SubscribeRequestParams {
1972 #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
1974 pub meta: Option<RequestMetaObject>,
1975 pub uri: String,
1977}
1978
1979impl SubscribeRequestParams {
1980 pub fn new(uri: impl Into<String>) -> Self {
1982 Self {
1983 meta: None,
1984 uri: uri.into(),
1985 }
1986 }
1987}
1988
1989impl RequestParamsMeta for SubscribeRequestParams {
1990 fn meta(&self) -> Option<&RequestMetaObject> {
1991 self.meta.as_ref()
1992 }
1993 fn meta_mut(&mut self) -> &mut Option<RequestMetaObject> {
1994 &mut self.meta
1995 }
1996}
1997
1998#[deprecated(
2000 note = "resources/subscribe is legacy-only; use subscriptions/listen for protocol version 2026-07-28"
2001)]
2002pub type SubscribeRequest = Request<SubscribeRequestMethod, SubscribeRequestParams>;
2003
2004const_string!(UnsubscribeRequestMethod = "resources/unsubscribe");
2005#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
2007#[serde(rename_all = "camelCase")]
2008#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
2009#[non_exhaustive]
2010pub struct UnsubscribeRequestParams {
2011 #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
2013 pub meta: Option<RequestMetaObject>,
2014 pub uri: String,
2016}
2017
2018impl UnsubscribeRequestParams {
2019 pub fn new(uri: impl Into<String>) -> Self {
2021 Self {
2022 meta: None,
2023 uri: uri.into(),
2024 }
2025 }
2026}
2027
2028impl RequestParamsMeta for UnsubscribeRequestParams {
2029 fn meta(&self) -> Option<&RequestMetaObject> {
2030 self.meta.as_ref()
2031 }
2032 fn meta_mut(&mut self) -> &mut Option<RequestMetaObject> {
2033 &mut self.meta
2034 }
2035}
2036
2037#[deprecated(
2039 note = "resources/unsubscribe is legacy-only; cancel the subscriptions/listen request for protocol version 2026-07-28"
2040)]
2041pub type UnsubscribeRequest = Request<UnsubscribeRequestMethod, UnsubscribeRequestParams>;
2042
2043const_string!(ResourceUpdatedNotificationMethod = "notifications/resources/updated");
2044#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
2046#[serde(rename_all = "camelCase")]
2047#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
2048#[non_exhaustive]
2049pub struct ResourceUpdatedNotificationParam {
2050 pub uri: String,
2052 #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
2053 pub meta: Option<NotificationMetaObject>,
2054}
2055
2056impl ResourceUpdatedNotificationParam {
2057 pub fn new(uri: impl Into<String>) -> Self {
2059 Self {
2060 uri: uri.into(),
2061 meta: None,
2062 }
2063 }
2064}
2065
2066pub type ResourceUpdatedNotification =
2068 Notification<ResourceUpdatedNotificationMethod, ResourceUpdatedNotificationParam>;
2069
2070#[derive(Debug, Default, Serialize, Deserialize, Clone, PartialEq, Eq)]
2076#[serde(rename_all = "camelCase")]
2077#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
2078#[non_exhaustive]
2079pub struct SubscriptionFilter {
2080 #[serde(default, skip_serializing_if = "Option::is_none")]
2081 #[cfg_attr(feature = "schemars", schemars(with = "bool"))]
2082 pub tools_list_changed: Option<bool>,
2083 #[serde(default, skip_serializing_if = "Option::is_none")]
2084 #[cfg_attr(feature = "schemars", schemars(with = "bool"))]
2085 pub prompts_list_changed: Option<bool>,
2086 #[serde(default, skip_serializing_if = "Option::is_none")]
2087 #[cfg_attr(feature = "schemars", schemars(with = "bool"))]
2088 pub resources_list_changed: Option<bool>,
2089 #[serde(default, skip_serializing_if = "Option::is_none")]
2090 #[cfg_attr(feature = "schemars", schemars(with = "Vec<String>"))]
2091 pub resource_subscriptions: Option<Vec<String>>,
2092}
2093
2094impl SubscriptionFilter {
2095 pub fn new() -> Self {
2097 Self::default()
2098 }
2099
2100 pub fn builder() -> SubscriptionFilterBuilder {
2102 SubscriptionFilterBuilder::default()
2103 }
2104
2105 pub fn intersection(&self, other: &Self) -> Self {
2107 let resource_subscriptions = self
2108 .resource_subscriptions
2109 .as_ref()
2110 .and_then(|requested| {
2111 other.resource_subscriptions.as_ref().map(|accepted| {
2112 requested
2113 .iter()
2114 .filter(|uri| accepted.contains(uri))
2115 .cloned()
2116 .collect()
2117 })
2118 })
2119 .filter(|uris: &Vec<String>| !uris.is_empty());
2120 Self {
2121 tools_list_changed: (self.tools_list_changed == Some(true)
2122 && other.tools_list_changed == Some(true))
2123 .then_some(true),
2124 prompts_list_changed: (self.prompts_list_changed == Some(true)
2125 && other.prompts_list_changed == Some(true))
2126 .then_some(true),
2127 resources_list_changed: (self.resources_list_changed == Some(true)
2128 && other.resources_list_changed == Some(true))
2129 .then_some(true),
2130 resource_subscriptions,
2131 }
2132 }
2133
2134 pub fn is_subset_of(&self, other: &Self) -> bool {
2136 let booleans_are_subset = [
2137 (self.tools_list_changed, other.tools_list_changed),
2138 (self.prompts_list_changed, other.prompts_list_changed),
2139 (self.resources_list_changed, other.resources_list_changed),
2140 ]
2141 .into_iter()
2142 .all(|(accepted, requested)| accepted != Some(true) || requested == Some(true));
2143 let resources_are_subset = self.resource_subscriptions.as_ref().is_none_or(|accepted| {
2144 accepted.iter().all(|uri| {
2145 other
2146 .resource_subscriptions
2147 .as_ref()
2148 .is_some_and(|requested| requested.contains(uri))
2149 })
2150 });
2151 booleans_are_subset && resources_are_subset
2152 }
2153
2154 pub fn supported_by(&self, capabilities: &ServerCapabilities) -> Self {
2156 Self {
2157 tools_list_changed: (self.tools_list_changed == Some(true)
2158 && capabilities
2159 .tools
2160 .as_ref()
2161 .is_some_and(|tools| tools.list_changed == Some(true)))
2162 .then_some(true),
2163 prompts_list_changed: (self.prompts_list_changed == Some(true)
2164 && capabilities
2165 .prompts
2166 .as_ref()
2167 .is_some_and(|prompts| prompts.list_changed == Some(true)))
2168 .then_some(true),
2169 resources_list_changed: (self.resources_list_changed == Some(true)
2170 && capabilities
2171 .resources
2172 .as_ref()
2173 .is_some_and(|resources| resources.list_changed == Some(true)))
2174 .then_some(true),
2175 resource_subscriptions: capabilities
2176 .resources
2177 .as_ref()
2178 .is_some_and(|resources| resources.subscribe == Some(true))
2179 .then(|| self.resource_subscriptions.clone())
2180 .flatten(),
2181 }
2182 }
2183}
2184
2185#[derive(Debug, Default)]
2187#[non_exhaustive]
2188pub struct SubscriptionFilterBuilder {
2189 filter: SubscriptionFilter,
2190}
2191
2192impl SubscriptionFilterBuilder {
2193 pub fn tools_list_changed(mut self) -> Self {
2195 self.filter.tools_list_changed = Some(true);
2196 self
2197 }
2198
2199 pub fn prompts_list_changed(mut self) -> Self {
2201 self.filter.prompts_list_changed = Some(true);
2202 self
2203 }
2204
2205 pub fn resources_list_changed(mut self) -> Self {
2207 self.filter.resources_list_changed = Some(true);
2208 self
2209 }
2210
2211 pub fn resource_subscriptions(
2213 mut self,
2214 uris: impl IntoIterator<Item = impl Into<String>>,
2215 ) -> Self {
2216 self.filter.resource_subscriptions = Some(uris.into_iter().map(Into::into).collect());
2217 self
2218 }
2219
2220 pub fn resource_subscription(mut self, uri: impl Into<String>) -> Self {
2222 self.filter
2223 .resource_subscriptions
2224 .get_or_insert_default()
2225 .push(uri.into());
2226 self
2227 }
2228
2229 pub fn build(self) -> SubscriptionFilter {
2231 self.filter
2232 }
2233}
2234
2235const_string!(SubscriptionsListenRequestMethod = "subscriptions/listen");
2236
2237#[cfg(feature = "schemars")]
2238fn subscriptions_listen_request_meta_schema(
2239 generator: &mut schemars::SchemaGenerator,
2240) -> schemars::Schema {
2241 let progress_token = generator.subschema_for::<ProgressToken>();
2242 let client_info = generator.subschema_for::<Implementation>();
2243 let client_capabilities = generator.subschema_for::<ClientCapabilities>();
2244 let log_level = generator.subschema_for::<LoggingLevel>();
2245 schemars::json_schema!({
2246 "type": "object",
2247 "properties": {
2248 "progressToken": progress_token,
2249 "io.modelcontextprotocol/protocolVersion": {
2250 "type": "string",
2251 },
2252 "io.modelcontextprotocol/clientInfo": client_info,
2253 "io.modelcontextprotocol/clientCapabilities": client_capabilities,
2254 "io.modelcontextprotocol/logLevel": log_level,
2255 },
2256 "required": RequestMetaObject::DRAFT_REQUIRED_KEYS,
2257 "additionalProperties": true,
2258 })
2259}
2260
2261#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
2263#[serde(rename_all = "camelCase")]
2264#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
2265#[non_exhaustive]
2266pub struct SubscriptionsListenRequestParams {
2267 #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
2269 #[cfg_attr(
2270 feature = "schemars",
2271 schemars(required, schema_with = "subscriptions_listen_request_meta_schema")
2272 )]
2273 pub meta: Option<RequestMetaObject>,
2274 pub notifications: SubscriptionFilter,
2276}
2277
2278impl SubscriptionsListenRequestParams {
2279 pub fn new(notifications: SubscriptionFilter) -> Self {
2281 Self {
2282 meta: None,
2283 notifications,
2284 }
2285 }
2286
2287 pub fn with_meta(mut self, meta: RequestMetaObject) -> Self {
2289 self.meta = Some(meta);
2290 self
2291 }
2292}
2293
2294impl RequestParamsMeta for SubscriptionsListenRequestParams {
2295 fn meta(&self) -> Option<&RequestMetaObject> {
2296 self.meta.as_ref()
2297 }
2298
2299 fn meta_mut(&mut self) -> &mut Option<RequestMetaObject> {
2300 &mut self.meta
2301 }
2302}
2303
2304pub type SubscriptionsListenRequest =
2306 Request<SubscriptionsListenRequestMethod, SubscriptionsListenRequestParams>;
2307
2308const SUBSCRIPTION_ID_META_KEY: &str = "io.modelcontextprotocol/subscriptionId";
2309
2310#[derive(Debug, Serialize, Clone, PartialEq)]
2312#[serde(transparent)]
2313#[non_exhaustive]
2314pub struct SubscriptionsListenResultMeta(MetaObject);
2315
2316impl SubscriptionsListenResultMeta {
2317 pub fn new(subscription_id: RequestId) -> Self {
2319 let mut meta = MetaObject::new();
2320 meta.insert(
2321 SUBSCRIPTION_ID_META_KEY.to_owned(),
2322 subscription_id.into_json_value(),
2323 );
2324 Self(meta)
2325 }
2326
2327 pub fn subscription_id(&self) -> Option<RequestId> {
2329 self.0
2330 .get(SUBSCRIPTION_ID_META_KEY)
2331 .and_then(|value| RequestId::deserialize(value).ok())
2332 }
2333
2334 pub fn set_subscription_id(&mut self, subscription_id: RequestId) {
2336 self.0.insert(
2337 SUBSCRIPTION_ID_META_KEY.to_owned(),
2338 subscription_id.into_json_value(),
2339 );
2340 }
2341
2342 pub fn server_info(&self) -> Option<Implementation> {
2344 server_info_from_meta(&self.0)
2345 }
2346
2347 pub fn set_server_info(&mut self, server_info: Implementation) {
2349 set_server_info_on_meta(&mut self.0, server_info);
2350 }
2351}
2352
2353impl<'de> Deserialize<'de> for SubscriptionsListenResultMeta {
2354 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
2355 where
2356 D: serde::Deserializer<'de>,
2357 {
2358 let meta = MetaObject::deserialize(deserializer)?;
2359 let Some(value) = meta.get(SUBSCRIPTION_ID_META_KEY) else {
2360 return Err(serde::de::Error::missing_field(SUBSCRIPTION_ID_META_KEY));
2361 };
2362 RequestId::deserialize(value).map_err(serde::de::Error::custom)?;
2363 Ok(Self(meta))
2364 }
2365}
2366
2367impl std::ops::Deref for SubscriptionsListenResultMeta {
2368 type Target = MetaObject;
2369
2370 fn deref(&self) -> &Self::Target {
2371 &self.0
2372 }
2373}
2374
2375impl std::ops::DerefMut for SubscriptionsListenResultMeta {
2376 fn deref_mut(&mut self) -> &mut Self::Target {
2377 &mut self.0
2378 }
2379}
2380
2381#[cfg(feature = "schemars")]
2382impl schemars::JsonSchema for SubscriptionsListenResultMeta {
2383 fn schema_name() -> Cow<'static, str> {
2384 Cow::Borrowed("SubscriptionsListenResultMeta")
2385 }
2386
2387 fn json_schema(generator: &mut schemars::SchemaGenerator) -> schemars::Schema {
2388 let subscription_id = generator.subschema_for::<RequestId>();
2389 let server_info = generator.subschema_for::<Implementation>();
2390 schemars::json_schema!({
2391 "type": "object",
2392 "properties": {
2393 "io.modelcontextprotocol/serverInfo": {
2394 "description": "Identifies the server software producing the response. Servers SHOULD include this field on every response unless specifically configured not to do so.",
2395 "allOf": [server_info],
2396 },
2397 "io.modelcontextprotocol/subscriptionId": subscription_id,
2398 },
2399 "required": ["io.modelcontextprotocol/subscriptionId"],
2400 "additionalProperties": true,
2401 })
2402 }
2403}
2404
2405#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
2407#[serde(rename_all = "camelCase")]
2408#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
2409#[non_exhaustive]
2410pub struct SubscriptionsListenResult {
2411 pub result_type: ResultType,
2412 #[serde(rename = "_meta")]
2413 pub meta: SubscriptionsListenResultMeta,
2414}
2415
2416impl SubscriptionsListenResult {
2417 pub fn new(meta: SubscriptionsListenResultMeta) -> Self {
2419 Self {
2420 result_type: ResultType::COMPLETE,
2421 meta,
2422 }
2423 }
2424
2425 pub fn complete(subscription_id: RequestId) -> Self {
2427 Self::new(SubscriptionsListenResultMeta::new(subscription_id))
2428 }
2429}
2430
2431const_string!(
2432 SubscriptionsAcknowledgedNotificationMethod = "notifications/subscriptions/acknowledged"
2433);
2434
2435#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
2437#[serde(rename_all = "camelCase")]
2438#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
2439#[non_exhaustive]
2440pub struct SubscriptionsAcknowledgedNotificationParams {
2441 #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
2442 #[cfg_attr(feature = "schemars", schemars(with = "NotificationMetaObject"))]
2443 pub meta: Option<NotificationMetaObject>,
2444 pub notifications: SubscriptionFilter,
2445}
2446
2447impl SubscriptionsAcknowledgedNotificationParams {
2448 pub fn new(notifications: SubscriptionFilter) -> Self {
2450 Self {
2451 meta: None,
2452 notifications,
2453 }
2454 }
2455
2456 pub fn with_meta(mut self, meta: NotificationMetaObject) -> Self {
2458 self.meta = Some(meta);
2459 self
2460 }
2461}
2462
2463pub type SubscriptionsAcknowledgedNotification = Notification<
2465 SubscriptionsAcknowledgedNotificationMethod,
2466 SubscriptionsAcknowledgedNotificationParams,
2467>;
2468
2469const_string!(ListPromptsRequestMethod = "prompts/list");
2474pub type ListPromptsRequest =
2476 RequestOptionalParam<ListPromptsRequestMethod, PaginatedRequestParams>;
2477
2478paginated_result!(ListPromptsResult {
2479 prompts: Vec<Prompt>
2480});
2481
2482const_string!(GetPromptRequestMethod = "prompts/get");
2483#[derive(Default, Debug, Serialize, Deserialize, Clone, PartialEq)]
2485#[serde(rename_all = "camelCase")]
2486#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
2487#[non_exhaustive]
2488pub struct GetPromptRequestParams {
2489 #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
2491 pub meta: Option<RequestMetaObject>,
2492 pub name: String,
2493 #[serde(skip_serializing_if = "Option::is_none")]
2494 pub arguments: Option<JsonObject>,
2495 #[serde(skip_serializing_if = "Option::is_none")]
2498 pub input_responses: Option<InputResponses>,
2499 #[serde(skip_serializing_if = "Option::is_none")]
2501 pub request_state: Option<String>,
2502}
2503
2504impl GetPromptRequestParams {
2505 pub fn new(name: impl Into<String>) -> Self {
2507 Self {
2508 meta: None,
2509 name: name.into(),
2510 arguments: None,
2511 input_responses: None,
2512 request_state: None,
2513 }
2514 }
2515
2516 pub fn with_arguments(mut self, arguments: JsonObject) -> Self {
2518 self.arguments = Some(arguments);
2519 self
2520 }
2521
2522 pub fn with_meta(mut self, meta: RequestMetaObject) -> Self {
2524 self.meta = Some(meta);
2525 self
2526 }
2527
2528 pub fn with_input_responses(mut self, input_responses: InputResponses) -> Self {
2530 self.input_responses = Some(input_responses);
2531 self
2532 }
2533
2534 pub fn with_request_state(mut self, request_state: impl Into<String>) -> Self {
2536 self.request_state = Some(request_state.into());
2537 self
2538 }
2539}
2540
2541impl RequestParamsMeta for GetPromptRequestParams {
2542 fn meta(&self) -> Option<&RequestMetaObject> {
2543 self.meta.as_ref()
2544 }
2545 fn meta_mut(&mut self) -> &mut Option<RequestMetaObject> {
2546 &mut self.meta
2547 }
2548}
2549
2550pub type GetPromptRequest = Request<GetPromptRequestMethod, GetPromptRequestParams>;
2552
2553const_string!(PromptListChangedNotificationMethod = "notifications/prompts/list_changed");
2554pub type PromptListChangedNotification = NotificationNoParam<PromptListChangedNotificationMethod>;
2556
2557const_string!(ToolListChangedNotificationMethod = "notifications/tools/list_changed");
2558pub type ToolListChangedNotification = NotificationNoParam<ToolListChangedNotificationMethod>;
2560
2561#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Copy)]
2567#[serde(rename_all = "lowercase")] #[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
2569#[expect(clippy::exhaustive_enums, reason = "intentionally exhaustive")]
2570#[deprecated(
2571 since = "2.0.0",
2572 note = "Logging is deprecated by SEP-2577 and will be removed in a future release. See https://github.com/modelcontextprotocol/modelcontextprotocol/pull/2577"
2573)]
2574pub enum LoggingLevel {
2575 Debug,
2576 Info,
2577 Notice,
2578 Warning,
2579 Error,
2580 Critical,
2581 Alert,
2582 Emergency,
2583}
2584
2585const_string!(SetLevelRequestMethod = "logging/setLevel");
2586#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
2588#[serde(rename_all = "camelCase")]
2589#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
2590#[non_exhaustive]
2591#[deprecated(
2592 since = "2.0.0",
2593 note = "Logging is deprecated by SEP-2577 and will be removed in a future release. See https://github.com/modelcontextprotocol/modelcontextprotocol/pull/2577"
2594)]
2595pub struct SetLevelRequestParams {
2596 #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
2598 pub meta: Option<RequestMetaObject>,
2599 pub level: LoggingLevel,
2601}
2602
2603impl SetLevelRequestParams {
2604 pub fn new(level: LoggingLevel) -> Self {
2606 Self { meta: None, level }
2607 }
2608}
2609
2610impl RequestParamsMeta for SetLevelRequestParams {
2611 fn meta(&self) -> Option<&RequestMetaObject> {
2612 self.meta.as_ref()
2613 }
2614 fn meta_mut(&mut self) -> &mut Option<RequestMetaObject> {
2615 &mut self.meta
2616 }
2617}
2618
2619#[deprecated(
2621 since = "2.0.0",
2622 note = "Logging is deprecated by SEP-2577 and will be removed in a future release. See https://github.com/modelcontextprotocol/modelcontextprotocol/pull/2577"
2623)]
2624pub type SetLevelRequest = Request<SetLevelRequestMethod, SetLevelRequestParams>;
2625
2626const_string!(LoggingMessageNotificationMethod = "notifications/message");
2627#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
2629#[serde(rename_all = "camelCase")]
2630#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
2631#[non_exhaustive]
2632#[deprecated(
2633 since = "2.0.0",
2634 note = "Logging is deprecated by SEP-2577 and will be removed in a future release. See https://github.com/modelcontextprotocol/modelcontextprotocol/pull/2577"
2635)]
2636pub struct LoggingMessageNotificationParam {
2637 pub level: LoggingLevel,
2639 #[serde(skip_serializing_if = "Option::is_none")]
2641 pub logger: Option<String>,
2642 pub data: Value,
2644 #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
2645 pub meta: Option<NotificationMetaObject>,
2646}
2647
2648impl LoggingMessageNotificationParam {
2649 pub fn new(level: LoggingLevel, data: Value) -> Self {
2651 Self {
2652 level,
2653 logger: None,
2654 data,
2655 meta: None,
2656 }
2657 }
2658
2659 pub fn with_logger(mut self, logger: impl Into<String>) -> Self {
2661 self.logger = Some(logger.into());
2662 self
2663 }
2664}
2665
2666#[deprecated(
2668 since = "2.0.0",
2669 note = "Logging is deprecated by SEP-2577 and will be removed in a future release. See https://github.com/modelcontextprotocol/modelcontextprotocol/pull/2577"
2670)]
2671pub type LoggingMessageNotification =
2672 Notification<LoggingMessageNotificationMethod, LoggingMessageNotificationParam>;
2673
2674const_string!(CreateMessageRequestMethod = "sampling/createMessage");
2679#[deprecated(
2680 since = "2.0.0",
2681 note = "Sampling is deprecated by SEP-2577 and will be removed in a future release. See https://github.com/modelcontextprotocol/modelcontextprotocol/pull/2577"
2682)]
2683pub type CreateMessageRequest = Request<CreateMessageRequestMethod, CreateMessageRequestParams>;
2684
2685#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
2690#[serde(rename_all = "camelCase")]
2691#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
2692#[expect(clippy::exhaustive_enums, reason = "intentionally exhaustive")]
2693pub enum Role {
2694 User,
2696 Assistant,
2698}
2699
2700#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Default)]
2702#[serde(rename_all = "lowercase")]
2703#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
2704#[non_exhaustive]
2705pub enum ToolChoiceMode {
2706 #[default]
2708 Auto,
2709 Required,
2711 None,
2713}
2714
2715#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Default)]
2717#[serde(rename_all = "camelCase")]
2718#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
2719#[non_exhaustive]
2720#[deprecated(
2721 since = "2.0.0",
2722 note = "Sampling is deprecated by SEP-2577 and will be removed in a future release. See https://github.com/modelcontextprotocol/modelcontextprotocol/pull/2577"
2723)]
2724pub struct ToolChoice {
2725 #[serde(skip_serializing_if = "Option::is_none")]
2726 pub mode: Option<ToolChoiceMode>,
2727}
2728
2729impl ToolChoice {
2730 pub fn auto() -> Self {
2731 Self {
2732 mode: Some(ToolChoiceMode::Auto),
2733 }
2734 }
2735
2736 pub fn required() -> Self {
2737 Self {
2738 mode: Some(ToolChoiceMode::Required),
2739 }
2740 }
2741
2742 pub fn none() -> Self {
2743 Self {
2744 mode: Some(ToolChoiceMode::None),
2745 }
2746 }
2747}
2748
2749#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
2751#[serde(untagged)]
2752#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
2753#[expect(clippy::exhaustive_enums, reason = "intentionally exhaustive")]
2754pub enum SamplingContent<T> {
2755 Single(T),
2756 Multiple(Vec<T>),
2757}
2758
2759impl<T> SamplingContent<T> {
2760 pub fn into_vec(self) -> Vec<T> {
2762 match self {
2763 SamplingContent::Single(item) => vec![item],
2764 SamplingContent::Multiple(items) => items,
2765 }
2766 }
2767
2768 pub fn is_empty(&self) -> bool {
2770 match self {
2771 SamplingContent::Single(_) => false,
2772 SamplingContent::Multiple(items) => items.is_empty(),
2773 }
2774 }
2775
2776 pub fn len(&self) -> usize {
2778 match self {
2779 SamplingContent::Single(_) => 1,
2780 SamplingContent::Multiple(items) => items.len(),
2781 }
2782 }
2783}
2784
2785impl<T> Default for SamplingContent<T> {
2786 fn default() -> Self {
2787 SamplingContent::Multiple(Vec::new())
2788 }
2789}
2790
2791impl<T> SamplingContent<T> {
2792 pub fn first(&self) -> Option<&T> {
2794 match self {
2795 SamplingContent::Single(item) => Some(item),
2796 SamplingContent::Multiple(items) => items.first(),
2797 }
2798 }
2799
2800 pub fn iter(&self) -> impl Iterator<Item = &T> {
2802 let items: Vec<&T> = match self {
2803 SamplingContent::Single(item) => vec![item],
2804 SamplingContent::Multiple(items) => items.iter().collect(),
2805 };
2806 items.into_iter()
2807 }
2808}
2809
2810impl SamplingMessageContentBlock {
2811 pub fn as_text(&self) -> Option<&TextContent> {
2813 match self {
2814 SamplingMessageContentBlock::Text(text) => Some(text),
2815 _ => None,
2816 }
2817 }
2818
2819 pub fn as_tool_use(&self) -> Option<&ToolUseContent> {
2821 match self {
2822 SamplingMessageContentBlock::ToolUse(tool_use) => Some(tool_use),
2823 _ => None,
2824 }
2825 }
2826
2827 pub fn as_tool_result(&self) -> Option<&ToolResultContent> {
2829 match self {
2830 SamplingMessageContentBlock::ToolResult(tool_result) => Some(tool_result),
2831 _ => None,
2832 }
2833 }
2834}
2835
2836impl<T> From<T> for SamplingContent<T> {
2837 fn from(item: T) -> Self {
2838 SamplingContent::Single(item)
2839 }
2840}
2841
2842impl<T> From<Vec<T>> for SamplingContent<T> {
2843 fn from(items: Vec<T>) -> Self {
2844 SamplingContent::Multiple(items)
2845 }
2846}
2847
2848#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
2854#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
2855#[non_exhaustive]
2856#[deprecated(
2857 since = "2.0.0",
2858 note = "Sampling is deprecated by SEP-2577 and will be removed in a future release. See https://github.com/modelcontextprotocol/modelcontextprotocol/pull/2577"
2859)]
2860pub struct SamplingMessage {
2861 pub role: Role,
2863 pub content: SamplingContent<SamplingMessageContentBlock>,
2865 #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
2866 pub meta: Option<MetaObject>,
2867}
2868
2869#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
2871#[serde(tag = "type", rename_all = "snake_case")]
2872#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
2873#[non_exhaustive]
2874#[deprecated(
2875 since = "2.0.0",
2876 note = "Sampling is deprecated by SEP-2577 and will be removed in a future release. See https://github.com/modelcontextprotocol/modelcontextprotocol/pull/2577"
2877)]
2878pub enum SamplingMessageContentBlock {
2879 Text(TextContent),
2880 Image(ImageContent),
2881 Audio(AudioContent),
2882 ToolUse(ToolUseContent),
2884 ToolResult(ToolResultContent),
2886}
2887
2888impl SamplingMessageContentBlock {
2889 pub fn text(text: impl Into<String>) -> Self {
2891 Self::Text(TextContent::new(text))
2892 }
2893
2894 pub fn tool_use(id: impl Into<String>, name: impl Into<String>, input: JsonObject) -> Self {
2895 Self::ToolUse(ToolUseContent::new(id, name, input))
2896 }
2897
2898 pub fn tool_result(tool_use_id: impl Into<String>, content: Vec<ContentBlock>) -> Self {
2899 Self::ToolResult(ToolResultContent::new(tool_use_id, content))
2900 }
2901}
2902
2903impl SamplingMessage {
2904 pub fn new(role: Role, content: impl Into<SamplingMessageContentBlock>) -> Self {
2905 Self {
2906 role,
2907 content: SamplingContent::Single(content.into()),
2908 meta: None,
2909 }
2910 }
2911
2912 pub fn new_multiple(role: Role, contents: Vec<SamplingMessageContentBlock>) -> Self {
2913 Self {
2914 role,
2915 content: SamplingContent::Multiple(contents),
2916 meta: None,
2917 }
2918 }
2919
2920 pub fn user_text(text: impl Into<String>) -> Self {
2921 Self::new(Role::User, SamplingMessageContentBlock::text(text))
2922 }
2923
2924 pub fn assistant_text(text: impl Into<String>) -> Self {
2925 Self::new(Role::Assistant, SamplingMessageContentBlock::text(text))
2926 }
2927
2928 pub fn user_tool_result(tool_use_id: impl Into<String>, content: Vec<ContentBlock>) -> Self {
2929 Self::new(
2930 Role::User,
2931 SamplingMessageContentBlock::tool_result(tool_use_id, content),
2932 )
2933 }
2934
2935 pub fn assistant_tool_use(
2936 id: impl Into<String>,
2937 name: impl Into<String>,
2938 input: JsonObject,
2939 ) -> Self {
2940 Self::new(
2941 Role::Assistant,
2942 SamplingMessageContentBlock::tool_use(id, name, input),
2943 )
2944 }
2945}
2946
2947impl From<TextContent> for SamplingMessageContentBlock {
2948 fn from(text: TextContent) -> Self {
2949 SamplingMessageContentBlock::Text(text)
2950 }
2951}
2952
2953impl From<String> for SamplingMessageContentBlock {
2955 fn from(text: String) -> Self {
2956 SamplingMessageContentBlock::text(text)
2957 }
2958}
2959
2960impl From<&str> for SamplingMessageContentBlock {
2961 fn from(text: &str) -> Self {
2962 SamplingMessageContentBlock::text(text)
2963 }
2964}
2965
2966impl TryFrom<ContentBlock> for SamplingMessageContentBlock {
2967 type Error = &'static str;
2968
2969 fn try_from(content: ContentBlock) -> Result<Self, Self::Error> {
2970 match content {
2971 ContentBlock::Text(text) => Ok(SamplingMessageContentBlock::Text(text)),
2972 ContentBlock::Image(image) => Ok(SamplingMessageContentBlock::Image(image)),
2973 ContentBlock::Audio(audio) => Ok(SamplingMessageContentBlock::Audio(audio)),
2974 ContentBlock::Resource(_) => {
2975 Err("Resource content is not supported in sampling messages")
2976 }
2977 ContentBlock::ResourceLink(_) => {
2978 Err("ResourceLink content is not supported in sampling messages")
2979 }
2980 }
2981 }
2982}
2983
2984impl TryFrom<ContentBlock> for SamplingContent<SamplingMessageContentBlock> {
2985 type Error = &'static str;
2986
2987 fn try_from(content: ContentBlock) -> Result<Self, Self::Error> {
2988 Ok(SamplingContent::Single(content.try_into()?))
2989 }
2990}
2991
2992#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
2997#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
2998#[non_exhaustive]
2999pub enum ContextInclusion {
3000 #[serde(rename = "allServers")]
3002 AllServers,
3003 #[serde(rename = "none")]
3005 None,
3006 #[serde(rename = "thisServer")]
3008 ThisServer,
3009}
3010
3011#[derive(Default, Debug, Serialize, Deserialize, Clone, PartialEq)]
3020#[serde(rename_all = "camelCase")]
3021#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
3022#[non_exhaustive]
3023#[deprecated(
3024 since = "2.0.0",
3025 note = "Sampling is deprecated by SEP-2577 and will be removed in a future release. See https://github.com/modelcontextprotocol/modelcontextprotocol/pull/2577"
3026)]
3027pub struct CreateMessageRequestParams {
3028 #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
3030 pub meta: Option<RequestMetaObject>,
3031 pub messages: Vec<SamplingMessage>,
3033 #[serde(skip_serializing_if = "Option::is_none")]
3035 pub model_preferences: Option<ModelPreferences>,
3036 #[serde(skip_serializing_if = "Option::is_none")]
3038 pub system_prompt: Option<String>,
3039 #[serde(skip_serializing_if = "Option::is_none")]
3041 pub include_context: Option<ContextInclusion>,
3042 #[serde(
3044 default,
3045 deserialize_with = "serde_impl::json_float::option_f32",
3046 skip_serializing_if = "Option::is_none"
3047 )]
3048 pub temperature: Option<f32>,
3049 pub max_tokens: u32,
3051 #[serde(skip_serializing_if = "Option::is_none")]
3053 pub stop_sequences: Option<Vec<String>>,
3054 #[serde(skip_serializing_if = "Option::is_none")]
3056 pub metadata: Option<Value>,
3057 #[serde(skip_serializing_if = "Option::is_none")]
3059 pub tools: Option<Vec<Tool>>,
3060 #[serde(skip_serializing_if = "Option::is_none")]
3062 pub tool_choice: Option<ToolChoice>,
3063}
3064
3065impl RequestParamsMeta for CreateMessageRequestParams {
3066 fn meta(&self) -> Option<&RequestMetaObject> {
3067 self.meta.as_ref()
3068 }
3069 fn meta_mut(&mut self) -> &mut Option<RequestMetaObject> {
3070 &mut self.meta
3071 }
3072}
3073
3074impl CreateMessageRequestParams {
3075 pub fn new(messages: Vec<SamplingMessage>, max_tokens: u32) -> Self {
3077 Self {
3078 meta: None,
3079 messages,
3080 model_preferences: None,
3081 system_prompt: None,
3082 include_context: None,
3083 temperature: None,
3084 max_tokens,
3085 stop_sequences: None,
3086 metadata: None,
3087 tools: None,
3088 tool_choice: None,
3089 }
3090 }
3091
3092 pub fn with_model_preferences(mut self, model_preferences: ModelPreferences) -> Self {
3094 self.model_preferences = Some(model_preferences);
3095 self
3096 }
3097
3098 pub fn with_system_prompt(mut self, system_prompt: impl Into<String>) -> Self {
3100 self.system_prompt = Some(system_prompt.into());
3101 self
3102 }
3103
3104 pub fn with_include_context(mut self, include_context: ContextInclusion) -> Self {
3106 self.include_context = Some(include_context);
3107 self
3108 }
3109
3110 pub fn with_temperature(mut self, temperature: f32) -> Self {
3112 self.temperature = Some(temperature);
3113 self
3114 }
3115
3116 pub fn with_stop_sequences(mut self, stop_sequences: Vec<String>) -> Self {
3118 self.stop_sequences = Some(stop_sequences);
3119 self
3120 }
3121
3122 pub fn with_metadata(mut self, metadata: Value) -> Self {
3124 self.metadata = Some(metadata);
3125 self
3126 }
3127
3128 pub fn with_tools(mut self, tools: Vec<Tool>) -> Self {
3130 self.tools = Some(tools);
3131 self
3132 }
3133
3134 pub fn with_tool_choice(mut self, tool_choice: ToolChoice) -> Self {
3136 self.tool_choice = Some(tool_choice);
3137 self
3138 }
3139
3140 pub fn validate(&self) -> Result<(), String> {
3148 for msg in &self.messages {
3149 for content in msg.content.iter() {
3150 match content {
3152 SamplingMessageContentBlock::ToolUse(_) if msg.role != Role::Assistant => {
3153 return Err("ToolUse content is only allowed in assistant messages".into());
3154 }
3155 SamplingMessageContentBlock::ToolResult(_) if msg.role != Role::User => {
3156 return Err("ToolResult content is only allowed in user messages".into());
3157 }
3158 _ => {}
3159 }
3160 }
3161
3162 let contents: Vec<_> = msg.content.iter().collect();
3164 let has_tool_result = contents
3165 .iter()
3166 .any(|c| matches!(c, SamplingMessageContentBlock::ToolResult(_)));
3167 if has_tool_result
3168 && contents
3169 .iter()
3170 .any(|c| !matches!(c, SamplingMessageContentBlock::ToolResult(_)))
3171 {
3172 return Err(
3173 "SamplingMessage with tool result content MUST NOT contain other content types"
3174 .into(),
3175 );
3176 }
3177 }
3178
3179 self.validate_tool_use_result_balance()?;
3181
3182 Ok(())
3183 }
3184
3185 fn validate_tool_use_result_balance(&self) -> Result<(), String> {
3186 let mut pending_tool_use_ids: Vec<String> = Vec::new();
3187 for msg in &self.messages {
3188 if msg.role == Role::Assistant {
3189 for content in msg.content.iter() {
3190 if let SamplingMessageContentBlock::ToolUse(tu) = content {
3191 pending_tool_use_ids.push(tu.id.clone());
3192 }
3193 }
3194 } else if msg.role == Role::User {
3195 for content in msg.content.iter() {
3196 if let SamplingMessageContentBlock::ToolResult(tr) = content {
3197 if !pending_tool_use_ids.contains(&tr.tool_use_id) {
3198 return Err(format!(
3199 "ToolResult with toolUseId '{}' has no matching ToolUse",
3200 tr.tool_use_id
3201 ));
3202 }
3203 pending_tool_use_ids.retain(|id| id != &tr.tool_use_id);
3204 }
3205 }
3206 }
3207 }
3208 if !pending_tool_use_ids.is_empty() {
3209 return Err(format!(
3210 "ToolUse with id(s) {:?} not balanced with ToolResult",
3211 pending_tool_use_ids
3212 ));
3213 }
3214 Ok(())
3215 }
3216}
3217
3218#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
3224#[serde(rename_all = "camelCase")]
3225#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
3226#[non_exhaustive]
3227#[deprecated(
3228 since = "2.0.0",
3229 note = "Sampling is deprecated by SEP-2577 and will be removed in a future release. See https://github.com/modelcontextprotocol/modelcontextprotocol/pull/2577"
3230)]
3231pub struct ModelPreferences {
3232 #[serde(skip_serializing_if = "Option::is_none")]
3234 pub hints: Option<Vec<ModelHint>>,
3235 #[serde(
3237 default,
3238 deserialize_with = "serde_impl::json_float::option_f32",
3239 skip_serializing_if = "Option::is_none"
3240 )]
3241 pub cost_priority: Option<f32>,
3242 #[serde(
3244 default,
3245 deserialize_with = "serde_impl::json_float::option_f32",
3246 skip_serializing_if = "Option::is_none"
3247 )]
3248 pub speed_priority: Option<f32>,
3249 #[serde(
3251 default,
3252 deserialize_with = "serde_impl::json_float::option_f32",
3253 skip_serializing_if = "Option::is_none"
3254 )]
3255 pub intelligence_priority: Option<f32>,
3256}
3257
3258impl ModelPreferences {
3259 pub fn new() -> Self {
3261 Self {
3262 hints: None,
3263 cost_priority: None,
3264 speed_priority: None,
3265 intelligence_priority: None,
3266 }
3267 }
3268
3269 pub fn with_hints(mut self, hints: Vec<ModelHint>) -> Self {
3271 self.hints = Some(hints);
3272 self
3273 }
3274
3275 pub fn with_cost_priority(mut self, cost_priority: f32) -> Self {
3277 self.cost_priority = Some(cost_priority);
3278 self
3279 }
3280
3281 pub fn with_speed_priority(mut self, speed_priority: f32) -> Self {
3283 self.speed_priority = Some(speed_priority);
3284 self
3285 }
3286
3287 pub fn with_intelligence_priority(mut self, intelligence_priority: f32) -> Self {
3289 self.intelligence_priority = Some(intelligence_priority);
3290 self
3291 }
3292}
3293
3294impl Default for ModelPreferences {
3295 fn default() -> Self {
3296 Self::new()
3297 }
3298}
3299
3300#[derive(Default, Debug, Serialize, Deserialize, Clone, PartialEq)]
3305#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
3306#[non_exhaustive]
3307#[deprecated(
3308 since = "2.0.0",
3309 note = "Sampling is deprecated by SEP-2577 and will be removed in a future release. See https://github.com/modelcontextprotocol/modelcontextprotocol/pull/2577"
3310)]
3311pub struct ModelHint {
3312 #[serde(skip_serializing_if = "Option::is_none")]
3314 pub name: Option<String>,
3315}
3316
3317impl ModelHint {
3318 pub fn new(name: impl Into<String>) -> Self {
3320 Self {
3321 name: Some(name.into()),
3322 }
3323 }
3324}
3325
3326#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Default)]
3335#[serde(rename_all = "camelCase")]
3336#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
3337#[non_exhaustive]
3338pub struct CompletionContext {
3339 #[serde(skip_serializing_if = "Option::is_none")]
3341 pub arguments: Option<std::collections::HashMap<String, String>>,
3342}
3343
3344impl CompletionContext {
3345 pub fn new() -> Self {
3347 Self::default()
3348 }
3349
3350 pub fn with_arguments(arguments: std::collections::HashMap<String, String>) -> Self {
3352 Self {
3353 arguments: Some(arguments),
3354 }
3355 }
3356
3357 pub fn get_argument(&self, name: &str) -> Option<&String> {
3359 self.arguments.as_ref()?.get(name)
3360 }
3361
3362 pub fn has_arguments(&self) -> bool {
3364 self.arguments.as_ref().is_some_and(|args| !args.is_empty())
3365 }
3366
3367 pub fn argument_names(&self) -> impl Iterator<Item = &str> {
3369 self.arguments
3370 .as_ref()
3371 .into_iter()
3372 .flat_map(|args| args.keys())
3373 .map(|k| k.as_str())
3374 }
3375}
3376
3377#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
3378#[serde(rename_all = "camelCase")]
3379#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
3380#[non_exhaustive]
3381pub struct CompleteRequestParams {
3382 #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
3384 pub meta: Option<RequestMetaObject>,
3385 pub r#ref: Reference,
3386 pub argument: ArgumentInfo,
3387 #[serde(skip_serializing_if = "Option::is_none")]
3389 pub context: Option<CompletionContext>,
3390}
3391
3392impl CompleteRequestParams {
3393 pub fn new(r#ref: Reference, argument: ArgumentInfo) -> Self {
3395 Self {
3396 meta: None,
3397 r#ref,
3398 argument,
3399 context: None,
3400 }
3401 }
3402
3403 pub fn with_context(mut self, context: CompletionContext) -> Self {
3405 self.context = Some(context);
3406 self
3407 }
3408}
3409
3410impl RequestParamsMeta for CompleteRequestParams {
3411 fn meta(&self) -> Option<&RequestMetaObject> {
3412 self.meta.as_ref()
3413 }
3414 fn meta_mut(&mut self) -> &mut Option<RequestMetaObject> {
3415 &mut self.meta
3416 }
3417}
3418
3419pub type CompleteRequest = Request<CompleteRequestMethod, CompleteRequestParams>;
3420
3421#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Default)]
3422#[serde(rename_all = "camelCase")]
3423#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
3424#[non_exhaustive]
3425pub struct CompletionInfo {
3426 pub values: Vec<String>,
3427 #[serde(skip_serializing_if = "Option::is_none")]
3428 pub total: Option<u32>,
3429 #[serde(skip_serializing_if = "Option::is_none")]
3430 pub has_more: Option<bool>,
3431}
3432
3433impl CompletionInfo {
3434 pub const MAX_VALUES: usize = 100;
3436
3437 pub fn new(values: Vec<String>) -> Result<Self, String> {
3439 if values.len() > Self::MAX_VALUES {
3440 return Err(format!(
3441 "Too many completion values: {} (max: {})",
3442 values.len(),
3443 Self::MAX_VALUES
3444 ));
3445 }
3446 Ok(Self {
3447 values,
3448 total: None,
3449 has_more: None,
3450 })
3451 }
3452
3453 pub fn with_all_values(values: Vec<String>) -> Result<Self, String> {
3455 let completion = Self::new(values)?;
3456 Ok(Self {
3457 total: Some(completion.values.len() as u32),
3458 has_more: Some(false),
3459 ..completion
3460 })
3461 }
3462
3463 pub fn with_pagination(
3465 values: Vec<String>,
3466 total: Option<u32>,
3467 has_more: bool,
3468 ) -> Result<Self, String> {
3469 let completion = Self::new(values)?;
3470 Ok(Self {
3471 total,
3472 has_more: Some(has_more),
3473 ..completion
3474 })
3475 }
3476
3477 pub fn has_more_results(&self) -> bool {
3479 self.has_more.unwrap_or(false)
3480 }
3481
3482 pub fn total_available(&self) -> Option<u32> {
3484 self.total
3485 }
3486
3487 pub fn validate(&self) -> Result<(), String> {
3489 if self.values.len() > Self::MAX_VALUES {
3490 return Err(format!(
3491 "Too many completion values: {} (max: {})",
3492 self.values.len(),
3493 Self::MAX_VALUES
3494 ));
3495 }
3496 Ok(())
3497 }
3498}
3499
3500#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
3501#[serde(rename_all = "camelCase")]
3502#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
3503#[non_exhaustive]
3504pub struct CompleteResult {
3505 #[serde(default, skip_serializing_if = "Option::is_none")]
3516 pub result_type: Option<ResultType>,
3517 pub completion: CompletionInfo,
3518 #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
3519 pub meta: Option<MetaObject>,
3520}
3521
3522impl Default for CompleteResult {
3523 fn default() -> Self {
3524 Self::new(CompletionInfo::default())
3525 }
3526}
3527
3528impl CompleteResult {
3529 pub fn new(completion: CompletionInfo) -> Self {
3531 Self {
3532 result_type: Some(ResultType::COMPLETE),
3533 completion,
3534 meta: None,
3535 }
3536 }
3537}
3538
3539#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
3540#[serde(tag = "type")]
3541#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
3542#[non_exhaustive]
3543pub enum Reference {
3544 #[serde(rename = "ref/resource")]
3545 Resource(ResourceTemplateReference),
3546 #[serde(rename = "ref/prompt")]
3547 Prompt(PromptReference),
3548}
3549
3550impl Reference {
3551 pub fn for_prompt(name: impl Into<String>) -> Self {
3553 Self::Prompt(PromptReference {
3557 name: name.into(),
3558 title: None,
3559 })
3560 }
3561
3562 pub fn for_resource(uri: impl Into<String>) -> Self {
3564 Self::Resource(ResourceTemplateReference { uri: uri.into() })
3565 }
3566
3567 pub fn reference_type(&self) -> &'static str {
3569 match self {
3570 Self::Prompt(_) => "ref/prompt",
3571 Self::Resource(_) => "ref/resource",
3572 }
3573 }
3574
3575 pub fn as_prompt_name(&self) -> Option<&str> {
3577 match self {
3578 Self::Prompt(prompt_ref) => Some(&prompt_ref.name),
3579 _ => None,
3580 }
3581 }
3582
3583 pub fn as_resource_uri(&self) -> Option<&str> {
3585 match self {
3586 Self::Resource(resource_ref) => Some(&resource_ref.uri),
3587 _ => None,
3588 }
3589 }
3590}
3591
3592#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
3593#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
3594#[non_exhaustive]
3595pub struct ResourceTemplateReference {
3596 pub uri: String,
3597}
3598
3599impl ResourceTemplateReference {
3600 pub fn new(uri: impl Into<String>) -> Self {
3601 Self { uri: uri.into() }
3602 }
3603}
3604
3605#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
3606#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
3607#[non_exhaustive]
3608pub struct PromptReference {
3609 pub name: String,
3610 #[serde(skip_serializing_if = "Option::is_none")]
3611 pub title: Option<String>,
3612}
3613
3614impl PromptReference {
3615 pub fn new(name: impl Into<String>) -> Self {
3617 Self {
3618 name: name.into(),
3619 title: None,
3620 }
3621 }
3622
3623 pub fn with_title(mut self, title: impl Into<String>) -> Self {
3625 self.title = Some(title.into());
3626 self
3627 }
3628}
3629
3630const_string!(CompleteRequestMethod = "completion/complete");
3631#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
3632#[serde(rename_all = "camelCase")]
3633#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
3634#[non_exhaustive]
3635pub struct ArgumentInfo {
3636 pub name: String,
3637 pub value: String,
3638}
3639
3640impl ArgumentInfo {
3641 pub fn new(name: impl Into<String>, value: impl Into<String>) -> Self {
3642 Self {
3643 name: name.into(),
3644 value: value.into(),
3645 }
3646 }
3647}
3648
3649#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
3654#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
3655#[non_exhaustive]
3656#[deprecated(
3657 since = "2.0.0",
3658 note = "Roots is deprecated by SEP-2577 and will be removed in a future release. See https://github.com/modelcontextprotocol/modelcontextprotocol/pull/2577"
3659)]
3660pub struct Root {
3661 pub uri: String,
3662 #[serde(skip_serializing_if = "Option::is_none")]
3663 pub name: Option<String>,
3664 #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
3665 pub meta: Option<MetaObject>,
3666}
3667
3668impl Root {
3669 pub fn new(uri: impl Into<String>) -> Self {
3671 Self {
3672 uri: uri.into(),
3673 name: None,
3674 meta: None,
3675 }
3676 }
3677
3678 pub fn with_name(mut self, name: impl Into<String>) -> Self {
3680 self.name = Some(name.into());
3681 self
3682 }
3683
3684 pub fn with_meta(mut self, meta: MetaObject) -> Self {
3686 self.meta = Some(meta);
3687 self
3688 }
3689}
3690
3691const_string!(ListRootsRequestMethod = "roots/list");
3692#[deprecated(
3693 since = "2.0.0",
3694 note = "Roots is deprecated by SEP-2577 and will be removed in a future release. See https://github.com/modelcontextprotocol/modelcontextprotocol/pull/2577"
3695)]
3696pub type ListRootsRequest = RequestNoParam<ListRootsRequestMethod>;
3697
3698#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Default)]
3699#[serde(rename_all = "camelCase")]
3700#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
3701#[non_exhaustive]
3702#[deprecated(
3703 since = "2.0.0",
3704 note = "Roots is deprecated by SEP-2577 and will be removed in a future release. See https://github.com/modelcontextprotocol/modelcontextprotocol/pull/2577"
3705)]
3706pub struct ListRootsResult {
3707 pub roots: Vec<Root>,
3708 #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
3709 pub meta: Option<MetaObject>,
3710}
3711
3712impl ListRootsResult {
3713 pub fn new(roots: Vec<Root>) -> Self {
3715 Self { roots, meta: None }
3716 }
3717
3718 pub fn with_meta(mut self, meta: MetaObject) -> Self {
3720 self.meta = Some(meta);
3721 self
3722 }
3723}
3724
3725const_string!(RootsListChangedNotificationMethod = "notifications/roots/list_changed");
3726pub type RootsListChangedNotification = NotificationNoParam<RootsListChangedNotificationMethod>;
3727
3728const_string!(ElicitationCreateRequestMethod = "elicitation/create");
3735const_string!(ElicitationResponseNotificationMethod = "notifications/elicitation/response");
3736
3737#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq)]
3744#[serde(rename_all = "lowercase")]
3745#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
3746#[non_exhaustive]
3747pub enum ElicitationAction {
3748 Accept,
3750 Decline,
3752 Cancel,
3754}
3755
3756#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
3758#[serde(tag = "mode")]
3759#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
3760enum ElicitRequestParamsWire {
3761 #[serde(rename = "form", rename_all = "camelCase")]
3762 Form {
3763 #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
3764 meta: Option<RequestMetaObject>,
3765 message: String,
3766 requested_schema: ElicitationSchema,
3767 },
3768 #[serde(rename = "url", rename_all = "camelCase")]
3769 Url {
3770 #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
3771 meta: Option<RequestMetaObject>,
3772 message: String,
3773 url: String,
3774 elicitation_id: String,
3775 },
3776 #[serde(untagged, rename_all = "camelCase")]
3777 LegacyForm {
3778 #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
3779 meta: Option<RequestMetaObject>,
3780 message: String,
3781 requested_schema: ElicitationSchema,
3782 },
3783}
3784
3785impl TryFrom<ElicitRequestParamsWire> for ElicitRequestParams {
3786 type Error = serde_json::Error;
3787
3788 fn try_from(value: ElicitRequestParamsWire) -> Result<Self, Self::Error> {
3789 match value {
3790 ElicitRequestParamsWire::Form {
3791 meta,
3792 message,
3793 requested_schema,
3794 }
3795 | ElicitRequestParamsWire::LegacyForm {
3796 meta,
3797 message,
3798 requested_schema,
3799 } => Ok(ElicitRequestParams::FormElicitationParams {
3800 meta,
3801 message,
3802 requested_schema,
3803 }),
3804 ElicitRequestParamsWire::Url {
3805 meta,
3806 message,
3807 url,
3808 elicitation_id,
3809 } => Ok(ElicitRequestParams::UrlElicitationParams {
3810 meta,
3811 message,
3812 url,
3813 elicitation_id,
3814 }),
3815 }
3816 }
3817}
3818
3819#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
3850#[serde(tag = "mode", try_from = "ElicitRequestParamsWire")]
3851#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
3852#[non_exhaustive]
3853pub enum ElicitRequestParams {
3854 #[serde(rename = "form", rename_all = "camelCase")]
3855 FormElicitationParams {
3856 #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
3858 meta: Option<RequestMetaObject>,
3859 message: String,
3863
3864 requested_schema: ElicitationSchema,
3868 },
3869 #[serde(rename = "url", rename_all = "camelCase")]
3870 UrlElicitationParams {
3871 #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
3873 meta: Option<RequestMetaObject>,
3874 message: String,
3878
3879 url: String,
3882 elicitation_id: String,
3884 },
3885}
3886
3887impl RequestParamsMeta for ElicitRequestParams {
3888 fn meta(&self) -> Option<&RequestMetaObject> {
3889 match self {
3890 ElicitRequestParams::FormElicitationParams { meta, .. } => meta.as_ref(),
3891 ElicitRequestParams::UrlElicitationParams { meta, .. } => meta.as_ref(),
3892 }
3893 }
3894 fn meta_mut(&mut self) -> &mut Option<RequestMetaObject> {
3895 match self {
3896 ElicitRequestParams::FormElicitationParams { meta, .. } => meta,
3897 ElicitRequestParams::UrlElicitationParams { meta, .. } => meta,
3898 }
3899 }
3900}
3901
3902#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
3907#[serde(rename_all = "camelCase")]
3908#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
3909#[non_exhaustive]
3910pub struct ElicitResult {
3911 pub action: ElicitationAction,
3913
3914 #[serde(skip_serializing_if = "Option::is_none")]
3918 pub content: Option<Value>,
3919
3920 #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
3922 pub meta: Option<MetaObject>,
3923}
3924
3925impl ElicitResult {
3926 pub fn new(action: ElicitationAction) -> Self {
3928 Self {
3929 action,
3930 content: None,
3931 meta: None,
3932 }
3933 }
3934
3935 pub fn with_content(mut self, content: Value) -> Self {
3937 self.content = Some(content);
3938 self
3939 }
3940
3941 pub fn with_meta(mut self, meta: MetaObject) -> Self {
3943 self.meta = Some(meta);
3944 self
3945 }
3946}
3947
3948pub type ElicitRequest = Request<ElicitationCreateRequestMethod, ElicitRequestParams>;
3950
3951fn deserialize_present_value<'de, D>(deserializer: D) -> Result<Option<Value>, D::Error>
3958where
3959 D: serde::Deserializer<'de>,
3960{
3961 Value::deserialize(deserializer).map(Some)
3962}
3963
3964#[derive(Debug, Serialize, Clone, PartialEq)]
3969#[serde(rename_all = "camelCase")]
3970#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
3971#[non_exhaustive]
3972pub struct CallToolResult {
3973 #[serde(default, skip_serializing_if = "Option::is_none")]
3984 pub result_type: Option<ResultType>,
3985 #[serde(default)]
3987 pub content: Vec<ContentBlock>,
3988 #[serde(skip_serializing_if = "Option::is_none")]
3992 pub structured_content: Option<Value>,
3993 #[serde(skip_serializing_if = "Option::is_none")]
3995 pub is_error: Option<bool>,
3996 #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
3998 pub meta: Option<MetaObject>,
3999}
4000
4001impl<'de> Deserialize<'de> for CallToolResult {
4010 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
4011 where
4012 D: serde::Deserializer<'de>,
4013 {
4014 #[derive(Deserialize)]
4015 #[serde(rename_all = "camelCase")]
4016 struct Helper {
4017 #[serde(default)]
4018 result_type: Option<ResultType>,
4019 content: Option<Vec<ContentBlock>>,
4020 #[serde(default, deserialize_with = "deserialize_present_value")]
4021 structured_content: Option<Value>,
4022 is_error: Option<bool>,
4023 #[serde(rename = "_meta")]
4024 meta: Option<MetaObject>,
4025 }
4026
4027 let helper = Helper::deserialize(deserializer)?;
4028
4029 if helper
4030 .result_type
4031 .as_ref()
4032 .is_some_and(|result_type| !result_type.is_complete())
4033 {
4034 return Err(serde::de::Error::custom(
4035 "CallToolResult requires resultType to be \"complete\" when present",
4036 ));
4037 }
4038
4039 if helper.content.is_none()
4040 && helper.structured_content.is_none()
4041 && helper.is_error.is_none()
4042 && helper.meta.is_none()
4043 {
4044 return Err(serde::de::Error::custom(
4045 "expected at least one known CallToolResult field \
4046 (content, structuredContent, isError, or _meta)",
4047 ));
4048 }
4049
4050 Ok(CallToolResult {
4051 result_type: helper.result_type,
4052 content: helper.content.unwrap_or_default(),
4053 structured_content: helper.structured_content,
4054 is_error: helper.is_error,
4055 meta: helper.meta,
4056 })
4057 }
4058}
4059
4060impl Default for CallToolResult {
4061 fn default() -> Self {
4062 CallToolResult {
4063 result_type: Some(ResultType::COMPLETE),
4064 content: Vec::new(),
4065 structured_content: None,
4066 is_error: None,
4067 meta: None,
4068 }
4069 }
4070}
4071
4072impl CallToolResult {
4073 pub fn success(content: Vec<ContentBlock>) -> Self {
4075 CallToolResult {
4076 result_type: Some(ResultType::COMPLETE),
4077 content,
4078 structured_content: None,
4079 is_error: Some(false),
4080 meta: None,
4081 }
4082 }
4083
4084 pub fn error(content: Vec<ContentBlock>) -> Self {
4133 CallToolResult {
4134 result_type: Some(ResultType::COMPLETE),
4135 content,
4136 structured_content: None,
4137 is_error: Some(true),
4138 meta: None,
4139 }
4140 }
4141 pub fn structured(value: Value) -> Self {
4156 CallToolResult {
4157 result_type: Some(ResultType::COMPLETE),
4158 content: vec![ContentBlock::text(value.to_string())],
4159 structured_content: Some(value),
4160 is_error: Some(false),
4161 meta: None,
4162 }
4163 }
4164 pub fn structured_error(value: Value) -> Self {
4183 CallToolResult {
4184 result_type: Some(ResultType::COMPLETE),
4185 content: vec![ContentBlock::text(value.to_string())],
4186 structured_content: Some(value),
4187 is_error: Some(true),
4188 meta: None,
4189 }
4190 }
4191
4192 pub fn with_meta(mut self, meta: Option<MetaObject>) -> Self {
4194 self.meta = meta;
4195 self
4196 }
4197
4198 pub fn into_typed<T>(self) -> Result<T, serde_json::Error>
4205 where
4206 T: DeserializeOwned,
4207 {
4208 let raw_text = match (self.structured_content, &self.content.first()) {
4209 (Some(value), _) => return serde_json::from_value(value),
4210 (None, Some(contents)) => {
4211 if let Some(text) = contents.as_text() {
4212 let text = &text.text;
4213 Some(text)
4214 } else {
4215 None
4216 }
4217 }
4218 (None, None) => None,
4219 };
4220 if let Some(text) = raw_text {
4221 return serde_json::from_str(text);
4222 }
4223 serde_json::from_value(serde_json::Value::Null)
4224 }
4225}
4226
4227const_string!(ListToolsRequestMethod = "tools/list");
4228pub type ListToolsRequest = RequestOptionalParam<ListToolsRequestMethod, PaginatedRequestParams>;
4230
4231paginated_result!(
4232 ListToolsResult {
4233 tools: Vec<Tool>
4234 }
4235);
4236
4237const_string!(CallToolRequestMethod = "tools/call");
4238#[derive(Default, Debug, Serialize, Deserialize, Clone, PartialEq)]
4243#[serde(rename_all = "camelCase")]
4244#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
4245#[non_exhaustive]
4246pub struct CallToolRequestParams {
4247 #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
4249 pub meta: Option<RequestMetaObject>,
4250 pub name: Cow<'static, str>,
4252 #[serde(skip_serializing_if = "Option::is_none")]
4254 pub arguments: Option<JsonObject>,
4255 #[serde(skip_serializing_if = "Option::is_none")]
4258 pub input_responses: Option<InputResponses>,
4259 #[serde(skip_serializing_if = "Option::is_none")]
4262 pub request_state: Option<String>,
4263}
4264
4265impl CallToolRequestParams {
4266 pub fn new(name: impl Into<Cow<'static, str>>) -> Self {
4268 Self {
4269 meta: None,
4270 name: name.into(),
4271 arguments: None,
4272 input_responses: None,
4273 request_state: None,
4274 }
4275 }
4276
4277 pub fn with_arguments(mut self, arguments: JsonObject) -> Self {
4279 self.arguments = Some(arguments);
4280 self
4281 }
4282
4283 pub fn with_input_responses(mut self, input_responses: InputResponses) -> Self {
4285 self.input_responses = Some(input_responses);
4286 self
4287 }
4288
4289 pub fn with_request_state(mut self, request_state: impl Into<String>) -> Self {
4291 self.request_state = Some(request_state.into());
4292 self
4293 }
4294}
4295
4296impl RequestParamsMeta for CallToolRequestParams {
4297 fn meta(&self) -> Option<&RequestMetaObject> {
4298 self.meta.as_ref()
4299 }
4300 fn meta_mut(&mut self) -> &mut Option<RequestMetaObject> {
4301 &mut self.meta
4302 }
4303}
4304
4305pub type CallToolRequest = Request<CallToolRequestMethod, CallToolRequestParams>;
4307
4308#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
4314#[serde(rename_all = "camelCase")]
4315#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
4316#[non_exhaustive]
4317#[deprecated(
4318 since = "2.0.0",
4319 note = "Sampling is deprecated by SEP-2577 and will be removed in a future release. See https://github.com/modelcontextprotocol/modelcontextprotocol/pull/2577"
4320)]
4321pub struct CreateMessageResult {
4322 pub model: String,
4324 #[serde(skip_serializing_if = "Option::is_none")]
4326 pub stop_reason: Option<String>,
4327 #[serde(flatten)]
4329 pub message: SamplingMessage,
4330}
4331
4332impl CreateMessageResult {
4333 pub fn new(message: SamplingMessage, model: String) -> Self {
4335 Self {
4336 message,
4337 model,
4338 stop_reason: None,
4339 }
4340 }
4341
4342 pub const STOP_REASON_END_TURN: &str = "endTurn";
4343 pub const STOP_REASON_END_SEQUENCE: &str = "stopSequence";
4344 pub const STOP_REASON_END_MAX_TOKEN: &str = "maxTokens";
4345 pub const STOP_REASON_TOOL_USE: &str = "toolUse";
4346
4347 pub fn with_stop_reason(mut self, stop_reason: impl Into<String>) -> Self {
4349 self.stop_reason = Some(stop_reason.into());
4350 self
4351 }
4352
4353 pub fn with_model(mut self, model: impl Into<String>) -> Self {
4355 self.model = model.into();
4356 self
4357 }
4358
4359 pub fn validate(&self) -> Result<(), String> {
4361 if self.message.role != Role::Assistant {
4362 return Err("CreateMessageResult role must be 'assistant'".into());
4363 }
4364 Ok(())
4365 }
4366}
4367
4368#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
4369#[serde(rename_all = "camelCase")]
4370#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
4371#[non_exhaustive]
4372pub struct GetPromptResult {
4373 #[serde(default, skip_serializing_if = "Option::is_none")]
4384 pub result_type: Option<ResultType>,
4385 #[serde(skip_serializing_if = "Option::is_none")]
4386 pub description: Option<String>,
4387 pub messages: Vec<PromptMessage>,
4388 #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
4389 pub meta: Option<MetaObject>,
4390}
4391
4392impl Default for GetPromptResult {
4393 fn default() -> Self {
4394 Self::new(Vec::new())
4395 }
4396}
4397
4398impl GetPromptResult {
4399 pub fn new(messages: Vec<PromptMessage>) -> Self {
4401 Self {
4402 result_type: Some(ResultType::COMPLETE),
4403 description: None,
4404 messages,
4405 meta: None,
4406 }
4407 }
4408
4409 pub fn with_description<D: Into<String>>(mut self, description: D) -> Self {
4411 self.description = Some(description.into());
4412 self
4413 }
4414}
4415
4416const_string!(GetTaskMethod = "tasks/get");
4421pub type GetTaskRequest = Request<GetTaskMethod, GetTaskParams>;
4422
4423#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
4424#[serde(rename_all = "camelCase")]
4425#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
4426#[non_exhaustive]
4427pub struct GetTaskParams {
4428 #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
4429 pub meta: Option<RequestMetaObject>,
4430 pub task_id: String,
4432}
4433
4434impl GetTaskParams {
4435 pub fn new(task_id: impl Into<String>) -> Self {
4436 Self {
4437 meta: None,
4438 task_id: task_id.into(),
4439 }
4440 }
4441}
4442
4443impl RequestParamsMeta for GetTaskParams {
4444 fn meta(&self) -> Option<&RequestMetaObject> {
4445 self.meta.as_ref()
4446 }
4447 fn meta_mut(&mut self) -> &mut Option<RequestMetaObject> {
4448 &mut self.meta
4449 }
4450}
4451
4452const_string!(UpdateTaskMethod = "tasks/update");
4453pub type UpdateTaskRequest = Request<UpdateTaskMethod, UpdateTaskParams>;
4454
4455#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
4458#[serde(rename_all = "camelCase")]
4459#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
4460#[non_exhaustive]
4461pub struct UpdateTaskParams {
4462 #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
4463 pub meta: Option<RequestMetaObject>,
4464 pub task_id: String,
4466 pub input_responses: InputResponses,
4470}
4471
4472impl UpdateTaskParams {
4473 pub fn new(task_id: impl Into<String>, input_responses: InputResponses) -> Self {
4474 Self {
4475 meta: None,
4476 task_id: task_id.into(),
4477 input_responses,
4478 }
4479 }
4480}
4481
4482impl RequestParamsMeta for UpdateTaskParams {
4483 fn meta(&self) -> Option<&RequestMetaObject> {
4484 self.meta.as_ref()
4485 }
4486 fn meta_mut(&mut self) -> &mut Option<RequestMetaObject> {
4487 &mut self.meta
4488 }
4489}
4490
4491const_string!(CancelTaskMethod = "tasks/cancel");
4492pub type CancelTaskRequest = Request<CancelTaskMethod, CancelTaskParams>;
4493
4494#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
4495#[serde(rename_all = "camelCase")]
4496#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
4497#[non_exhaustive]
4498pub struct CancelTaskParams {
4499 #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
4501 pub meta: Option<RequestMetaObject>,
4502 pub task_id: String,
4503}
4504
4505impl CancelTaskParams {
4506 pub fn new(task_id: impl Into<String>) -> Self {
4507 Self {
4508 meta: None,
4509 task_id: task_id.into(),
4510 }
4511 }
4512}
4513
4514impl RequestParamsMeta for CancelTaskParams {
4515 fn meta(&self) -> Option<&RequestMetaObject> {
4516 self.meta.as_ref()
4517 }
4518 fn meta_mut(&mut self) -> &mut Option<RequestMetaObject> {
4519 &mut self.meta
4520 }
4521}
4522
4523const_string!(TaskStatusNotificationMethod = "notifications/tasks");
4527
4528#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
4534#[serde(rename_all = "camelCase")]
4535#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
4536#[non_exhaustive]
4537pub struct TaskStatusNotificationParams {
4538 #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
4539 pub meta: Option<NotificationMetaObject>,
4540 #[serde(flatten)]
4541 pub task: crate::model::DetailedTask,
4542}
4543
4544impl TaskStatusNotificationParams {
4545 pub fn new(task: crate::model::DetailedTask) -> Self {
4546 Self { meta: None, task }
4547 }
4548
4549 pub fn with_meta(mut self, meta: NotificationMetaObject) -> Self {
4550 self.meta = Some(meta);
4551 self
4552 }
4553}
4554
4555impl From<crate::model::DetailedTask> for TaskStatusNotificationParams {
4556 fn from(task: crate::model::DetailedTask) -> Self {
4557 Self::new(task)
4558 }
4559}
4560
4561impl Deref for TaskStatusNotificationParams {
4562 type Target = crate::model::DetailedTask;
4563
4564 fn deref(&self) -> &Self::Target {
4565 &self.task
4566 }
4567}
4568
4569impl DerefMut for TaskStatusNotificationParams {
4570 fn deref_mut(&mut self) -> &mut Self::Target {
4571 &mut self.task
4572 }
4573}
4574
4575pub type TaskStatusNotification =
4576 Notification<TaskStatusNotificationMethod, TaskStatusNotificationParams>;
4577
4578macro_rules! ts_union {
4583 (
4584 export type $U:ident =
4585 $($rest:tt)*
4586 ) => {
4587 ts_union!(@declare $U { $($rest)* });
4588 ts_union!(@impl_from $U { $($rest)* });
4589 };
4590 (@declare $U:ident { $($variant:tt)* }) => {
4591 ts_union!(@declare_variant $U { } {$($variant)*} );
4592 };
4593 (@declare_variant $U:ident { $($declared:tt)* } {$(|)? box $V:ident $($rest:tt)*}) => {
4594 ts_union!(@declare_variant $U { $($declared)* $V(Box<$V>), } {$($rest)*});
4595 };
4596 (@declare_variant $U:ident { $($declared:tt)* } {$(|)? $V:ident $($rest:tt)*}) => {
4597 ts_union!(@declare_variant $U { $($declared)* $V($V), } {$($rest)*});
4598 };
4599 (@declare_variant $U:ident { $($declared:tt)* } { ; }) => {
4600 ts_union!(@declare_end $U { $($declared)* } );
4601 };
4602 (@declare_end $U:ident { $($declared:tt)* }) => {
4603 #[derive(Debug, Serialize, Deserialize, Clone)]
4604 #[serde(untagged)]
4605 #[allow(clippy::large_enum_variant)]
4606 #[non_exhaustive]
4607 #[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
4608 pub enum $U {
4609 $($declared)*
4610 }
4611 };
4612 (@impl_from $U: ident {$(|)? box $V:ident $($rest:tt)*}) => {
4613 impl From<$V> for $U {
4614 fn from(value: $V) -> Self {
4615 $U::$V(Box::new(value))
4616 }
4617 }
4618 ts_union!(@impl_from $U {$($rest)*});
4619 };
4620 (@impl_from $U: ident {$(|)? $V:ident $($rest:tt)*}) => {
4621 impl From<$V> for $U {
4622 fn from(value: $V) -> Self {
4623 $U::$V(value)
4624 }
4625 }
4626 ts_union!(@impl_from $U {$($rest)*});
4627 };
4628 (@impl_from $U: ident { ; }) => {};
4629 (@impl_from $U: ident { }) => {};
4630}
4631
4632ts_union!(
4633 export type ClientRequest =
4634 | PingRequest
4635 | InitializeRequest
4636 | DiscoverRequest
4637 | CompleteRequest
4638 | SetLevelRequest
4639 | GetPromptRequest
4640 | ListPromptsRequest
4641 | ListResourcesRequest
4642 | ListResourceTemplatesRequest
4643 | ReadResourceRequest
4644 | SubscriptionsListenRequest
4645 | SubscribeRequest
4646 | UnsubscribeRequest
4647 | CallToolRequest
4648 | ListToolsRequest
4649 | GetTaskRequest
4650 | UpdateTaskRequest
4651 | CancelTaskRequest
4652 | CustomRequest;
4653);
4654
4655impl ClientRequest {
4656 pub fn method(&self) -> &str {
4657 match &self {
4658 ClientRequest::PingRequest(r) => r.method.as_str(),
4659 ClientRequest::InitializeRequest(r) => r.method.as_str(),
4660 ClientRequest::DiscoverRequest(r) => r.method.as_str(),
4661 ClientRequest::CompleteRequest(r) => r.method.as_str(),
4662 ClientRequest::SetLevelRequest(r) => r.method.as_str(),
4663 ClientRequest::GetPromptRequest(r) => r.method.as_str(),
4664 ClientRequest::ListPromptsRequest(r) => r.method.as_str(),
4665 ClientRequest::ListResourcesRequest(r) => r.method.as_str(),
4666 ClientRequest::ListResourceTemplatesRequest(r) => r.method.as_str(),
4667 ClientRequest::ReadResourceRequest(r) => r.method.as_str(),
4668 ClientRequest::SubscriptionsListenRequest(r) => r.method.as_str(),
4669 ClientRequest::SubscribeRequest(r) => r.method.as_str(),
4670 ClientRequest::UnsubscribeRequest(r) => r.method.as_str(),
4671 ClientRequest::CallToolRequest(r) => r.method.as_str(),
4672 ClientRequest::ListToolsRequest(r) => r.method.as_str(),
4673 ClientRequest::GetTaskRequest(r) => r.method.as_str(),
4674 ClientRequest::UpdateTaskRequest(r) => r.method.as_str(),
4675 ClientRequest::CancelTaskRequest(r) => r.method.as_str(),
4676 ClientRequest::CustomRequest(r) => r.method.as_str(),
4677 }
4678 }
4679}
4680
4681ts_union!(
4682 export type ClientNotification =
4683 | CancelledNotification
4684 | ProgressNotification
4685 | InitializedNotification
4686 | RootsListChangedNotification
4687 | CustomNotification;
4688);
4689
4690ts_union!(
4691 export type ClientResult =
4692 box CreateMessageResult
4693 | ListRootsResult
4694 | ElicitResult
4695 | EmptyResult
4696 | CustomResult;
4697);
4698
4699impl ClientResult {
4700 pub fn empty(_: ()) -> ClientResult {
4701 ClientResult::EmptyResult(EmptyResult {})
4702 }
4703}
4704
4705pub type ClientJsonRpcMessage = JsonRpcMessage<ClientRequest, ClientResult, ClientNotification>;
4706
4707ts_union!(
4708 export type ServerRequest =
4709 | PingRequest
4710 | CreateMessageRequest
4711 | ListRootsRequest
4712 | ElicitRequest
4713 | CustomRequest;
4714);
4715
4716ts_union!(
4717 export type ServerNotification =
4718 | CancelledNotification
4719 | ProgressNotification
4720 | LoggingMessageNotification
4721 | ResourceUpdatedNotification
4722 | ResourceListChangedNotification
4723 | ToolListChangedNotification
4724 | PromptListChangedNotification
4725 | SubscriptionsAcknowledgedNotification
4726 | TaskStatusNotification
4727 | CustomNotification;
4728);
4729
4730ts_union!(
4731 export type ServerResult =
4732 | DiscoverResult
4733 | InitializeResult
4734 | CompleteResult
4735 | GetPromptResult
4736 | ListPromptsResult
4737 | ListResourcesResult
4738 | ListResourceTemplatesResult
4739 | ReadResourceResult
4740 | SubscriptionsListenResult
4741 | ListToolsResult
4742 | ElicitResult
4743 | CreateTaskResult
4744 | GetTaskResult
4745 | CallToolResult
4746 | InputRequiredResult
4747 | TaskAckResult
4751 | EmptyResult
4752 | CustomResult
4753 ;
4754);
4755
4756impl ServerResult {
4757 pub fn empty(_: ()) -> ServerResult {
4758 ServerResult::EmptyResult(EmptyResult {})
4759 }
4760
4761 pub fn task_ack(_: ()) -> ServerResult {
4764 ServerResult::TaskAckResult(TaskAckResult::new())
4765 }
4766
4767 pub fn strip_result_type_for_legacy_peer(&mut self) {
4789 let result_type = match self {
4790 ServerResult::CompleteResult(r) => &mut r.result_type,
4791 ServerResult::GetPromptResult(r) => &mut r.result_type,
4792 ServerResult::ListPromptsResult(r) => &mut r.result_type,
4793 ServerResult::ListResourcesResult(r) => &mut r.result_type,
4794 ServerResult::ListResourceTemplatesResult(r) => &mut r.result_type,
4795 ServerResult::ReadResourceResult(r) => &mut r.result_type,
4796 ServerResult::ListToolsResult(r) => &mut r.result_type,
4797 ServerResult::CallToolResult(r) => &mut r.result_type,
4798 _ => return,
4799 };
4800 result_type.take_if(|result_type| result_type.is_complete());
4801 }
4802
4803 pub fn fill_missing_cache_hints(&mut self) {
4831 let (result_type, ttl_ms, cache_scope) = match self {
4832 ServerResult::ListToolsResult(r) => (&r.result_type, &mut r.ttl_ms, &mut r.cache_scope),
4833 ServerResult::ListPromptsResult(r) => {
4834 (&r.result_type, &mut r.ttl_ms, &mut r.cache_scope)
4835 }
4836 ServerResult::ListResourcesResult(r) => {
4837 (&r.result_type, &mut r.ttl_ms, &mut r.cache_scope)
4838 }
4839 ServerResult::ListResourceTemplatesResult(r) => {
4840 (&r.result_type, &mut r.ttl_ms, &mut r.cache_scope)
4841 }
4842 ServerResult::ReadResourceResult(r) => {
4843 (&r.result_type, &mut r.ttl_ms, &mut r.cache_scope)
4844 }
4845 _ => return,
4846 };
4847 if result_type.as_ref().is_some_and(|t| !t.is_complete()) {
4850 return;
4851 }
4852 ttl_ms.get_or_insert(0);
4853 cache_scope.get_or_insert(CacheScope::Private);
4854 }
4855}
4856
4857pub type ServerJsonRpcMessage = JsonRpcMessage<ServerRequest, ServerResult, ServerNotification>;
4858
4859impl TryInto<CancelledNotification> for ServerNotification {
4860 type Error = ServerNotification;
4861 fn try_into(self) -> Result<CancelledNotification, Self::Error> {
4862 if let ServerNotification::CancelledNotification(t) = self {
4863 Ok(t)
4864 } else {
4865 Err(self)
4866 }
4867 }
4868}
4869
4870impl TryInto<CancelledNotification> for ClientNotification {
4871 type Error = ClientNotification;
4872 fn try_into(self) -> Result<CancelledNotification, Self::Error> {
4873 if let ClientNotification::CancelledNotification(t) = self {
4874 Ok(t)
4875 } else {
4876 Err(self)
4877 }
4878 }
4879}
4880
4881#[cfg(test)]
4886mod tests {
4887 use serde_json::json;
4888
4889 use super::*;
4890
4891 #[test]
4892 fn known_versions_are_ordered_oldest_first() {
4893 assert!(
4895 ProtocolVersion::KNOWN_VERSIONS
4896 .windows(2)
4897 .all(|pair| pair[0].as_str() < pair[1].as_str())
4898 );
4899 }
4900
4901 #[test]
4905 fn latest_with_initialize_is_the_newest_known_version_that_has_one() {
4906 let derived = ProtocolVersion::KNOWN_VERSIONS
4907 .iter()
4908 .filter(|version| version.has_initialize())
4909 .max_by(|left, right| left.as_str().cmp(right.as_str()))
4910 .expect("some known version should have an initialize handshake");
4911 assert_eq!(
4912 derived,
4913 &ProtocolVersion::LATEST_WITH_INITIALIZE,
4914 "LATEST_WITH_INITIALIZE must track KNOWN_VERSIONS"
4915 );
4916 }
4917
4918 #[test]
4919 fn has_initialize_splits_known_versions_at_no_initialize() {
4920 for version in ProtocolVersion::KNOWN_VERSIONS {
4921 assert_eq!(
4922 version.has_initialize(),
4923 version.as_str() < ProtocolVersion::NO_INITIALIZE.as_str(),
4924 "{version} classified inconsistently"
4925 );
4926 }
4927 }
4928
4929 #[test]
4930 fn known_up_to_includes_the_ceiling_itself() {
4931 assert_eq!(
4932 ProtocolVersion::known_up_to(&ProtocolVersion::V_2024_11_05),
4933 &[ProtocolVersion::V_2024_11_05]
4934 );
4935 }
4936
4937 #[test]
4938 fn known_up_to_the_newest_version_yields_every_known_version() {
4939 assert_eq!(
4940 ProtocolVersion::known_up_to(&ProtocolVersion::V_2026_07_28),
4941 ProtocolVersion::KNOWN_VERSIONS
4942 );
4943 }
4944
4945 #[test]
4946 fn known_up_to_an_unknown_ceiling_stops_at_the_versions_below_it() {
4947 let unknown = ProtocolVersion(Cow::Borrowed("2025-07-01"));
4948 assert_eq!(
4949 ProtocolVersion::known_up_to(&unknown),
4950 &[
4951 ProtocolVersion::V_2024_11_05,
4952 ProtocolVersion::V_2025_03_26,
4953 ProtocolVersion::V_2025_06_18,
4954 ]
4955 );
4956 }
4957
4958 #[test]
4959 fn known_up_to_a_ceiling_below_every_known_version_is_empty() {
4960 let ancient = ProtocolVersion(Cow::Borrowed("1999-01-01"));
4961 assert!(ProtocolVersion::known_up_to(&ancient).is_empty());
4962 }
4963
4964 #[cfg(feature = "transport-streamable-http-client")]
4965 #[test]
4966 fn transport_closed_marker_accepts_only_the_process_local_token() {
4967 let local = ErrorData::transport_closed("closed");
4968 let spoofed = ErrorData::internal_error(
4969 "spoofed",
4970 Some(json!({ "io.modelcontextprotocol/transportClosed": true })),
4971 );
4972
4973 assert!(local.is_transport_closed());
4974 assert!(!spoofed.is_transport_closed());
4975 }
4976
4977 #[test]
4978 fn cancelled_notification_request_id_is_optional_on_wire() {
4979 let p = CancelledNotificationParam::new(None, Some("user cancelled".into()));
4981 let v = serde_json::to_value(&p).unwrap();
4982 assert!(v.get("requestId").is_none());
4983
4984 let p = CancelledNotificationParam::new(Some(RequestId::Number(1)), None);
4986 let v = serde_json::to_value(&p).unwrap();
4987 assert_eq!(v["requestId"], json!(1));
4988 let back: CancelledNotificationParam = serde_json::from_value(v).unwrap();
4989 assert_eq!(back.request_id, Some(RequestId::Number(1)));
4990 }
4991
4992 #[test]
4993 fn test_notification_serde() {
4994 let raw = json!( {
4995 "jsonrpc": JsonRpcVersion2_0,
4996 "method": InitializedNotificationMethod,
4997 });
4998 let message: ClientJsonRpcMessage =
4999 serde_json::from_value(raw.clone()).expect("invalid notification");
5000 match &message {
5001 ClientJsonRpcMessage::Notification(JsonRpcNotification {
5002 notification: ClientNotification::InitializedNotification(_n),
5003 ..
5004 }) => {}
5005 _ => panic!("Expected Notification"),
5006 }
5007 let json = serde_json::to_value(message).expect("valid json");
5008 assert_eq!(json, raw);
5009 }
5010
5011 #[test]
5012 fn test_custom_client_notification_roundtrip() {
5013 let raw = json!( {
5014 "jsonrpc": JsonRpcVersion2_0,
5015 "method": "notifications/custom",
5016 "params": {"foo": "bar"},
5017 });
5018
5019 let message: ClientJsonRpcMessage =
5020 serde_json::from_value(raw.clone()).expect("invalid notification");
5021 match &message {
5022 ClientJsonRpcMessage::Notification(JsonRpcNotification {
5023 notification: ClientNotification::CustomNotification(notification),
5024 ..
5025 }) => {
5026 assert_eq!(notification.method, "notifications/custom");
5027 assert_eq!(
5028 notification
5029 .params
5030 .as_ref()
5031 .and_then(|p| p.get("foo"))
5032 .expect("foo present"),
5033 "bar"
5034 );
5035 }
5036 _ => panic!("Expected custom client notification"),
5037 }
5038
5039 let json = serde_json::to_value(message).expect("valid json");
5040 assert_eq!(json, raw);
5041 }
5042
5043 #[test]
5044 fn test_custom_server_notification_roundtrip() {
5045 let raw = json!( {
5046 "jsonrpc": JsonRpcVersion2_0,
5047 "method": "notifications/custom-server",
5048 "params": {"hello": "world"},
5049 });
5050
5051 let message: ServerJsonRpcMessage =
5052 serde_json::from_value(raw.clone()).expect("invalid notification");
5053 match &message {
5054 ServerJsonRpcMessage::Notification(JsonRpcNotification {
5055 notification: ServerNotification::CustomNotification(notification),
5056 ..
5057 }) => {
5058 assert_eq!(notification.method, "notifications/custom-server");
5059 assert_eq!(
5060 notification
5061 .params
5062 .as_ref()
5063 .and_then(|p| p.get("hello"))
5064 .expect("hello present"),
5065 "world"
5066 );
5067 }
5068 _ => panic!("Expected custom server notification"),
5069 }
5070
5071 let json = serde_json::to_value(message).expect("valid json");
5072 assert_eq!(json, raw);
5073 }
5074
5075 #[test]
5076 fn test_custom_request_roundtrip() {
5077 let raw = json!( {
5078 "jsonrpc": JsonRpcVersion2_0,
5079 "id": 42,
5080 "method": "requests/custom",
5081 "params": {"foo": "bar"},
5082 });
5083
5084 let message: ClientJsonRpcMessage =
5085 serde_json::from_value(raw.clone()).expect("invalid request");
5086 match &message {
5087 ClientJsonRpcMessage::Request(JsonRpcRequest { id, request, .. }) => {
5088 assert_eq!(id, &RequestId::Number(42));
5089 match request {
5090 ClientRequest::CustomRequest(custom) => {
5091 let expected_request = json!({
5092 "method": "requests/custom",
5093 "params": {"foo": "bar"},
5094 });
5095 let actual_request =
5096 serde_json::to_value(custom).expect("serialize custom request");
5097 assert_eq!(actual_request, expected_request);
5098 }
5099 other => panic!("Expected custom request, got: {other:?}"),
5100 }
5101 }
5102 other => panic!("Expected request, got: {other:?}"),
5103 }
5104
5105 let json = serde_json::to_value(message).expect("valid json");
5106 assert_eq!(json, raw);
5107 }
5108
5109 #[test]
5110 fn test_request_conversion() {
5111 let raw = json!( {
5112 "jsonrpc": JsonRpcVersion2_0,
5113 "id": 1,
5114 "method": "request",
5115 "params": {"key": "value"},
5116 });
5117 let message: JsonRpcMessage = serde_json::from_value(raw.clone()).expect("invalid request");
5118
5119 match &message {
5120 JsonRpcMessage::Request(r) => {
5121 assert_eq!(r.id, RequestId::Number(1));
5122 assert_eq!(r.request.method, "request");
5123 assert_eq!(
5124 &r.request.params,
5125 json!({"key": "value"})
5126 .as_object()
5127 .expect("should be an object")
5128 );
5129 }
5130 _ => panic!("Expected Request"),
5131 }
5132 let json = serde_json::to_value(&message).expect("valid json");
5133 assert_eq!(json, raw);
5134 }
5135
5136 #[test]
5137 fn test_initial_request_response_serde() {
5138 let request = json!({
5139 "jsonrpc": "2.0",
5140 "id": 1,
5141 "method": "initialize",
5142 "params": {
5143 "protocolVersion": "2024-11-05",
5144 "capabilities": {
5145 "roots": {
5146 "listChanged": true
5147 },
5148 "sampling": {}
5149 },
5150 "clientInfo": {
5151 "name": "ExampleClient",
5152 "version": "1.0.0"
5153 }
5154 }
5155 });
5156 let raw_response_json = json!({
5157 "jsonrpc": "2.0",
5158 "id": 1,
5159 "result": {
5160 "protocolVersion": "2024-11-05",
5161 "capabilities": {
5162 "logging": {},
5163 "prompts": {
5164 "listChanged": true
5165 },
5166 "resources": {
5167 "subscribe": true,
5168 "listChanged": true
5169 },
5170 "tools": {
5171 "listChanged": true
5172 }
5173 },
5174 "serverInfo": {
5175 "name": "ExampleServer",
5176 "version": "1.0.0"
5177 }
5178 }
5179 });
5180 let request: ClientJsonRpcMessage =
5181 serde_json::from_value(request.clone()).expect("invalid request");
5182 let (request, id) = request.into_request().expect("should be a request");
5183 assert_eq!(id, RequestId::Number(1));
5184 match request {
5185 ClientRequest::InitializeRequest(Request {
5186 method: _,
5187 params:
5188 InitializeRequestParams {
5189 meta: _,
5190 protocol_version: _,
5191 capabilities,
5192 client_info,
5193 },
5194 ..
5195 }) => {
5196 assert_eq!(capabilities.roots.unwrap().list_changed, Some(true));
5197 let sampling = capabilities.sampling.unwrap();
5198 assert_eq!(sampling.tools, None);
5199 assert_eq!(sampling.context, None);
5200 assert_eq!(client_info.name, "ExampleClient");
5201 assert_eq!(client_info.version, "1.0.0");
5202 }
5203 _ => panic!("Expected InitializeRequest"),
5204 }
5205 let server_response: ServerJsonRpcMessage =
5206 serde_json::from_value(raw_response_json.clone()).expect("invalid response");
5207 let (response, id) = server_response
5208 .clone()
5209 .into_response()
5210 .expect("expect response");
5211 assert_eq!(id, RequestId::Number(1));
5212 match response {
5213 ServerResult::InitializeResult(InitializeResult {
5214 protocol_version: _,
5215 capabilities,
5216 server_info,
5217 instructions,
5218 ..
5219 }) => {
5220 assert_eq!(capabilities.logging.unwrap().len(), 0);
5221 assert_eq!(capabilities.prompts.unwrap().list_changed, Some(true));
5222 assert_eq!(
5223 capabilities.resources.as_ref().unwrap().subscribe,
5224 Some(true)
5225 );
5226 assert_eq!(capabilities.resources.unwrap().list_changed, Some(true));
5227 assert_eq!(capabilities.tools.unwrap().list_changed, Some(true));
5228 assert_eq!(server_info.name, "ExampleServer");
5229 assert_eq!(server_info.version, "1.0.0");
5230 assert_eq!(server_info.icons, None);
5231 assert_eq!(instructions, None);
5232 }
5233 other => panic!("Expected InitializeResult, got {other:?}"),
5234 }
5235
5236 let server_response_json: Value = serde_json::to_value(&server_response).expect("msg");
5237
5238 assert_eq!(server_response_json, raw_response_json);
5239 }
5240
5241 #[test]
5242 fn test_negative_and_large_request_ids() {
5243 let negative_id_json = json!({
5245 "jsonrpc": "2.0",
5246 "id": -1,
5247 "method": "test",
5248 "params": {}
5249 });
5250
5251 let message: JsonRpcMessage =
5252 serde_json::from_value(negative_id_json.clone()).expect("Should parse negative ID");
5253
5254 match &message {
5255 JsonRpcMessage::Request(r) => {
5256 assert_eq!(r.id, RequestId::Number(-1));
5257 }
5258 _ => panic!("Expected Request"),
5259 }
5260
5261 let serialized = serde_json::to_value(&message).expect("Should serialize");
5263 assert_eq!(serialized, negative_id_json);
5264
5265 let large_negative_json = json!({
5267 "jsonrpc": "2.0",
5268 "id": -9007199254740991i64, "method": "test",
5270 "params": {}
5271 });
5272
5273 let message: JsonRpcMessage = serde_json::from_value(large_negative_json.clone())
5274 .expect("Should parse large negative ID");
5275
5276 match &message {
5277 JsonRpcMessage::Request(r) => {
5278 assert_eq!(r.id, RequestId::Number(-9007199254740991i64));
5279 }
5280 _ => panic!("Expected Request"),
5281 }
5282
5283 let large_positive_json = json!({
5285 "jsonrpc": "2.0",
5286 "id": 9007199254740991i64,
5287 "method": "test",
5288 "params": {}
5289 });
5290
5291 let message: JsonRpcMessage = serde_json::from_value(large_positive_json.clone())
5292 .expect("Should parse large positive ID");
5293
5294 match &message {
5295 JsonRpcMessage::Request(r) => {
5296 assert_eq!(r.id, RequestId::Number(9007199254740991i64));
5297 }
5298 _ => panic!("Expected Request"),
5299 }
5300
5301 let zero_id_json = json!({
5303 "jsonrpc": "2.0",
5304 "id": 0,
5305 "method": "test",
5306 "params": {}
5307 });
5308
5309 let message: JsonRpcMessage =
5310 serde_json::from_value(zero_id_json.clone()).expect("Should parse zero ID");
5311
5312 match &message {
5313 JsonRpcMessage::Request(r) => {
5314 assert_eq!(r.id, RequestId::Number(0));
5315 }
5316 _ => panic!("Expected Request"),
5317 }
5318 }
5319
5320 #[test]
5321 fn test_protocol_version_order() {
5322 let v1 = ProtocolVersion::V_2024_11_05;
5323 let v2 = ProtocolVersion::V_2025_03_26;
5324 let v3 = ProtocolVersion::V_2025_06_18;
5325 let v4 = ProtocolVersion::V_2025_11_25;
5326 assert!(v1 < v2);
5327 assert!(v2 < v3);
5328 assert!(v3 < v4);
5329 }
5330
5331 #[test]
5332 fn test_icon_serialization() {
5333 let icon = Icon {
5334 src: "https://example.com/icon.png".to_string(),
5335 mime_type: Some("image/png".to_string()),
5336 sizes: Some(vec!["48x48".to_string()]),
5337 theme: Some(IconTheme::Light),
5338 };
5339
5340 let json = serde_json::to_value(&icon).unwrap();
5341 assert_eq!(json["src"], "https://example.com/icon.png");
5342 assert_eq!(json["mimeType"], "image/png");
5343 assert_eq!(json["sizes"][0], "48x48");
5344 assert_eq!(json["theme"], "light");
5345
5346 let deserialized: Icon = serde_json::from_value(json).unwrap();
5348 assert_eq!(deserialized, icon);
5349 }
5350
5351 #[test]
5352 fn test_icon_minimal() {
5353 let icon = Icon {
5354 src: "data:image/svg+xml;base64,PHN2Zy8+".to_string(),
5355 mime_type: None,
5356 sizes: None,
5357 theme: None,
5358 };
5359
5360 let json = serde_json::to_value(&icon).unwrap();
5361 assert_eq!(json["src"], "data:image/svg+xml;base64,PHN2Zy8+");
5362 assert!(json.get("mimeType").is_none());
5363 assert!(json.get("sizes").is_none());
5364 assert!(json.get("theme").is_none());
5365 }
5366
5367 #[test]
5368 fn test_implementation_with_icons() {
5369 let implementation = Implementation {
5370 name: "test-server".to_string(),
5371 title: Some("Test Server".to_string()),
5372 version: "1.0.0".to_string(),
5373 description: Some("A test server for unit testing".to_string()),
5374 icons: Some(vec![
5375 Icon {
5376 src: "https://example.com/icon.png".to_string(),
5377 mime_type: Some("image/png".to_string()),
5378 sizes: Some(vec!["48x48".to_string()]),
5379 theme: Some(IconTheme::Dark),
5380 },
5381 Icon {
5382 src: "https://example.com/icon.svg".to_string(),
5383 mime_type: Some("image/svg+xml".to_string()),
5384 sizes: Some(vec!["any".to_string()]),
5385 theme: Some(IconTheme::Light),
5386 },
5387 ]),
5388 website_url: Some("https://example.com".to_string()),
5389 };
5390
5391 let json = serde_json::to_value(&implementation).unwrap();
5392 assert_eq!(json["name"], "test-server");
5393 assert_eq!(json["description"], "A test server for unit testing");
5394 assert_eq!(json["websiteUrl"], "https://example.com");
5395 assert!(json["icons"].is_array());
5396 assert_eq!(json["icons"][0]["src"], "https://example.com/icon.png");
5397 assert_eq!(json["icons"][0]["sizes"][0], "48x48");
5398 assert_eq!(json["icons"][1]["mimeType"], "image/svg+xml");
5399 assert_eq!(json["icons"][1]["sizes"][0], "any");
5400 assert_eq!(json["icons"][0]["theme"], "dark");
5401 assert_eq!(json["icons"][1]["theme"], "light");
5402 }
5403
5404 #[test]
5405 fn test_backward_compatibility() {
5406 let old_json = json!({
5408 "name": "legacy-server",
5409 "version": "0.9.0"
5410 });
5411
5412 let implementation: Implementation = serde_json::from_value(old_json).unwrap();
5413 assert_eq!(implementation.name, "legacy-server");
5414 assert_eq!(implementation.version, "0.9.0");
5415 assert_eq!(implementation.description, None);
5416 assert_eq!(implementation.icons, None);
5417 assert_eq!(implementation.website_url, None);
5418 }
5419
5420 #[test]
5421 fn test_initialize_with_icons() {
5422 let init_result = InitializeResult {
5423 protocol_version: ProtocolVersion::default(),
5424 capabilities: ServerCapabilities::default(),
5425 server_info: Implementation {
5426 name: "icon-server".to_string(),
5427 title: None,
5428 version: "2.0.0".to_string(),
5429 description: None,
5430 icons: Some(vec![Icon {
5431 src: "https://example.com/server.png".to_string(),
5432 mime_type: Some("image/png".to_string()),
5433 sizes: Some(vec!["48x48".to_string()]),
5434 theme: Some(IconTheme::Light),
5435 }]),
5436 website_url: Some("https://docs.example.com".to_string()),
5437 },
5438 instructions: None,
5439 meta: None,
5440 };
5441
5442 let json = serde_json::to_value(&init_result).unwrap();
5443 assert!(json["serverInfo"]["icons"].is_array());
5444 assert_eq!(
5445 json["serverInfo"]["icons"][0]["src"],
5446 "https://example.com/server.png"
5447 );
5448 assert_eq!(json["serverInfo"]["icons"][0]["sizes"][0], "48x48");
5449 assert_eq!(json["serverInfo"]["icons"][0]["theme"], "light");
5450 assert_eq!(json["serverInfo"]["websiteUrl"], "https://docs.example.com");
5451 }
5452
5453 #[test]
5454 fn elicitation_without_mode_deserializes_as_form() {
5455 let json_data_without_tag = json!({
5456 "message": "Please provide more details.",
5457 "requestedSchema": {
5458 "title": "User Details",
5459 "type": "object",
5460 "properties": {
5461 "name": { "type": "string" },
5462 "age": { "type": "integer" }
5463 },
5464 "required": ["name", "age"]
5465 }
5466 });
5467 let elicitation: ElicitRequestParams =
5468 serde_json::from_value(json_data_without_tag).expect("Deserialization failed");
5469 if let ElicitRequestParams::FormElicitationParams {
5470 meta,
5471 message,
5472 requested_schema,
5473 } = elicitation
5474 {
5475 assert_eq!(meta, None);
5476 assert_eq!(message, "Please provide more details.");
5477 assert_eq!(requested_schema.title, Some(Cow::from("User Details")));
5478 assert_eq!(requested_schema.type_, ObjectTypeConst);
5479 } else {
5480 panic!("Expected FormElicitationParams");
5481 }
5482 }
5483
5484 #[test]
5485 fn test_elicitation_deserialization() {
5486 let json_data_form = json!({
5487 "_meta": { "meta_form_key_1": "meta form value 1" },
5488 "mode": "form",
5489 "message": "Please provide more details.",
5490 "requestedSchema": {
5491 "title": "User Details",
5492 "type": "object",
5493 "properties": {
5494 "name": { "type": "string" },
5495 "age": { "type": "integer" }
5496 },
5497 "required": ["name", "age"]
5498 }
5499 });
5500 let elicitation_form: ElicitRequestParams =
5501 serde_json::from_value(json_data_form).expect("Deserialization failed");
5502 if let ElicitRequestParams::FormElicitationParams {
5503 meta,
5504 message,
5505 requested_schema,
5506 } = elicitation_form
5507 {
5508 assert_eq!(
5509 meta,
5510 Some(RequestMetaObject(MetaObject(
5511 object!({ "meta_form_key_1": "meta form value 1" })
5512 )))
5513 );
5514 assert_eq!(message, "Please provide more details.");
5515 assert_eq!(requested_schema.title, Some(Cow::from("User Details")));
5516 assert_eq!(requested_schema.type_, ObjectTypeConst);
5517 } else {
5518 panic!("Expected FormElicitationParams");
5519 }
5520
5521 let json_data_url = json!({
5522 "_meta": { "meta_url_key_1": "meta url value 1" },
5523 "mode": "url",
5524 "message": "Please fill out the form at the following URL.",
5525 "url": "https://example.com/form",
5526 "elicitationId": "elicitation-123"
5527 });
5528 let elicitation_url: ElicitRequestParams =
5529 serde_json::from_value(json_data_url).expect("Deserialization failed");
5530 if let ElicitRequestParams::UrlElicitationParams {
5531 meta,
5532 message,
5533 url,
5534 elicitation_id,
5535 } = elicitation_url
5536 {
5537 assert_eq!(
5538 meta,
5539 Some(RequestMetaObject(MetaObject(
5540 object!({ "meta_url_key_1": "meta url value 1" })
5541 )))
5542 );
5543 assert_eq!(message, "Please fill out the form at the following URL.");
5544 assert_eq!(url, "https://example.com/form");
5545 assert_eq!(elicitation_id, "elicitation-123");
5546 } else {
5547 panic!("Expected UrlElicitationParams");
5548 }
5549 }
5550
5551 #[test]
5552 fn test_elicitation_serialization() {
5553 let form_elicitation = ElicitRequestParams::FormElicitationParams {
5554 meta: Some(RequestMetaObject(MetaObject(
5555 object!({ "meta_form_key_1": "meta form value 1" }),
5556 ))),
5557 message: "Please provide more details.".to_string(),
5558 requested_schema: ElicitationSchema::builder()
5559 .title("User Details")
5560 .string_property("name", |s| s)
5561 .build()
5562 .expect("Valid schema"),
5563 };
5564 let json_form = serde_json::to_value(&form_elicitation).expect("Serialization failed");
5565 let expected_form_json = json!({
5566 "_meta": { "meta_form_key_1": "meta form value 1" },
5567 "mode": "form",
5568 "message": "Please provide more details.",
5569 "requestedSchema": {
5570 "title":"User Details",
5571 "type":"object",
5572 "properties":{
5573 "name": { "type": "string" },
5574 },
5575 }
5576 });
5577 assert_eq!(json_form, expected_form_json);
5578
5579 let url_elicitation = ElicitRequestParams::UrlElicitationParams {
5580 meta: Some(RequestMetaObject(MetaObject(
5581 object!({ "meta_url_key_1": "meta url value 1" }),
5582 ))),
5583 message: "Please fill out the form at the following URL.".to_string(),
5584 url: "https://example.com/form".to_string(),
5585 elicitation_id: "elicitation-123".to_string(),
5586 };
5587 let json_url = serde_json::to_value(&url_elicitation).expect("Serialization failed");
5588 let expected_url_json = json!({
5589 "_meta": { "meta_url_key_1": "meta url value 1" },
5590 "mode": "url",
5591 "message": "Please fill out the form at the following URL.",
5592 "url": "https://example.com/form",
5593 "elicitationId": "elicitation-123"
5594 });
5595 assert_eq!(json_url, expected_url_json);
5596 }
5597
5598 #[test]
5599 fn notification_without_params_should_deserialize_as_bare_jsonrpc_message() {
5600 let payload = b"{\"method\":\"notifications/initialized\",\"jsonrpc\":\"2.0\"}";
5601 let result: Result<JsonRpcMessage, _> = serde_json::from_slice(payload);
5602 assert!(
5603 matches!(result, Ok(JsonRpcMessage::Notification(_))),
5604 "Expected Ok(Notification), got: {:?}",
5605 result
5606 );
5607 }
5608}