Skip to main content

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