Skip to main content

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