Skip to main content

rmcp/
model.rs

1// Internal references to the SEP-2577-deprecated Roots/Sampling/Logging types
2// defined in this module are expected; the deprecation is advisory for downstream users.
3#![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
41/// A JSON object type alias for convenient handling of JSON data.
42///
43/// You can use [`crate::object!`] or [`crate::model::object`] to create a json object quickly.
44/// This is commonly used for storing arbitrary JSON data in MCP messages.
45pub type JsonObject<F = Value> = serde_json::Map<String, F>;
46
47/// unwrap the JsonObject under [`serde_json::Value`]
48///
49/// # Panic
50/// This will panic when the value is not a object in debug mode.
51pub 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/// Use this macro just like [`serde_json::json!`]
60#[cfg(feature = "macros")]
61#[macro_export]
62macro_rules! object {
63    ({$($tt:tt)*}) => {
64        $crate::model::object(serde_json::json! {
65            {$($tt)*}
66        })
67    };
68}
69
70/// This is commonly used for representing empty objects in MCP messages.
71///
72/// without returning any specific data.
73#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Copy, Eq)]
74#[serde(deny_unknown_fields)]
75#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
76#[expect(clippy::exhaustive_structs, reason = "intentionally exhaustive")]
77pub struct EmptyObject {}
78
79pub trait ConstString: Default {
80    const VALUE: &str;
81    fn as_str(&self) -> &'static str {
82        Self::VALUE
83    }
84}
85#[macro_export]
86macro_rules! const_string {
87    ($name:ident = $value:literal) => {
88        #[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
89        #[expect(clippy::exhaustive_structs, reason = "intentionally exhaustive")]
90        pub struct $name;
91
92        impl ConstString for $name {
93            const VALUE: &str = $value;
94        }
95
96        impl serde::Serialize for $name {
97            fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
98            where
99                S: serde::Serializer,
100            {
101                $value.serialize(serializer)
102            }
103        }
104
105        impl<'de> serde::Deserialize<'de> for $name {
106            fn deserialize<D>(deserializer: D) -> Result<$name, D::Error>
107            where
108                D: serde::Deserializer<'de>,
109            {
110                let s: String = serde::Deserialize::deserialize(deserializer)?;
111                if s == $value {
112                    Ok($name)
113                } else {
114                    Err(serde::de::Error::custom(format!(concat!(
115                        "expect const string value \"",
116                        $value,
117                        "\""
118                    ))))
119                }
120            }
121        }
122
123        #[cfg(feature = "schemars")]
124        impl schemars::JsonSchema for $name {
125            fn schema_name() -> Cow<'static, str> {
126                Cow::Borrowed(stringify!($name))
127            }
128
129            fn json_schema(_: &mut schemars::SchemaGenerator) -> schemars::Schema {
130                use serde_json::{Map, json};
131
132                let mut schema_map = Map::new();
133                schema_map.insert("type".to_string(), json!("string"));
134                schema_map.insert("format".to_string(), json!("const"));
135                schema_map.insert("const".to_string(), json!($value));
136
137                schemars::Schema::from(schema_map)
138            }
139        }
140    };
141}
142
143const_string!(JsonRpcVersion2_0 = "2.0");
144
145// =============================================================================
146// CORE PROTOCOL TYPES
147// =============================================================================
148
149/// Represents the MCP protocol version used for communication.
150///
151/// This ensures compatibility between clients and servers by specifying
152/// which version of the Model Context Protocol is being used.
153#[derive(Debug, Clone, Eq, PartialEq, Hash, PartialOrd)]
154#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
155pub struct ProtocolVersion(Cow<'static, str>);
156
157impl Default for ProtocolVersion {
158    fn default() -> Self {
159        Self::LATEST
160    }
161}
162
163impl std::fmt::Display for ProtocolVersion {
164    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
165        self.0.fmt(f)
166    }
167}
168
169impl ProtocolVersion {
170    pub const V_2026_07_28: Self = Self(Cow::Borrowed("2026-07-28"));
171    pub const V_2025_11_25: Self = Self(Cow::Borrowed("2025-11-25"));
172    pub const V_2025_06_18: Self = Self(Cow::Borrowed("2025-06-18"));
173    pub const V_2025_03_26: Self = Self(Cow::Borrowed("2025-03-26"));
174    pub const V_2024_11_05: Self = Self(Cow::Borrowed("2024-11-05"));
175    pub const LATEST: Self = Self::V_2025_11_25;
176
177    /// First protocol version that requires SEP-2243 standard HTTP headers.
178    pub const STANDARD_HEADERS: Self = Self::V_2026_07_28;
179
180    /// All protocol versions known to this SDK.
181    pub const KNOWN_VERSIONS: &[Self] = &[
182        Self::V_2024_11_05,
183        Self::V_2025_03_26,
184        Self::V_2025_06_18,
185        Self::V_2025_11_25,
186        Self::V_2026_07_28,
187    ];
188
189    /// Returns the string representation of this protocol version.
190    pub fn as_str(&self) -> &str {
191        &self.0
192    }
193}
194
195impl Serialize for ProtocolVersion {
196    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
197    where
198        S: serde::Serializer,
199    {
200        self.0.serialize(serializer)
201    }
202}
203
204impl<'de> Deserialize<'de> for ProtocolVersion {
205    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
206    where
207        D: serde::Deserializer<'de>,
208    {
209        let s: String = Deserialize::deserialize(deserializer)?;
210        #[allow(clippy::single_match)]
211        match s.as_str() {
212            "2024-11-05" => return Ok(ProtocolVersion::V_2024_11_05),
213            "2025-03-26" => return Ok(ProtocolVersion::V_2025_03_26),
214            "2025-06-18" => return Ok(ProtocolVersion::V_2025_06_18),
215            "2025-11-25" => return Ok(ProtocolVersion::V_2025_11_25),
216            "2026-07-28" => return Ok(ProtocolVersion::V_2026_07_28),
217            _ => {}
218        }
219        Ok(ProtocolVersion(Cow::Owned(s)))
220    }
221}
222
223/// A flexible identifier type that can be either a number or a string.
224///
225/// This is commonly used for request IDs and other identifiers in JSON-RPC
226/// where the specification allows both numeric and string values.
227#[derive(Debug, Clone, Eq, PartialEq, Hash)]
228#[expect(clippy::exhaustive_enums, reason = "intentionally exhaustive")]
229pub enum NumberOrString {
230    /// A numeric identifier
231    Number(i64),
232    /// A string identifier
233    String(Arc<str>),
234}
235
236impl NumberOrString {
237    pub fn into_json_value(self) -> Value {
238        match self {
239            NumberOrString::Number(n) => Value::Number(serde_json::Number::from(n)),
240            NumberOrString::String(s) => Value::String(s.to_string()),
241        }
242    }
243
244    pub(crate) fn numeric_string_value(&self) -> Option<i64> {
245        match self {
246            Self::String(id) => id.parse().ok(),
247            Self::Number(_) => None,
248        }
249    }
250
251    pub(crate) fn matches_response_id(&self, response_id: &Self) -> bool {
252        self == response_id
253            || matches!(
254                self,
255                Self::Number(request_id)
256                    if response_id.numeric_string_value() == Some(*request_id)
257            )
258    }
259}
260
261impl std::fmt::Display for NumberOrString {
262    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
263        match self {
264            NumberOrString::Number(n) => n.fmt(f),
265            NumberOrString::String(s) => s.fmt(f),
266        }
267    }
268}
269
270impl Serialize for NumberOrString {
271    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
272    where
273        S: serde::Serializer,
274    {
275        match self {
276            NumberOrString::Number(n) => n.serialize(serializer),
277            NumberOrString::String(s) => s.serialize(serializer),
278        }
279    }
280}
281
282impl<'de> Deserialize<'de> for NumberOrString {
283    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
284    where
285        D: serde::Deserializer<'de>,
286    {
287        let value: Value = Deserialize::deserialize(deserializer)?;
288        match value {
289            Value::Number(n) => {
290                if let Some(i) = n.as_i64() {
291                    Ok(NumberOrString::Number(i))
292                } else if let Some(u) = n.as_u64() {
293                    // Handle large unsigned numbers that fit in i64
294                    if u <= i64::MAX as u64 {
295                        Ok(NumberOrString::Number(u as i64))
296                    } else {
297                        Err(serde::de::Error::custom("Number too large for i64"))
298                    }
299                } else {
300                    Err(serde::de::Error::custom("Expected an integer"))
301                }
302            }
303            Value::String(s) => Ok(NumberOrString::String(s.into())),
304            _ => Err(serde::de::Error::custom("Expect number or string")),
305        }
306    }
307}
308
309#[cfg(feature = "schemars")]
310impl schemars::JsonSchema for NumberOrString {
311    fn schema_name() -> Cow<'static, str> {
312        Cow::Borrowed("NumberOrString")
313    }
314
315    fn json_schema(_: &mut schemars::SchemaGenerator) -> schemars::Schema {
316        use serde_json::{Map, json};
317
318        let mut number_schema = Map::new();
319        number_schema.insert("type".to_string(), json!("number"));
320
321        let mut string_schema = Map::new();
322        string_schema.insert("type".to_string(), json!("string"));
323
324        let mut schema_map = Map::new();
325        schema_map.insert("oneOf".to_string(), json!([number_schema, string_schema]));
326
327        schemars::Schema::from(schema_map)
328    }
329}
330
331/// Type alias for request identifiers used in JSON-RPC communication.
332pub type RequestId = NumberOrString;
333
334/// A token used to track the progress of long-running operations.
335///
336/// Progress tokens allow clients and servers to associate progress notifications
337/// with specific requests, enabling real-time updates on operation status.
338#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Hash, Eq)]
339#[serde(transparent)]
340#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
341#[expect(clippy::exhaustive_structs, reason = "intentionally exhaustive")]
342pub struct ProgressToken(pub NumberOrString);
343
344// =============================================================================
345// JSON-RPC MESSAGE STRUCTURES
346// =============================================================================
347
348/// Represents a JSON-RPC request with method, parameters, and extensions.
349///
350/// This is the core structure for all MCP requests, containing:
351/// - `method`: The name of the method being called
352/// - `params`: The parameters for the method
353/// - `extensions`: Additional context data (similar to HTTP headers)
354#[derive(Debug, Clone, Default)]
355#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
356#[non_exhaustive]
357pub struct Request<M = String, P = JsonObject> {
358    pub method: M,
359    pub params: P,
360    /// extensions will carry anything possible in the context, including the metadata
361    /// ([`RequestMetaObject`] for requests, [`NotificationMetaObject`] for notifications)
362    ///
363    /// this is similar with the Extensions in `http` crate
364    #[cfg_attr(feature = "schemars", schemars(skip))]
365    pub extensions: Extensions,
366}
367
368impl<M: Default, P> Request<M, P> {
369    pub fn new(params: P) -> Self {
370        Self {
371            method: Default::default(),
372            params,
373            extensions: Extensions::default(),
374        }
375    }
376}
377
378impl<M, P> GetExtensions for Request<M, P> {
379    fn extensions(&self) -> &Extensions {
380        &self.extensions
381    }
382    fn extensions_mut(&mut self) -> &mut Extensions {
383        &mut self.extensions
384    }
385}
386
387#[derive(Debug, Clone, Default)]
388#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
389#[expect(clippy::exhaustive_structs, reason = "intentionally exhaustive")]
390pub struct RequestOptionalParam<M = String, P = JsonObject> {
391    pub method: M,
392    // #[serde(skip_serializing_if = "Option::is_none")]
393    pub params: Option<P>,
394    /// extensions will carry anything possible in the context, including the metadata
395    /// ([`RequestMetaObject`] for requests, [`NotificationMetaObject`] for notifications)
396    ///
397    /// this is similar with the Extensions in `http` crate
398    #[cfg_attr(feature = "schemars", schemars(skip))]
399    pub extensions: Extensions,
400}
401
402impl<M: Default, P> RequestOptionalParam<M, P> {
403    pub fn with_param(params: P) -> Self {
404        Self {
405            method: Default::default(),
406            params: Some(params),
407            extensions: Extensions::default(),
408        }
409    }
410}
411
412#[derive(Debug, Clone, Default)]
413#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
414#[expect(clippy::exhaustive_structs, reason = "intentionally exhaustive")]
415pub struct RequestNoParam<M = String> {
416    pub method: M,
417    /// extensions will carry anything possible in the context, including the metadata
418    /// ([`RequestMetaObject`] for requests, [`NotificationMetaObject`] for notifications)
419    ///
420    /// this is similar with the Extensions in `http` crate
421    #[cfg_attr(feature = "schemars", schemars(skip))]
422    pub extensions: Extensions,
423}
424
425impl<M> GetExtensions for RequestNoParam<M> {
426    fn extensions(&self) -> &Extensions {
427        &self.extensions
428    }
429    fn extensions_mut(&mut self) -> &mut Extensions {
430        &mut self.extensions
431    }
432}
433#[derive(Debug, Clone, Default)]
434#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
435#[non_exhaustive]
436pub struct Notification<M = String, P = JsonObject> {
437    pub method: M,
438    pub params: P,
439    /// extensions will carry anything possible in the context, including the metadata
440    /// ([`RequestMetaObject`] for requests, [`NotificationMetaObject`] for notifications)
441    ///
442    /// this is similar with the Extensions in `http` crate
443    #[cfg_attr(feature = "schemars", schemars(skip))]
444    pub extensions: Extensions,
445}
446
447impl<M: Default, P> Notification<M, P> {
448    pub fn new(params: P) -> Self {
449        Self {
450            method: Default::default(),
451            params,
452            extensions: Extensions::default(),
453        }
454    }
455}
456
457#[derive(Debug, Clone, Default)]
458#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
459#[expect(clippy::exhaustive_structs, reason = "intentionally exhaustive")]
460pub struct NotificationNoParam<M = String> {
461    pub method: M,
462    /// extensions will carry anything possible in the context, including the metadata
463    /// ([`RequestMetaObject`] for requests, [`NotificationMetaObject`] for notifications)
464    ///
465    /// this is similar with the Extensions in `http` crate
466    #[cfg_attr(feature = "schemars", schemars(skip))]
467    pub extensions: Extensions,
468}
469
470#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
471#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
472#[expect(clippy::exhaustive_structs, reason = "intentionally exhaustive")]
473pub struct JsonRpcRequest<R = Request> {
474    pub jsonrpc: JsonRpcVersion2_0,
475    pub id: RequestId,
476    #[serde(flatten)]
477    pub request: R,
478}
479
480impl<R> JsonRpcRequest<R> {
481    /// Create a new JsonRpcRequest.
482    pub fn new(id: RequestId, request: R) -> Self {
483        Self {
484            jsonrpc: JsonRpcVersion2_0,
485            id,
486            request,
487        }
488    }
489}
490
491type DefaultResponse = JsonObject;
492#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
493#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
494#[expect(clippy::exhaustive_structs, reason = "intentionally exhaustive")]
495pub struct JsonRpcResponse<R = JsonObject> {
496    pub jsonrpc: JsonRpcVersion2_0,
497    pub id: RequestId,
498    pub result: R,
499}
500
501#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
502#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
503#[expect(clippy::exhaustive_structs, reason = "intentionally exhaustive")]
504pub struct JsonRpcError {
505    pub jsonrpc: JsonRpcVersion2_0,
506    // MCP 2026-07-28 §Error Responses: `id` is optional and omitted when the
507    // server cannot read the request id (e.g. parse error / invalid request).
508    // https://modelcontextprotocol.io/specification/2026-07-28/basic#error-responses
509    #[serde(default, skip_serializing_if = "Option::is_none")]
510    pub id: Option<RequestId>,
511    pub error: ErrorData,
512}
513
514impl JsonRpcError {
515    /// Create a new JsonRpcError.
516    pub fn new(id: Option<RequestId>, error: ErrorData) -> Self {
517        Self {
518            jsonrpc: JsonRpcVersion2_0,
519            id,
520            error,
521        }
522    }
523}
524
525#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
526#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
527#[expect(clippy::exhaustive_structs, reason = "intentionally exhaustive")]
528pub struct JsonRpcNotification<N = Notification> {
529    pub jsonrpc: JsonRpcVersion2_0,
530    #[serde(flatten)]
531    pub notification: N,
532}
533
534/// Standard JSON-RPC error codes used throughout the MCP protocol.
535///
536/// These codes follow the JSON-RPC 2.0 specification and provide
537/// standardized error reporting across all MCP implementations.
538#[derive(Debug, Clone, Copy, Default, Serialize, Deserialize, PartialEq, Eq)]
539#[serde(transparent)]
540#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
541#[expect(clippy::exhaustive_structs, reason = "intentionally exhaustive")]
542pub struct ErrorCode(pub i32);
543
544impl ErrorCode {
545    /// The request used a protocol version the server does not support.
546    pub const UNSUPPORTED_PROTOCOL_VERSION: Self = Self(-32022);
547    /// Processing the request requires a client capability that was not declared.
548    pub const MISSING_REQUIRED_CLIENT_CAPABILITY: Self = Self(-32021);
549    pub const HEADER_MISMATCH: Self = Self(-32020);
550    pub const RESOURCE_NOT_FOUND: Self = Self(-32002);
551    pub const INVALID_REQUEST: Self = Self(-32600);
552    pub const METHOD_NOT_FOUND: Self = Self(-32601);
553    pub const INVALID_PARAMS: Self = Self(-32602);
554    pub const INTERNAL_ERROR: Self = Self(-32603);
555    pub const PARSE_ERROR: Self = Self(-32700);
556}
557
558/// Error information for JSON-RPC error responses.
559///
560/// This structure follows the JSON-RPC 2.0 specification for error reporting,
561/// providing a standardized way to communicate errors between clients and servers.
562#[derive(Default, Debug, Serialize, Deserialize, Clone, PartialEq)]
563#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
564#[expect(clippy::exhaustive_structs, reason = "intentionally exhaustive")]
565pub struct ErrorData {
566    /// The error type that occurred (using standard JSON-RPC error codes)
567    pub code: ErrorCode,
568
569    /// A short description of the error. The message SHOULD be limited to a concise single sentence.
570    pub message: Cow<'static, str>,
571
572    /// Additional information about the error. The value of this member is defined by the
573    /// sender (e.g. detailed error information, nested errors etc.).
574    #[serde(skip_serializing_if = "Option::is_none")]
575    pub data: Option<Value>,
576}
577
578impl ErrorData {
579    const TRANSPORT_CLOSED_MARKER: &str = "io.modelcontextprotocol/transportClosed";
580
581    pub fn new(
582        code: ErrorCode,
583        message: impl Into<Cow<'static, str>>,
584        data: Option<Value>,
585    ) -> Self {
586        Self {
587            code,
588            message: message.into(),
589            data,
590        }
591    }
592    /// Resource-not-found error (`-32002`). The server upgrades this to `INVALID_PARAMS`
593    /// (`-32602`) for peers negotiating protocol `2026-07-28` or newer (SEP-2164).
594    pub fn resource_not_found(message: impl Into<Cow<'static, str>>, data: Option<Value>) -> Self {
595        Self::new(ErrorCode::RESOURCE_NOT_FOUND, message, data)
596    }
597    pub fn header_mismatch(message: impl Into<Cow<'static, str>>, data: Option<Value>) -> Self {
598        Self::new(ErrorCode::HEADER_MISMATCH, message, data)
599    }
600    /// Create an unsupported-protocol-version error.
601    pub fn unsupported_protocol_version(
602        requested: ProtocolVersion,
603        supported: &[ProtocolVersion],
604    ) -> Self {
605        Self::new(
606            ErrorCode::UNSUPPORTED_PROTOCOL_VERSION,
607            "Unsupported protocol version",
608            Some(serde_json::json!({
609                "requested": requested,
610                "supported": supported,
611            })),
612        )
613    }
614    /// Create a missing-required-capability error.
615    pub fn missing_required_client_capability(required: ClientCapabilities) -> Self {
616        Self::new(
617            ErrorCode::MISSING_REQUIRED_CLIENT_CAPABILITY,
618            "Missing required client capability",
619            Some(serde_json::json!({
620                "requiredCapabilities": required,
621            })),
622        )
623    }
624    pub fn parse_error(message: impl Into<Cow<'static, str>>, data: Option<Value>) -> Self {
625        Self::new(ErrorCode::PARSE_ERROR, message, data)
626    }
627    pub fn invalid_request(message: impl Into<Cow<'static, str>>, data: Option<Value>) -> Self {
628        Self::new(ErrorCode::INVALID_REQUEST, message, data)
629    }
630    pub fn method_not_found<M: ConstString>() -> Self {
631        Self::new(ErrorCode::METHOD_NOT_FOUND, M::VALUE, None)
632    }
633    pub fn invalid_params(message: impl Into<Cow<'static, str>>, data: Option<Value>) -> Self {
634        Self::new(ErrorCode::INVALID_PARAMS, message, data)
635    }
636    pub fn internal_error(message: impl Into<Cow<'static, str>>, data: Option<Value>) -> Self {
637        Self::new(ErrorCode::INTERNAL_ERROR, message, data)
638    }
639
640    #[cfg(feature = "transport-streamable-http-client")]
641    pub(crate) fn transport_closed(message: impl Into<Cow<'static, str>>) -> Self {
642        let mut data = JsonObject::new();
643        data.insert(
644            Self::TRANSPORT_CLOSED_MARKER.to_owned(),
645            Value::from(Self::transport_closed_token()),
646        );
647        Self::internal_error(message, Some(Value::Object(data)))
648    }
649
650    pub(crate) fn is_transport_closed(&self) -> bool {
651        self.data
652            .as_ref()
653            .and_then(|data| data.get(Self::TRANSPORT_CLOSED_MARKER))
654            .and_then(Value::as_u64)
655            == Some(Self::transport_closed_token())
656    }
657
658    fn transport_closed_token() -> u64 {
659        static TOKEN: OnceLock<u64> = OnceLock::new();
660        *TOKEN.get_or_init(|| {
661            let mut hasher = RandomState::new().build_hasher();
662            hasher.write(b"rmcp transport-closed marker");
663            hasher.finish()
664        })
665    }
666}
667
668/// Represents any JSON-RPC message that can be sent or received.
669///
670/// This enum covers all possible message types in the JSON-RPC protocol:
671/// individual requests/responses, notifications, and errors.
672/// It serves as the top-level message container for MCP communication.
673#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
674#[serde(untagged)]
675#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
676#[expect(clippy::exhaustive_enums, reason = "intentionally exhaustive")]
677pub enum JsonRpcMessage<Req = Request, Resp = DefaultResponse, Noti = Notification> {
678    /// A single request expecting a response
679    Request(JsonRpcRequest<Req>),
680    /// A response to a previous request
681    Response(JsonRpcResponse<Resp>),
682    /// A one-way notification (no response expected)
683    Notification(JsonRpcNotification<Noti>),
684    /// An error response
685    Error(JsonRpcError),
686}
687
688impl<Req, Resp, Not> JsonRpcMessage<Req, Resp, Not> {
689    #[inline]
690    pub const fn request(request: Req, id: RequestId) -> Self {
691        JsonRpcMessage::Request(JsonRpcRequest {
692            jsonrpc: JsonRpcVersion2_0,
693            id,
694            request,
695        })
696    }
697    #[inline]
698    pub const fn response(response: Resp, id: RequestId) -> Self {
699        JsonRpcMessage::Response(JsonRpcResponse {
700            jsonrpc: JsonRpcVersion2_0,
701            id,
702            result: response,
703        })
704    }
705    #[inline]
706    pub const fn error(error: ErrorData, id: Option<RequestId>) -> Self {
707        JsonRpcMessage::Error(JsonRpcError {
708            jsonrpc: JsonRpcVersion2_0,
709            id,
710            error,
711        })
712    }
713    #[inline]
714    pub const fn notification(notification: Not) -> Self {
715        JsonRpcMessage::Notification(JsonRpcNotification {
716            jsonrpc: JsonRpcVersion2_0,
717            notification,
718        })
719    }
720    pub fn into_request(self) -> Option<(Req, RequestId)> {
721        match self {
722            JsonRpcMessage::Request(r) => Some((r.request, r.id)),
723            _ => None,
724        }
725    }
726    pub fn into_response(self) -> Option<(Resp, RequestId)> {
727        match self {
728            JsonRpcMessage::Response(r) => Some((r.result, r.id)),
729            _ => None,
730        }
731    }
732    pub fn into_notification(self) -> Option<Not> {
733        match self {
734            JsonRpcMessage::Notification(n) => Some(n.notification),
735            _ => None,
736        }
737    }
738    pub fn into_error(self) -> Option<(ErrorData, Option<RequestId>)> {
739        match self {
740            JsonRpcMessage::Error(e) => Some((e.error, e.id)),
741            _ => None,
742        }
743    }
744    pub fn into_result(self) -> Option<(Result<Resp, ErrorData>, Option<RequestId>)> {
745        match self {
746            JsonRpcMessage::Response(r) => Some((Ok(r.result), Some(r.id))),
747            JsonRpcMessage::Error(e) => Some((Err(e.error), e.id)),
748
749            _ => None,
750        }
751    }
752}
753
754// =============================================================================
755// INITIALIZATION AND CONNECTION SETUP
756// =============================================================================
757
758/// # Empty result
759/// A response that indicates success but carries no data.
760pub type EmptyResult = EmptyObject;
761
762impl From<()> for EmptyResult {
763    fn from(_value: ()) -> Self {
764        EmptyResult {}
765    }
766}
767
768impl From<EmptyResult> for () {
769    fn from(_value: EmptyResult) {}
770}
771
772/// Indicates the type of a result object, allowing the client to
773/// determine how to parse the response.
774///
775/// The spec defines this as an open string (`"complete" | "input_required" | string`),
776/// so unknown values are preserved rather than rejected. Servers implementing this
777/// protocol version MUST include `resultType` in every result. For backward
778/// compatibility, clients MUST treat an absent field as `"complete"`.
779///
780/// Ordinary results model the field as `Option<ResultType>`: `None` means the
781/// field is absent on the wire. Constructors default to `Some(COMPLETE)`, and
782/// the server handler strips the `"complete"` discriminator before responding
783/// to peers that negotiated a protocol version older than `2026-07-28`, so
784/// legacy sessions keep their historical wire shape (see
785/// [`ServerResult::strip_result_type_for_legacy_peer`]).
786#[derive(Debug, Clone, PartialEq, Eq)]
787#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
788pub struct ResultType(Cow<'static, str>);
789
790impl ResultType {
791    pub const COMPLETE: Self = Self(Cow::Borrowed("complete"));
792    pub const INPUT_REQUIRED: Self = Self(Cow::Borrowed("input_required"));
793    /// SEP-2663 Tasks extension: the result is a task handle ([`CreateTaskResult`]).
794    pub const TASK: Self = Self(Cow::Borrowed("task"));
795
796    pub fn as_str(&self) -> &str {
797        &self.0
798    }
799
800    /// Returns `true` if this is `"input_required"`.
801    pub fn is_input_required(&self) -> bool {
802        self.0 == "input_required"
803    }
804
805    /// Returns `true` if this is `"complete"`.
806    pub fn is_complete(&self) -> bool {
807        self.0 == "complete"
808    }
809
810    /// Returns `true` if this is `"task"` (SEP-2663 Tasks extension).
811    pub fn is_task(&self) -> bool {
812        self.0 == "task"
813    }
814}
815
816impl Default for ResultType {
817    fn default() -> Self {
818        Self::COMPLETE
819    }
820}
821
822impl Serialize for ResultType {
823    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
824    where
825        S: serde::Serializer,
826    {
827        self.0.serialize(serializer)
828    }
829}
830
831impl<'de> Deserialize<'de> for ResultType {
832    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
833    where
834        D: serde::Deserializer<'de>,
835    {
836        let s: String = Deserialize::deserialize(deserializer)?;
837        match s.as_str() {
838            "complete" => Ok(Self::COMPLETE),
839            "input_required" => Ok(Self::INPUT_REQUIRED),
840            _ => Ok(Self(Cow::Owned(s))),
841        }
842    }
843}
844
845impl std::fmt::Display for ResultType {
846    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
847        self.0.fmt(f)
848    }
849}
850
851/// A catch-all response either side can use for custom requests.
852#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
853#[serde(transparent)]
854#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
855#[expect(clippy::exhaustive_structs, reason = "intentionally exhaustive")]
856pub struct CustomResult(pub Value);
857
858impl CustomResult {
859    pub fn new(result: Value) -> Self {
860        Self(result)
861    }
862
863    /// Deserialize the result into a strongly-typed structure.
864    pub fn result_as<T: DeserializeOwned>(&self) -> Result<T, serde_json::Error> {
865        serde_json::from_value(self.0.clone())
866    }
867}
868
869#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
870#[serde(rename_all = "camelCase")]
871#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
872#[non_exhaustive]
873pub struct CancelledNotificationParam {
874    #[serde(skip_serializing_if = "Option::is_none")]
875    pub request_id: Option<RequestId>,
876    #[serde(skip_serializing_if = "Option::is_none")]
877    pub reason: Option<String>,
878    #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
879    pub meta: Option<NotificationMetaObject>,
880}
881
882impl CancelledNotificationParam {
883    pub fn new(request_id: Option<RequestId>, reason: Option<String>) -> Self {
884        Self {
885            request_id,
886            reason,
887            meta: None,
888        }
889    }
890}
891
892const_string!(CancelledNotificationMethod = "notifications/cancelled");
893
894/// # Cancellation
895/// This notification can be sent by either side to indicate that it is cancelling a previously-issued request.
896///
897/// The request SHOULD still be in-flight, but due to communication latency, it is always possible that this notification MAY arrive after the request has already finished.
898///
899/// This notification indicates that the result will be unused, so any associated processing SHOULD cease.
900///
901/// A client MUST NOT attempt to cancel its `initialize` request.
902pub type CancelledNotification =
903    Notification<CancelledNotificationMethod, CancelledNotificationParam>;
904
905/// A catch-all notification either side can use to send custom messages to its peer.
906///
907/// This preserves the raw `method` name and `params` payload so handlers can
908/// deserialize them into domain-specific types.
909#[derive(Debug, Clone)]
910#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
911#[expect(clippy::exhaustive_structs, reason = "intentionally exhaustive")]
912pub struct CustomNotification {
913    pub method: String,
914    pub params: Option<Value>,
915    /// extensions will carry anything possible in the context, including the metadata
916    /// ([`RequestMetaObject`] for requests, [`NotificationMetaObject`] for notifications)
917    ///
918    /// this is similar with the Extensions in `http` crate
919    #[cfg_attr(feature = "schemars", schemars(skip))]
920    pub extensions: Extensions,
921}
922
923impl CustomNotification {
924    pub fn new(method: impl Into<String>, params: Option<Value>) -> Self {
925        Self {
926            method: method.into(),
927            params,
928            extensions: Extensions::default(),
929        }
930    }
931
932    /// Deserialize `params` into a strongly-typed structure.
933    pub fn params_as<T: DeserializeOwned>(&self) -> Result<Option<T>, serde_json::Error> {
934        self.params
935            .as_ref()
936            .map(|params| serde_json::from_value(params.clone()))
937            .transpose()
938    }
939}
940
941/// A catch-all request either side can use to send custom messages to its peer.
942///
943/// This preserves the raw `method` name and `params` payload so handlers can
944/// deserialize them into domain-specific types.
945#[derive(Debug, Clone)]
946#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
947#[expect(clippy::exhaustive_structs, reason = "intentionally exhaustive")]
948pub struct CustomRequest {
949    pub method: String,
950    pub params: Option<Value>,
951    /// extensions will carry anything possible in the context, including the metadata
952    /// ([`RequestMetaObject`] for requests, [`NotificationMetaObject`] for notifications)
953    ///
954    /// this is similar with the Extensions in `http` crate
955    #[cfg_attr(feature = "schemars", schemars(skip))]
956    pub extensions: Extensions,
957}
958
959impl CustomRequest {
960    pub fn new(method: impl Into<String>, params: Option<Value>) -> Self {
961        Self {
962            method: method.into(),
963            params,
964            extensions: Extensions::default(),
965        }
966    }
967
968    /// Deserialize `params` into a strongly-typed structure.
969    pub fn params_as<T: DeserializeOwned>(&self) -> Result<Option<T>, serde_json::Error> {
970        self.params
971            .as_ref()
972            .map(|params| serde_json::from_value(params.clone()))
973            .transpose()
974    }
975}
976
977const_string!(InitializeResultMethod = "initialize");
978/// # Initialization
979/// This request is sent from the client to the server when it first connects, asking it to begin initialization.
980pub type InitializeRequest = Request<InitializeResultMethod, InitializeRequestParams>;
981
982const_string!(InitializedNotificationMethod = "notifications/initialized");
983/// This notification is sent from the client to the server after initialization has finished.
984pub type InitializedNotification = NotificationNoParam<InitializedNotificationMethod>;
985
986/// Parameters sent by a client when initializing a connection to an MCP server.
987///
988/// This contains the client's protocol version, capabilities, and implementation
989/// information, allowing the server to understand what the client supports.
990#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
991#[serde(rename_all = "camelCase")]
992#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
993#[non_exhaustive]
994pub struct InitializeRequestParams {
995    /// Protocol-level metadata for this request (SEP-1319)
996    #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
997    pub meta: Option<RequestMetaObject>,
998    /// The MCP protocol version this client supports
999    pub protocol_version: ProtocolVersion,
1000    /// The capabilities this client supports (sampling, roots, etc.)
1001    pub capabilities: ClientCapabilities,
1002    /// Information about the client implementation
1003    pub client_info: Implementation,
1004}
1005
1006impl InitializeRequestParams {
1007    /// Create a new InitializeRequestParams.
1008    pub fn new(capabilities: ClientCapabilities, client_info: Implementation) -> Self {
1009        Self {
1010            meta: None,
1011            protocol_version: ProtocolVersion::default(),
1012            capabilities,
1013            client_info,
1014        }
1015    }
1016
1017    pub fn with_protocol_version(mut self, protocol_version: ProtocolVersion) -> Self {
1018        self.protocol_version = protocol_version;
1019        self
1020    }
1021}
1022
1023impl RequestParamsMeta for InitializeRequestParams {
1024    fn meta(&self) -> Option<&RequestMetaObject> {
1025        self.meta.as_ref()
1026    }
1027    fn meta_mut(&mut self) -> &mut Option<RequestMetaObject> {
1028        &mut self.meta
1029    }
1030}
1031
1032/// The server's response to an initialization request.
1033///
1034/// Contains the server's protocol version, capabilities, and implementation
1035/// information, along with optional instructions for the client.
1036#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
1037#[serde(rename_all = "camelCase")]
1038#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
1039#[non_exhaustive]
1040pub struct InitializeResult {
1041    /// The MCP protocol version this server supports
1042    pub protocol_version: ProtocolVersion,
1043    /// The capabilities this server provides (tools, resources, prompts, etc.)
1044    pub capabilities: ServerCapabilities,
1045    /// Information about the server implementation
1046    pub server_info: Implementation,
1047    /// Optional human-readable instructions about using this server
1048    #[serde(skip_serializing_if = "Option::is_none")]
1049    pub instructions: Option<String>,
1050    #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
1051    pub meta: Option<MetaObject>,
1052}
1053
1054impl InitializeResult {
1055    /// Create a new `InitializeResult` with default protocol version and the given capabilities.
1056    pub fn new(capabilities: ServerCapabilities) -> Self {
1057        Self {
1058            protocol_version: ProtocolVersion::default(),
1059            capabilities,
1060            server_info: Implementation::from_build_env(),
1061            instructions: None,
1062            meta: None,
1063        }
1064    }
1065
1066    /// Set instructions on this result.
1067    pub fn with_instructions(mut self, instructions: impl Into<String>) -> Self {
1068        self.instructions = Some(instructions.into());
1069        self
1070    }
1071
1072    /// Set the server info on this result.
1073    pub fn with_server_info(mut self, server_info: Implementation) -> Self {
1074        self.server_info = server_info;
1075        self
1076    }
1077
1078    /// Set the protocol version on this result.
1079    pub fn with_protocol_version(mut self, protocol_version: ProtocolVersion) -> Self {
1080        self.protocol_version = protocol_version;
1081        self
1082    }
1083}
1084
1085pub type ServerInfo = InitializeResult;
1086pub type ClientInfo = InitializeRequestParams;
1087
1088/// Information negotiated about a server peer.
1089///
1090/// Unlike [`InitializeResult`], the server implementation identity is optional
1091/// because discovery responses are not required to provide it.
1092#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
1093#[serde(rename_all = "camelCase")]
1094#[non_exhaustive]
1095pub struct ServerPeerInfo {
1096    /// The negotiated MCP protocol version.
1097    pub protocol_version: ProtocolVersion,
1098    /// The capabilities this server provides.
1099    pub capabilities: ServerCapabilities,
1100    /// Information about the server implementation, when provided.
1101    #[serde(skip_serializing_if = "Option::is_none")]
1102    pub server_info: Option<Implementation>,
1103    /// Optional human-readable instructions about using this server.
1104    #[serde(skip_serializing_if = "Option::is_none")]
1105    pub instructions: Option<String>,
1106    /// Protocol-level response metadata.
1107    #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
1108    pub meta: Option<MetaObject>,
1109}
1110
1111impl ServerPeerInfo {
1112    /// Create peer information without a server implementation identity.
1113    pub fn new(protocol_version: ProtocolVersion, capabilities: ServerCapabilities) -> Self {
1114        Self {
1115            protocol_version,
1116            capabilities,
1117            server_info: None,
1118            instructions: None,
1119            meta: None,
1120        }
1121    }
1122
1123    /// Set the server implementation identity.
1124    pub fn with_server_info(mut self, server_info: Implementation) -> Self {
1125        self.server_info = Some(server_info);
1126        self
1127    }
1128
1129    /// Set instructions supplied by the server.
1130    pub fn with_instructions(mut self, instructions: impl Into<String>) -> Self {
1131        self.instructions = Some(instructions.into());
1132        self
1133    }
1134}
1135
1136impl From<InitializeResult> for ServerPeerInfo {
1137    fn from(result: InitializeResult) -> Self {
1138        Self {
1139            protocol_version: result.protocol_version,
1140            capabilities: result.capabilities,
1141            server_info: Some(result.server_info),
1142            instructions: result.instructions,
1143            meta: result.meta,
1144        }
1145    }
1146}
1147
1148const_string!(DiscoverRequestMethod = "server/discover");
1149
1150/// Parameters for [`DiscoverRequest`].
1151#[derive(Debug, Serialize, Deserialize, Clone, Copy, PartialEq, Eq, Default)]
1152#[serde(deny_unknown_fields)]
1153#[expect(clippy::exhaustive_structs, reason = "intentionally exhaustive")]
1154pub struct DiscoverRequestParams {}
1155
1156#[cfg(feature = "schemars")]
1157#[derive(schemars::JsonSchema)]
1158#[expect(dead_code, reason = "schema-only representation of request parameters")]
1159struct DiscoverRequestParamsSchema {
1160    #[schemars(rename = "_meta")]
1161    meta: RequestMetaObject,
1162}
1163
1164#[cfg(feature = "schemars")]
1165impl schemars::JsonSchema for DiscoverRequestParams {
1166    fn schema_name() -> Cow<'static, str> {
1167        Cow::Borrowed("DiscoverRequestParams")
1168    }
1169
1170    fn json_schema(generator: &mut schemars::SchemaGenerator) -> schemars::Schema {
1171        DiscoverRequestParamsSchema::json_schema(generator)
1172    }
1173}
1174
1175/// A request for the server's supported protocol versions and capabilities.
1176pub type DiscoverRequest = Request<DiscoverRequestMethod, DiscoverRequestParams>;
1177
1178/// The server's response to a [`DiscoverRequest`].
1179#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
1180#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
1181#[serde(rename_all = "camelCase")]
1182#[non_exhaustive]
1183pub struct DiscoverResult {
1184    /// Identifies how the result should be parsed.
1185    pub result_type: ResultType,
1186    /// Protocol versions implemented by this server.
1187    pub supported_versions: Vec<ProtocolVersion>,
1188    /// Capabilities provided by this server.
1189    pub capabilities: ServerCapabilities,
1190    /// Optional guidance for using the server.
1191    #[serde(skip_serializing_if = "Option::is_none")]
1192    pub instructions: Option<String>,
1193    /// How long clients may consider this response fresh, in milliseconds.
1194    pub ttl_ms: u64,
1195    /// Whether the cached result may be shared across authorization contexts.
1196    pub cache_scope: CacheScope,
1197    /// Protocol-level response metadata.
1198    #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
1199    pub meta: Option<MetaObject>,
1200}
1201
1202const SERVER_INFO_META_KEY: &str = "io.modelcontextprotocol/serverInfo";
1203
1204fn server_info_from_meta(meta: &MetaObject) -> Option<Implementation> {
1205    meta.get(SERVER_INFO_META_KEY)
1206        .and_then(|value| serde_json::from_value(value.clone()).ok())
1207}
1208
1209fn set_server_info_on_meta(meta: &mut MetaObject, server_info: Implementation) {
1210    let server_info =
1211        serde_json::to_value(server_info).expect("Implementation serialization cannot fail");
1212    meta.insert(SERVER_INFO_META_KEY.to_owned(), server_info);
1213}
1214
1215impl DiscoverResult {
1216    /// Create a non-cacheable private discovery result.
1217    pub fn new(supported_versions: Vec<ProtocolVersion>, capabilities: ServerCapabilities) -> Self {
1218        Self {
1219            result_type: ResultType::COMPLETE,
1220            supported_versions,
1221            capabilities,
1222            instructions: None,
1223            ttl_ms: 0,
1224            cache_scope: CacheScope::Private,
1225            meta: None,
1226        }
1227    }
1228
1229    /// Return the server implementation information stored in result metadata.
1230    pub fn server_info(&self) -> Option<Implementation> {
1231        server_info_from_meta(self.meta.as_ref()?)
1232    }
1233
1234    /// Store server implementation information in result metadata.
1235    pub fn set_server_info(&mut self, server_info: Implementation) {
1236        set_server_info_on_meta(self.meta.get_or_insert_default(), server_info);
1237    }
1238
1239    /// Store server implementation information in result metadata.
1240    pub fn with_server_info(mut self, server_info: Implementation) -> Self {
1241        self.set_server_info(server_info);
1242        self
1243    }
1244
1245    /// Create a discovery result from the server's initialization information.
1246    pub fn from_server_info(
1247        supported_versions: Vec<ProtocolVersion>,
1248        server_info: ServerInfo,
1249    ) -> Self {
1250        let ServerInfo {
1251            capabilities,
1252            server_info,
1253            instructions,
1254            meta,
1255            ..
1256        } = server_info;
1257        let mut result = Self {
1258            result_type: ResultType::COMPLETE,
1259            supported_versions,
1260            capabilities,
1261            instructions,
1262            ttl_ms: 0,
1263            cache_scope: CacheScope::Private,
1264            meta,
1265        };
1266        result.set_server_info(server_info);
1267        result
1268    }
1269
1270    /// Set the cache lifetime hint in milliseconds.
1271    pub fn with_ttl_ms(mut self, ttl_ms: u64) -> Self {
1272        self.ttl_ms = ttl_ms;
1273        self
1274    }
1275
1276    /// Set the cache scope.
1277    pub fn with_cache_scope(mut self, cache_scope: CacheScope) -> Self {
1278        self.cache_scope = cache_scope;
1279        self
1280    }
1281}
1282
1283impl ServerPeerInfo {
1284    /// Create peer information from a discovery result and the selected version.
1285    pub fn from_discover_result(protocol_version: ProtocolVersion, result: DiscoverResult) -> Self {
1286        let server_info = result.server_info();
1287        Self {
1288            protocol_version,
1289            capabilities: result.capabilities,
1290            server_info,
1291            instructions: result.instructions,
1292            meta: result.meta,
1293        }
1294    }
1295}
1296
1297#[allow(clippy::derivable_impls)]
1298impl Default for ServerInfo {
1299    fn default() -> Self {
1300        ServerInfo {
1301            protocol_version: ProtocolVersion::default(),
1302            capabilities: ServerCapabilities::default(),
1303            server_info: Implementation::from_build_env(),
1304            instructions: None,
1305            meta: None,
1306        }
1307    }
1308}
1309
1310#[allow(clippy::derivable_impls)]
1311impl Default for ClientInfo {
1312    fn default() -> Self {
1313        ClientInfo {
1314            meta: None,
1315            protocol_version: ProtocolVersion::default(),
1316            capabilities: ClientCapabilities::default(),
1317            client_info: Implementation::from_build_env(),
1318        }
1319    }
1320}
1321
1322/// Icon themes supported by the MCP specification
1323#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq, Hash, Copy)]
1324#[serde(rename_all = "lowercase")] //match spec
1325#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
1326#[non_exhaustive]
1327pub enum IconTheme {
1328    /// Indicates the icon is designed to be used with a light background
1329    Light,
1330    /// Indicates the icon is designed to be used with a dark background
1331    Dark,
1332}
1333
1334/// A URL pointing to an icon resource or a base64-encoded data URI.
1335///
1336/// Clients that support rendering icons MUST support at least the following MIME types:
1337/// - image/png - PNG images (safe, universal compatibility)
1338/// - image/jpeg (and image/jpg) - JPEG images (safe, universal compatibility)
1339///
1340/// Clients that support rendering icons SHOULD also support:
1341/// - image/svg+xml - SVG images (scalable but requires security precautions)
1342/// - image/webp - WebP images (modern, efficient format)
1343#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
1344#[serde(rename_all = "camelCase")]
1345#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
1346#[non_exhaustive]
1347pub struct Icon {
1348    /// A standard URI pointing to an icon resource
1349    pub src: String,
1350    /// Optional override if the server's MIME type is missing or generic
1351    #[serde(skip_serializing_if = "Option::is_none")]
1352    pub mime_type: Option<String>,
1353    /// Size specification, each string should be in WxH format (e.g., `\"48x48\"`, `\"96x96\"`) or `\"any\"` for scalable formats like SVG
1354    #[serde(skip_serializing_if = "Option::is_none")]
1355    pub sizes: Option<Vec<String>>,
1356    /// Optional specifier for the theme this icon is designed for
1357    /// If not provided, the client should assume the icon can be used with any theme.
1358    #[serde(skip_serializing_if = "Option::is_none")]
1359    pub theme: Option<IconTheme>,
1360}
1361
1362impl Icon {
1363    /// Create a new Icon with the given source URL.
1364    pub fn new(src: impl Into<String>) -> Self {
1365        Self {
1366            src: src.into(),
1367            mime_type: None,
1368            sizes: None,
1369            theme: None,
1370        }
1371    }
1372
1373    /// Set the MIME type.
1374    pub fn with_mime_type(mut self, mime_type: impl Into<String>) -> Self {
1375        self.mime_type = Some(mime_type.into());
1376        self
1377    }
1378
1379    /// Set the sizes.
1380    pub fn with_sizes(mut self, sizes: Vec<String>) -> Self {
1381        self.sizes = Some(sizes);
1382        self
1383    }
1384
1385    /// Set the theme.
1386    pub fn with_theme(mut self, theme: IconTheme) -> Self {
1387        self.theme = Some(theme);
1388        self
1389    }
1390}
1391
1392#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
1393#[serde(rename_all = "camelCase")]
1394#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
1395#[non_exhaustive]
1396pub struct Implementation {
1397    pub name: String,
1398    #[serde(skip_serializing_if = "Option::is_none")]
1399    pub title: Option<String>,
1400    pub version: String,
1401    #[serde(skip_serializing_if = "Option::is_none")]
1402    pub description: Option<String>,
1403    #[serde(skip_serializing_if = "Option::is_none")]
1404    pub icons: Option<Vec<Icon>>,
1405    #[serde(skip_serializing_if = "Option::is_none")]
1406    pub website_url: Option<String>,
1407}
1408
1409impl Default for Implementation {
1410    fn default() -> Self {
1411        Self::from_build_env()
1412    }
1413}
1414
1415impl Implementation {
1416    /// Create a new Implementation.
1417    pub fn new(name: impl Into<String>, version: impl Into<String>) -> Self {
1418        Self {
1419            name: name.into(),
1420            title: None,
1421            version: version.into(),
1422            description: None,
1423            icons: None,
1424            website_url: None,
1425        }
1426    }
1427
1428    pub fn from_build_env() -> Self {
1429        Implementation {
1430            name: env!("CARGO_CRATE_NAME").to_owned(),
1431            title: None,
1432            version: env!("CARGO_PKG_VERSION").to_owned(),
1433            description: None,
1434            icons: None,
1435            website_url: None,
1436        }
1437    }
1438
1439    /// Set the human-readable title.
1440    pub fn with_title(mut self, title: impl Into<String>) -> Self {
1441        self.title = Some(title.into());
1442        self
1443    }
1444
1445    /// Set the description.
1446    pub fn with_description(mut self, description: impl Into<String>) -> Self {
1447        self.description = Some(description.into());
1448        self
1449    }
1450
1451    /// Set the icons.
1452    pub fn with_icons(mut self, icons: Vec<Icon>) -> Self {
1453        self.icons = Some(icons);
1454        self
1455    }
1456
1457    /// Set the website URL.
1458    pub fn with_website_url(mut self, website_url: impl Into<String>) -> Self {
1459        self.website_url = Some(website_url.into());
1460        self
1461    }
1462}
1463
1464#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Default)]
1465#[serde(rename_all = "camelCase")]
1466#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
1467#[non_exhaustive]
1468pub struct PaginatedRequestParams {
1469    /// Protocol-level metadata for this request (SEP-1319)
1470    #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
1471    pub meta: Option<RequestMetaObject>,
1472    #[serde(skip_serializing_if = "Option::is_none")]
1473    pub cursor: Option<String>,
1474}
1475
1476impl PaginatedRequestParams {
1477    pub fn with_cursor(mut self, cursor: Option<String>) -> Self {
1478        self.cursor = cursor;
1479        self
1480    }
1481}
1482
1483impl RequestParamsMeta for PaginatedRequestParams {
1484    fn meta(&self) -> Option<&RequestMetaObject> {
1485        self.meta.as_ref()
1486    }
1487    fn meta_mut(&mut self) -> &mut Option<RequestMetaObject> {
1488        &mut self.meta
1489    }
1490}
1491
1492// =============================================================================
1493// PROGRESS AND PAGINATION
1494// =============================================================================
1495
1496const_string!(PingRequestMethod = "ping");
1497pub type PingRequest = RequestNoParam<PingRequestMethod>;
1498
1499const_string!(ProgressNotificationMethod = "notifications/progress");
1500#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
1501#[serde(rename_all = "camelCase")]
1502#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
1503#[non_exhaustive]
1504pub struct ProgressNotificationParam {
1505    pub progress_token: ProgressToken,
1506    /// The progress thus far. This should increase every time progress is made, even if the total is unknown.
1507    pub progress: f64,
1508    /// Total number of items to process (or total progress required), if known
1509    #[serde(skip_serializing_if = "Option::is_none")]
1510    pub total: Option<f64>,
1511    /// An optional message describing the current progress.
1512    #[serde(skip_serializing_if = "Option::is_none")]
1513    pub message: Option<String>,
1514    #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
1515    pub meta: Option<NotificationMetaObject>,
1516}
1517
1518impl ProgressNotificationParam {
1519    /// Create a new ProgressNotificationParam with required fields.
1520    pub fn new(progress_token: ProgressToken, progress: f64) -> Self {
1521        Self {
1522            progress_token,
1523            progress,
1524            total: None,
1525            message: None,
1526            meta: None,
1527        }
1528    }
1529
1530    /// Set the total number of items to process.
1531    pub fn with_total(mut self, total: f64) -> Self {
1532        self.total = Some(total);
1533        self
1534    }
1535
1536    /// Set a message describing the current progress.
1537    pub fn with_message(mut self, message: impl Into<String>) -> Self {
1538        self.message = Some(message.into());
1539        self
1540    }
1541}
1542
1543pub type ProgressNotification = Notification<ProgressNotificationMethod, ProgressNotificationParam>;
1544
1545pub type Cursor = String;
1546
1547/// Scope describing who may cache cacheable list/read results (SEP-2549).
1548///
1549/// Defaults to [`CacheScope::Public`] when absent from the wire.
1550#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
1551#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
1552#[serde(rename_all = "lowercase")]
1553#[non_exhaustive]
1554pub enum CacheScope {
1555    /// Any client or intermediary may cache and serve the response to any user.
1556    #[default]
1557    Public,
1558    /// Only the requesting user's client may cache the response.
1559    Private,
1560}
1561
1562/// Normalize a `ttlMs` value during deserialization.
1563///
1564/// Per SEP-2549, `ttlMs` MUST be `>= 0`; if a server returns a negative value,
1565/// clients SHOULD treat it as `0` (immediately stale). This tolerates that case
1566/// rather than erroring, while still accepting an absent field as `None`.
1567fn deserialize_ttl_ms<'de, D>(deserializer: D) -> Result<Option<u64>, D::Error>
1568where
1569    D: serde::Deserializer<'de>,
1570{
1571    let value = Option::<i64>::deserialize(deserializer)?;
1572    Ok(value.map(|ttl_ms| ttl_ms.max(0) as u64))
1573}
1574
1575macro_rules! paginated_result {
1576    ($t:ident {
1577        $i_item: ident: $t_item: ty
1578    }) => {
1579        #[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
1580        #[serde(rename_all = "camelCase")]
1581        #[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
1582        #[expect(clippy::exhaustive_structs, reason = "intentionally exhaustive")]
1583        pub struct $t {
1584            /// Result type discriminator (SEP-2322). Required by the [spec schema]
1585            /// for servers implementing protocol version `2026-07-28`, but optional
1586            /// here because this type also models results from older protocol
1587            /// versions, which do not carry the field: `None` means absent on the
1588            /// wire, and per the spec "the client MUST treat the absent field as
1589            /// `"complete"`". Constructors default to `Some(ResultType::COMPLETE)`;
1590            /// the server handler clears the field when responding to peers that
1591            /// negotiated an older version.
1592            ///
1593            /// [spec schema]: https://github.com/modelcontextprotocol/modelcontextprotocol/blob/271ecc9accafdd9b83a3c869fa67c22953b2af80/schema/2026-07-28/schema.ts#L219-L235
1594            #[serde(default, skip_serializing_if = "Option::is_none")]
1595            pub result_type: Option<ResultType>,
1596            #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
1597            pub meta: Option<MetaObject>,
1598            #[serde(default, skip_serializing_if = "Option::is_none")]
1599            pub next_cursor: Option<Cursor>,
1600            /// Time, in milliseconds, that this result may be treated as fresh (SEP-2549).
1601            /// Required by spec version 2026-07-28, but optional here to maintain compatibility
1602            /// with older spec versions.
1603            #[serde(
1604                default,
1605                deserialize_with = "deserialize_ttl_ms",
1606                skip_serializing_if = "Option::is_none"
1607            )]
1608            pub ttl_ms: Option<u64>,
1609            /// Scope describing who may cache this result (SEP-2549).
1610            /// Required by spec version 2026-07-28, but optional here to maintain compatibility
1611            /// with older spec versions.
1612            #[serde(default, skip_serializing_if = "Option::is_none")]
1613            pub cache_scope: Option<CacheScope>,
1614            pub $i_item: $t_item,
1615        }
1616
1617        impl Default for $t {
1618            fn default() -> Self {
1619                Self::with_all_items(Default::default())
1620            }
1621        }
1622
1623        impl $t {
1624            pub fn with_all_items(items: $t_item) -> Self {
1625                Self {
1626                    result_type: Some(ResultType::COMPLETE),
1627                    meta: None,
1628                    next_cursor: None,
1629                    ttl_ms: None,
1630                    cache_scope: None,
1631                    $i_item: items,
1632                }
1633            }
1634
1635            /// Set the time, in milliseconds, that this result may be treated as fresh.
1636            pub fn with_ttl_ms(mut self, ttl_ms: u64) -> Self {
1637                self.ttl_ms = Some(ttl_ms);
1638                self
1639            }
1640
1641            /// Set the cache scope for this result.
1642            pub fn with_cache_scope(mut self, cache_scope: CacheScope) -> Self {
1643                self.cache_scope = Some(cache_scope);
1644                self
1645            }
1646        }
1647    };
1648}
1649
1650// =============================================================================
1651// RESOURCE MANAGEMENT
1652// =============================================================================
1653
1654const_string!(ListResourcesRequestMethod = "resources/list");
1655/// Request to list all available resources from a server
1656pub type ListResourcesRequest =
1657    RequestOptionalParam<ListResourcesRequestMethod, PaginatedRequestParams>;
1658
1659paginated_result!(ListResourcesResult {
1660    resources: Vec<Resource>
1661});
1662
1663const_string!(ListResourceTemplatesRequestMethod = "resources/templates/list");
1664/// Request to list all available resource templates from a server
1665pub type ListResourceTemplatesRequest =
1666    RequestOptionalParam<ListResourceTemplatesRequestMethod, PaginatedRequestParams>;
1667
1668paginated_result!(ListResourceTemplatesResult {
1669    resource_templates: Vec<ResourceTemplate>
1670});
1671
1672const_string!(ReadResourceRequestMethod = "resources/read");
1673/// Parameters for reading a specific resource
1674#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
1675#[serde(rename_all = "camelCase")]
1676#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
1677#[non_exhaustive]
1678pub struct ReadResourceRequestParams {
1679    /// Protocol-level metadata for this request (SEP-1319)
1680    #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
1681    pub meta: Option<RequestMetaObject>,
1682    /// The URI of the resource to read
1683    pub uri: String,
1684    /// Client responses to server-initiated input requests from a previous
1685    /// [`InputRequiredResult`].
1686    #[serde(skip_serializing_if = "Option::is_none")]
1687    pub input_responses: Option<InputResponses>,
1688    /// Opaque request state echoed back from a previous [`InputRequiredResult`].
1689    #[serde(skip_serializing_if = "Option::is_none")]
1690    pub request_state: Option<String>,
1691}
1692
1693impl ReadResourceRequestParams {
1694    /// Create a new ReadResourceRequestParams with the given URI.
1695    pub fn new(uri: impl Into<String>) -> Self {
1696        Self {
1697            meta: None,
1698            uri: uri.into(),
1699            input_responses: None,
1700            request_state: None,
1701        }
1702    }
1703
1704    /// Set the metadata for this request.
1705    pub fn with_meta(mut self, meta: RequestMetaObject) -> Self {
1706        self.meta = Some(meta);
1707        self
1708    }
1709
1710    /// Sets the input responses for an MRTR retry.
1711    pub fn with_input_responses(mut self, input_responses: InputResponses) -> Self {
1712        self.input_responses = Some(input_responses);
1713        self
1714    }
1715
1716    /// Sets the request state for an MRTR retry.
1717    pub fn with_request_state(mut self, request_state: impl Into<String>) -> Self {
1718        self.request_state = Some(request_state.into());
1719        self
1720    }
1721}
1722
1723impl RequestParamsMeta for ReadResourceRequestParams {
1724    fn meta(&self) -> Option<&RequestMetaObject> {
1725        self.meta.as_ref()
1726    }
1727    fn meta_mut(&mut self) -> &mut Option<RequestMetaObject> {
1728        &mut self.meta
1729    }
1730}
1731
1732/// Result containing the contents of a read resource
1733#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
1734#[serde(rename_all = "camelCase")]
1735#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
1736#[non_exhaustive]
1737pub struct ReadResourceResult {
1738    /// Result type discriminator (SEP-2322). Required by the [spec schema]
1739    /// for servers implementing protocol version `2026-07-28`, but optional
1740    /// here because this type also models results from older protocol
1741    /// versions, which do not carry the field: `None` means absent on the
1742    /// wire, and per the spec "the client MUST treat the absent field as
1743    /// `"complete"`". Constructors default to `Some(ResultType::COMPLETE)`;
1744    /// the server handler clears the field when responding to peers that
1745    /// negotiated an older version.
1746    ///
1747    /// [spec schema]: https://github.com/modelcontextprotocol/modelcontextprotocol/blob/271ecc9accafdd9b83a3c869fa67c22953b2af80/schema/2026-07-28/schema.ts#L219-L235
1748    #[serde(default, skip_serializing_if = "Option::is_none")]
1749    pub result_type: Option<ResultType>,
1750    /// Time, in milliseconds, that this result may be treated as fresh (SEP-2549).
1751    /// Required by spec version 2026-07-28, but optional here to maintain compatibility
1752    /// with older spec versions.
1753    #[serde(
1754        default,
1755        deserialize_with = "deserialize_ttl_ms",
1756        skip_serializing_if = "Option::is_none"
1757    )]
1758    pub ttl_ms: Option<u64>,
1759    /// Scope describing who may cache this result (SEP-2549).
1760    /// Required by spec version 2026-07-28, but optional here to maintain compatibility
1761    /// with older spec versions.
1762    #[serde(default, skip_serializing_if = "Option::is_none")]
1763    pub cache_scope: Option<CacheScope>,
1764    /// The actual content of the resource
1765    pub contents: Vec<ResourceContents>,
1766    #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
1767    pub meta: Option<MetaObject>,
1768}
1769
1770impl ReadResourceResult {
1771    /// Create a new ReadResourceResult with the given contents.
1772    pub fn new(contents: Vec<ResourceContents>) -> Self {
1773        Self {
1774            result_type: Some(ResultType::COMPLETE),
1775            ttl_ms: None,
1776            cache_scope: None,
1777            contents,
1778            meta: None,
1779        }
1780    }
1781
1782    /// Set the time, in milliseconds, that this result may be treated as fresh.
1783    pub fn with_ttl_ms(mut self, ttl_ms: u64) -> Self {
1784        self.ttl_ms = Some(ttl_ms);
1785        self
1786    }
1787
1788    /// Set the cache scope for this result.
1789    pub fn with_cache_scope(mut self, cache_scope: CacheScope) -> Self {
1790        self.cache_scope = Some(cache_scope);
1791        self
1792    }
1793}
1794
1795/// Request to read a specific resource
1796pub type ReadResourceRequest = Request<ReadResourceRequestMethod, ReadResourceRequestParams>;
1797
1798const_string!(ResourceListChangedNotificationMethod = "notifications/resources/list_changed");
1799/// Notification sent when the list of available resources changes
1800pub type ResourceListChangedNotification =
1801    NotificationNoParam<ResourceListChangedNotificationMethod>;
1802
1803const_string!(SubscribeRequestMethod = "resources/subscribe");
1804/// Parameters for subscribing to resource updates
1805#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
1806#[serde(rename_all = "camelCase")]
1807#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
1808#[non_exhaustive]
1809pub struct SubscribeRequestParams {
1810    /// Protocol-level metadata for this request (SEP-1319)
1811    #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
1812    pub meta: Option<RequestMetaObject>,
1813    /// The URI of the resource to subscribe to
1814    pub uri: String,
1815}
1816
1817impl SubscribeRequestParams {
1818    /// Create a new SubscribeRequestParams.
1819    pub fn new(uri: impl Into<String>) -> Self {
1820        Self {
1821            meta: None,
1822            uri: uri.into(),
1823        }
1824    }
1825}
1826
1827impl RequestParamsMeta for SubscribeRequestParams {
1828    fn meta(&self) -> Option<&RequestMetaObject> {
1829        self.meta.as_ref()
1830    }
1831    fn meta_mut(&mut self) -> &mut Option<RequestMetaObject> {
1832        &mut self.meta
1833    }
1834}
1835
1836/// Request to subscribe to resource updates
1837#[deprecated(
1838    note = "resources/subscribe is legacy-only; use subscriptions/listen for protocol version 2026-07-28"
1839)]
1840pub type SubscribeRequest = Request<SubscribeRequestMethod, SubscribeRequestParams>;
1841
1842const_string!(UnsubscribeRequestMethod = "resources/unsubscribe");
1843/// Parameters for unsubscribing from resource updates
1844#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
1845#[serde(rename_all = "camelCase")]
1846#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
1847#[non_exhaustive]
1848pub struct UnsubscribeRequestParams {
1849    /// Protocol-level metadata for this request (SEP-1319)
1850    #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
1851    pub meta: Option<RequestMetaObject>,
1852    /// The URI of the resource to unsubscribe from
1853    pub uri: String,
1854}
1855
1856impl UnsubscribeRequestParams {
1857    /// Creates a new `UnsubscribeRequestParams` for the given URI.
1858    pub fn new(uri: impl Into<String>) -> Self {
1859        Self {
1860            meta: None,
1861            uri: uri.into(),
1862        }
1863    }
1864}
1865
1866impl RequestParamsMeta for UnsubscribeRequestParams {
1867    fn meta(&self) -> Option<&RequestMetaObject> {
1868        self.meta.as_ref()
1869    }
1870    fn meta_mut(&mut self) -> &mut Option<RequestMetaObject> {
1871        &mut self.meta
1872    }
1873}
1874
1875/// Request to unsubscribe from resource updates
1876#[deprecated(
1877    note = "resources/unsubscribe is legacy-only; cancel the subscriptions/listen request for protocol version 2026-07-28"
1878)]
1879pub type UnsubscribeRequest = Request<UnsubscribeRequestMethod, UnsubscribeRequestParams>;
1880
1881const_string!(ResourceUpdatedNotificationMethod = "notifications/resources/updated");
1882/// Parameters for a resource update notification
1883#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
1884#[serde(rename_all = "camelCase")]
1885#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
1886#[non_exhaustive]
1887pub struct ResourceUpdatedNotificationParam {
1888    /// The URI of the resource that was updated
1889    pub uri: String,
1890    #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
1891    pub meta: Option<NotificationMetaObject>,
1892}
1893
1894impl ResourceUpdatedNotificationParam {
1895    /// Create a new ResourceUpdatedNotificationParam.
1896    pub fn new(uri: impl Into<String>) -> Self {
1897        Self {
1898            uri: uri.into(),
1899            meta: None,
1900        }
1901    }
1902}
1903
1904/// Notification sent when a subscribed resource is updated
1905pub type ResourceUpdatedNotification =
1906    Notification<ResourceUpdatedNotificationMethod, ResourceUpdatedNotificationParam>;
1907
1908// =============================================================================
1909// SUBSCRIPTIONS
1910// =============================================================================
1911
1912/// Notification categories a client opts in to on a `subscriptions/listen` stream.
1913#[derive(Debug, Default, Serialize, Deserialize, Clone, PartialEq, Eq)]
1914#[serde(rename_all = "camelCase")]
1915#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
1916#[non_exhaustive]
1917pub struct SubscriptionFilter {
1918    #[serde(default, skip_serializing_if = "Option::is_none")]
1919    #[cfg_attr(feature = "schemars", schemars(with = "bool"))]
1920    pub tools_list_changed: Option<bool>,
1921    #[serde(default, skip_serializing_if = "Option::is_none")]
1922    #[cfg_attr(feature = "schemars", schemars(with = "bool"))]
1923    pub prompts_list_changed: Option<bool>,
1924    #[serde(default, skip_serializing_if = "Option::is_none")]
1925    #[cfg_attr(feature = "schemars", schemars(with = "bool"))]
1926    pub resources_list_changed: Option<bool>,
1927    #[serde(default, skip_serializing_if = "Option::is_none")]
1928    #[cfg_attr(feature = "schemars", schemars(with = "Vec<String>"))]
1929    pub resource_subscriptions: Option<Vec<String>>,
1930}
1931
1932impl SubscriptionFilter {
1933    /// Create an empty filter that opts in to no notifications.
1934    pub fn new() -> Self {
1935        Self::default()
1936    }
1937
1938    /// Create a builder for a subscription filter.
1939    pub fn builder() -> SubscriptionFilterBuilder {
1940        SubscriptionFilterBuilder::default()
1941    }
1942
1943    /// Return the subset present in both filters.
1944    pub fn intersection(&self, other: &Self) -> Self {
1945        let resource_subscriptions = self
1946            .resource_subscriptions
1947            .as_ref()
1948            .and_then(|requested| {
1949                other.resource_subscriptions.as_ref().map(|accepted| {
1950                    requested
1951                        .iter()
1952                        .filter(|uri| accepted.contains(uri))
1953                        .cloned()
1954                        .collect()
1955                })
1956            })
1957            .filter(|uris: &Vec<String>| !uris.is_empty());
1958        Self {
1959            tools_list_changed: (self.tools_list_changed == Some(true)
1960                && other.tools_list_changed == Some(true))
1961            .then_some(true),
1962            prompts_list_changed: (self.prompts_list_changed == Some(true)
1963                && other.prompts_list_changed == Some(true))
1964            .then_some(true),
1965            resources_list_changed: (self.resources_list_changed == Some(true)
1966                && other.resources_list_changed == Some(true))
1967            .then_some(true),
1968            resource_subscriptions,
1969        }
1970    }
1971
1972    /// Return whether this filter accepts only notifications requested by `other`.
1973    pub fn is_subset_of(&self, other: &Self) -> bool {
1974        let booleans_are_subset = [
1975            (self.tools_list_changed, other.tools_list_changed),
1976            (self.prompts_list_changed, other.prompts_list_changed),
1977            (self.resources_list_changed, other.resources_list_changed),
1978        ]
1979        .into_iter()
1980        .all(|(accepted, requested)| accepted != Some(true) || requested == Some(true));
1981        let resources_are_subset = self.resource_subscriptions.as_ref().is_none_or(|accepted| {
1982            accepted.iter().all(|uri| {
1983                other
1984                    .resource_subscriptions
1985                    .as_ref()
1986                    .is_some_and(|requested| requested.contains(uri))
1987            })
1988        });
1989        booleans_are_subset && resources_are_subset
1990    }
1991
1992    /// Return the requested notification types advertised by server capabilities.
1993    pub fn supported_by(&self, capabilities: &ServerCapabilities) -> Self {
1994        Self {
1995            tools_list_changed: (self.tools_list_changed == Some(true)
1996                && capabilities
1997                    .tools
1998                    .as_ref()
1999                    .is_some_and(|tools| tools.list_changed == Some(true)))
2000            .then_some(true),
2001            prompts_list_changed: (self.prompts_list_changed == Some(true)
2002                && capabilities
2003                    .prompts
2004                    .as_ref()
2005                    .is_some_and(|prompts| prompts.list_changed == Some(true)))
2006            .then_some(true),
2007            resources_list_changed: (self.resources_list_changed == Some(true)
2008                && capabilities
2009                    .resources
2010                    .as_ref()
2011                    .is_some_and(|resources| resources.list_changed == Some(true)))
2012            .then_some(true),
2013            resource_subscriptions: capabilities
2014                .resources
2015                .as_ref()
2016                .is_some_and(|resources| resources.subscribe == Some(true))
2017                .then(|| self.resource_subscriptions.clone())
2018                .flatten(),
2019        }
2020    }
2021}
2022
2023/// Builder for [`SubscriptionFilter`].
2024#[derive(Debug, Default)]
2025#[non_exhaustive]
2026pub struct SubscriptionFilterBuilder {
2027    filter: SubscriptionFilter,
2028}
2029
2030impl SubscriptionFilterBuilder {
2031    /// Opt in to `notifications/tools/list_changed`.
2032    pub fn tools_list_changed(mut self) -> Self {
2033        self.filter.tools_list_changed = Some(true);
2034        self
2035    }
2036
2037    /// Opt in to `notifications/prompts/list_changed`.
2038    pub fn prompts_list_changed(mut self) -> Self {
2039        self.filter.prompts_list_changed = Some(true);
2040        self
2041    }
2042
2043    /// Opt in to `notifications/resources/list_changed`.
2044    pub fn resources_list_changed(mut self) -> Self {
2045        self.filter.resources_list_changed = Some(true);
2046        self
2047    }
2048
2049    /// Opt in to updates for all supplied resource URIs.
2050    pub fn resource_subscriptions(
2051        mut self,
2052        uris: impl IntoIterator<Item = impl Into<String>>,
2053    ) -> Self {
2054        self.filter.resource_subscriptions = Some(uris.into_iter().map(Into::into).collect());
2055        self
2056    }
2057
2058    /// Add one resource URI to the update subscription set.
2059    pub fn resource_subscription(mut self, uri: impl Into<String>) -> Self {
2060        self.filter
2061            .resource_subscriptions
2062            .get_or_insert_default()
2063            .push(uri.into());
2064        self
2065    }
2066
2067    /// Build the filter.
2068    pub fn build(self) -> SubscriptionFilter {
2069        self.filter
2070    }
2071}
2072
2073const_string!(SubscriptionsListenRequestMethod = "subscriptions/listen");
2074
2075#[cfg(feature = "schemars")]
2076fn subscriptions_listen_request_meta_schema(
2077    generator: &mut schemars::SchemaGenerator,
2078) -> schemars::Schema {
2079    let progress_token = generator.subschema_for::<ProgressToken>();
2080    let client_info = generator.subschema_for::<Implementation>();
2081    let client_capabilities = generator.subschema_for::<ClientCapabilities>();
2082    let log_level = generator.subschema_for::<LoggingLevel>();
2083    schemars::json_schema!({
2084        "type": "object",
2085        "properties": {
2086            "progressToken": progress_token,
2087            "io.modelcontextprotocol/protocolVersion": {
2088                "type": "string",
2089            },
2090            "io.modelcontextprotocol/clientInfo": client_info,
2091            "io.modelcontextprotocol/clientCapabilities": client_capabilities,
2092            "io.modelcontextprotocol/logLevel": log_level,
2093        },
2094        "required": RequestMetaObject::DRAFT_REQUIRED_KEYS,
2095        "additionalProperties": true,
2096    })
2097}
2098
2099/// Parameters for opening a long-lived notification subscription.
2100#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
2101#[serde(rename_all = "camelCase")]
2102#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
2103#[non_exhaustive]
2104pub struct SubscriptionsListenRequestParams {
2105    /// Protocol-level metadata. Required by the 2026-07-28 wire schema.
2106    #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
2107    #[cfg_attr(
2108        feature = "schemars",
2109        schemars(required, schema_with = "subscriptions_listen_request_meta_schema")
2110    )]
2111    pub meta: Option<RequestMetaObject>,
2112    /// Notification categories requested for this stream.
2113    pub notifications: SubscriptionFilter,
2114}
2115
2116impl SubscriptionsListenRequestParams {
2117    /// Create listen parameters for a notification filter.
2118    pub fn new(notifications: SubscriptionFilter) -> Self {
2119        Self {
2120            meta: None,
2121            notifications,
2122        }
2123    }
2124
2125    /// Set protocol-level request metadata.
2126    pub fn with_meta(mut self, meta: RequestMetaObject) -> Self {
2127        self.meta = Some(meta);
2128        self
2129    }
2130}
2131
2132impl RequestParamsMeta for SubscriptionsListenRequestParams {
2133    fn meta(&self) -> Option<&RequestMetaObject> {
2134        self.meta.as_ref()
2135    }
2136
2137    fn meta_mut(&mut self) -> &mut Option<RequestMetaObject> {
2138        &mut self.meta
2139    }
2140}
2141
2142/// Request that opens a long-lived notification subscription.
2143pub type SubscriptionsListenRequest =
2144    Request<SubscriptionsListenRequestMethod, SubscriptionsListenRequestParams>;
2145
2146const SUBSCRIPTION_ID_META_KEY: &str = "io.modelcontextprotocol/subscriptionId";
2147
2148/// Metadata on the final result of a `subscriptions/listen` request.
2149#[derive(Debug, Serialize, Clone, PartialEq)]
2150#[serde(transparent)]
2151#[non_exhaustive]
2152pub struct SubscriptionsListenResultMeta(MetaObject);
2153
2154impl SubscriptionsListenResultMeta {
2155    /// Create result metadata for the originating listen request.
2156    pub fn new(subscription_id: RequestId) -> Self {
2157        let mut meta = MetaObject::new();
2158        meta.insert(
2159            SUBSCRIPTION_ID_META_KEY.to_owned(),
2160            subscription_id.into_json_value(),
2161        );
2162        Self(meta)
2163    }
2164
2165    /// Return the originating listen request ID, if the metadata remains valid.
2166    pub fn subscription_id(&self) -> Option<RequestId> {
2167        self.0
2168            .get(SUBSCRIPTION_ID_META_KEY)
2169            .and_then(|value| RequestId::deserialize(value).ok())
2170    }
2171
2172    /// Replace the originating listen request ID.
2173    pub fn set_subscription_id(&mut self, subscription_id: RequestId) {
2174        self.0.insert(
2175            SUBSCRIPTION_ID_META_KEY.to_owned(),
2176            subscription_id.into_json_value(),
2177        );
2178    }
2179
2180    /// Return the server implementation information stored in result metadata.
2181    pub fn server_info(&self) -> Option<Implementation> {
2182        server_info_from_meta(&self.0)
2183    }
2184
2185    /// Store server implementation information in result metadata.
2186    pub fn set_server_info(&mut self, server_info: Implementation) {
2187        set_server_info_on_meta(&mut self.0, server_info);
2188    }
2189}
2190
2191impl<'de> Deserialize<'de> for SubscriptionsListenResultMeta {
2192    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
2193    where
2194        D: serde::Deserializer<'de>,
2195    {
2196        let meta = MetaObject::deserialize(deserializer)?;
2197        let Some(value) = meta.get(SUBSCRIPTION_ID_META_KEY) else {
2198            return Err(serde::de::Error::missing_field(SUBSCRIPTION_ID_META_KEY));
2199        };
2200        RequestId::deserialize(value).map_err(serde::de::Error::custom)?;
2201        Ok(Self(meta))
2202    }
2203}
2204
2205impl std::ops::Deref for SubscriptionsListenResultMeta {
2206    type Target = MetaObject;
2207
2208    fn deref(&self) -> &Self::Target {
2209        &self.0
2210    }
2211}
2212
2213impl std::ops::DerefMut for SubscriptionsListenResultMeta {
2214    fn deref_mut(&mut self) -> &mut Self::Target {
2215        &mut self.0
2216    }
2217}
2218
2219#[cfg(feature = "schemars")]
2220impl schemars::JsonSchema for SubscriptionsListenResultMeta {
2221    fn schema_name() -> Cow<'static, str> {
2222        Cow::Borrowed("SubscriptionsListenResultMeta")
2223    }
2224
2225    fn json_schema(generator: &mut schemars::SchemaGenerator) -> schemars::Schema {
2226        let subscription_id = generator.subschema_for::<RequestId>();
2227        let server_info = generator.subschema_for::<Implementation>();
2228        schemars::json_schema!({
2229            "type": "object",
2230            "properties": {
2231                "io.modelcontextprotocol/serverInfo": {
2232                    "description": "Identifies the server software producing the response. Servers SHOULD include this field on every response unless specifically configured not to do so.",
2233                    "allOf": [server_info],
2234                },
2235                "io.modelcontextprotocol/subscriptionId": subscription_id,
2236            },
2237            "required": ["io.modelcontextprotocol/subscriptionId"],
2238            "additionalProperties": true,
2239        })
2240    }
2241}
2242
2243/// Final response indicating that a subscription ended gracefully.
2244#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
2245#[serde(rename_all = "camelCase")]
2246#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
2247#[non_exhaustive]
2248pub struct SubscriptionsListenResult {
2249    pub result_type: ResultType,
2250    #[serde(rename = "_meta")]
2251    pub meta: SubscriptionsListenResultMeta,
2252}
2253
2254impl SubscriptionsListenResult {
2255    /// Create a completed subscription result.
2256    pub fn new(meta: SubscriptionsListenResultMeta) -> Self {
2257        Self {
2258            result_type: ResultType::COMPLETE,
2259            meta,
2260        }
2261    }
2262
2263    /// Create a completed result for the originating listen request.
2264    pub fn complete(subscription_id: RequestId) -> Self {
2265        Self::new(SubscriptionsListenResultMeta::new(subscription_id))
2266    }
2267}
2268
2269const_string!(
2270    SubscriptionsAcknowledgedNotificationMethod = "notifications/subscriptions/acknowledged"
2271);
2272
2273/// Parameters reporting the accepted subset of a subscription filter.
2274#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
2275#[serde(rename_all = "camelCase")]
2276#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
2277#[non_exhaustive]
2278pub struct SubscriptionsAcknowledgedNotificationParams {
2279    #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
2280    #[cfg_attr(feature = "schemars", schemars(with = "NotificationMetaObject"))]
2281    pub meta: Option<NotificationMetaObject>,
2282    pub notifications: SubscriptionFilter,
2283}
2284
2285impl SubscriptionsAcknowledgedNotificationParams {
2286    /// Create acknowledgment parameters for the accepted filter.
2287    pub fn new(notifications: SubscriptionFilter) -> Self {
2288        Self {
2289            meta: None,
2290            notifications,
2291        }
2292    }
2293
2294    /// Set notification metadata.
2295    pub fn with_meta(mut self, meta: NotificationMetaObject) -> Self {
2296        self.meta = Some(meta);
2297        self
2298    }
2299}
2300
2301/// First notification sent on an established subscription stream.
2302pub type SubscriptionsAcknowledgedNotification = Notification<
2303    SubscriptionsAcknowledgedNotificationMethod,
2304    SubscriptionsAcknowledgedNotificationParams,
2305>;
2306
2307// =============================================================================
2308// PROMPT MANAGEMENT
2309// =============================================================================
2310
2311const_string!(ListPromptsRequestMethod = "prompts/list");
2312/// Request to list all available prompts from a server
2313pub type ListPromptsRequest =
2314    RequestOptionalParam<ListPromptsRequestMethod, PaginatedRequestParams>;
2315
2316paginated_result!(ListPromptsResult {
2317    prompts: Vec<Prompt>
2318});
2319
2320const_string!(GetPromptRequestMethod = "prompts/get");
2321/// Parameters for retrieving a specific prompt
2322#[derive(Default, Debug, Serialize, Deserialize, Clone, PartialEq)]
2323#[serde(rename_all = "camelCase")]
2324#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
2325#[non_exhaustive]
2326pub struct GetPromptRequestParams {
2327    /// Protocol-level metadata for this request (SEP-1319)
2328    #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
2329    pub meta: Option<RequestMetaObject>,
2330    pub name: String,
2331    #[serde(skip_serializing_if = "Option::is_none")]
2332    pub arguments: Option<JsonObject>,
2333    /// Client responses to server-initiated input requests from a previous
2334    /// [`InputRequiredResult`].
2335    #[serde(skip_serializing_if = "Option::is_none")]
2336    pub input_responses: Option<InputResponses>,
2337    /// Opaque request state echoed back from a previous [`InputRequiredResult`].
2338    #[serde(skip_serializing_if = "Option::is_none")]
2339    pub request_state: Option<String>,
2340}
2341
2342impl GetPromptRequestParams {
2343    /// Create a new `GetPromptRequestParams` with the given prompt name.
2344    pub fn new(name: impl Into<String>) -> Self {
2345        Self {
2346            meta: None,
2347            name: name.into(),
2348            arguments: None,
2349            input_responses: None,
2350            request_state: None,
2351        }
2352    }
2353
2354    /// Set the arguments for this prompt request.
2355    pub fn with_arguments(mut self, arguments: JsonObject) -> Self {
2356        self.arguments = Some(arguments);
2357        self
2358    }
2359
2360    /// Set the metadata for this request.
2361    pub fn with_meta(mut self, meta: RequestMetaObject) -> Self {
2362        self.meta = Some(meta);
2363        self
2364    }
2365
2366    /// Sets the input responses for an MRTR retry.
2367    pub fn with_input_responses(mut self, input_responses: InputResponses) -> Self {
2368        self.input_responses = Some(input_responses);
2369        self
2370    }
2371
2372    /// Sets the request state for an MRTR retry.
2373    pub fn with_request_state(mut self, request_state: impl Into<String>) -> Self {
2374        self.request_state = Some(request_state.into());
2375        self
2376    }
2377}
2378
2379impl RequestParamsMeta for GetPromptRequestParams {
2380    fn meta(&self) -> Option<&RequestMetaObject> {
2381        self.meta.as_ref()
2382    }
2383    fn meta_mut(&mut self) -> &mut Option<RequestMetaObject> {
2384        &mut self.meta
2385    }
2386}
2387
2388/// Request to get a specific prompt
2389pub type GetPromptRequest = Request<GetPromptRequestMethod, GetPromptRequestParams>;
2390
2391const_string!(PromptListChangedNotificationMethod = "notifications/prompts/list_changed");
2392/// Notification sent when the list of available prompts changes
2393pub type PromptListChangedNotification = NotificationNoParam<PromptListChangedNotificationMethod>;
2394
2395const_string!(ToolListChangedNotificationMethod = "notifications/tools/list_changed");
2396/// Notification sent when the list of available tools changes
2397pub type ToolListChangedNotification = NotificationNoParam<ToolListChangedNotificationMethod>;
2398
2399// =============================================================================
2400// LOGGING
2401// =============================================================================
2402
2403/// Logging levels supported by the MCP protocol
2404#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Copy)]
2405#[serde(rename_all = "lowercase")] //match spec
2406#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
2407#[expect(clippy::exhaustive_enums, reason = "intentionally exhaustive")]
2408#[deprecated(
2409    since = "2.0.0",
2410    note = "Logging is deprecated by SEP-2577 and will be removed in a future release. See https://github.com/modelcontextprotocol/modelcontextprotocol/pull/2577"
2411)]
2412pub enum LoggingLevel {
2413    Debug,
2414    Info,
2415    Notice,
2416    Warning,
2417    Error,
2418    Critical,
2419    Alert,
2420    Emergency,
2421}
2422
2423const_string!(SetLevelRequestMethod = "logging/setLevel");
2424/// Parameters for setting the logging level
2425#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
2426#[serde(rename_all = "camelCase")]
2427#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
2428#[non_exhaustive]
2429#[deprecated(
2430    since = "2.0.0",
2431    note = "Logging is deprecated by SEP-2577 and will be removed in a future release. See https://github.com/modelcontextprotocol/modelcontextprotocol/pull/2577"
2432)]
2433pub struct SetLevelRequestParams {
2434    /// Protocol-level metadata for this request (SEP-1319)
2435    #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
2436    pub meta: Option<RequestMetaObject>,
2437    /// The desired logging level
2438    pub level: LoggingLevel,
2439}
2440
2441impl SetLevelRequestParams {
2442    /// Create a new SetLevelRequestParams with the given logging level.
2443    pub fn new(level: LoggingLevel) -> Self {
2444        Self { meta: None, level }
2445    }
2446}
2447
2448impl RequestParamsMeta for SetLevelRequestParams {
2449    fn meta(&self) -> Option<&RequestMetaObject> {
2450        self.meta.as_ref()
2451    }
2452    fn meta_mut(&mut self) -> &mut Option<RequestMetaObject> {
2453        &mut self.meta
2454    }
2455}
2456
2457/// Request to set the logging level
2458#[deprecated(
2459    since = "2.0.0",
2460    note = "Logging is deprecated by SEP-2577 and will be removed in a future release. See https://github.com/modelcontextprotocol/modelcontextprotocol/pull/2577"
2461)]
2462pub type SetLevelRequest = Request<SetLevelRequestMethod, SetLevelRequestParams>;
2463
2464const_string!(LoggingMessageNotificationMethod = "notifications/message");
2465/// Parameters for a logging message notification
2466#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
2467#[serde(rename_all = "camelCase")]
2468#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
2469#[non_exhaustive]
2470#[deprecated(
2471    since = "2.0.0",
2472    note = "Logging is deprecated by SEP-2577 and will be removed in a future release. See https://github.com/modelcontextprotocol/modelcontextprotocol/pull/2577"
2473)]
2474pub struct LoggingMessageNotificationParam {
2475    /// The severity level of this log message
2476    pub level: LoggingLevel,
2477    /// Optional logger name that generated this message
2478    #[serde(skip_serializing_if = "Option::is_none")]
2479    pub logger: Option<String>,
2480    /// The actual log data
2481    pub data: Value,
2482    #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
2483    pub meta: Option<NotificationMetaObject>,
2484}
2485
2486impl LoggingMessageNotificationParam {
2487    /// Create a new LoggingMessageNotificationParam.
2488    pub fn new(level: LoggingLevel, data: Value) -> Self {
2489        Self {
2490            level,
2491            logger: None,
2492            data,
2493            meta: None,
2494        }
2495    }
2496
2497    /// Set the logger name.
2498    pub fn with_logger(mut self, logger: impl Into<String>) -> Self {
2499        self.logger = Some(logger.into());
2500        self
2501    }
2502}
2503
2504/// Notification containing a log message
2505#[deprecated(
2506    since = "2.0.0",
2507    note = "Logging is deprecated by SEP-2577 and will be removed in a future release. See https://github.com/modelcontextprotocol/modelcontextprotocol/pull/2577"
2508)]
2509pub type LoggingMessageNotification =
2510    Notification<LoggingMessageNotificationMethod, LoggingMessageNotificationParam>;
2511
2512// =============================================================================
2513// SAMPLING (LLM INTERACTION)
2514// =============================================================================
2515
2516const_string!(CreateMessageRequestMethod = "sampling/createMessage");
2517#[deprecated(
2518    since = "2.0.0",
2519    note = "Sampling is deprecated by SEP-2577 and will be removed in a future release. See https://github.com/modelcontextprotocol/modelcontextprotocol/pull/2577"
2520)]
2521pub type CreateMessageRequest = Request<CreateMessageRequestMethod, CreateMessageRequestParams>;
2522
2523/// Represents the role of a participant in a conversation or message exchange.
2524///
2525/// Used in sampling and chat contexts to distinguish between different
2526/// types of message senders in the conversation flow.
2527#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
2528#[serde(rename_all = "camelCase")]
2529#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
2530#[expect(clippy::exhaustive_enums, reason = "intentionally exhaustive")]
2531pub enum Role {
2532    /// A human user or client making a request
2533    User,
2534    /// An AI assistant or server providing a response
2535    Assistant,
2536}
2537
2538/// Tool selection mode (SEP-1577).
2539#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Default)]
2540#[serde(rename_all = "lowercase")]
2541#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
2542#[non_exhaustive]
2543pub enum ToolChoiceMode {
2544    /// Model decides whether to use tools
2545    #[default]
2546    Auto,
2547    /// Model must use at least one tool
2548    Required,
2549    /// Model must not use tools
2550    None,
2551}
2552
2553/// Tool choice configuration (SEP-1577).
2554#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Default)]
2555#[serde(rename_all = "camelCase")]
2556#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
2557#[non_exhaustive]
2558#[deprecated(
2559    since = "2.0.0",
2560    note = "Sampling is deprecated by SEP-2577 and will be removed in a future release. See https://github.com/modelcontextprotocol/modelcontextprotocol/pull/2577"
2561)]
2562pub struct ToolChoice {
2563    #[serde(skip_serializing_if = "Option::is_none")]
2564    pub mode: Option<ToolChoiceMode>,
2565}
2566
2567impl ToolChoice {
2568    pub fn auto() -> Self {
2569        Self {
2570            mode: Some(ToolChoiceMode::Auto),
2571        }
2572    }
2573
2574    pub fn required() -> Self {
2575        Self {
2576            mode: Some(ToolChoiceMode::Required),
2577        }
2578    }
2579
2580    pub fn none() -> Self {
2581        Self {
2582            mode: Some(ToolChoiceMode::None),
2583        }
2584    }
2585}
2586
2587/// Single or array content wrapper (SEP-1577).
2588#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
2589#[serde(untagged)]
2590#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
2591#[expect(clippy::exhaustive_enums, reason = "intentionally exhaustive")]
2592pub enum SamplingContent<T> {
2593    Single(T),
2594    Multiple(Vec<T>),
2595}
2596
2597impl<T> SamplingContent<T> {
2598    /// Convert to a Vec regardless of whether it's single or multiple
2599    pub fn into_vec(self) -> Vec<T> {
2600        match self {
2601            SamplingContent::Single(item) => vec![item],
2602            SamplingContent::Multiple(items) => items,
2603        }
2604    }
2605
2606    /// Check if the content is empty
2607    pub fn is_empty(&self) -> bool {
2608        match self {
2609            SamplingContent::Single(_) => false,
2610            SamplingContent::Multiple(items) => items.is_empty(),
2611        }
2612    }
2613
2614    /// Get the number of content items
2615    pub fn len(&self) -> usize {
2616        match self {
2617            SamplingContent::Single(_) => 1,
2618            SamplingContent::Multiple(items) => items.len(),
2619        }
2620    }
2621}
2622
2623impl<T> Default for SamplingContent<T> {
2624    fn default() -> Self {
2625        SamplingContent::Multiple(Vec::new())
2626    }
2627}
2628
2629impl<T> SamplingContent<T> {
2630    /// Get the first item if present
2631    pub fn first(&self) -> Option<&T> {
2632        match self {
2633            SamplingContent::Single(item) => Some(item),
2634            SamplingContent::Multiple(items) => items.first(),
2635        }
2636    }
2637
2638    /// Iterate over all content items
2639    pub fn iter(&self) -> impl Iterator<Item = &T> {
2640        let items: Vec<&T> = match self {
2641            SamplingContent::Single(item) => vec![item],
2642            SamplingContent::Multiple(items) => items.iter().collect(),
2643        };
2644        items.into_iter()
2645    }
2646}
2647
2648impl SamplingMessageContentBlock {
2649    /// Get the text content if this is a Text variant
2650    pub fn as_text(&self) -> Option<&TextContent> {
2651        match self {
2652            SamplingMessageContentBlock::Text(text) => Some(text),
2653            _ => None,
2654        }
2655    }
2656
2657    /// Get the tool use content if this is a ToolUse variant
2658    pub fn as_tool_use(&self) -> Option<&ToolUseContent> {
2659        match self {
2660            SamplingMessageContentBlock::ToolUse(tool_use) => Some(tool_use),
2661            _ => None,
2662        }
2663    }
2664
2665    /// Get the tool result content if this is a ToolResult variant
2666    pub fn as_tool_result(&self) -> Option<&ToolResultContent> {
2667        match self {
2668            SamplingMessageContentBlock::ToolResult(tool_result) => Some(tool_result),
2669            _ => None,
2670        }
2671    }
2672}
2673
2674impl<T> From<T> for SamplingContent<T> {
2675    fn from(item: T) -> Self {
2676        SamplingContent::Single(item)
2677    }
2678}
2679
2680impl<T> From<Vec<T>> for SamplingContent<T> {
2681    fn from(items: Vec<T>) -> Self {
2682        SamplingContent::Multiple(items)
2683    }
2684}
2685
2686/// A message in a sampling conversation, containing a role and content.
2687///
2688/// This represents a single message in a conversation flow, used primarily
2689/// in LLM sampling requests where the conversation history is important
2690/// for generating appropriate responses.
2691#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
2692#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
2693#[non_exhaustive]
2694#[deprecated(
2695    since = "2.0.0",
2696    note = "Sampling is deprecated by SEP-2577 and will be removed in a future release. See https://github.com/modelcontextprotocol/modelcontextprotocol/pull/2577"
2697)]
2698pub struct SamplingMessage {
2699    /// The role of the message sender (User or Assistant)
2700    pub role: Role,
2701    /// The actual content of the message (text, image, audio, tool use, or tool result)
2702    pub content: SamplingContent<SamplingMessageContentBlock>,
2703    #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
2704    pub meta: Option<MetaObject>,
2705}
2706
2707/// Content types for sampling messages (SEP-1577).
2708#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
2709#[serde(tag = "type", rename_all = "snake_case")]
2710#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
2711#[non_exhaustive]
2712#[deprecated(
2713    since = "2.0.0",
2714    note = "Sampling is deprecated by SEP-2577 and will be removed in a future release. See https://github.com/modelcontextprotocol/modelcontextprotocol/pull/2577"
2715)]
2716pub enum SamplingMessageContentBlock {
2717    Text(TextContent),
2718    Image(ImageContent),
2719    Audio(AudioContent),
2720    /// Assistant only
2721    ToolUse(ToolUseContent),
2722    /// User only
2723    ToolResult(ToolResultContent),
2724}
2725
2726impl SamplingMessageContentBlock {
2727    /// Create a text content
2728    pub fn text(text: impl Into<String>) -> Self {
2729        Self::Text(TextContent::new(text))
2730    }
2731
2732    pub fn tool_use(id: impl Into<String>, name: impl Into<String>, input: JsonObject) -> Self {
2733        Self::ToolUse(ToolUseContent::new(id, name, input))
2734    }
2735
2736    pub fn tool_result(tool_use_id: impl Into<String>, content: Vec<ContentBlock>) -> Self {
2737        Self::ToolResult(ToolResultContent::new(tool_use_id, content))
2738    }
2739}
2740
2741impl SamplingMessage {
2742    pub fn new(role: Role, content: impl Into<SamplingMessageContentBlock>) -> Self {
2743        Self {
2744            role,
2745            content: SamplingContent::Single(content.into()),
2746            meta: None,
2747        }
2748    }
2749
2750    pub fn new_multiple(role: Role, contents: Vec<SamplingMessageContentBlock>) -> Self {
2751        Self {
2752            role,
2753            content: SamplingContent::Multiple(contents),
2754            meta: None,
2755        }
2756    }
2757
2758    pub fn user_text(text: impl Into<String>) -> Self {
2759        Self::new(Role::User, SamplingMessageContentBlock::text(text))
2760    }
2761
2762    pub fn assistant_text(text: impl Into<String>) -> Self {
2763        Self::new(Role::Assistant, SamplingMessageContentBlock::text(text))
2764    }
2765
2766    pub fn user_tool_result(tool_use_id: impl Into<String>, content: Vec<ContentBlock>) -> Self {
2767        Self::new(
2768            Role::User,
2769            SamplingMessageContentBlock::tool_result(tool_use_id, content),
2770        )
2771    }
2772
2773    pub fn assistant_tool_use(
2774        id: impl Into<String>,
2775        name: impl Into<String>,
2776        input: JsonObject,
2777    ) -> Self {
2778        Self::new(
2779            Role::Assistant,
2780            SamplingMessageContentBlock::tool_use(id, name, input),
2781        )
2782    }
2783}
2784
2785impl From<TextContent> for SamplingMessageContentBlock {
2786    fn from(text: TextContent) -> Self {
2787        SamplingMessageContentBlock::Text(text)
2788    }
2789}
2790
2791// Conversion from String to SamplingMessageContentBlock (as text)
2792impl From<String> for SamplingMessageContentBlock {
2793    fn from(text: String) -> Self {
2794        SamplingMessageContentBlock::text(text)
2795    }
2796}
2797
2798impl From<&str> for SamplingMessageContentBlock {
2799    fn from(text: &str) -> Self {
2800        SamplingMessageContentBlock::text(text)
2801    }
2802}
2803
2804impl TryFrom<ContentBlock> for SamplingMessageContentBlock {
2805    type Error = &'static str;
2806
2807    fn try_from(content: ContentBlock) -> Result<Self, Self::Error> {
2808        match content {
2809            ContentBlock::Text(text) => Ok(SamplingMessageContentBlock::Text(text)),
2810            ContentBlock::Image(image) => Ok(SamplingMessageContentBlock::Image(image)),
2811            ContentBlock::Audio(audio) => Ok(SamplingMessageContentBlock::Audio(audio)),
2812            ContentBlock::Resource(_) => {
2813                Err("Resource content is not supported in sampling messages")
2814            }
2815            ContentBlock::ResourceLink(_) => {
2816                Err("ResourceLink content is not supported in sampling messages")
2817            }
2818        }
2819    }
2820}
2821
2822impl TryFrom<ContentBlock> for SamplingContent<SamplingMessageContentBlock> {
2823    type Error = &'static str;
2824
2825    fn try_from(content: ContentBlock) -> Result<Self, Self::Error> {
2826        Ok(SamplingContent::Single(content.try_into()?))
2827    }
2828}
2829
2830/// Specifies how much context should be included in sampling requests.
2831///
2832/// This allows clients to control what additional context information
2833/// should be provided to the LLM when processing sampling requests.
2834#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
2835#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
2836#[non_exhaustive]
2837pub enum ContextInclusion {
2838    /// Include context from all connected MCP servers
2839    #[serde(rename = "allServers")]
2840    AllServers,
2841    /// Include no additional context
2842    #[serde(rename = "none")]
2843    None,
2844    /// Include context only from the requesting server
2845    #[serde(rename = "thisServer")]
2846    ThisServer,
2847}
2848
2849/// Parameters for creating a message through LLM sampling.
2850///
2851/// This structure contains all the necessary information for a client to
2852/// generate an LLM response, including conversation history, model preferences,
2853/// and generation parameters.
2854///
2855/// This implements `TaskAugmentedRequestParamsMeta` as sampling requests can be
2856/// long-running and may benefit from task-based execution.
2857#[derive(Default, Debug, Serialize, Deserialize, Clone, PartialEq)]
2858#[serde(rename_all = "camelCase")]
2859#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
2860#[non_exhaustive]
2861#[deprecated(
2862    since = "2.0.0",
2863    note = "Sampling is deprecated by SEP-2577 and will be removed in a future release. See https://github.com/modelcontextprotocol/modelcontextprotocol/pull/2577"
2864)]
2865pub struct CreateMessageRequestParams {
2866    /// Protocol-level metadata for this request (SEP-1319)
2867    #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
2868    pub meta: Option<RequestMetaObject>,
2869    /// The conversation history and current messages
2870    pub messages: Vec<SamplingMessage>,
2871    /// Preferences for model selection and behavior
2872    #[serde(skip_serializing_if = "Option::is_none")]
2873    pub model_preferences: Option<ModelPreferences>,
2874    /// System prompt to guide the model's behavior
2875    #[serde(skip_serializing_if = "Option::is_none")]
2876    pub system_prompt: Option<String>,
2877    /// How much context to include from MCP servers
2878    #[serde(skip_serializing_if = "Option::is_none")]
2879    pub include_context: Option<ContextInclusion>,
2880    /// Temperature for controlling randomness (0.0 to 1.0)
2881    #[serde(skip_serializing_if = "Option::is_none")]
2882    pub temperature: Option<f32>,
2883    /// Maximum number of tokens to generate
2884    pub max_tokens: u32,
2885    /// Sequences that should stop generation
2886    #[serde(skip_serializing_if = "Option::is_none")]
2887    pub stop_sequences: Option<Vec<String>>,
2888    /// Additional metadata for the request
2889    #[serde(skip_serializing_if = "Option::is_none")]
2890    pub metadata: Option<Value>,
2891    /// Tools available for the model to call (SEP-1577)
2892    #[serde(skip_serializing_if = "Option::is_none")]
2893    pub tools: Option<Vec<Tool>>,
2894    /// Tool selection behavior (SEP-1577)
2895    #[serde(skip_serializing_if = "Option::is_none")]
2896    pub tool_choice: Option<ToolChoice>,
2897}
2898
2899impl RequestParamsMeta for CreateMessageRequestParams {
2900    fn meta(&self) -> Option<&RequestMetaObject> {
2901        self.meta.as_ref()
2902    }
2903    fn meta_mut(&mut self) -> &mut Option<RequestMetaObject> {
2904        &mut self.meta
2905    }
2906}
2907
2908impl CreateMessageRequestParams {
2909    /// Create a new CreateMessageRequestParams with required fields.
2910    pub fn new(messages: Vec<SamplingMessage>, max_tokens: u32) -> Self {
2911        Self {
2912            meta: None,
2913            messages,
2914            model_preferences: None,
2915            system_prompt: None,
2916            include_context: None,
2917            temperature: None,
2918            max_tokens,
2919            stop_sequences: None,
2920            metadata: None,
2921            tools: None,
2922            tool_choice: None,
2923        }
2924    }
2925
2926    /// Set model preferences.
2927    pub fn with_model_preferences(mut self, model_preferences: ModelPreferences) -> Self {
2928        self.model_preferences = Some(model_preferences);
2929        self
2930    }
2931
2932    /// Set system prompt.
2933    pub fn with_system_prompt(mut self, system_prompt: impl Into<String>) -> Self {
2934        self.system_prompt = Some(system_prompt.into());
2935        self
2936    }
2937
2938    /// Set include context.
2939    pub fn with_include_context(mut self, include_context: ContextInclusion) -> Self {
2940        self.include_context = Some(include_context);
2941        self
2942    }
2943
2944    /// Set temperature.
2945    pub fn with_temperature(mut self, temperature: f32) -> Self {
2946        self.temperature = Some(temperature);
2947        self
2948    }
2949
2950    /// Set stop sequences.
2951    pub fn with_stop_sequences(mut self, stop_sequences: Vec<String>) -> Self {
2952        self.stop_sequences = Some(stop_sequences);
2953        self
2954    }
2955
2956    /// Set metadata.
2957    pub fn with_metadata(mut self, metadata: Value) -> Self {
2958        self.metadata = Some(metadata);
2959        self
2960    }
2961
2962    /// Set tools.
2963    pub fn with_tools(mut self, tools: Vec<Tool>) -> Self {
2964        self.tools = Some(tools);
2965        self
2966    }
2967
2968    /// Set tool choice.
2969    pub fn with_tool_choice(mut self, tool_choice: ToolChoice) -> Self {
2970        self.tool_choice = Some(tool_choice);
2971        self
2972    }
2973
2974    /// Validate the sampling request parameters per SEP-1577 spec requirements.
2975    ///
2976    /// Checks:
2977    /// - ToolUse content is only allowed in assistant messages
2978    /// - ToolResult content is only allowed in user messages
2979    /// - Messages with tool result content MUST NOT contain other content types
2980    /// - Every assistant ToolUse must be balanced with a corresponding user ToolResult
2981    pub fn validate(&self) -> Result<(), String> {
2982        for msg in &self.messages {
2983            for content in msg.content.iter() {
2984                // ToolUse only in assistant messages, ToolResult only in user messages
2985                match content {
2986                    SamplingMessageContentBlock::ToolUse(_) if msg.role != Role::Assistant => {
2987                        return Err("ToolUse content is only allowed in assistant messages".into());
2988                    }
2989                    SamplingMessageContentBlock::ToolResult(_) if msg.role != Role::User => {
2990                        return Err("ToolResult content is only allowed in user messages".into());
2991                    }
2992                    _ => {}
2993                }
2994            }
2995
2996            // Tool result messages MUST NOT contain other content types
2997            let contents: Vec<_> = msg.content.iter().collect();
2998            let has_tool_result = contents
2999                .iter()
3000                .any(|c| matches!(c, SamplingMessageContentBlock::ToolResult(_)));
3001            if has_tool_result
3002                && contents
3003                    .iter()
3004                    .any(|c| !matches!(c, SamplingMessageContentBlock::ToolResult(_)))
3005            {
3006                return Err(
3007                    "SamplingMessage with tool result content MUST NOT contain other content types"
3008                        .into(),
3009                );
3010            }
3011        }
3012
3013        // Every assistant ToolUse must be balanced with a user ToolResult
3014        self.validate_tool_use_result_balance()?;
3015
3016        Ok(())
3017    }
3018
3019    fn validate_tool_use_result_balance(&self) -> Result<(), String> {
3020        let mut pending_tool_use_ids: Vec<String> = Vec::new();
3021        for msg in &self.messages {
3022            if msg.role == Role::Assistant {
3023                for content in msg.content.iter() {
3024                    if let SamplingMessageContentBlock::ToolUse(tu) = content {
3025                        pending_tool_use_ids.push(tu.id.clone());
3026                    }
3027                }
3028            } else if msg.role == Role::User {
3029                for content in msg.content.iter() {
3030                    if let SamplingMessageContentBlock::ToolResult(tr) = content {
3031                        if !pending_tool_use_ids.contains(&tr.tool_use_id) {
3032                            return Err(format!(
3033                                "ToolResult with toolUseId '{}' has no matching ToolUse",
3034                                tr.tool_use_id
3035                            ));
3036                        }
3037                        pending_tool_use_ids.retain(|id| id != &tr.tool_use_id);
3038                    }
3039                }
3040            }
3041        }
3042        if !pending_tool_use_ids.is_empty() {
3043            return Err(format!(
3044                "ToolUse with id(s) {:?} not balanced with ToolResult",
3045                pending_tool_use_ids
3046            ));
3047        }
3048        Ok(())
3049    }
3050}
3051
3052/// Preferences for model selection and behavior in sampling requests.
3053///
3054/// This allows servers to express their preferences for which model to use
3055/// and how to balance different priorities when the client has multiple
3056/// model options available.
3057#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
3058#[serde(rename_all = "camelCase")]
3059#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
3060#[non_exhaustive]
3061#[deprecated(
3062    since = "2.0.0",
3063    note = "Sampling is deprecated by SEP-2577 and will be removed in a future release. See https://github.com/modelcontextprotocol/modelcontextprotocol/pull/2577"
3064)]
3065pub struct ModelPreferences {
3066    /// Specific model names or families to prefer (e.g., "claude", "gpt")
3067    #[serde(skip_serializing_if = "Option::is_none")]
3068    pub hints: Option<Vec<ModelHint>>,
3069    /// Priority for cost optimization (0.0 to 1.0, higher = prefer cheaper models)
3070    #[serde(skip_serializing_if = "Option::is_none")]
3071    pub cost_priority: Option<f32>,
3072    /// Priority for speed/latency (0.0 to 1.0, higher = prefer faster models)
3073    #[serde(skip_serializing_if = "Option::is_none")]
3074    pub speed_priority: Option<f32>,
3075    /// Priority for intelligence/capability (0.0 to 1.0, higher = prefer more capable models)
3076    #[serde(skip_serializing_if = "Option::is_none")]
3077    pub intelligence_priority: Option<f32>,
3078}
3079
3080impl ModelPreferences {
3081    /// Create a new default ModelPreferences.
3082    pub fn new() -> Self {
3083        Self {
3084            hints: None,
3085            cost_priority: None,
3086            speed_priority: None,
3087            intelligence_priority: None,
3088        }
3089    }
3090
3091    /// Set hints for model selection.
3092    pub fn with_hints(mut self, hints: Vec<ModelHint>) -> Self {
3093        self.hints = Some(hints);
3094        self
3095    }
3096
3097    /// Set cost priority (0.0 to 1.0).
3098    pub fn with_cost_priority(mut self, cost_priority: f32) -> Self {
3099        self.cost_priority = Some(cost_priority);
3100        self
3101    }
3102
3103    /// Set speed priority (0.0 to 1.0).
3104    pub fn with_speed_priority(mut self, speed_priority: f32) -> Self {
3105        self.speed_priority = Some(speed_priority);
3106        self
3107    }
3108
3109    /// Set intelligence priority (0.0 to 1.0).
3110    pub fn with_intelligence_priority(mut self, intelligence_priority: f32) -> Self {
3111        self.intelligence_priority = Some(intelligence_priority);
3112        self
3113    }
3114}
3115
3116impl Default for ModelPreferences {
3117    fn default() -> Self {
3118        Self::new()
3119    }
3120}
3121
3122/// A hint suggesting a preferred model name or family.
3123///
3124/// Model hints are advisory suggestions that help clients choose appropriate
3125/// models. They can be specific model names or general families like "claude" or "gpt".
3126#[derive(Default, Debug, Serialize, Deserialize, Clone, PartialEq)]
3127#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
3128#[non_exhaustive]
3129#[deprecated(
3130    since = "2.0.0",
3131    note = "Sampling is deprecated by SEP-2577 and will be removed in a future release. See https://github.com/modelcontextprotocol/modelcontextprotocol/pull/2577"
3132)]
3133pub struct ModelHint {
3134    /// The suggested model name or family identifier
3135    #[serde(skip_serializing_if = "Option::is_none")]
3136    pub name: Option<String>,
3137}
3138
3139impl ModelHint {
3140    /// Create a new ModelHint with a name.
3141    pub fn new(name: impl Into<String>) -> Self {
3142        Self {
3143            name: Some(name.into()),
3144        }
3145    }
3146}
3147
3148// =============================================================================
3149// COMPLETION AND AUTOCOMPLETE
3150// =============================================================================
3151
3152/// Context for completion requests providing previously resolved arguments.
3153///
3154/// This enables context-aware completion where subsequent argument completions
3155/// can take into account the values of previously resolved arguments.
3156#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Default)]
3157#[serde(rename_all = "camelCase")]
3158#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
3159#[non_exhaustive]
3160pub struct CompletionContext {
3161    /// Previously resolved argument values that can inform completion suggestions
3162    #[serde(skip_serializing_if = "Option::is_none")]
3163    pub arguments: Option<std::collections::HashMap<String, String>>,
3164}
3165
3166impl CompletionContext {
3167    /// Create a new empty completion context
3168    pub fn new() -> Self {
3169        Self::default()
3170    }
3171
3172    /// Create a completion context with the given arguments
3173    pub fn with_arguments(arguments: std::collections::HashMap<String, String>) -> Self {
3174        Self {
3175            arguments: Some(arguments),
3176        }
3177    }
3178
3179    /// Get a specific argument value by name
3180    pub fn get_argument(&self, name: &str) -> Option<&String> {
3181        self.arguments.as_ref()?.get(name)
3182    }
3183
3184    /// Check if the context has any arguments
3185    pub fn has_arguments(&self) -> bool {
3186        self.arguments.as_ref().is_some_and(|args| !args.is_empty())
3187    }
3188
3189    /// Get all argument names
3190    pub fn argument_names(&self) -> impl Iterator<Item = &str> {
3191        self.arguments
3192            .as_ref()
3193            .into_iter()
3194            .flat_map(|args| args.keys())
3195            .map(|k| k.as_str())
3196    }
3197}
3198
3199#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
3200#[serde(rename_all = "camelCase")]
3201#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
3202#[non_exhaustive]
3203pub struct CompleteRequestParams {
3204    /// Protocol-level metadata for this request (SEP-1319)
3205    #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
3206    pub meta: Option<RequestMetaObject>,
3207    pub r#ref: Reference,
3208    pub argument: ArgumentInfo,
3209    /// Optional context containing previously resolved argument values
3210    #[serde(skip_serializing_if = "Option::is_none")]
3211    pub context: Option<CompletionContext>,
3212}
3213
3214impl CompleteRequestParams {
3215    /// Create a new CompleteRequestParams with required fields.
3216    pub fn new(r#ref: Reference, argument: ArgumentInfo) -> Self {
3217        Self {
3218            meta: None,
3219            r#ref,
3220            argument,
3221            context: None,
3222        }
3223    }
3224
3225    /// Set the completion context
3226    pub fn with_context(mut self, context: CompletionContext) -> Self {
3227        self.context = Some(context);
3228        self
3229    }
3230}
3231
3232impl RequestParamsMeta for CompleteRequestParams {
3233    fn meta(&self) -> Option<&RequestMetaObject> {
3234        self.meta.as_ref()
3235    }
3236    fn meta_mut(&mut self) -> &mut Option<RequestMetaObject> {
3237        &mut self.meta
3238    }
3239}
3240
3241pub type CompleteRequest = Request<CompleteRequestMethod, CompleteRequestParams>;
3242
3243#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Default)]
3244#[serde(rename_all = "camelCase")]
3245#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
3246#[non_exhaustive]
3247pub struct CompletionInfo {
3248    pub values: Vec<String>,
3249    #[serde(skip_serializing_if = "Option::is_none")]
3250    pub total: Option<u32>,
3251    #[serde(skip_serializing_if = "Option::is_none")]
3252    pub has_more: Option<bool>,
3253}
3254
3255impl CompletionInfo {
3256    /// Maximum number of completion values allowed per response according to MCP specification
3257    pub const MAX_VALUES: usize = 100;
3258
3259    /// Create a new CompletionInfo with validation for maximum values
3260    pub fn new(values: Vec<String>) -> Result<Self, String> {
3261        if values.len() > Self::MAX_VALUES {
3262            return Err(format!(
3263                "Too many completion values: {} (max: {})",
3264                values.len(),
3265                Self::MAX_VALUES
3266            ));
3267        }
3268        Ok(Self {
3269            values,
3270            total: None,
3271            has_more: None,
3272        })
3273    }
3274
3275    /// Create CompletionInfo with all values and no pagination
3276    pub fn with_all_values(values: Vec<String>) -> Result<Self, String> {
3277        let completion = Self::new(values)?;
3278        Ok(Self {
3279            total: Some(completion.values.len() as u32),
3280            has_more: Some(false),
3281            ..completion
3282        })
3283    }
3284
3285    /// Create CompletionInfo with pagination information
3286    pub fn with_pagination(
3287        values: Vec<String>,
3288        total: Option<u32>,
3289        has_more: bool,
3290    ) -> Result<Self, String> {
3291        let completion = Self::new(values)?;
3292        Ok(Self {
3293            total,
3294            has_more: Some(has_more),
3295            ..completion
3296        })
3297    }
3298
3299    /// Check if this completion response indicates more results are available
3300    pub fn has_more_results(&self) -> bool {
3301        self.has_more.unwrap_or(false)
3302    }
3303
3304    /// Get the total number of available completions, if known
3305    pub fn total_available(&self) -> Option<u32> {
3306        self.total
3307    }
3308
3309    /// Validate that the completion info complies with MCP specification
3310    pub fn validate(&self) -> Result<(), String> {
3311        if self.values.len() > Self::MAX_VALUES {
3312            return Err(format!(
3313                "Too many completion values: {} (max: {})",
3314                self.values.len(),
3315                Self::MAX_VALUES
3316            ));
3317        }
3318        Ok(())
3319    }
3320}
3321
3322#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
3323#[serde(rename_all = "camelCase")]
3324#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
3325#[non_exhaustive]
3326pub struct CompleteResult {
3327    /// Result type discriminator (SEP-2322). Required by the [spec schema]
3328    /// for servers implementing protocol version `2026-07-28`, but optional
3329    /// here because this type also models results from older protocol
3330    /// versions, which do not carry the field: `None` means absent on the
3331    /// wire, and per the spec "the client MUST treat the absent field as
3332    /// `"complete"`". Constructors default to `Some(ResultType::COMPLETE)`;
3333    /// the server handler clears the field when responding to peers that
3334    /// negotiated an older version.
3335    ///
3336    /// [spec schema]: https://github.com/modelcontextprotocol/modelcontextprotocol/blob/271ecc9accafdd9b83a3c869fa67c22953b2af80/schema/2026-07-28/schema.ts#L219-L235
3337    #[serde(default, skip_serializing_if = "Option::is_none")]
3338    pub result_type: Option<ResultType>,
3339    pub completion: CompletionInfo,
3340    #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
3341    pub meta: Option<MetaObject>,
3342}
3343
3344impl Default for CompleteResult {
3345    fn default() -> Self {
3346        Self::new(CompletionInfo::default())
3347    }
3348}
3349
3350impl CompleteResult {
3351    /// Create a new CompleteResult with the given completion info.
3352    pub fn new(completion: CompletionInfo) -> Self {
3353        Self {
3354            result_type: Some(ResultType::COMPLETE),
3355            completion,
3356            meta: None,
3357        }
3358    }
3359}
3360
3361#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
3362#[serde(tag = "type")]
3363#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
3364#[non_exhaustive]
3365pub enum Reference {
3366    #[serde(rename = "ref/resource")]
3367    Resource(ResourceTemplateReference),
3368    #[serde(rename = "ref/prompt")]
3369    Prompt(PromptReference),
3370}
3371
3372impl Reference {
3373    /// Create a prompt reference
3374    pub fn for_prompt(name: impl Into<String>) -> Self {
3375        // Not accepting `title` currently as it'll break the API
3376        // Until further decision, keep it `None`, modify later
3377        // if required, add `title` to the API
3378        Self::Prompt(PromptReference {
3379            name: name.into(),
3380            title: None,
3381        })
3382    }
3383
3384    /// Create a resource reference
3385    pub fn for_resource(uri: impl Into<String>) -> Self {
3386        Self::Resource(ResourceTemplateReference { uri: uri.into() })
3387    }
3388
3389    /// Get the reference type as a string
3390    pub fn reference_type(&self) -> &'static str {
3391        match self {
3392            Self::Prompt(_) => "ref/prompt",
3393            Self::Resource(_) => "ref/resource",
3394        }
3395    }
3396
3397    /// Extract prompt name if this is a prompt reference
3398    pub fn as_prompt_name(&self) -> Option<&str> {
3399        match self {
3400            Self::Prompt(prompt_ref) => Some(&prompt_ref.name),
3401            _ => None,
3402        }
3403    }
3404
3405    /// Extract resource URI if this is a resource reference
3406    pub fn as_resource_uri(&self) -> Option<&str> {
3407        match self {
3408            Self::Resource(resource_ref) => Some(&resource_ref.uri),
3409            _ => None,
3410        }
3411    }
3412}
3413
3414#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
3415#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
3416#[non_exhaustive]
3417pub struct ResourceTemplateReference {
3418    pub uri: String,
3419}
3420
3421impl ResourceTemplateReference {
3422    pub fn new(uri: impl Into<String>) -> Self {
3423        Self { uri: uri.into() }
3424    }
3425}
3426
3427#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
3428#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
3429#[non_exhaustive]
3430pub struct PromptReference {
3431    pub name: String,
3432    #[serde(skip_serializing_if = "Option::is_none")]
3433    pub title: Option<String>,
3434}
3435
3436impl PromptReference {
3437    /// Creates a new `PromptReference` with the given name. `title` defaults to `None`.
3438    pub fn new(name: impl Into<String>) -> Self {
3439        Self {
3440            name: name.into(),
3441            title: None,
3442        }
3443    }
3444
3445    /// Sets the human-readable title for this prompt reference.
3446    pub fn with_title(mut self, title: impl Into<String>) -> Self {
3447        self.title = Some(title.into());
3448        self
3449    }
3450}
3451
3452const_string!(CompleteRequestMethod = "completion/complete");
3453#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
3454#[serde(rename_all = "camelCase")]
3455#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
3456#[non_exhaustive]
3457pub struct ArgumentInfo {
3458    pub name: String,
3459    pub value: String,
3460}
3461
3462impl ArgumentInfo {
3463    pub fn new(name: impl Into<String>, value: impl Into<String>) -> Self {
3464        Self {
3465            name: name.into(),
3466            value: value.into(),
3467        }
3468    }
3469}
3470
3471// =============================================================================
3472// ROOTS AND WORKSPACE MANAGEMENT
3473// =============================================================================
3474
3475#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
3476#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
3477#[non_exhaustive]
3478#[deprecated(
3479    since = "2.0.0",
3480    note = "Roots is deprecated by SEP-2577 and will be removed in a future release. See https://github.com/modelcontextprotocol/modelcontextprotocol/pull/2577"
3481)]
3482pub struct Root {
3483    pub uri: String,
3484    #[serde(skip_serializing_if = "Option::is_none")]
3485    pub name: Option<String>,
3486    #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
3487    pub meta: Option<MetaObject>,
3488}
3489
3490impl Root {
3491    /// Creates a new `Root` with the given URI. `name` defaults to `None`.
3492    pub fn new(uri: impl Into<String>) -> Self {
3493        Self {
3494            uri: uri.into(),
3495            name: None,
3496            meta: None,
3497        }
3498    }
3499
3500    /// Sets the human-readable name for this root.
3501    pub fn with_name(mut self, name: impl Into<String>) -> Self {
3502        self.name = Some(name.into());
3503        self
3504    }
3505
3506    /// Sets the protocol-level metadata for this root.
3507    pub fn with_meta(mut self, meta: MetaObject) -> Self {
3508        self.meta = Some(meta);
3509        self
3510    }
3511}
3512
3513const_string!(ListRootsRequestMethod = "roots/list");
3514#[deprecated(
3515    since = "2.0.0",
3516    note = "Roots is deprecated by SEP-2577 and will be removed in a future release. See https://github.com/modelcontextprotocol/modelcontextprotocol/pull/2577"
3517)]
3518pub type ListRootsRequest = RequestNoParam<ListRootsRequestMethod>;
3519
3520#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Default)]
3521#[serde(rename_all = "camelCase")]
3522#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
3523#[non_exhaustive]
3524#[deprecated(
3525    since = "2.0.0",
3526    note = "Roots is deprecated by SEP-2577 and will be removed in a future release. See https://github.com/modelcontextprotocol/modelcontextprotocol/pull/2577"
3527)]
3528pub struct ListRootsResult {
3529    pub roots: Vec<Root>,
3530    #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
3531    pub meta: Option<MetaObject>,
3532}
3533
3534impl ListRootsResult {
3535    /// Creates a new `ListRootsResult` with the given roots.
3536    pub fn new(roots: Vec<Root>) -> Self {
3537        Self { roots, meta: None }
3538    }
3539
3540    /// Sets the protocol-level metadata for this result.
3541    pub fn with_meta(mut self, meta: MetaObject) -> Self {
3542        self.meta = Some(meta);
3543        self
3544    }
3545}
3546
3547const_string!(RootsListChangedNotificationMethod = "notifications/roots/list_changed");
3548pub type RootsListChangedNotification = NotificationNoParam<RootsListChangedNotificationMethod>;
3549
3550// =============================================================================
3551// ELICITATION (INTERACTIVE USER INPUT)
3552// =============================================================================
3553
3554// Method constants for elicitation operations.
3555// Elicitation allows servers to request interactive input from users during tool execution.
3556const_string!(ElicitationCreateRequestMethod = "elicitation/create");
3557const_string!(ElicitationResponseNotificationMethod = "notifications/elicitation/response");
3558
3559/// Represents the possible actions a user can take in response to an elicitation request.
3560///
3561/// When a server requests user input through elicitation, the user can:
3562/// - Accept: Provide the requested information and continue
3563/// - Decline: Refuse to provide the information but continue the operation
3564/// - Cancel: Stop the entire operation
3565#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq)]
3566#[serde(rename_all = "lowercase")]
3567#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
3568#[non_exhaustive]
3569pub enum ElicitationAction {
3570    /// User accepts the request and provides the requested information
3571    Accept,
3572    /// User declines to provide the information but allows the operation to continue
3573    Decline,
3574    /// User cancels the entire operation
3575    Cancel,
3576}
3577
3578/// Wire representation for tagged elicitation parameters and legacy forms without `mode`.
3579#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
3580#[serde(tag = "mode")]
3581#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
3582enum ElicitRequestParamsWire {
3583    #[serde(rename = "form", rename_all = "camelCase")]
3584    Form {
3585        #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
3586        meta: Option<RequestMetaObject>,
3587        message: String,
3588        requested_schema: ElicitationSchema,
3589    },
3590    #[serde(rename = "url", rename_all = "camelCase")]
3591    Url {
3592        #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
3593        meta: Option<RequestMetaObject>,
3594        message: String,
3595        url: String,
3596        elicitation_id: String,
3597    },
3598    #[serde(untagged, rename_all = "camelCase")]
3599    LegacyForm {
3600        #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
3601        meta: Option<RequestMetaObject>,
3602        message: String,
3603        requested_schema: ElicitationSchema,
3604    },
3605}
3606
3607impl TryFrom<ElicitRequestParamsWire> for ElicitRequestParams {
3608    type Error = serde_json::Error;
3609
3610    fn try_from(value: ElicitRequestParamsWire) -> Result<Self, Self::Error> {
3611        match value {
3612            ElicitRequestParamsWire::Form {
3613                meta,
3614                message,
3615                requested_schema,
3616            }
3617            | ElicitRequestParamsWire::LegacyForm {
3618                meta,
3619                message,
3620                requested_schema,
3621            } => Ok(ElicitRequestParams::FormElicitationParams {
3622                meta,
3623                message,
3624                requested_schema,
3625            }),
3626            ElicitRequestParamsWire::Url {
3627                meta,
3628                message,
3629                url,
3630                elicitation_id,
3631            } => Ok(ElicitRequestParams::UrlElicitationParams {
3632                meta,
3633                message,
3634                url,
3635                elicitation_id,
3636            }),
3637        }
3638    }
3639}
3640
3641/// Parameters for creating an elicitation request to gather user input.
3642///
3643/// This structure contains everything needed to request interactive input from a user:
3644/// - A human-readable message explaining what information is needed
3645/// - A type-safe schema defining the expected structure of the response
3646///
3647/// # Example
3648/// 1. Form-based elicitation request
3649/// ```rust
3650/// use rmcp::model::*;
3651///
3652/// let params = ElicitRequestParams::FormElicitationParams {
3653///    meta: None,
3654///     message: "Please provide your email".to_string(),
3655///     requested_schema: ElicitationSchema::builder()
3656///         .required_email("email")
3657///         .build()
3658///         .unwrap(),
3659/// };
3660/// ```
3661/// 2. URL-based elicitation request
3662/// ```rust
3663/// use rmcp::model::*;
3664/// let params = ElicitRequestParams::UrlElicitationParams {
3665///     meta: None,
3666///     message: "Please provide your feedback at the following URL".to_string(),
3667///     url: "https://example.com/feedback".to_string(),
3668///     elicitation_id: "unique-id-123".to_string(),
3669/// };
3670/// ```
3671#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
3672#[serde(tag = "mode", try_from = "ElicitRequestParamsWire")]
3673#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
3674#[non_exhaustive]
3675pub enum ElicitRequestParams {
3676    #[serde(rename = "form", rename_all = "camelCase")]
3677    FormElicitationParams {
3678        /// Protocol-level metadata for this request (SEP-1319)
3679        #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
3680        meta: Option<RequestMetaObject>,
3681        /// Human-readable message explaining what input is needed from the user.
3682        /// This should be clear and provide sufficient context for the user to understand
3683        /// what information they need to provide.
3684        message: String,
3685
3686        /// Type-safe schema defining the expected structure and validation rules for the user's response.
3687        /// This enforces the MCP 2025-06-18 specification that elicitation schemas must be objects
3688        /// with primitive-typed properties.
3689        requested_schema: ElicitationSchema,
3690    },
3691    #[serde(rename = "url", rename_all = "camelCase")]
3692    UrlElicitationParams {
3693        /// Protocol-level metadata for this request (SEP-1319)
3694        #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
3695        meta: Option<RequestMetaObject>,
3696        /// Human-readable message explaining what input is needed from the user.
3697        /// This should be clear and provide sufficient context for the user to understand
3698        /// what information they need to provide.
3699        message: String,
3700
3701        /// The URL where the user can provide the requested information.
3702        /// The client should direct the user to this URL to complete the elicitation.
3703        url: String,
3704        /// The unique identifier for this elicitation request.
3705        elicitation_id: String,
3706    },
3707}
3708
3709impl RequestParamsMeta for ElicitRequestParams {
3710    fn meta(&self) -> Option<&RequestMetaObject> {
3711        match self {
3712            ElicitRequestParams::FormElicitationParams { meta, .. } => meta.as_ref(),
3713            ElicitRequestParams::UrlElicitationParams { meta, .. } => meta.as_ref(),
3714        }
3715    }
3716    fn meta_mut(&mut self) -> &mut Option<RequestMetaObject> {
3717        match self {
3718            ElicitRequestParams::FormElicitationParams { meta, .. } => meta,
3719            ElicitRequestParams::UrlElicitationParams { meta, .. } => meta,
3720        }
3721    }
3722}
3723
3724/// The result returned by a client in response to an elicitation request.
3725///
3726/// Contains the user's decision (accept/decline/cancel) and optionally their input data
3727/// if they chose to accept the request.
3728#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
3729#[serde(rename_all = "camelCase")]
3730#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
3731#[non_exhaustive]
3732pub struct ElicitResult {
3733    /// The user's decision on how to handle the elicitation request
3734    pub action: ElicitationAction,
3735
3736    /// The actual data provided by the user, if they accepted the request.
3737    /// Must conform to the JSON schema specified in the original request.
3738    /// Only present when action is Accept.
3739    #[serde(skip_serializing_if = "Option::is_none")]
3740    pub content: Option<Value>,
3741
3742    /// Optional protocol-level metadata for this result.
3743    #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
3744    pub meta: Option<MetaObject>,
3745}
3746
3747impl ElicitResult {
3748    /// Create a new ElicitResult.
3749    pub fn new(action: ElicitationAction) -> Self {
3750        Self {
3751            action,
3752            content: None,
3753            meta: None,
3754        }
3755    }
3756
3757    /// Set the content on this result.
3758    pub fn with_content(mut self, content: Value) -> Self {
3759        self.content = Some(content);
3760        self
3761    }
3762
3763    /// Set the metadata on this result.
3764    pub fn with_meta(mut self, meta: MetaObject) -> Self {
3765        self.meta = Some(meta);
3766        self
3767    }
3768}
3769
3770/// Request type for creating an elicitation to gather user input
3771pub type ElicitRequest = Request<ElicitationCreateRequestMethod, ElicitRequestParams>;
3772
3773// =============================================================================
3774// TOOL EXECUTION RESULTS
3775// =============================================================================
3776
3777/// The result of a tool call operation.
3778///
3779/// Contains the content returned by the tool execution and an optional
3780/// flag indicating whether the operation resulted in an error.
3781#[derive(Debug, Serialize, Clone, PartialEq)]
3782#[serde(rename_all = "camelCase")]
3783#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
3784#[non_exhaustive]
3785pub struct CallToolResult {
3786    /// Result type discriminator (SEP-2322). Required by the [spec schema]
3787    /// for servers implementing protocol version `2026-07-28`, but optional
3788    /// here because this type also models results from older protocol
3789    /// versions, which do not carry the field: `None` means absent on the
3790    /// wire, and per the spec "the client MUST treat the absent field as
3791    /// `"complete"`". Constructors default to `Some(ResultType::COMPLETE)`;
3792    /// the server handler clears the field when responding to peers that
3793    /// negotiated an older version.
3794    ///
3795    /// [spec schema]: https://github.com/modelcontextprotocol/modelcontextprotocol/blob/271ecc9accafdd9b83a3c869fa67c22953b2af80/schema/2026-07-28/schema.ts#L219-L235
3796    #[serde(default, skip_serializing_if = "Option::is_none")]
3797    pub result_type: Option<ResultType>,
3798    /// The content returned by the tool (text, images, etc.)
3799    #[serde(default)]
3800    pub content: Vec<ContentBlock>,
3801    /// An optional JSON object that represents the structured result of the tool call
3802    #[serde(skip_serializing_if = "Option::is_none")]
3803    pub structured_content: Option<Value>,
3804    /// Whether this result represents an error condition
3805    #[serde(skip_serializing_if = "Option::is_none")]
3806    pub is_error: Option<bool>,
3807    /// Optional protocol-level metadata for this result
3808    #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
3809    pub meta: Option<MetaObject>,
3810}
3811
3812// Custom Deserialize implementation that:
3813// 1. Defaults `content` to `[]` when the field is missing (lenient per Postel's law)
3814// 2. Requires at least one known field to be present, so that `CallToolResult` doesn't
3815//    greedily match arbitrary JSON objects when used inside `#[serde(untagged)]` enums
3816//    (e.g. `ServerResult`), which would shadow `CustomResult`.
3817// 3. Rejects non-`complete` result types so other `ServerResult` variants can match.
3818impl<'de> Deserialize<'de> for CallToolResult {
3819    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
3820    where
3821        D: serde::Deserializer<'de>,
3822    {
3823        #[derive(Deserialize)]
3824        #[serde(rename_all = "camelCase")]
3825        struct Helper {
3826            #[serde(default)]
3827            result_type: Option<ResultType>,
3828            content: Option<Vec<ContentBlock>>,
3829            structured_content: Option<Value>,
3830            is_error: Option<bool>,
3831            #[serde(rename = "_meta")]
3832            meta: Option<MetaObject>,
3833        }
3834
3835        let helper = Helper::deserialize(deserializer)?;
3836
3837        if helper
3838            .result_type
3839            .as_ref()
3840            .is_some_and(|result_type| !result_type.is_complete())
3841        {
3842            return Err(serde::de::Error::custom(
3843                "CallToolResult requires resultType to be \"complete\" when present",
3844            ));
3845        }
3846
3847        if helper.content.is_none()
3848            && helper.structured_content.is_none()
3849            && helper.is_error.is_none()
3850            && helper.meta.is_none()
3851        {
3852            return Err(serde::de::Error::custom(
3853                "expected at least one known CallToolResult field \
3854                 (content, structuredContent, isError, or _meta)",
3855            ));
3856        }
3857
3858        Ok(CallToolResult {
3859            result_type: helper.result_type,
3860            content: helper.content.unwrap_or_default(),
3861            structured_content: helper.structured_content,
3862            is_error: helper.is_error,
3863            meta: helper.meta,
3864        })
3865    }
3866}
3867
3868impl Default for CallToolResult {
3869    fn default() -> Self {
3870        CallToolResult {
3871            result_type: Some(ResultType::COMPLETE),
3872            content: Vec::new(),
3873            structured_content: None,
3874            is_error: None,
3875            meta: None,
3876        }
3877    }
3878}
3879
3880impl CallToolResult {
3881    /// Create a successful tool result with unstructured content
3882    pub fn success(content: Vec<ContentBlock>) -> Self {
3883        CallToolResult {
3884            result_type: Some(ResultType::COMPLETE),
3885            content,
3886            structured_content: None,
3887            is_error: Some(false),
3888            meta: None,
3889        }
3890    }
3891
3892    /// Create a tool-level error result with caller-visible content.
3893    ///
3894    /// # When to use this vs `Err(ErrorData)`
3895    ///
3896    /// MCP distinguishes two failure modes for a `call_tool` invocation, and
3897    /// the right one to use depends on **whose problem it is**:
3898    ///
3899    /// - **Tool-level error** — `Ok(CallToolResult::error(...))`.
3900    ///   The request was valid and routed to your tool, but executing the
3901    ///   tool failed in a way the caller should see (a query returned no
3902    ///   rows, an external API returned 500, the user's input is plausible
3903    ///   but produced no result, etc.). The caller's MCP client renders the
3904    ///   `content` you provide; your message reaches the user. **This is the
3905    ///   right choice for almost every "the tool ran and didn't work" case.**
3906    ///
3907    /// - **Protocol error** — `Err(ErrorData)` with a JSON-RPC code.
3908    ///   The server cannot route the request at all, or an infrastructure
3909    ///   error makes the server itself unusable
3910    ///   ([`ErrorCode::INTERNAL_ERROR`], `-32603`). MCP clients typically
3911    ///   render protocol errors opaquely (e.g. "Tool result missing due to
3912    ///   internal error") — the caller does **not** see your message.
3913    ///
3914    /// # Example
3915    ///
3916    /// ```rust,ignore
3917    /// use rmcp::model::{CallToolResult, Content, ErrorData};
3918    ///
3919    /// async fn lookup(query: &str) -> Result<CallToolResult, ErrorData> {
3920    ///     // Caller passed a malformed query — the server can't run anything.
3921    ///     // This is a protocol error, the caller's client will render it
3922    ///     // as -32602 invalid_params:
3923    ///     if query.is_empty() {
3924    ///         return Err(ErrorData::invalid_params("query must be non-empty", None));
3925    ///     }
3926    ///
3927    ///     // Tool ran, no result. Caller should see the explanation:
3928    ///     let rows = run_query(query).await;
3929    ///     if rows.is_empty() {
3930    ///         return Ok(CallToolResult::error(vec![ContentBlock::text(
3931    ///             format!("no rows matched '{query}'"),
3932    ///         )]));
3933    ///     }
3934    ///
3935    ///     Ok(CallToolResult::success(vec![ContentBlock::text(format_rows(&rows))]))
3936    /// }
3937    /// # async fn run_query(_: &str) -> Vec<&'static str> { vec![] }
3938    /// # fn format_rows(_: &[&str]) -> String { String::new() }
3939    /// ```
3940    pub fn error(content: Vec<ContentBlock>) -> Self {
3941        CallToolResult {
3942            result_type: Some(ResultType::COMPLETE),
3943            content,
3944            structured_content: None,
3945            is_error: Some(true),
3946            meta: None,
3947        }
3948    }
3949    /// Create a successful tool result with structured content
3950    ///
3951    /// # Example
3952    ///
3953    /// ```rust,ignore
3954    /// use rmcp::model::CallToolResult;
3955    /// use serde_json::json;
3956    ///
3957    /// let result = CallToolResult::structured(json!({
3958    ///     "temperature": 22.5,
3959    ///     "humidity": 65,
3960    ///     "description": "Partly cloudy"
3961    /// }));
3962    /// ```
3963    pub fn structured(value: Value) -> Self {
3964        CallToolResult {
3965            result_type: Some(ResultType::COMPLETE),
3966            content: vec![ContentBlock::text(value.to_string())],
3967            structured_content: Some(value),
3968            is_error: Some(false),
3969            meta: None,
3970        }
3971    }
3972    /// Create an error tool result with structured content
3973    ///
3974    /// # Example
3975    ///
3976    /// ```rust,ignore
3977    /// use rmcp::model::CallToolResult;
3978    /// use serde_json::json;
3979    ///
3980    /// let result = CallToolResult::structured_error(json!({
3981    ///     "error_code": "INVALID_INPUT",
3982    ///     "message": "Temperature value out of range",
3983    ///     "details": {
3984    ///         "min": -50,
3985    ///         "max": 50,
3986    ///         "provided": 100
3987    ///     }
3988    /// }));
3989    /// ```
3990    pub fn structured_error(value: Value) -> Self {
3991        CallToolResult {
3992            result_type: Some(ResultType::COMPLETE),
3993            content: vec![ContentBlock::text(value.to_string())],
3994            structured_content: Some(value),
3995            is_error: Some(true),
3996            meta: None,
3997        }
3998    }
3999
4000    /// Set the metadata on this result
4001    pub fn with_meta(mut self, meta: Option<MetaObject>) -> Self {
4002        self.meta = meta;
4003        self
4004    }
4005
4006    /// Convert the `structured_content` part of response into a certain type.
4007    ///
4008    /// # About json schema validation
4009    /// Since rust is a strong type language, we don't need to do json schema validation here.
4010    ///
4011    /// But if you do have to validate the response data, you can use [`jsonschema`](https://crates.io/crates/jsonschema) crate.
4012    pub fn into_typed<T>(self) -> Result<T, serde_json::Error>
4013    where
4014        T: DeserializeOwned,
4015    {
4016        let raw_text = match (self.structured_content, &self.content.first()) {
4017            (Some(value), _) => return serde_json::from_value(value),
4018            (None, Some(contents)) => {
4019                if let Some(text) = contents.as_text() {
4020                    let text = &text.text;
4021                    Some(text)
4022                } else {
4023                    None
4024                }
4025            }
4026            (None, None) => None,
4027        };
4028        if let Some(text) = raw_text {
4029            return serde_json::from_str(text);
4030        }
4031        serde_json::from_value(serde_json::Value::Null)
4032    }
4033}
4034
4035const_string!(ListToolsRequestMethod = "tools/list");
4036/// Request to list all available tools from a server
4037pub type ListToolsRequest = RequestOptionalParam<ListToolsRequestMethod, PaginatedRequestParams>;
4038
4039paginated_result!(
4040    ListToolsResult {
4041        tools: Vec<Tool>
4042    }
4043);
4044
4045const_string!(CallToolRequestMethod = "tools/call");
4046/// Parameters for calling a tool provided by an MCP server.
4047///
4048/// Contains the tool name and optional arguments needed to execute
4049/// the tool operation.
4050#[derive(Default, Debug, Serialize, Deserialize, Clone, PartialEq)]
4051#[serde(rename_all = "camelCase")]
4052#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
4053#[non_exhaustive]
4054pub struct CallToolRequestParams {
4055    /// Protocol-level metadata for this request (SEP-1319)
4056    #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
4057    pub meta: Option<RequestMetaObject>,
4058    /// The name of the tool to call
4059    pub name: Cow<'static, str>,
4060    /// Arguments to pass to the tool (must match the tool's input schema)
4061    #[serde(skip_serializing_if = "Option::is_none")]
4062    pub arguments: Option<JsonObject>,
4063    /// Client responses to server-initiated input requests from a previous
4064    /// [`InputRequiredResult`]. Present only when retrying after an incomplete result.
4065    #[serde(skip_serializing_if = "Option::is_none")]
4066    pub input_responses: Option<InputResponses>,
4067    /// Opaque request state echoed back from a previous [`InputRequiredResult`].
4068    /// Clients MUST return this value exactly as received.
4069    #[serde(skip_serializing_if = "Option::is_none")]
4070    pub request_state: Option<String>,
4071}
4072
4073impl CallToolRequestParams {
4074    /// Creates a new `CallToolRequestParams` with the given tool name.
4075    pub fn new(name: impl Into<Cow<'static, str>>) -> Self {
4076        Self {
4077            meta: None,
4078            name: name.into(),
4079            arguments: None,
4080            input_responses: None,
4081            request_state: None,
4082        }
4083    }
4084
4085    /// Sets the arguments for this tool call.
4086    pub fn with_arguments(mut self, arguments: JsonObject) -> Self {
4087        self.arguments = Some(arguments);
4088        self
4089    }
4090
4091    /// Sets the input responses for an MRTR retry.
4092    pub fn with_input_responses(mut self, input_responses: InputResponses) -> Self {
4093        self.input_responses = Some(input_responses);
4094        self
4095    }
4096
4097    /// Sets the request state for an MRTR retry.
4098    pub fn with_request_state(mut self, request_state: impl Into<String>) -> Self {
4099        self.request_state = Some(request_state.into());
4100        self
4101    }
4102}
4103
4104impl RequestParamsMeta for CallToolRequestParams {
4105    fn meta(&self) -> Option<&RequestMetaObject> {
4106        self.meta.as_ref()
4107    }
4108    fn meta_mut(&mut self) -> &mut Option<RequestMetaObject> {
4109        &mut self.meta
4110    }
4111}
4112
4113/// Request to call a specific tool
4114pub type CallToolRequest = Request<CallToolRequestMethod, CallToolRequestParams>;
4115
4116/// Result of sampling/createMessage (SEP-1577).
4117/// The result of a sampling/createMessage request containing the generated response.
4118///
4119/// This structure contains the generated message along with metadata about
4120/// how the generation was performed and why it stopped.
4121#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
4122#[serde(rename_all = "camelCase")]
4123#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
4124#[non_exhaustive]
4125#[deprecated(
4126    since = "2.0.0",
4127    note = "Sampling is deprecated by SEP-2577 and will be removed in a future release. See https://github.com/modelcontextprotocol/modelcontextprotocol/pull/2577"
4128)]
4129pub struct CreateMessageResult {
4130    /// The identifier of the model that generated the response
4131    pub model: String,
4132    /// The reason why generation stopped (e.g., "endTurn", "maxTokens")
4133    #[serde(skip_serializing_if = "Option::is_none")]
4134    pub stop_reason: Option<String>,
4135    /// The generated message with role and content
4136    #[serde(flatten)]
4137    pub message: SamplingMessage,
4138}
4139
4140impl CreateMessageResult {
4141    /// Create a new CreateMessageResult with required fields.
4142    pub fn new(message: SamplingMessage, model: String) -> Self {
4143        Self {
4144            message,
4145            model,
4146            stop_reason: None,
4147        }
4148    }
4149
4150    pub const STOP_REASON_END_TURN: &str = "endTurn";
4151    pub const STOP_REASON_END_SEQUENCE: &str = "stopSequence";
4152    pub const STOP_REASON_END_MAX_TOKEN: &str = "maxTokens";
4153    pub const STOP_REASON_TOOL_USE: &str = "toolUse";
4154
4155    /// Set the stop reason.
4156    pub fn with_stop_reason(mut self, stop_reason: impl Into<String>) -> Self {
4157        self.stop_reason = Some(stop_reason.into());
4158        self
4159    }
4160
4161    /// Set the model identifier.
4162    pub fn with_model(mut self, model: impl Into<String>) -> Self {
4163        self.model = model.into();
4164        self
4165    }
4166
4167    /// Validate the result per SEP-1577: role must be "assistant".
4168    pub fn validate(&self) -> Result<(), String> {
4169        if self.message.role != Role::Assistant {
4170            return Err("CreateMessageResult role must be 'assistant'".into());
4171        }
4172        Ok(())
4173    }
4174}
4175
4176#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
4177#[serde(rename_all = "camelCase")]
4178#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
4179#[non_exhaustive]
4180pub struct GetPromptResult {
4181    /// Result type discriminator (SEP-2322). Required by the [spec schema]
4182    /// for servers implementing protocol version `2026-07-28`, but optional
4183    /// here because this type also models results from older protocol
4184    /// versions, which do not carry the field: `None` means absent on the
4185    /// wire, and per the spec "the client MUST treat the absent field as
4186    /// `"complete"`". Constructors default to `Some(ResultType::COMPLETE)`;
4187    /// the server handler clears the field when responding to peers that
4188    /// negotiated an older version.
4189    ///
4190    /// [spec schema]: https://github.com/modelcontextprotocol/modelcontextprotocol/blob/271ecc9accafdd9b83a3c869fa67c22953b2af80/schema/2026-07-28/schema.ts#L219-L235
4191    #[serde(default, skip_serializing_if = "Option::is_none")]
4192    pub result_type: Option<ResultType>,
4193    #[serde(skip_serializing_if = "Option::is_none")]
4194    pub description: Option<String>,
4195    pub messages: Vec<PromptMessage>,
4196    #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
4197    pub meta: Option<MetaObject>,
4198}
4199
4200impl Default for GetPromptResult {
4201    fn default() -> Self {
4202        Self::new(Vec::new())
4203    }
4204}
4205
4206impl GetPromptResult {
4207    /// Create a new GetPromptResult with required fields.
4208    pub fn new(messages: Vec<PromptMessage>) -> Self {
4209        Self {
4210            result_type: Some(ResultType::COMPLETE),
4211            description: None,
4212            messages,
4213            meta: None,
4214        }
4215    }
4216
4217    /// Set the description
4218    pub fn with_description<D: Into<String>>(mut self, description: D) -> Self {
4219        self.description = Some(description.into());
4220        self
4221    }
4222}
4223
4224// =============================================================================
4225// TASK MANAGEMENT (SEP-2663 Tasks extension: `io.modelcontextprotocol/tasks`)
4226// =============================================================================
4227
4228const_string!(GetTaskMethod = "tasks/get");
4229pub type GetTaskRequest = Request<GetTaskMethod, GetTaskParams>;
4230
4231#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
4232#[serde(rename_all = "camelCase")]
4233#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
4234#[non_exhaustive]
4235pub struct GetTaskParams {
4236    #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
4237    pub meta: Option<RequestMetaObject>,
4238    /// Identifier of the task to query.
4239    pub task_id: String,
4240}
4241
4242impl GetTaskParams {
4243    pub fn new(task_id: impl Into<String>) -> Self {
4244        Self {
4245            meta: None,
4246            task_id: task_id.into(),
4247        }
4248    }
4249}
4250
4251impl RequestParamsMeta for GetTaskParams {
4252    fn meta(&self) -> Option<&RequestMetaObject> {
4253        self.meta.as_ref()
4254    }
4255    fn meta_mut(&mut self) -> &mut Option<RequestMetaObject> {
4256        &mut self.meta
4257    }
4258}
4259
4260const_string!(UpdateTaskMethod = "tasks/update");
4261pub type UpdateTaskRequest = Request<UpdateTaskMethod, UpdateTaskParams>;
4262
4263/// Parameters for `tasks/update` (SEP-2663): deliver responses to outstanding
4264/// in-task server-to-client requests surfaced via `tasks/get` `inputRequests`.
4265#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
4266#[serde(rename_all = "camelCase")]
4267#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
4268#[non_exhaustive]
4269pub struct UpdateTaskParams {
4270    #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
4271    pub meta: Option<RequestMetaObject>,
4272    /// Identifier of the task to update.
4273    pub task_id: String,
4274    /// Responses to outstanding `inputRequests` previously surfaced by the
4275    /// server. Each key MUST correspond to a currently-outstanding
4276    /// `inputRequests` key.
4277    pub input_responses: InputResponses,
4278}
4279
4280impl UpdateTaskParams {
4281    pub fn new(task_id: impl Into<String>, input_responses: InputResponses) -> Self {
4282        Self {
4283            meta: None,
4284            task_id: task_id.into(),
4285            input_responses,
4286        }
4287    }
4288}
4289
4290impl RequestParamsMeta for UpdateTaskParams {
4291    fn meta(&self) -> Option<&RequestMetaObject> {
4292        self.meta.as_ref()
4293    }
4294    fn meta_mut(&mut self) -> &mut Option<RequestMetaObject> {
4295        &mut self.meta
4296    }
4297}
4298
4299const_string!(CancelTaskMethod = "tasks/cancel");
4300pub type CancelTaskRequest = Request<CancelTaskMethod, CancelTaskParams>;
4301
4302#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
4303#[serde(rename_all = "camelCase")]
4304#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
4305#[non_exhaustive]
4306pub struct CancelTaskParams {
4307    /// Protocol-level metadata for this request (SEP-1319)
4308    #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
4309    pub meta: Option<RequestMetaObject>,
4310    pub task_id: String,
4311}
4312
4313impl CancelTaskParams {
4314    pub fn new(task_id: impl Into<String>) -> Self {
4315        Self {
4316            meta: None,
4317            task_id: task_id.into(),
4318        }
4319    }
4320}
4321
4322impl RequestParamsMeta for CancelTaskParams {
4323    fn meta(&self) -> Option<&RequestMetaObject> {
4324        self.meta.as_ref()
4325    }
4326    fn meta_mut(&mut self) -> &mut Option<RequestMetaObject> {
4327        &mut self.meta
4328    }
4329}
4330
4331// ---------------------------------------------------------------------------
4332// Task status notification (SEP-2663 `notifications/tasks`)
4333// ---------------------------------------------------------------------------
4334const_string!(TaskStatusNotificationMethod = "notifications/tasks");
4335
4336/// Parameters for a task status notification (spec `TaskStatusNotificationParams`).
4337///
4338/// Carries a complete [`DetailedTask`] for the current status, identical to
4339/// what `tasks/get` would have returned at that moment. The task fields are
4340/// flattened at the top level: `NotificationParams & Task`.
4341#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
4342#[serde(rename_all = "camelCase")]
4343#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
4344#[non_exhaustive]
4345pub struct TaskStatusNotificationParams {
4346    #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
4347    pub meta: Option<NotificationMetaObject>,
4348    #[serde(flatten)]
4349    pub task: crate::model::DetailedTask,
4350}
4351
4352impl TaskStatusNotificationParams {
4353    pub fn new(task: crate::model::DetailedTask) -> Self {
4354        Self { meta: None, task }
4355    }
4356
4357    pub fn with_meta(mut self, meta: NotificationMetaObject) -> Self {
4358        self.meta = Some(meta);
4359        self
4360    }
4361}
4362
4363impl From<crate::model::DetailedTask> for TaskStatusNotificationParams {
4364    fn from(task: crate::model::DetailedTask) -> Self {
4365        Self::new(task)
4366    }
4367}
4368
4369impl Deref for TaskStatusNotificationParams {
4370    type Target = crate::model::DetailedTask;
4371
4372    fn deref(&self) -> &Self::Target {
4373        &self.task
4374    }
4375}
4376
4377impl DerefMut for TaskStatusNotificationParams {
4378    fn deref_mut(&mut self) -> &mut Self::Target {
4379        &mut self.task
4380    }
4381}
4382
4383pub type TaskStatusNotification =
4384    Notification<TaskStatusNotificationMethod, TaskStatusNotificationParams>;
4385
4386// =============================================================================
4387// MESSAGE TYPE UNIONS
4388// =============================================================================
4389
4390macro_rules! ts_union {
4391    (
4392        export type $U:ident =
4393            $($rest:tt)*
4394    ) => {
4395        ts_union!(@declare $U { $($rest)* });
4396        ts_union!(@impl_from $U { $($rest)* });
4397    };
4398    (@declare $U:ident { $($variant:tt)* }) => {
4399        ts_union!(@declare_variant $U { } {$($variant)*} );
4400    };
4401    (@declare_variant $U:ident { $($declared:tt)* } {$(|)? box $V:ident $($rest:tt)*}) => {
4402        ts_union!(@declare_variant $U { $($declared)* $V(Box<$V>), }  {$($rest)*});
4403    };
4404    (@declare_variant $U:ident { $($declared:tt)* } {$(|)? $V:ident $($rest:tt)*}) => {
4405        ts_union!(@declare_variant $U { $($declared)* $V($V), } {$($rest)*});
4406    };
4407    (@declare_variant $U:ident { $($declared:tt)* }  { ; }) => {
4408        ts_union!(@declare_end $U { $($declared)* } );
4409    };
4410    (@declare_end $U:ident { $($declared:tt)* }) => {
4411        #[derive(Debug, Serialize, Deserialize, Clone)]
4412        #[serde(untagged)]
4413        #[allow(clippy::large_enum_variant)]
4414        #[non_exhaustive]
4415        #[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
4416        pub enum $U {
4417            $($declared)*
4418        }
4419    };
4420    (@impl_from $U: ident {$(|)? box $V:ident $($rest:tt)*}) => {
4421        impl From<$V> for $U {
4422            fn from(value: $V) -> Self {
4423                $U::$V(Box::new(value))
4424            }
4425        }
4426        ts_union!(@impl_from $U {$($rest)*});
4427    };
4428    (@impl_from $U: ident {$(|)? $V:ident $($rest:tt)*}) => {
4429        impl From<$V> for $U {
4430            fn from(value: $V) -> Self {
4431                $U::$V(value)
4432            }
4433        }
4434        ts_union!(@impl_from $U {$($rest)*});
4435    };
4436    (@impl_from $U: ident  { ; }) => {};
4437    (@impl_from $U: ident  { }) => {};
4438}
4439
4440ts_union!(
4441    export type ClientRequest =
4442    | PingRequest
4443    | InitializeRequest
4444    | DiscoverRequest
4445    | CompleteRequest
4446    | SetLevelRequest
4447    | GetPromptRequest
4448    | ListPromptsRequest
4449    | ListResourcesRequest
4450    | ListResourceTemplatesRequest
4451    | ReadResourceRequest
4452    | SubscriptionsListenRequest
4453    | SubscribeRequest
4454    | UnsubscribeRequest
4455    | CallToolRequest
4456    | ListToolsRequest
4457    | GetTaskRequest
4458    | UpdateTaskRequest
4459    | CancelTaskRequest
4460    | CustomRequest;
4461);
4462
4463impl ClientRequest {
4464    pub fn method(&self) -> &str {
4465        match &self {
4466            ClientRequest::PingRequest(r) => r.method.as_str(),
4467            ClientRequest::InitializeRequest(r) => r.method.as_str(),
4468            ClientRequest::DiscoverRequest(r) => r.method.as_str(),
4469            ClientRequest::CompleteRequest(r) => r.method.as_str(),
4470            ClientRequest::SetLevelRequest(r) => r.method.as_str(),
4471            ClientRequest::GetPromptRequest(r) => r.method.as_str(),
4472            ClientRequest::ListPromptsRequest(r) => r.method.as_str(),
4473            ClientRequest::ListResourcesRequest(r) => r.method.as_str(),
4474            ClientRequest::ListResourceTemplatesRequest(r) => r.method.as_str(),
4475            ClientRequest::ReadResourceRequest(r) => r.method.as_str(),
4476            ClientRequest::SubscriptionsListenRequest(r) => r.method.as_str(),
4477            ClientRequest::SubscribeRequest(r) => r.method.as_str(),
4478            ClientRequest::UnsubscribeRequest(r) => r.method.as_str(),
4479            ClientRequest::CallToolRequest(r) => r.method.as_str(),
4480            ClientRequest::ListToolsRequest(r) => r.method.as_str(),
4481            ClientRequest::GetTaskRequest(r) => r.method.as_str(),
4482            ClientRequest::UpdateTaskRequest(r) => r.method.as_str(),
4483            ClientRequest::CancelTaskRequest(r) => r.method.as_str(),
4484            ClientRequest::CustomRequest(r) => r.method.as_str(),
4485        }
4486    }
4487}
4488
4489ts_union!(
4490    export type ClientNotification =
4491    | CancelledNotification
4492    | ProgressNotification
4493    | InitializedNotification
4494    | RootsListChangedNotification
4495    | CustomNotification;
4496);
4497
4498ts_union!(
4499    export type ClientResult =
4500    box CreateMessageResult
4501    | ListRootsResult
4502    | ElicitResult
4503    | EmptyResult
4504    | CustomResult;
4505);
4506
4507impl ClientResult {
4508    pub fn empty(_: ()) -> ClientResult {
4509        ClientResult::EmptyResult(EmptyResult {})
4510    }
4511}
4512
4513pub type ClientJsonRpcMessage = JsonRpcMessage<ClientRequest, ClientResult, ClientNotification>;
4514
4515ts_union!(
4516    export type ServerRequest =
4517    | PingRequest
4518    | CreateMessageRequest
4519    | ListRootsRequest
4520    | ElicitRequest
4521    | CustomRequest;
4522);
4523
4524ts_union!(
4525    export type ServerNotification =
4526    | CancelledNotification
4527    | ProgressNotification
4528    | LoggingMessageNotification
4529    | ResourceUpdatedNotification
4530    | ResourceListChangedNotification
4531    | ToolListChangedNotification
4532    | PromptListChangedNotification
4533    | SubscriptionsAcknowledgedNotification
4534    | TaskStatusNotification
4535    | CustomNotification;
4536);
4537
4538ts_union!(
4539    export type ServerResult =
4540    | DiscoverResult
4541    | InitializeResult
4542    | CompleteResult
4543    | GetPromptResult
4544    | ListPromptsResult
4545    | ListResourcesResult
4546    | ListResourceTemplatesResult
4547    | ReadResourceResult
4548    | SubscriptionsListenResult
4549    | ListToolsResult
4550    | ElicitResult
4551    | CreateTaskResult
4552    | GetTaskResult
4553    | CallToolResult
4554    | InputRequiredResult
4555    // TaskAckResult must come after CallToolResult/InputRequiredResult in this
4556    // untagged union: it only carries `resultType`, so it would otherwise
4557    // shadow any result that includes `resultType: "complete"`.
4558    | TaskAckResult
4559    | EmptyResult
4560    | CustomResult
4561    ;
4562);
4563
4564impl ServerResult {
4565    pub fn empty(_: ()) -> ServerResult {
4566        ServerResult::EmptyResult(EmptyResult {})
4567    }
4568
4569    /// Empty `tasks/update` / `tasks/cancel` acknowledgement carrying the
4570    /// SEP-2322 `resultType: "complete"` discriminator (SEP-2663).
4571    pub fn task_ack(_: ()) -> ServerResult {
4572        ServerResult::TaskAckResult(TaskAckResult::new())
4573    }
4574
4575    /// Strip the SEP-2322 `resultType: "complete"` discriminator so the result
4576    /// keeps the wire shape that predates protocol version `2026-07-28`.
4577    ///
4578    /// The server handler calls this before responding to a peer that
4579    /// negotiated an older protocol version, where the field did not exist and
4580    /// strict peers may reject it. Only the `"complete"` value is stripped:
4581    /// results whose discriminator carries meaning (`"input_required"`,
4582    /// `"task"`) are already gated to `2026-07-28`+ sessions, and custom
4583    /// extension values are preserved.
4584    ///
4585    /// # Examples
4586    ///
4587    /// ```
4588    /// use rmcp::model::{CallToolResult, ServerResult};
4589    ///
4590    /// let mut result = ServerResult::CallToolResult(CallToolResult::success(vec![]));
4591    /// result.strip_result_type_for_legacy_peer();
4592    ///
4593    /// let json = serde_json::to_value(&result).unwrap();
4594    /// assert!(json.get("resultType").is_none());
4595    /// ```
4596    pub fn strip_result_type_for_legacy_peer(&mut self) {
4597        let result_type = match self {
4598            ServerResult::CompleteResult(r) => &mut r.result_type,
4599            ServerResult::GetPromptResult(r) => &mut r.result_type,
4600            ServerResult::ListPromptsResult(r) => &mut r.result_type,
4601            ServerResult::ListResourcesResult(r) => &mut r.result_type,
4602            ServerResult::ListResourceTemplatesResult(r) => &mut r.result_type,
4603            ServerResult::ReadResourceResult(r) => &mut r.result_type,
4604            ServerResult::ListToolsResult(r) => &mut r.result_type,
4605            ServerResult::CallToolResult(r) => &mut r.result_type,
4606            _ => return,
4607        };
4608        result_type.take_if(|result_type| result_type.is_complete());
4609    }
4610}
4611
4612pub type ServerJsonRpcMessage = JsonRpcMessage<ServerRequest, ServerResult, ServerNotification>;
4613
4614impl TryInto<CancelledNotification> for ServerNotification {
4615    type Error = ServerNotification;
4616    fn try_into(self) -> Result<CancelledNotification, Self::Error> {
4617        if let ServerNotification::CancelledNotification(t) = self {
4618            Ok(t)
4619        } else {
4620            Err(self)
4621        }
4622    }
4623}
4624
4625impl TryInto<CancelledNotification> for ClientNotification {
4626    type Error = ClientNotification;
4627    fn try_into(self) -> Result<CancelledNotification, Self::Error> {
4628        if let ClientNotification::CancelledNotification(t) = self {
4629            Ok(t)
4630        } else {
4631            Err(self)
4632        }
4633    }
4634}
4635
4636// =============================================================================
4637// TESTS
4638// =============================================================================
4639
4640#[cfg(test)]
4641mod tests {
4642    use serde_json::json;
4643
4644    use super::*;
4645
4646    #[cfg(feature = "transport-streamable-http-client")]
4647    #[test]
4648    fn transport_closed_marker_accepts_only_the_process_local_token() {
4649        let local = ErrorData::transport_closed("closed");
4650        let spoofed = ErrorData::internal_error(
4651            "spoofed",
4652            Some(json!({ "io.modelcontextprotocol/transportClosed": true })),
4653        );
4654
4655        assert!(local.is_transport_closed());
4656        assert!(!spoofed.is_transport_closed());
4657    }
4658
4659    #[test]
4660    fn cancelled_notification_request_id_is_optional_on_wire() {
4661        // None → requestId 생략
4662        let p = CancelledNotificationParam::new(None, Some("user cancelled".into()));
4663        let v = serde_json::to_value(&p).unwrap();
4664        assert!(v.get("requestId").is_none());
4665
4666        // Some → requestId 방출 + 라운드트립
4667        let p = CancelledNotificationParam::new(Some(RequestId::Number(1)), None);
4668        let v = serde_json::to_value(&p).unwrap();
4669        assert_eq!(v["requestId"], json!(1));
4670        let back: CancelledNotificationParam = serde_json::from_value(v).unwrap();
4671        assert_eq!(back.request_id, Some(RequestId::Number(1)));
4672    }
4673
4674    #[test]
4675    fn test_notification_serde() {
4676        let raw = json!( {
4677            "jsonrpc": JsonRpcVersion2_0,
4678            "method": InitializedNotificationMethod,
4679        });
4680        let message: ClientJsonRpcMessage =
4681            serde_json::from_value(raw.clone()).expect("invalid notification");
4682        match &message {
4683            ClientJsonRpcMessage::Notification(JsonRpcNotification {
4684                notification: ClientNotification::InitializedNotification(_n),
4685                ..
4686            }) => {}
4687            _ => panic!("Expected Notification"),
4688        }
4689        let json = serde_json::to_value(message).expect("valid json");
4690        assert_eq!(json, raw);
4691    }
4692
4693    #[test]
4694    fn test_custom_client_notification_roundtrip() {
4695        let raw = json!( {
4696            "jsonrpc": JsonRpcVersion2_0,
4697            "method": "notifications/custom",
4698            "params": {"foo": "bar"},
4699        });
4700
4701        let message: ClientJsonRpcMessage =
4702            serde_json::from_value(raw.clone()).expect("invalid notification");
4703        match &message {
4704            ClientJsonRpcMessage::Notification(JsonRpcNotification {
4705                notification: ClientNotification::CustomNotification(notification),
4706                ..
4707            }) => {
4708                assert_eq!(notification.method, "notifications/custom");
4709                assert_eq!(
4710                    notification
4711                        .params
4712                        .as_ref()
4713                        .and_then(|p| p.get("foo"))
4714                        .expect("foo present"),
4715                    "bar"
4716                );
4717            }
4718            _ => panic!("Expected custom client notification"),
4719        }
4720
4721        let json = serde_json::to_value(message).expect("valid json");
4722        assert_eq!(json, raw);
4723    }
4724
4725    #[test]
4726    fn test_custom_server_notification_roundtrip() {
4727        let raw = json!( {
4728            "jsonrpc": JsonRpcVersion2_0,
4729            "method": "notifications/custom-server",
4730            "params": {"hello": "world"},
4731        });
4732
4733        let message: ServerJsonRpcMessage =
4734            serde_json::from_value(raw.clone()).expect("invalid notification");
4735        match &message {
4736            ServerJsonRpcMessage::Notification(JsonRpcNotification {
4737                notification: ServerNotification::CustomNotification(notification),
4738                ..
4739            }) => {
4740                assert_eq!(notification.method, "notifications/custom-server");
4741                assert_eq!(
4742                    notification
4743                        .params
4744                        .as_ref()
4745                        .and_then(|p| p.get("hello"))
4746                        .expect("hello present"),
4747                    "world"
4748                );
4749            }
4750            _ => panic!("Expected custom server notification"),
4751        }
4752
4753        let json = serde_json::to_value(message).expect("valid json");
4754        assert_eq!(json, raw);
4755    }
4756
4757    #[test]
4758    fn test_custom_request_roundtrip() {
4759        let raw = json!( {
4760            "jsonrpc": JsonRpcVersion2_0,
4761            "id": 42,
4762            "method": "requests/custom",
4763            "params": {"foo": "bar"},
4764        });
4765
4766        let message: ClientJsonRpcMessage =
4767            serde_json::from_value(raw.clone()).expect("invalid request");
4768        match &message {
4769            ClientJsonRpcMessage::Request(JsonRpcRequest { id, request, .. }) => {
4770                assert_eq!(id, &RequestId::Number(42));
4771                match request {
4772                    ClientRequest::CustomRequest(custom) => {
4773                        let expected_request = json!({
4774                            "method": "requests/custom",
4775                            "params": {"foo": "bar"},
4776                        });
4777                        let actual_request =
4778                            serde_json::to_value(custom).expect("serialize custom request");
4779                        assert_eq!(actual_request, expected_request);
4780                    }
4781                    other => panic!("Expected custom request, got: {other:?}"),
4782                }
4783            }
4784            other => panic!("Expected request, got: {other:?}"),
4785        }
4786
4787        let json = serde_json::to_value(message).expect("valid json");
4788        assert_eq!(json, raw);
4789    }
4790
4791    #[test]
4792    fn test_request_conversion() {
4793        let raw = json!( {
4794            "jsonrpc": JsonRpcVersion2_0,
4795            "id": 1,
4796            "method": "request",
4797            "params": {"key": "value"},
4798        });
4799        let message: JsonRpcMessage = serde_json::from_value(raw.clone()).expect("invalid request");
4800
4801        match &message {
4802            JsonRpcMessage::Request(r) => {
4803                assert_eq!(r.id, RequestId::Number(1));
4804                assert_eq!(r.request.method, "request");
4805                assert_eq!(
4806                    &r.request.params,
4807                    json!({"key": "value"})
4808                        .as_object()
4809                        .expect("should be an object")
4810                );
4811            }
4812            _ => panic!("Expected Request"),
4813        }
4814        let json = serde_json::to_value(&message).expect("valid json");
4815        assert_eq!(json, raw);
4816    }
4817
4818    #[test]
4819    fn test_initial_request_response_serde() {
4820        let request = json!({
4821          "jsonrpc": "2.0",
4822          "id": 1,
4823          "method": "initialize",
4824          "params": {
4825            "protocolVersion": "2024-11-05",
4826            "capabilities": {
4827              "roots": {
4828                "listChanged": true
4829              },
4830              "sampling": {}
4831            },
4832            "clientInfo": {
4833              "name": "ExampleClient",
4834              "version": "1.0.0"
4835            }
4836          }
4837        });
4838        let raw_response_json = json!({
4839          "jsonrpc": "2.0",
4840          "id": 1,
4841          "result": {
4842            "protocolVersion": "2024-11-05",
4843            "capabilities": {
4844              "logging": {},
4845              "prompts": {
4846                "listChanged": true
4847              },
4848              "resources": {
4849                "subscribe": true,
4850                "listChanged": true
4851              },
4852              "tools": {
4853                "listChanged": true
4854              }
4855            },
4856            "serverInfo": {
4857              "name": "ExampleServer",
4858              "version": "1.0.0"
4859            }
4860          }
4861        });
4862        let request: ClientJsonRpcMessage =
4863            serde_json::from_value(request.clone()).expect("invalid request");
4864        let (request, id) = request.into_request().expect("should be a request");
4865        assert_eq!(id, RequestId::Number(1));
4866        match request {
4867            ClientRequest::InitializeRequest(Request {
4868                method: _,
4869                params:
4870                    InitializeRequestParams {
4871                        meta: _,
4872                        protocol_version: _,
4873                        capabilities,
4874                        client_info,
4875                    },
4876                ..
4877            }) => {
4878                assert_eq!(capabilities.roots.unwrap().list_changed, Some(true));
4879                let sampling = capabilities.sampling.unwrap();
4880                assert_eq!(sampling.tools, None);
4881                assert_eq!(sampling.context, None);
4882                assert_eq!(client_info.name, "ExampleClient");
4883                assert_eq!(client_info.version, "1.0.0");
4884            }
4885            _ => panic!("Expected InitializeRequest"),
4886        }
4887        let server_response: ServerJsonRpcMessage =
4888            serde_json::from_value(raw_response_json.clone()).expect("invalid response");
4889        let (response, id) = server_response
4890            .clone()
4891            .into_response()
4892            .expect("expect response");
4893        assert_eq!(id, RequestId::Number(1));
4894        match response {
4895            ServerResult::InitializeResult(InitializeResult {
4896                protocol_version: _,
4897                capabilities,
4898                server_info,
4899                instructions,
4900                ..
4901            }) => {
4902                assert_eq!(capabilities.logging.unwrap().len(), 0);
4903                assert_eq!(capabilities.prompts.unwrap().list_changed, Some(true));
4904                assert_eq!(
4905                    capabilities.resources.as_ref().unwrap().subscribe,
4906                    Some(true)
4907                );
4908                assert_eq!(capabilities.resources.unwrap().list_changed, Some(true));
4909                assert_eq!(capabilities.tools.unwrap().list_changed, Some(true));
4910                assert_eq!(server_info.name, "ExampleServer");
4911                assert_eq!(server_info.version, "1.0.0");
4912                assert_eq!(server_info.icons, None);
4913                assert_eq!(instructions, None);
4914            }
4915            other => panic!("Expected InitializeResult, got {other:?}"),
4916        }
4917
4918        let server_response_json: Value = serde_json::to_value(&server_response).expect("msg");
4919
4920        assert_eq!(server_response_json, raw_response_json);
4921    }
4922
4923    #[test]
4924    fn test_negative_and_large_request_ids() {
4925        // Test negative ID
4926        let negative_id_json = json!({
4927            "jsonrpc": "2.0",
4928            "id": -1,
4929            "method": "test",
4930            "params": {}
4931        });
4932
4933        let message: JsonRpcMessage =
4934            serde_json::from_value(negative_id_json.clone()).expect("Should parse negative ID");
4935
4936        match &message {
4937            JsonRpcMessage::Request(r) => {
4938                assert_eq!(r.id, RequestId::Number(-1));
4939            }
4940            _ => panic!("Expected Request"),
4941        }
4942
4943        // Test roundtrip serialization
4944        let serialized = serde_json::to_value(&message).expect("Should serialize");
4945        assert_eq!(serialized, negative_id_json);
4946
4947        // Test large negative ID
4948        let large_negative_json = json!({
4949            "jsonrpc": "2.0",
4950            "id": -9007199254740991i64,  // JavaScript's MIN_SAFE_INTEGER
4951            "method": "test",
4952            "params": {}
4953        });
4954
4955        let message: JsonRpcMessage = serde_json::from_value(large_negative_json.clone())
4956            .expect("Should parse large negative ID");
4957
4958        match &message {
4959            JsonRpcMessage::Request(r) => {
4960                assert_eq!(r.id, RequestId::Number(-9007199254740991i64));
4961            }
4962            _ => panic!("Expected Request"),
4963        }
4964
4965        // Test large positive ID (JavaScript's MAX_SAFE_INTEGER)
4966        let large_positive_json = json!({
4967            "jsonrpc": "2.0",
4968            "id": 9007199254740991i64,
4969            "method": "test",
4970            "params": {}
4971        });
4972
4973        let message: JsonRpcMessage = serde_json::from_value(large_positive_json.clone())
4974            .expect("Should parse large positive ID");
4975
4976        match &message {
4977            JsonRpcMessage::Request(r) => {
4978                assert_eq!(r.id, RequestId::Number(9007199254740991i64));
4979            }
4980            _ => panic!("Expected Request"),
4981        }
4982
4983        // Test zero ID
4984        let zero_id_json = json!({
4985            "jsonrpc": "2.0",
4986            "id": 0,
4987            "method": "test",
4988            "params": {}
4989        });
4990
4991        let message: JsonRpcMessage =
4992            serde_json::from_value(zero_id_json.clone()).expect("Should parse zero ID");
4993
4994        match &message {
4995            JsonRpcMessage::Request(r) => {
4996                assert_eq!(r.id, RequestId::Number(0));
4997            }
4998            _ => panic!("Expected Request"),
4999        }
5000    }
5001
5002    #[test]
5003    fn test_protocol_version_order() {
5004        let v1 = ProtocolVersion::V_2024_11_05;
5005        let v2 = ProtocolVersion::V_2025_03_26;
5006        let v3 = ProtocolVersion::V_2025_06_18;
5007        let v4 = ProtocolVersion::V_2025_11_25;
5008        assert!(v1 < v2);
5009        assert!(v2 < v3);
5010        assert!(v3 < v4);
5011    }
5012
5013    #[test]
5014    fn test_icon_serialization() {
5015        let icon = Icon {
5016            src: "https://example.com/icon.png".to_string(),
5017            mime_type: Some("image/png".to_string()),
5018            sizes: Some(vec!["48x48".to_string()]),
5019            theme: Some(IconTheme::Light),
5020        };
5021
5022        let json = serde_json::to_value(&icon).unwrap();
5023        assert_eq!(json["src"], "https://example.com/icon.png");
5024        assert_eq!(json["mimeType"], "image/png");
5025        assert_eq!(json["sizes"][0], "48x48");
5026        assert_eq!(json["theme"], "light");
5027
5028        // Test deserialization
5029        let deserialized: Icon = serde_json::from_value(json).unwrap();
5030        assert_eq!(deserialized, icon);
5031    }
5032
5033    #[test]
5034    fn test_icon_minimal() {
5035        let icon = Icon {
5036            src: "data:image/svg+xml;base64,PHN2Zy8+".to_string(),
5037            mime_type: None,
5038            sizes: None,
5039            theme: None,
5040        };
5041
5042        let json = serde_json::to_value(&icon).unwrap();
5043        assert_eq!(json["src"], "data:image/svg+xml;base64,PHN2Zy8+");
5044        assert!(json.get("mimeType").is_none());
5045        assert!(json.get("sizes").is_none());
5046        assert!(json.get("theme").is_none());
5047    }
5048
5049    #[test]
5050    fn test_implementation_with_icons() {
5051        let implementation = Implementation {
5052            name: "test-server".to_string(),
5053            title: Some("Test Server".to_string()),
5054            version: "1.0.0".to_string(),
5055            description: Some("A test server for unit testing".to_string()),
5056            icons: Some(vec![
5057                Icon {
5058                    src: "https://example.com/icon.png".to_string(),
5059                    mime_type: Some("image/png".to_string()),
5060                    sizes: Some(vec!["48x48".to_string()]),
5061                    theme: Some(IconTheme::Dark),
5062                },
5063                Icon {
5064                    src: "https://example.com/icon.svg".to_string(),
5065                    mime_type: Some("image/svg+xml".to_string()),
5066                    sizes: Some(vec!["any".to_string()]),
5067                    theme: Some(IconTheme::Light),
5068                },
5069            ]),
5070            website_url: Some("https://example.com".to_string()),
5071        };
5072
5073        let json = serde_json::to_value(&implementation).unwrap();
5074        assert_eq!(json["name"], "test-server");
5075        assert_eq!(json["description"], "A test server for unit testing");
5076        assert_eq!(json["websiteUrl"], "https://example.com");
5077        assert!(json["icons"].is_array());
5078        assert_eq!(json["icons"][0]["src"], "https://example.com/icon.png");
5079        assert_eq!(json["icons"][0]["sizes"][0], "48x48");
5080        assert_eq!(json["icons"][1]["mimeType"], "image/svg+xml");
5081        assert_eq!(json["icons"][1]["sizes"][0], "any");
5082        assert_eq!(json["icons"][0]["theme"], "dark");
5083        assert_eq!(json["icons"][1]["theme"], "light");
5084    }
5085
5086    #[test]
5087    fn test_backward_compatibility() {
5088        // Test that old JSON without icons still deserializes correctly
5089        let old_json = json!({
5090            "name": "legacy-server",
5091            "version": "0.9.0"
5092        });
5093
5094        let implementation: Implementation = serde_json::from_value(old_json).unwrap();
5095        assert_eq!(implementation.name, "legacy-server");
5096        assert_eq!(implementation.version, "0.9.0");
5097        assert_eq!(implementation.description, None);
5098        assert_eq!(implementation.icons, None);
5099        assert_eq!(implementation.website_url, None);
5100    }
5101
5102    #[test]
5103    fn test_initialize_with_icons() {
5104        let init_result = InitializeResult {
5105            protocol_version: ProtocolVersion::default(),
5106            capabilities: ServerCapabilities::default(),
5107            server_info: Implementation {
5108                name: "icon-server".to_string(),
5109                title: None,
5110                version: "2.0.0".to_string(),
5111                description: None,
5112                icons: Some(vec![Icon {
5113                    src: "https://example.com/server.png".to_string(),
5114                    mime_type: Some("image/png".to_string()),
5115                    sizes: Some(vec!["48x48".to_string()]),
5116                    theme: Some(IconTheme::Light),
5117                }]),
5118                website_url: Some("https://docs.example.com".to_string()),
5119            },
5120            instructions: None,
5121            meta: None,
5122        };
5123
5124        let json = serde_json::to_value(&init_result).unwrap();
5125        assert!(json["serverInfo"]["icons"].is_array());
5126        assert_eq!(
5127            json["serverInfo"]["icons"][0]["src"],
5128            "https://example.com/server.png"
5129        );
5130        assert_eq!(json["serverInfo"]["icons"][0]["sizes"][0], "48x48");
5131        assert_eq!(json["serverInfo"]["icons"][0]["theme"], "light");
5132        assert_eq!(json["serverInfo"]["websiteUrl"], "https://docs.example.com");
5133    }
5134
5135    #[test]
5136    fn elicitation_without_mode_deserializes_as_form() {
5137        let json_data_without_tag = json!({
5138            "message": "Please provide more details.",
5139            "requestedSchema": {
5140                "title": "User Details",
5141                "type": "object",
5142                "properties": {
5143                    "name": { "type": "string" },
5144                    "age": { "type": "integer" }
5145                },
5146                "required": ["name", "age"]
5147            }
5148        });
5149        let elicitation: ElicitRequestParams =
5150            serde_json::from_value(json_data_without_tag).expect("Deserialization failed");
5151        if let ElicitRequestParams::FormElicitationParams {
5152            meta,
5153            message,
5154            requested_schema,
5155        } = elicitation
5156        {
5157            assert_eq!(meta, None);
5158            assert_eq!(message, "Please provide more details.");
5159            assert_eq!(requested_schema.title, Some(Cow::from("User Details")));
5160            assert_eq!(requested_schema.type_, ObjectTypeConst);
5161        } else {
5162            panic!("Expected FormElicitationParams");
5163        }
5164    }
5165
5166    #[test]
5167    fn test_elicitation_deserialization() {
5168        let json_data_form = json!({
5169            "_meta": { "meta_form_key_1": "meta form value 1" },
5170            "mode": "form",
5171            "message": "Please provide more details.",
5172            "requestedSchema": {
5173                "title": "User Details",
5174                "type": "object",
5175                "properties": {
5176                    "name": { "type": "string" },
5177                    "age": { "type": "integer" }
5178                },
5179                "required": ["name", "age"]
5180            }
5181        });
5182        let elicitation_form: ElicitRequestParams =
5183            serde_json::from_value(json_data_form).expect("Deserialization failed");
5184        if let ElicitRequestParams::FormElicitationParams {
5185            meta,
5186            message,
5187            requested_schema,
5188        } = elicitation_form
5189        {
5190            assert_eq!(
5191                meta,
5192                Some(RequestMetaObject(MetaObject(
5193                    object!({ "meta_form_key_1": "meta form value 1" })
5194                )))
5195            );
5196            assert_eq!(message, "Please provide more details.");
5197            assert_eq!(requested_schema.title, Some(Cow::from("User Details")));
5198            assert_eq!(requested_schema.type_, ObjectTypeConst);
5199        } else {
5200            panic!("Expected FormElicitationParams");
5201        }
5202
5203        let json_data_url = json!({
5204                "_meta": { "meta_url_key_1": "meta url value 1" },
5205            "mode": "url",
5206            "message": "Please fill out the form at the following URL.",
5207            "url": "https://example.com/form",
5208            "elicitationId": "elicitation-123"
5209        });
5210        let elicitation_url: ElicitRequestParams =
5211            serde_json::from_value(json_data_url).expect("Deserialization failed");
5212        if let ElicitRequestParams::UrlElicitationParams {
5213            meta,
5214            message,
5215            url,
5216            elicitation_id,
5217        } = elicitation_url
5218        {
5219            assert_eq!(
5220                meta,
5221                Some(RequestMetaObject(MetaObject(
5222                    object!({ "meta_url_key_1": "meta url value 1" })
5223                )))
5224            );
5225            assert_eq!(message, "Please fill out the form at the following URL.");
5226            assert_eq!(url, "https://example.com/form");
5227            assert_eq!(elicitation_id, "elicitation-123");
5228        } else {
5229            panic!("Expected UrlElicitationParams");
5230        }
5231    }
5232
5233    #[test]
5234    fn test_elicitation_serialization() {
5235        let form_elicitation = ElicitRequestParams::FormElicitationParams {
5236            meta: Some(RequestMetaObject(MetaObject(
5237                object!({ "meta_form_key_1": "meta form value 1" }),
5238            ))),
5239            message: "Please provide more details.".to_string(),
5240            requested_schema: ElicitationSchema::builder()
5241                .title("User Details")
5242                .string_property("name", |s| s)
5243                .build()
5244                .expect("Valid schema"),
5245        };
5246        let json_form = serde_json::to_value(&form_elicitation).expect("Serialization failed");
5247        let expected_form_json = json!({
5248            "_meta": { "meta_form_key_1": "meta form value 1" },
5249            "mode": "form",
5250            "message": "Please provide more details.",
5251            "requestedSchema": {
5252                "title":"User Details",
5253                "type":"object",
5254                "properties":{
5255                    "name": { "type": "string" },
5256                },
5257            }
5258        });
5259        assert_eq!(json_form, expected_form_json);
5260
5261        let url_elicitation = ElicitRequestParams::UrlElicitationParams {
5262            meta: Some(RequestMetaObject(MetaObject(
5263                object!({ "meta_url_key_1": "meta url value 1" }),
5264            ))),
5265            message: "Please fill out the form at the following URL.".to_string(),
5266            url: "https://example.com/form".to_string(),
5267            elicitation_id: "elicitation-123".to_string(),
5268        };
5269        let json_url = serde_json::to_value(&url_elicitation).expect("Serialization failed");
5270        let expected_url_json = json!({
5271            "_meta": { "meta_url_key_1": "meta url value 1" },
5272            "mode": "url",
5273            "message": "Please fill out the form at the following URL.",
5274            "url": "https://example.com/form",
5275            "elicitationId": "elicitation-123"
5276        });
5277        assert_eq!(json_url, expected_url_json);
5278    }
5279
5280    #[test]
5281    fn notification_without_params_should_deserialize_as_bare_jsonrpc_message() {
5282        let payload = b"{\"method\":\"notifications/initialized\",\"jsonrpc\":\"2.0\"}";
5283        let result: Result<JsonRpcMessage, _> = serde_json::from_slice(payload);
5284        assert!(
5285            matches!(result, Ok(JsonRpcMessage::Notification(_))),
5286            "Expected Ok(Notification), got: {:?}",
5287            result
5288        );
5289    }
5290}