Skip to main content

rmcp/
model.rs

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