rmcp/
model.rs

1use std::{borrow::Cow, sync::Arc};
2mod annotated;
3mod capabilities;
4mod content;
5mod elicitation_schema;
6mod extension;
7mod meta;
8mod prompt;
9mod resource;
10mod serde_impl;
11mod tool;
12pub use annotated::*;
13pub use capabilities::*;
14pub use content::*;
15pub use elicitation_schema::*;
16pub use extension::*;
17pub use meta::*;
18pub use prompt::*;
19pub use resource::*;
20use serde::{Deserialize, Serialize, de::DeserializeOwned};
21use serde_json::Value;
22pub use tool::*;
23
24/// A JSON object type alias for convenient handling of JSON data.
25///
26/// You can use [`crate::object!`] or [`crate::model::object`] to create a json object quickly.
27/// This is commonly used for storing arbitrary JSON data in MCP messages.
28pub type JsonObject<F = Value> = serde_json::Map<String, F>;
29
30/// unwrap the JsonObject under [`serde_json::Value`]
31///
32/// # Panic
33/// This will panic when the value is not a object in debug mode.
34pub fn object(value: serde_json::Value) -> JsonObject {
35    debug_assert!(value.is_object());
36    match value {
37        serde_json::Value::Object(map) => map,
38        _ => JsonObject::default(),
39    }
40}
41
42/// Use this macro just like [`serde_json::json!`]
43#[cfg(feature = "macros")]
44#[cfg_attr(docsrs, doc(cfg(feature = "macros")))]
45#[macro_export]
46macro_rules! object {
47    ({$($tt:tt)*}) => {
48        $crate::model::object(serde_json::json! {
49            {$($tt)*}
50        })
51    };
52}
53
54/// This is commonly used for representing empty objects in MCP messages.
55///
56/// without returning any specific data.
57#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Copy, Eq)]
58#[cfg_attr(feature = "server", derive(schemars::JsonSchema))]
59pub struct EmptyObject {}
60
61pub trait ConstString: Default {
62    const VALUE: &str;
63    fn as_str(&self) -> &'static str {
64        Self::VALUE
65    }
66}
67#[macro_export]
68macro_rules! const_string {
69    ($name:ident = $value:literal) => {
70        #[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
71        pub struct $name;
72
73        impl ConstString for $name {
74            const VALUE: &str = $value;
75        }
76
77        impl serde::Serialize for $name {
78            fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
79            where
80                S: serde::Serializer,
81            {
82                $value.serialize(serializer)
83            }
84        }
85
86        impl<'de> serde::Deserialize<'de> for $name {
87            fn deserialize<D>(deserializer: D) -> Result<$name, D::Error>
88            where
89                D: serde::Deserializer<'de>,
90            {
91                let s: String = serde::Deserialize::deserialize(deserializer)?;
92                if s == $value {
93                    Ok($name)
94                } else {
95                    Err(serde::de::Error::custom(format!(concat!(
96                        "expect const string value \"",
97                        $value,
98                        "\""
99                    ))))
100                }
101            }
102        }
103
104        #[cfg(feature = "schemars")]
105        impl schemars::JsonSchema for $name {
106            fn schema_name() -> Cow<'static, str> {
107                Cow::Borrowed(stringify!($name))
108            }
109
110            fn json_schema(_: &mut schemars::SchemaGenerator) -> schemars::Schema {
111                use serde_json::{Map, json};
112
113                let mut schema_map = Map::new();
114                schema_map.insert("type".to_string(), json!("string"));
115                schema_map.insert("format".to_string(), json!("const"));
116                schema_map.insert("const".to_string(), json!($value));
117
118                schemars::Schema::from(schema_map)
119            }
120        }
121    };
122}
123
124const_string!(JsonRpcVersion2_0 = "2.0");
125
126// =============================================================================
127// CORE PROTOCOL TYPES
128// =============================================================================
129
130/// Represents the MCP protocol version used for communication.
131///
132/// This ensures compatibility between clients and servers by specifying
133/// which version of the Model Context Protocol is being used.
134#[derive(Debug, Clone, Eq, PartialEq, Hash, PartialOrd)]
135#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
136pub struct ProtocolVersion(Cow<'static, str>);
137
138impl Default for ProtocolVersion {
139    fn default() -> Self {
140        Self::LATEST
141    }
142}
143
144impl std::fmt::Display for ProtocolVersion {
145    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
146        self.0.fmt(f)
147    }
148}
149
150impl ProtocolVersion {
151    pub const V_2025_06_18: Self = Self(Cow::Borrowed("2025-06-18"));
152    pub const V_2025_03_26: Self = Self(Cow::Borrowed("2025-03-26"));
153    pub const V_2024_11_05: Self = Self(Cow::Borrowed("2024-11-05"));
154    //  Keep LATEST at 2025-03-26 until full 2025-06-18 compliance and automated testing are in place.
155    pub const LATEST: Self = Self::V_2025_03_26;
156}
157
158impl Serialize for ProtocolVersion {
159    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
160    where
161        S: serde::Serializer,
162    {
163        self.0.serialize(serializer)
164    }
165}
166
167impl<'de> Deserialize<'de> for ProtocolVersion {
168    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
169    where
170        D: serde::Deserializer<'de>,
171    {
172        let s: String = Deserialize::deserialize(deserializer)?;
173        #[allow(clippy::single_match)]
174        match s.as_str() {
175            "2024-11-05" => return Ok(ProtocolVersion::V_2024_11_05),
176            "2025-03-26" => return Ok(ProtocolVersion::V_2025_03_26),
177            "2025-06-18" => return Ok(ProtocolVersion::V_2025_06_18),
178            _ => {}
179        }
180        Ok(ProtocolVersion(Cow::Owned(s)))
181    }
182}
183
184/// A flexible identifier type that can be either a number or a string.
185///
186/// This is commonly used for request IDs and other identifiers in JSON-RPC
187/// where the specification allows both numeric and string values.
188#[derive(Debug, Clone, Eq, PartialEq, Hash)]
189pub enum NumberOrString {
190    /// A numeric identifier
191    Number(i64),
192    /// A string identifier
193    String(Arc<str>),
194}
195
196impl NumberOrString {
197    pub fn into_json_value(self) -> Value {
198        match self {
199            NumberOrString::Number(n) => Value::Number(serde_json::Number::from(n)),
200            NumberOrString::String(s) => Value::String(s.to_string()),
201        }
202    }
203}
204
205impl std::fmt::Display for NumberOrString {
206    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
207        match self {
208            NumberOrString::Number(n) => n.fmt(f),
209            NumberOrString::String(s) => s.fmt(f),
210        }
211    }
212}
213
214impl Serialize for NumberOrString {
215    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
216    where
217        S: serde::Serializer,
218    {
219        match self {
220            NumberOrString::Number(n) => n.serialize(serializer),
221            NumberOrString::String(s) => s.serialize(serializer),
222        }
223    }
224}
225
226impl<'de> Deserialize<'de> for NumberOrString {
227    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
228    where
229        D: serde::Deserializer<'de>,
230    {
231        let value: Value = Deserialize::deserialize(deserializer)?;
232        match value {
233            Value::Number(n) => {
234                if let Some(i) = n.as_i64() {
235                    Ok(NumberOrString::Number(i))
236                } else if let Some(u) = n.as_u64() {
237                    // Handle large unsigned numbers that fit in i64
238                    if u <= i64::MAX as u64 {
239                        Ok(NumberOrString::Number(u as i64))
240                    } else {
241                        Err(serde::de::Error::custom("Number too large for i64"))
242                    }
243                } else {
244                    Err(serde::de::Error::custom("Expected an integer"))
245                }
246            }
247            Value::String(s) => Ok(NumberOrString::String(s.into())),
248            _ => Err(serde::de::Error::custom("Expect number or string")),
249        }
250    }
251}
252
253#[cfg(feature = "schemars")]
254impl schemars::JsonSchema for NumberOrString {
255    fn schema_name() -> Cow<'static, str> {
256        Cow::Borrowed("NumberOrString")
257    }
258
259    fn json_schema(_: &mut schemars::SchemaGenerator) -> schemars::Schema {
260        use serde_json::{Map, json};
261
262        let mut number_schema = Map::new();
263        number_schema.insert("type".to_string(), json!("number"));
264
265        let mut string_schema = Map::new();
266        string_schema.insert("type".to_string(), json!("string"));
267
268        let mut schema_map = Map::new();
269        schema_map.insert("oneOf".to_string(), json!([number_schema, string_schema]));
270
271        schemars::Schema::from(schema_map)
272    }
273}
274
275/// Type alias for request identifiers used in JSON-RPC communication.
276pub type RequestId = NumberOrString;
277
278/// A token used to track the progress of long-running operations.
279///
280/// Progress tokens allow clients and servers to associate progress notifications
281/// with specific requests, enabling real-time updates on operation status.
282#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Hash, Eq)]
283#[serde(transparent)]
284#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
285pub struct ProgressToken(pub NumberOrString);
286
287// =============================================================================
288// JSON-RPC MESSAGE STRUCTURES
289// =============================================================================
290
291/// Represents a JSON-RPC request with method, parameters, and extensions.
292///
293/// This is the core structure for all MCP requests, containing:
294/// - `method`: The name of the method being called
295/// - `params`: The parameters for the method
296/// - `extensions`: Additional context data (similar to HTTP headers)
297#[derive(Debug, Clone, Default)]
298#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
299pub struct Request<M = String, P = JsonObject> {
300    pub method: M,
301    pub params: P,
302    /// extensions will carry anything possible in the context, including [`Meta`]
303    ///
304    /// this is similar with the Extensions in `http` crate
305    #[cfg_attr(feature = "schemars", schemars(skip))]
306    pub extensions: Extensions,
307}
308
309impl<M: Default, P> Request<M, P> {
310    pub fn new(params: P) -> Self {
311        Self {
312            method: Default::default(),
313            params,
314            extensions: Extensions::default(),
315        }
316    }
317}
318
319impl<M, P> GetExtensions for Request<M, P> {
320    fn extensions(&self) -> &Extensions {
321        &self.extensions
322    }
323    fn extensions_mut(&mut self) -> &mut Extensions {
324        &mut self.extensions
325    }
326}
327
328#[derive(Debug, Clone, Default)]
329#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
330pub struct RequestOptionalParam<M = String, P = JsonObject> {
331    pub method: M,
332    // #[serde(skip_serializing_if = "Option::is_none")]
333    pub params: Option<P>,
334    /// extensions will carry anything possible in the context, including [`Meta`]
335    ///
336    /// this is similar with the Extensions in `http` crate
337    #[cfg_attr(feature = "schemars", schemars(skip))]
338    pub extensions: Extensions,
339}
340
341impl<M: Default, P> RequestOptionalParam<M, P> {
342    pub fn with_param(params: P) -> Self {
343        Self {
344            method: Default::default(),
345            params: Some(params),
346            extensions: Extensions::default(),
347        }
348    }
349}
350
351#[derive(Debug, Clone, Default)]
352#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
353pub struct RequestNoParam<M = String> {
354    pub method: M,
355    /// extensions will carry anything possible in the context, including [`Meta`]
356    ///
357    /// this is similar with the Extensions in `http` crate
358    #[cfg_attr(feature = "schemars", schemars(skip))]
359    pub extensions: Extensions,
360}
361
362impl<M> GetExtensions for RequestNoParam<M> {
363    fn extensions(&self) -> &Extensions {
364        &self.extensions
365    }
366    fn extensions_mut(&mut self) -> &mut Extensions {
367        &mut self.extensions
368    }
369}
370#[derive(Debug, Clone, Default)]
371#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
372pub struct Notification<M = String, P = JsonObject> {
373    pub method: M,
374    pub params: P,
375    /// extensions will carry anything possible in the context, including [`Meta`]
376    ///
377    /// this is similar with the Extensions in `http` crate
378    #[cfg_attr(feature = "schemars", schemars(skip))]
379    pub extensions: Extensions,
380}
381
382impl<M: Default, P> Notification<M, P> {
383    pub fn new(params: P) -> Self {
384        Self {
385            method: Default::default(),
386            params,
387            extensions: Extensions::default(),
388        }
389    }
390}
391
392#[derive(Debug, Clone, Default)]
393#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
394pub struct NotificationNoParam<M = String> {
395    pub method: M,
396    /// extensions will carry anything possible in the context, including [`Meta`]
397    ///
398    /// this is similar with the Extensions in `http` crate
399    #[cfg_attr(feature = "schemars", schemars(skip))]
400    pub extensions: Extensions,
401}
402
403#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
404#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
405pub struct JsonRpcRequest<R = Request> {
406    pub jsonrpc: JsonRpcVersion2_0,
407    pub id: RequestId,
408    #[serde(flatten)]
409    pub request: R,
410}
411
412type DefaultResponse = JsonObject;
413#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
414#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
415pub struct JsonRpcResponse<R = JsonObject> {
416    pub jsonrpc: JsonRpcVersion2_0,
417    pub id: RequestId,
418    pub result: R,
419}
420
421#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
422#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
423pub struct JsonRpcError {
424    pub jsonrpc: JsonRpcVersion2_0,
425    pub id: RequestId,
426    pub error: ErrorData,
427}
428
429#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
430#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
431pub struct JsonRpcNotification<N = Notification> {
432    pub jsonrpc: JsonRpcVersion2_0,
433    #[serde(flatten)]
434    pub notification: N,
435}
436
437/// Standard JSON-RPC error codes used throughout the MCP protocol.
438///
439/// These codes follow the JSON-RPC 2.0 specification and provide
440/// standardized error reporting across all MCP implementations.
441#[derive(Debug, Clone, Copy, Default, Serialize, Deserialize, PartialEq, Eq)]
442#[serde(transparent)]
443#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
444pub struct ErrorCode(pub i32);
445
446impl ErrorCode {
447    pub const RESOURCE_NOT_FOUND: Self = Self(-32002);
448    pub const INVALID_REQUEST: Self = Self(-32600);
449    pub const METHOD_NOT_FOUND: Self = Self(-32601);
450    pub const INVALID_PARAMS: Self = Self(-32602);
451    pub const INTERNAL_ERROR: Self = Self(-32603);
452    pub const PARSE_ERROR: Self = Self(-32700);
453}
454
455/// Error information for JSON-RPC error responses.
456///
457/// This structure follows the JSON-RPC 2.0 specification for error reporting,
458/// providing a standardized way to communicate errors between clients and servers.
459#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
460#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
461pub struct ErrorData {
462    /// The error type that occurred (using standard JSON-RPC error codes)
463    pub code: ErrorCode,
464
465    /// A short description of the error. The message SHOULD be limited to a concise single sentence.
466    pub message: Cow<'static, str>,
467
468    /// Additional information about the error. The value of this member is defined by the
469    /// sender (e.g. detailed error information, nested errors etc.).
470    #[serde(skip_serializing_if = "Option::is_none")]
471    pub data: Option<Value>,
472}
473
474impl ErrorData {
475    pub fn new(
476        code: ErrorCode,
477        message: impl Into<Cow<'static, str>>,
478        data: Option<Value>,
479    ) -> Self {
480        Self {
481            code,
482            message: message.into(),
483            data,
484        }
485    }
486    pub fn resource_not_found(message: impl Into<Cow<'static, str>>, data: Option<Value>) -> Self {
487        Self::new(ErrorCode::RESOURCE_NOT_FOUND, message, data)
488    }
489    pub fn parse_error(message: impl Into<Cow<'static, str>>, data: Option<Value>) -> Self {
490        Self::new(ErrorCode::PARSE_ERROR, message, data)
491    }
492    pub fn invalid_request(message: impl Into<Cow<'static, str>>, data: Option<Value>) -> Self {
493        Self::new(ErrorCode::INVALID_REQUEST, message, data)
494    }
495    pub fn method_not_found<M: ConstString>() -> Self {
496        Self::new(ErrorCode::METHOD_NOT_FOUND, M::VALUE, None)
497    }
498    pub fn invalid_params(message: impl Into<Cow<'static, str>>, data: Option<Value>) -> Self {
499        Self::new(ErrorCode::INVALID_PARAMS, message, data)
500    }
501    pub fn internal_error(message: impl Into<Cow<'static, str>>, data: Option<Value>) -> Self {
502        Self::new(ErrorCode::INTERNAL_ERROR, message, data)
503    }
504}
505
506/// Represents any JSON-RPC message that can be sent or received.
507///
508/// This enum covers all possible message types in the JSON-RPC protocol:
509/// individual requests/responses, notifications, and errors.
510/// It serves as the top-level message container for MCP communication.
511#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
512#[serde(untagged)]
513#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
514pub enum JsonRpcMessage<Req = Request, Resp = DefaultResponse, Noti = Notification> {
515    /// A single request expecting a response
516    Request(JsonRpcRequest<Req>),
517    /// A response to a previous request
518    Response(JsonRpcResponse<Resp>),
519    /// A one-way notification (no response expected)
520    Notification(JsonRpcNotification<Noti>),
521    /// An error response
522    Error(JsonRpcError),
523}
524
525impl<Req, Resp, Not> JsonRpcMessage<Req, Resp, Not> {
526    #[inline]
527    pub const fn request(request: Req, id: RequestId) -> Self {
528        JsonRpcMessage::Request(JsonRpcRequest {
529            jsonrpc: JsonRpcVersion2_0,
530            id,
531            request,
532        })
533    }
534    #[inline]
535    pub const fn response(response: Resp, id: RequestId) -> Self {
536        JsonRpcMessage::Response(JsonRpcResponse {
537            jsonrpc: JsonRpcVersion2_0,
538            id,
539            result: response,
540        })
541    }
542    #[inline]
543    pub const fn error(error: ErrorData, id: RequestId) -> Self {
544        JsonRpcMessage::Error(JsonRpcError {
545            jsonrpc: JsonRpcVersion2_0,
546            id,
547            error,
548        })
549    }
550    #[inline]
551    pub const fn notification(notification: Not) -> Self {
552        JsonRpcMessage::Notification(JsonRpcNotification {
553            jsonrpc: JsonRpcVersion2_0,
554            notification,
555        })
556    }
557    pub fn into_request(self) -> Option<(Req, RequestId)> {
558        match self {
559            JsonRpcMessage::Request(r) => Some((r.request, r.id)),
560            _ => None,
561        }
562    }
563    pub fn into_response(self) -> Option<(Resp, RequestId)> {
564        match self {
565            JsonRpcMessage::Response(r) => Some((r.result, r.id)),
566            _ => None,
567        }
568    }
569    pub fn into_notification(self) -> Option<Not> {
570        match self {
571            JsonRpcMessage::Notification(n) => Some(n.notification),
572            _ => None,
573        }
574    }
575    pub fn into_error(self) -> Option<(ErrorData, RequestId)> {
576        match self {
577            JsonRpcMessage::Error(e) => Some((e.error, e.id)),
578            _ => None,
579        }
580    }
581    pub fn into_result(self) -> Option<(Result<Resp, ErrorData>, RequestId)> {
582        match self {
583            JsonRpcMessage::Response(r) => Some((Ok(r.result), r.id)),
584            JsonRpcMessage::Error(e) => Some((Err(e.error), e.id)),
585
586            _ => None,
587        }
588    }
589}
590
591// =============================================================================
592// INITIALIZATION AND CONNECTION SETUP
593// =============================================================================
594
595/// # Empty result
596/// A response that indicates success but carries no data.
597pub type EmptyResult = EmptyObject;
598
599impl From<()> for EmptyResult {
600    fn from(_value: ()) -> Self {
601        EmptyResult {}
602    }
603}
604
605impl From<EmptyResult> for () {
606    fn from(_value: EmptyResult) {}
607}
608
609#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
610#[serde(rename_all = "camelCase")]
611#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
612pub struct CancelledNotificationParam {
613    pub request_id: RequestId,
614    pub reason: Option<String>,
615}
616
617const_string!(CancelledNotificationMethod = "notifications/cancelled");
618
619/// # Cancellation
620/// This notification can be sent by either side to indicate that it is cancelling a previously-issued request.
621///
622/// 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.
623///
624/// This notification indicates that the result will be unused, so any associated processing SHOULD cease.
625///
626/// A client MUST NOT attempt to cancel its `initialize` request.
627pub type CancelledNotification =
628    Notification<CancelledNotificationMethod, CancelledNotificationParam>;
629
630/// A catch-all notification the client can use to send custom messages to a server.
631///
632/// This preserves the raw `method` name and `params` payload so handlers can
633/// deserialize them into domain-specific types.
634#[derive(Debug, Clone)]
635#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
636pub struct CustomClientNotification {
637    pub method: String,
638    pub params: Option<Value>,
639    /// extensions will carry anything possible in the context, including [`Meta`]
640    ///
641    /// this is similar with the Extensions in `http` crate
642    #[cfg_attr(feature = "schemars", schemars(skip))]
643    pub extensions: Extensions,
644}
645
646impl CustomClientNotification {
647    pub fn new(method: impl Into<String>, params: Option<Value>) -> Self {
648        Self {
649            method: method.into(),
650            params,
651            extensions: Extensions::default(),
652        }
653    }
654
655    /// Deserialize `params` into a strongly-typed structure.
656    pub fn params_as<T: DeserializeOwned>(&self) -> Result<Option<T>, serde_json::Error> {
657        self.params
658            .as_ref()
659            .map(|params| serde_json::from_value(params.clone()))
660            .transpose()
661    }
662}
663
664const_string!(InitializeResultMethod = "initialize");
665/// # Initialization
666/// This request is sent from the client to the server when it first connects, asking it to begin initialization.
667pub type InitializeRequest = Request<InitializeResultMethod, InitializeRequestParam>;
668
669const_string!(InitializedNotificationMethod = "notifications/initialized");
670/// This notification is sent from the client to the server after initialization has finished.
671pub type InitializedNotification = NotificationNoParam<InitializedNotificationMethod>;
672
673/// Parameters sent by a client when initializing a connection to an MCP server.
674///
675/// This contains the client's protocol version, capabilities, and implementation
676/// information, allowing the server to understand what the client supports.
677#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
678#[serde(rename_all = "camelCase")]
679#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
680pub struct InitializeRequestParam {
681    /// The MCP protocol version this client supports
682    pub protocol_version: ProtocolVersion,
683    /// The capabilities this client supports (sampling, roots, etc.)
684    pub capabilities: ClientCapabilities,
685    /// Information about the client implementation
686    pub client_info: Implementation,
687}
688
689/// The server's response to an initialization request.
690///
691/// Contains the server's protocol version, capabilities, and implementation
692/// information, along with optional instructions for the client.
693#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
694#[serde(rename_all = "camelCase")]
695#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
696pub struct InitializeResult {
697    /// The MCP protocol version this server supports
698    pub protocol_version: ProtocolVersion,
699    /// The capabilities this server provides (tools, resources, prompts, etc.)
700    pub capabilities: ServerCapabilities,
701    /// Information about the server implementation
702    pub server_info: Implementation,
703    /// Optional human-readable instructions about using this server
704    #[serde(skip_serializing_if = "Option::is_none")]
705    pub instructions: Option<String>,
706}
707
708pub type ServerInfo = InitializeResult;
709pub type ClientInfo = InitializeRequestParam;
710
711#[allow(clippy::derivable_impls)]
712impl Default for ServerInfo {
713    fn default() -> Self {
714        ServerInfo {
715            protocol_version: ProtocolVersion::default(),
716            capabilities: ServerCapabilities::default(),
717            server_info: Implementation::from_build_env(),
718            instructions: None,
719        }
720    }
721}
722
723#[allow(clippy::derivable_impls)]
724impl Default for ClientInfo {
725    fn default() -> Self {
726        ClientInfo {
727            protocol_version: ProtocolVersion::default(),
728            capabilities: ClientCapabilities::default(),
729            client_info: Implementation::from_build_env(),
730        }
731    }
732}
733
734/// A URL pointing to an icon resource or a base64-encoded data URI.
735///
736/// Clients that support rendering icons MUST support at least the following MIME types:
737/// - image/png - PNG images (safe, universal compatibility)
738/// - image/jpeg (and image/jpg) - JPEG images (safe, universal compatibility)
739///
740/// Clients that support rendering icons SHOULD also support:
741/// - image/svg+xml - SVG images (scalable but requires security precautions)
742/// - image/webp - WebP images (modern, efficient format)
743#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
744#[serde(rename_all = "camelCase")]
745#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
746pub struct Icon {
747    /// A standard URI pointing to an icon resource
748    pub src: String,
749    /// Optional override if the server's MIME type is missing or generic
750    #[serde(skip_serializing_if = "Option::is_none")]
751    pub mime_type: Option<String>,
752    /// Size specification, each string should be in WxH format (e.g., `\"48x48\"`, `\"96x96\"`) or `\"any\"` for scalable formats like SVG
753    #[serde(skip_serializing_if = "Option::is_none")]
754    pub sizes: Option<Vec<String>>,
755}
756
757#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
758#[serde(rename_all = "camelCase")]
759#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
760pub struct Implementation {
761    pub name: String,
762    #[serde(skip_serializing_if = "Option::is_none")]
763    pub title: Option<String>,
764    pub version: String,
765    #[serde(skip_serializing_if = "Option::is_none")]
766    pub icons: Option<Vec<Icon>>,
767    #[serde(skip_serializing_if = "Option::is_none")]
768    pub website_url: Option<String>,
769}
770
771impl Default for Implementation {
772    fn default() -> Self {
773        Self::from_build_env()
774    }
775}
776
777impl Implementation {
778    pub fn from_build_env() -> Self {
779        Implementation {
780            name: env!("CARGO_CRATE_NAME").to_owned(),
781            title: None,
782            version: env!("CARGO_PKG_VERSION").to_owned(),
783            icons: None,
784            website_url: None,
785        }
786    }
787}
788
789#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Default)]
790#[serde(rename_all = "camelCase")]
791#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
792pub struct PaginatedRequestParam {
793    #[serde(skip_serializing_if = "Option::is_none")]
794    pub cursor: Option<String>,
795}
796// =============================================================================
797// PROGRESS AND PAGINATION
798// =============================================================================
799
800const_string!(PingRequestMethod = "ping");
801pub type PingRequest = RequestNoParam<PingRequestMethod>;
802
803const_string!(ProgressNotificationMethod = "notifications/progress");
804#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
805#[serde(rename_all = "camelCase")]
806#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
807pub struct ProgressNotificationParam {
808    pub progress_token: ProgressToken,
809    /// The progress thus far. This should increase every time progress is made, even if the total is unknown.
810    pub progress: f64,
811    /// Total number of items to process (or total progress required), if known
812    #[serde(skip_serializing_if = "Option::is_none")]
813    pub total: Option<f64>,
814    /// An optional message describing the current progress.
815    #[serde(skip_serializing_if = "Option::is_none")]
816    pub message: Option<String>,
817}
818
819pub type ProgressNotification = Notification<ProgressNotificationMethod, ProgressNotificationParam>;
820
821pub type Cursor = String;
822
823macro_rules! paginated_result {
824    ($t:ident {
825        $i_item: ident: $t_item: ty
826    }) => {
827        #[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Default)]
828        #[serde(rename_all = "camelCase")]
829        #[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
830        pub struct $t {
831            #[serde(skip_serializing_if = "Option::is_none")]
832            pub next_cursor: Option<Cursor>,
833            pub $i_item: $t_item,
834        }
835
836        impl $t {
837            pub fn with_all_items(
838                items: $t_item,
839            ) -> Self {
840                Self {
841                    next_cursor: None,
842                    $i_item: items,
843                }
844            }
845        }
846    };
847}
848
849// =============================================================================
850// RESOURCE MANAGEMENT
851// =============================================================================
852
853const_string!(ListResourcesRequestMethod = "resources/list");
854/// Request to list all available resources from a server
855pub type ListResourcesRequest =
856    RequestOptionalParam<ListResourcesRequestMethod, PaginatedRequestParam>;
857
858paginated_result!(ListResourcesResult {
859    resources: Vec<Resource>
860});
861
862const_string!(ListResourceTemplatesRequestMethod = "resources/templates/list");
863/// Request to list all available resource templates from a server
864pub type ListResourceTemplatesRequest =
865    RequestOptionalParam<ListResourceTemplatesRequestMethod, PaginatedRequestParam>;
866
867paginated_result!(ListResourceTemplatesResult {
868    resource_templates: Vec<ResourceTemplate>
869});
870
871const_string!(ReadResourceRequestMethod = "resources/read");
872/// Parameters for reading a specific resource
873#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
874#[serde(rename_all = "camelCase")]
875#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
876pub struct ReadResourceRequestParam {
877    /// The URI of the resource to read
878    pub uri: String,
879}
880
881/// Result containing the contents of a read resource
882#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
883#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
884pub struct ReadResourceResult {
885    /// The actual content of the resource
886    pub contents: Vec<ResourceContents>,
887}
888
889/// Request to read a specific resource
890pub type ReadResourceRequest = Request<ReadResourceRequestMethod, ReadResourceRequestParam>;
891
892const_string!(ResourceListChangedNotificationMethod = "notifications/resources/list_changed");
893/// Notification sent when the list of available resources changes
894pub type ResourceListChangedNotification =
895    NotificationNoParam<ResourceListChangedNotificationMethod>;
896
897const_string!(SubscribeRequestMethod = "resources/subscribe");
898/// Parameters for subscribing to resource updates
899#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
900#[serde(rename_all = "camelCase")]
901#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
902pub struct SubscribeRequestParam {
903    /// The URI of the resource to subscribe to
904    pub uri: String,
905}
906/// Request to subscribe to resource updates
907pub type SubscribeRequest = Request<SubscribeRequestMethod, SubscribeRequestParam>;
908
909const_string!(UnsubscribeRequestMethod = "resources/unsubscribe");
910/// Parameters for unsubscribing from resource updates
911#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
912#[serde(rename_all = "camelCase")]
913#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
914pub struct UnsubscribeRequestParam {
915    /// The URI of the resource to unsubscribe from
916    pub uri: String,
917}
918/// Request to unsubscribe from resource updates
919pub type UnsubscribeRequest = Request<UnsubscribeRequestMethod, UnsubscribeRequestParam>;
920
921const_string!(ResourceUpdatedNotificationMethod = "notifications/resources/updated");
922/// Parameters for a resource update notification
923#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
924#[serde(rename_all = "camelCase")]
925#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
926pub struct ResourceUpdatedNotificationParam {
927    /// The URI of the resource that was updated
928    pub uri: String,
929}
930/// Notification sent when a subscribed resource is updated
931pub type ResourceUpdatedNotification =
932    Notification<ResourceUpdatedNotificationMethod, ResourceUpdatedNotificationParam>;
933
934// =============================================================================
935// PROMPT MANAGEMENT
936// =============================================================================
937
938const_string!(ListPromptsRequestMethod = "prompts/list");
939/// Request to list all available prompts from a server
940pub type ListPromptsRequest = RequestOptionalParam<ListPromptsRequestMethod, PaginatedRequestParam>;
941
942paginated_result!(ListPromptsResult {
943    prompts: Vec<Prompt>
944});
945
946const_string!(GetPromptRequestMethod = "prompts/get");
947/// Parameters for retrieving a specific prompt
948#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
949#[serde(rename_all = "camelCase")]
950#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
951pub struct GetPromptRequestParam {
952    pub name: String,
953    #[serde(skip_serializing_if = "Option::is_none")]
954    pub arguments: Option<JsonObject>,
955}
956/// Request to get a specific prompt
957pub type GetPromptRequest = Request<GetPromptRequestMethod, GetPromptRequestParam>;
958
959const_string!(PromptListChangedNotificationMethod = "notifications/prompts/list_changed");
960/// Notification sent when the list of available prompts changes
961pub type PromptListChangedNotification = NotificationNoParam<PromptListChangedNotificationMethod>;
962
963const_string!(ToolListChangedNotificationMethod = "notifications/tools/list_changed");
964/// Notification sent when the list of available tools changes
965pub type ToolListChangedNotification = NotificationNoParam<ToolListChangedNotificationMethod>;
966
967// =============================================================================
968// LOGGING
969// =============================================================================
970
971/// Logging levels supported by the MCP protocol
972#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Copy)]
973#[serde(rename_all = "lowercase")] //match spec
974#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
975pub enum LoggingLevel {
976    Debug,
977    Info,
978    Notice,
979    Warning,
980    Error,
981    Critical,
982    Alert,
983    Emergency,
984}
985
986const_string!(SetLevelRequestMethod = "logging/setLevel");
987/// Parameters for setting the logging level
988#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
989#[serde(rename_all = "camelCase")]
990#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
991pub struct SetLevelRequestParam {
992    /// The desired logging level
993    pub level: LoggingLevel,
994}
995/// Request to set the logging level
996pub type SetLevelRequest = Request<SetLevelRequestMethod, SetLevelRequestParam>;
997
998const_string!(LoggingMessageNotificationMethod = "notifications/message");
999/// Parameters for a logging message notification
1000#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
1001#[serde(rename_all = "camelCase")]
1002#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
1003pub struct LoggingMessageNotificationParam {
1004    /// The severity level of this log message
1005    pub level: LoggingLevel,
1006    /// Optional logger name that generated this message
1007    #[serde(skip_serializing_if = "Option::is_none")]
1008    pub logger: Option<String>,
1009    /// The actual log data
1010    pub data: Value,
1011}
1012/// Notification containing a log message
1013pub type LoggingMessageNotification =
1014    Notification<LoggingMessageNotificationMethod, LoggingMessageNotificationParam>;
1015
1016// =============================================================================
1017// SAMPLING (LLM INTERACTION)
1018// =============================================================================
1019
1020const_string!(CreateMessageRequestMethod = "sampling/createMessage");
1021pub type CreateMessageRequest = Request<CreateMessageRequestMethod, CreateMessageRequestParam>;
1022
1023/// Represents the role of a participant in a conversation or message exchange.
1024///
1025/// Used in sampling and chat contexts to distinguish between different
1026/// types of message senders in the conversation flow.
1027#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1028#[serde(rename_all = "camelCase")]
1029#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
1030pub enum Role {
1031    /// A human user or client making a request
1032    User,
1033    /// An AI assistant or server providing a response
1034    Assistant,
1035}
1036
1037/// A message in a sampling conversation, containing a role and content.
1038///
1039/// This represents a single message in a conversation flow, used primarily
1040/// in LLM sampling requests where the conversation history is important
1041/// for generating appropriate responses.
1042#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
1043#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
1044pub struct SamplingMessage {
1045    /// The role of the message sender (User or Assistant)
1046    pub role: Role,
1047    /// The actual content of the message (text, image, etc.)
1048    pub content: Content,
1049}
1050
1051/// Specifies how much context should be included in sampling requests.
1052///
1053/// This allows clients to control what additional context information
1054/// should be provided to the LLM when processing sampling requests.
1055#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
1056#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
1057pub enum ContextInclusion {
1058    /// Include context from all connected MCP servers
1059    #[serde(rename = "allServers")]
1060    AllServers,
1061    /// Include no additional context
1062    #[serde(rename = "none")]
1063    None,
1064    /// Include context only from the requesting server
1065    #[serde(rename = "thisServer")]
1066    ThisServer,
1067}
1068
1069/// Parameters for creating a message through LLM sampling.
1070///
1071/// This structure contains all the necessary information for a client to
1072/// generate an LLM response, including conversation history, model preferences,
1073/// and generation parameters.
1074#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
1075#[serde(rename_all = "camelCase")]
1076#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
1077pub struct CreateMessageRequestParam {
1078    /// The conversation history and current messages
1079    pub messages: Vec<SamplingMessage>,
1080    /// Preferences for model selection and behavior
1081    #[serde(skip_serializing_if = "Option::is_none")]
1082    pub model_preferences: Option<ModelPreferences>,
1083    /// System prompt to guide the model's behavior
1084    #[serde(skip_serializing_if = "Option::is_none")]
1085    pub system_prompt: Option<String>,
1086    /// How much context to include from MCP servers
1087    #[serde(skip_serializing_if = "Option::is_none")]
1088    pub include_context: Option<ContextInclusion>,
1089    /// Temperature for controlling randomness (0.0 to 1.0)
1090    #[serde(skip_serializing_if = "Option::is_none")]
1091    pub temperature: Option<f32>,
1092    /// Maximum number of tokens to generate
1093    pub max_tokens: u32,
1094    /// Sequences that should stop generation
1095    #[serde(skip_serializing_if = "Option::is_none")]
1096    pub stop_sequences: Option<Vec<String>>,
1097    /// Additional metadata for the request
1098    #[serde(skip_serializing_if = "Option::is_none")]
1099    pub metadata: Option<Value>,
1100}
1101
1102/// Preferences for model selection and behavior in sampling requests.
1103///
1104/// This allows servers to express their preferences for which model to use
1105/// and how to balance different priorities when the client has multiple
1106/// model options available.
1107#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
1108#[serde(rename_all = "camelCase")]
1109#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
1110pub struct ModelPreferences {
1111    /// Specific model names or families to prefer (e.g., "claude", "gpt")
1112    #[serde(skip_serializing_if = "Option::is_none")]
1113    pub hints: Option<Vec<ModelHint>>,
1114    /// Priority for cost optimization (0.0 to 1.0, higher = prefer cheaper models)
1115    #[serde(skip_serializing_if = "Option::is_none")]
1116    pub cost_priority: Option<f32>,
1117    /// Priority for speed/latency (0.0 to 1.0, higher = prefer faster models)
1118    #[serde(skip_serializing_if = "Option::is_none")]
1119    pub speed_priority: Option<f32>,
1120    /// Priority for intelligence/capability (0.0 to 1.0, higher = prefer more capable models)
1121    #[serde(skip_serializing_if = "Option::is_none")]
1122    pub intelligence_priority: Option<f32>,
1123}
1124
1125/// A hint suggesting a preferred model name or family.
1126///
1127/// Model hints are advisory suggestions that help clients choose appropriate
1128/// models. They can be specific model names or general families like "claude" or "gpt".
1129#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
1130#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
1131pub struct ModelHint {
1132    /// The suggested model name or family identifier
1133    #[serde(skip_serializing_if = "Option::is_none")]
1134    pub name: Option<String>,
1135}
1136
1137// =============================================================================
1138// COMPLETION AND AUTOCOMPLETE
1139// =============================================================================
1140
1141/// Context for completion requests providing previously resolved arguments.
1142///
1143/// This enables context-aware completion where subsequent argument completions
1144/// can take into account the values of previously resolved arguments.
1145#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Default)]
1146#[serde(rename_all = "camelCase")]
1147#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
1148pub struct CompletionContext {
1149    /// Previously resolved argument values that can inform completion suggestions
1150    #[serde(skip_serializing_if = "Option::is_none")]
1151    pub arguments: Option<std::collections::HashMap<String, String>>,
1152}
1153
1154impl CompletionContext {
1155    /// Create a new empty completion context
1156    pub fn new() -> Self {
1157        Self::default()
1158    }
1159
1160    /// Create a completion context with the given arguments
1161    pub fn with_arguments(arguments: std::collections::HashMap<String, String>) -> Self {
1162        Self {
1163            arguments: Some(arguments),
1164        }
1165    }
1166
1167    /// Get a specific argument value by name
1168    pub fn get_argument(&self, name: &str) -> Option<&String> {
1169        self.arguments.as_ref()?.get(name)
1170    }
1171
1172    /// Check if the context has any arguments
1173    pub fn has_arguments(&self) -> bool {
1174        self.arguments.as_ref().is_some_and(|args| !args.is_empty())
1175    }
1176
1177    /// Get all argument names
1178    pub fn argument_names(&self) -> impl Iterator<Item = &str> {
1179        self.arguments
1180            .as_ref()
1181            .into_iter()
1182            .flat_map(|args| args.keys())
1183            .map(|k| k.as_str())
1184    }
1185}
1186
1187#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
1188#[serde(rename_all = "camelCase")]
1189#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
1190pub struct CompleteRequestParam {
1191    pub r#ref: Reference,
1192    pub argument: ArgumentInfo,
1193    /// Optional context containing previously resolved argument values
1194    #[serde(skip_serializing_if = "Option::is_none")]
1195    pub context: Option<CompletionContext>,
1196}
1197
1198pub type CompleteRequest = Request<CompleteRequestMethod, CompleteRequestParam>;
1199
1200#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Default)]
1201#[serde(rename_all = "camelCase")]
1202#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
1203pub struct CompletionInfo {
1204    pub values: Vec<String>,
1205    #[serde(skip_serializing_if = "Option::is_none")]
1206    pub total: Option<u32>,
1207    #[serde(skip_serializing_if = "Option::is_none")]
1208    pub has_more: Option<bool>,
1209}
1210
1211impl CompletionInfo {
1212    /// Maximum number of completion values allowed per response according to MCP specification
1213    pub const MAX_VALUES: usize = 100;
1214
1215    /// Create a new CompletionInfo with validation for maximum values
1216    pub fn new(values: Vec<String>) -> Result<Self, String> {
1217        if values.len() > Self::MAX_VALUES {
1218            return Err(format!(
1219                "Too many completion values: {} (max: {})",
1220                values.len(),
1221                Self::MAX_VALUES
1222            ));
1223        }
1224        Ok(Self {
1225            values,
1226            total: None,
1227            has_more: None,
1228        })
1229    }
1230
1231    /// Create CompletionInfo with all values and no pagination
1232    pub fn with_all_values(values: Vec<String>) -> Result<Self, String> {
1233        let completion = Self::new(values)?;
1234        Ok(Self {
1235            total: Some(completion.values.len() as u32),
1236            has_more: Some(false),
1237            ..completion
1238        })
1239    }
1240
1241    /// Create CompletionInfo with pagination information
1242    pub fn with_pagination(
1243        values: Vec<String>,
1244        total: Option<u32>,
1245        has_more: bool,
1246    ) -> Result<Self, String> {
1247        let completion = Self::new(values)?;
1248        Ok(Self {
1249            total,
1250            has_more: Some(has_more),
1251            ..completion
1252        })
1253    }
1254
1255    /// Check if this completion response indicates more results are available
1256    pub fn has_more_results(&self) -> bool {
1257        self.has_more.unwrap_or(false)
1258    }
1259
1260    /// Get the total number of available completions, if known
1261    pub fn total_available(&self) -> Option<u32> {
1262        self.total
1263    }
1264
1265    /// Validate that the completion info complies with MCP specification
1266    pub fn validate(&self) -> Result<(), String> {
1267        if self.values.len() > Self::MAX_VALUES {
1268            return Err(format!(
1269                "Too many completion values: {} (max: {})",
1270                self.values.len(),
1271                Self::MAX_VALUES
1272            ));
1273        }
1274        Ok(())
1275    }
1276}
1277
1278#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Default)]
1279#[serde(rename_all = "camelCase")]
1280#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
1281pub struct CompleteResult {
1282    pub completion: CompletionInfo,
1283}
1284
1285#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
1286#[serde(tag = "type")]
1287#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
1288pub enum Reference {
1289    #[serde(rename = "ref/resource")]
1290    Resource(ResourceReference),
1291    #[serde(rename = "ref/prompt")]
1292    Prompt(PromptReference),
1293}
1294
1295impl Reference {
1296    /// Create a prompt reference
1297    pub fn for_prompt(name: impl Into<String>) -> Self {
1298        // Not accepting `title` currently as it'll break the API
1299        // Until further decision, keep it `None`, modify later
1300        // if required, add `title` to the API
1301        Self::Prompt(PromptReference {
1302            name: name.into(),
1303            title: None,
1304        })
1305    }
1306
1307    /// Create a resource reference
1308    pub fn for_resource(uri: impl Into<String>) -> Self {
1309        Self::Resource(ResourceReference { uri: uri.into() })
1310    }
1311
1312    /// Get the reference type as a string
1313    pub fn reference_type(&self) -> &'static str {
1314        match self {
1315            Self::Prompt(_) => "ref/prompt",
1316            Self::Resource(_) => "ref/resource",
1317        }
1318    }
1319
1320    /// Extract prompt name if this is a prompt reference
1321    pub fn as_prompt_name(&self) -> Option<&str> {
1322        match self {
1323            Self::Prompt(prompt_ref) => Some(&prompt_ref.name),
1324            _ => None,
1325        }
1326    }
1327
1328    /// Extract resource URI if this is a resource reference
1329    pub fn as_resource_uri(&self) -> Option<&str> {
1330        match self {
1331            Self::Resource(resource_ref) => Some(&resource_ref.uri),
1332            _ => None,
1333        }
1334    }
1335}
1336
1337#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
1338#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
1339pub struct ResourceReference {
1340    pub uri: String,
1341}
1342
1343#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
1344#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
1345pub struct PromptReference {
1346    pub name: String,
1347    #[serde(skip_serializing_if = "Option::is_none")]
1348    pub title: Option<String>,
1349}
1350
1351const_string!(CompleteRequestMethod = "completion/complete");
1352#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
1353#[serde(rename_all = "camelCase")]
1354#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
1355pub struct ArgumentInfo {
1356    pub name: String,
1357    pub value: String,
1358}
1359
1360// =============================================================================
1361// ROOTS AND WORKSPACE MANAGEMENT
1362// =============================================================================
1363
1364#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
1365#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
1366pub struct Root {
1367    pub uri: String,
1368    #[serde(skip_serializing_if = "Option::is_none")]
1369    pub name: Option<String>,
1370}
1371
1372const_string!(ListRootsRequestMethod = "roots/list");
1373pub type ListRootsRequest = RequestNoParam<ListRootsRequestMethod>;
1374
1375#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Default)]
1376#[serde(rename_all = "camelCase")]
1377#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
1378pub struct ListRootsResult {
1379    pub roots: Vec<Root>,
1380}
1381
1382const_string!(RootsListChangedNotificationMethod = "notifications/roots/list_changed");
1383pub type RootsListChangedNotification = NotificationNoParam<RootsListChangedNotificationMethod>;
1384
1385// =============================================================================
1386// ELICITATION (INTERACTIVE USER INPUT)
1387// =============================================================================
1388
1389// Method constants for elicitation operations.
1390// Elicitation allows servers to request interactive input from users during tool execution.
1391const_string!(ElicitationCreateRequestMethod = "elicitation/create");
1392const_string!(ElicitationResponseNotificationMethod = "notifications/elicitation/response");
1393
1394/// Represents the possible actions a user can take in response to an elicitation request.
1395///
1396/// When a server requests user input through elicitation, the user can:
1397/// - Accept: Provide the requested information and continue
1398/// - Decline: Refuse to provide the information but continue the operation
1399/// - Cancel: Stop the entire operation
1400#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq)]
1401#[serde(rename_all = "lowercase")]
1402#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
1403pub enum ElicitationAction {
1404    /// User accepts the request and provides the requested information
1405    Accept,
1406    /// User declines to provide the information but allows the operation to continue
1407    Decline,
1408    /// User cancels the entire operation
1409    Cancel,
1410}
1411
1412/// Parameters for creating an elicitation request to gather user input.
1413///
1414/// This structure contains everything needed to request interactive input from a user:
1415/// - A human-readable message explaining what information is needed
1416/// - A type-safe schema defining the expected structure of the response
1417///
1418/// # Example
1419///
1420/// ```rust
1421/// use rmcp::model::*;
1422///
1423/// let params = CreateElicitationRequestParam {
1424///     message: "Please provide your email".to_string(),
1425///     requested_schema: ElicitationSchema::builder()
1426///         .required_email("email")
1427///         .build()
1428///         .unwrap(),
1429/// };
1430/// ```
1431#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
1432#[serde(rename_all = "camelCase")]
1433#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
1434pub struct CreateElicitationRequestParam {
1435    /// Human-readable message explaining what input is needed from the user.
1436    /// This should be clear and provide sufficient context for the user to understand
1437    /// what information they need to provide.
1438    pub message: String,
1439
1440    /// Type-safe schema defining the expected structure and validation rules for the user's response.
1441    /// This enforces the MCP 2025-06-18 specification that elicitation schemas must be objects
1442    /// with primitive-typed properties.
1443    pub requested_schema: ElicitationSchema,
1444}
1445
1446/// The result returned by a client in response to an elicitation request.
1447///
1448/// Contains the user's decision (accept/decline/cancel) and optionally their input data
1449/// if they chose to accept the request.
1450#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
1451#[serde(rename_all = "camelCase")]
1452#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
1453pub struct CreateElicitationResult {
1454    /// The user's decision on how to handle the elicitation request
1455    pub action: ElicitationAction,
1456
1457    /// The actual data provided by the user, if they accepted the request.
1458    /// Must conform to the JSON schema specified in the original request.
1459    /// Only present when action is Accept.
1460    #[serde(skip_serializing_if = "Option::is_none")]
1461    pub content: Option<Value>,
1462}
1463
1464/// Request type for creating an elicitation to gather user input
1465pub type CreateElicitationRequest =
1466    Request<ElicitationCreateRequestMethod, CreateElicitationRequestParam>;
1467
1468// =============================================================================
1469// TOOL EXECUTION RESULTS
1470// =============================================================================
1471
1472/// The result of a tool call operation.
1473///
1474/// Contains the content returned by the tool execution and an optional
1475/// flag indicating whether the operation resulted in an error.
1476#[derive(Debug, Serialize, Clone, PartialEq)]
1477#[serde(rename_all = "camelCase")]
1478#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
1479pub struct CallToolResult {
1480    /// The content returned by the tool (text, images, etc.)
1481    pub content: Vec<Content>,
1482    /// An optional JSON object that represents the structured result of the tool call
1483    #[serde(skip_serializing_if = "Option::is_none")]
1484    pub structured_content: Option<Value>,
1485    /// Whether this result represents an error condition
1486    #[serde(skip_serializing_if = "Option::is_none")]
1487    pub is_error: Option<bool>,
1488    /// Optional protocol-level metadata for this result
1489    #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
1490    pub meta: Option<Meta>,
1491}
1492
1493impl CallToolResult {
1494    /// Create a successful tool result with unstructured content
1495    pub fn success(content: Vec<Content>) -> Self {
1496        CallToolResult {
1497            content,
1498            structured_content: None,
1499            is_error: Some(false),
1500            meta: None,
1501        }
1502    }
1503    /// Create an error tool result with unstructured content
1504    pub fn error(content: Vec<Content>) -> Self {
1505        CallToolResult {
1506            content,
1507            structured_content: None,
1508            is_error: Some(true),
1509            meta: None,
1510        }
1511    }
1512    /// Create a successful tool result with structured content
1513    ///
1514    /// # Example
1515    ///
1516    /// ```rust,ignore
1517    /// use rmcp::model::CallToolResult;
1518    /// use serde_json::json;
1519    ///
1520    /// let result = CallToolResult::structured(json!({
1521    ///     "temperature": 22.5,
1522    ///     "humidity": 65,
1523    ///     "description": "Partly cloudy"
1524    /// }));
1525    /// ```
1526    pub fn structured(value: Value) -> Self {
1527        CallToolResult {
1528            content: vec![Content::text(value.to_string())],
1529            structured_content: Some(value),
1530            is_error: Some(false),
1531            meta: None,
1532        }
1533    }
1534    /// Create an error tool result with structured content
1535    ///
1536    /// # Example
1537    ///
1538    /// ```rust,ignore
1539    /// use rmcp::model::CallToolResult;
1540    /// use serde_json::json;
1541    ///
1542    /// let result = CallToolResult::structured_error(json!({
1543    ///     "error_code": "INVALID_INPUT",
1544    ///     "message": "Temperature value out of range",
1545    ///     "details": {
1546    ///         "min": -50,
1547    ///         "max": 50,
1548    ///         "provided": 100
1549    ///     }
1550    /// }));
1551    /// ```
1552    pub fn structured_error(value: Value) -> Self {
1553        CallToolResult {
1554            content: vec![Content::text(value.to_string())],
1555            structured_content: Some(value),
1556            is_error: Some(true),
1557            meta: None,
1558        }
1559    }
1560
1561    /// Convert the `structured_content` part of response into a certain type.
1562    ///
1563    /// # About json schema validation
1564    /// Since rust is a strong type language, we don't need to do json schema validation here.
1565    ///
1566    /// But if you do have to validate the response data, you can use [`jsonschema`](https://crates.io/crates/jsonschema) crate.
1567    pub fn into_typed<T>(self) -> Result<T, serde_json::Error>
1568    where
1569        T: DeserializeOwned,
1570    {
1571        let raw_text = match (self.structured_content, &self.content.first()) {
1572            (Some(value), _) => return serde_json::from_value(value),
1573            (None, Some(contents)) => {
1574                if let Some(text) = contents.as_text() {
1575                    let text = &text.text;
1576                    Some(text)
1577                } else {
1578                    None
1579                }
1580            }
1581            (None, None) => None,
1582        };
1583        if let Some(text) = raw_text {
1584            return serde_json::from_str(text);
1585        }
1586        serde_json::from_value(serde_json::Value::Null)
1587    }
1588}
1589
1590// Custom deserialize implementation to validate mutual exclusivity
1591impl<'de> Deserialize<'de> for CallToolResult {
1592    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
1593    where
1594        D: serde::Deserializer<'de>,
1595    {
1596        #[derive(Deserialize)]
1597        #[serde(rename_all = "camelCase")]
1598        struct CallToolResultHelper {
1599            #[serde(skip_serializing_if = "Option::is_none")]
1600            content: Option<Vec<Content>>,
1601            #[serde(skip_serializing_if = "Option::is_none")]
1602            structured_content: Option<Value>,
1603            #[serde(skip_serializing_if = "Option::is_none")]
1604            is_error: Option<bool>,
1605            /// Accept `_meta` during deserialization
1606            #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
1607            meta: Option<Meta>,
1608        }
1609
1610        let helper = CallToolResultHelper::deserialize(deserializer)?;
1611        let result = CallToolResult {
1612            content: helper.content.unwrap_or_default(),
1613            structured_content: helper.structured_content,
1614            is_error: helper.is_error,
1615            meta: helper.meta,
1616        };
1617
1618        // Validate mutual exclusivity
1619        if result.content.is_empty() && result.structured_content.is_none() {
1620            return Err(serde::de::Error::custom(
1621                "CallToolResult must have either content or structured_content",
1622            ));
1623        }
1624
1625        Ok(result)
1626    }
1627}
1628
1629const_string!(ListToolsRequestMethod = "tools/list");
1630/// Request to list all available tools from a server
1631pub type ListToolsRequest = RequestOptionalParam<ListToolsRequestMethod, PaginatedRequestParam>;
1632
1633paginated_result!(
1634    ListToolsResult {
1635        tools: Vec<Tool>
1636    }
1637);
1638
1639const_string!(CallToolRequestMethod = "tools/call");
1640/// Parameters for calling a tool provided by an MCP server.
1641///
1642/// Contains the tool name and optional arguments needed to execute
1643/// the tool operation.
1644#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
1645#[serde(rename_all = "camelCase")]
1646#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
1647pub struct CallToolRequestParam {
1648    /// The name of the tool to call
1649    pub name: Cow<'static, str>,
1650    /// Arguments to pass to the tool (must match the tool's input schema)
1651    #[serde(skip_serializing_if = "Option::is_none")]
1652    pub arguments: Option<JsonObject>,
1653}
1654
1655/// Request to call a specific tool
1656pub type CallToolRequest = Request<CallToolRequestMethod, CallToolRequestParam>;
1657
1658/// The result of a sampling/createMessage request containing the generated response.
1659///
1660/// This structure contains the generated message along with metadata about
1661/// how the generation was performed and why it stopped.
1662#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
1663#[serde(rename_all = "camelCase")]
1664#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
1665pub struct CreateMessageResult {
1666    /// The identifier of the model that generated the response
1667    pub model: String,
1668    /// The reason why generation stopped (e.g., "endTurn", "maxTokens")
1669    #[serde(skip_serializing_if = "Option::is_none")]
1670    pub stop_reason: Option<String>,
1671    /// The generated message with role and content
1672    #[serde(flatten)]
1673    pub message: SamplingMessage,
1674}
1675
1676impl CreateMessageResult {
1677    pub const STOP_REASON_END_TURN: &str = "endTurn";
1678    pub const STOP_REASON_END_SEQUENCE: &str = "stopSequence";
1679    pub const STOP_REASON_END_MAX_TOKEN: &str = "maxTokens";
1680}
1681
1682#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
1683#[serde(rename_all = "camelCase")]
1684#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
1685pub struct GetPromptResult {
1686    #[serde(skip_serializing_if = "Option::is_none")]
1687    pub description: Option<String>,
1688    pub messages: Vec<PromptMessage>,
1689}
1690
1691// =============================================================================
1692// MESSAGE TYPE UNIONS
1693// =============================================================================
1694
1695macro_rules! ts_union {
1696    (
1697        export type $U:ident =
1698            $($rest:tt)*
1699    ) => {
1700        ts_union!(@declare $U { $($rest)* });
1701        ts_union!(@impl_from $U { $($rest)* });
1702    };
1703    (@declare $U:ident { $($variant:tt)* }) => {
1704        ts_union!(@declare_variant $U { } {$($variant)*} );
1705    };
1706    (@declare_variant $U:ident { $($declared:tt)* } {$(|)? box $V:ident $($rest:tt)*}) => {
1707        ts_union!(@declare_variant $U { $($declared)* $V(Box<$V>), }  {$($rest)*});
1708    };
1709    (@declare_variant $U:ident { $($declared:tt)* } {$(|)? $V:ident $($rest:tt)*}) => {
1710        ts_union!(@declare_variant $U { $($declared)* $V($V), } {$($rest)*});
1711    };
1712    (@declare_variant $U:ident { $($declared:tt)* }  { ; }) => {
1713        ts_union!(@declare_end $U { $($declared)* } );
1714    };
1715    (@declare_end $U:ident { $($declared:tt)* }) => {
1716        #[derive(Debug, Serialize, Deserialize, Clone)]
1717        #[serde(untagged)]
1718        #[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
1719        pub enum $U {
1720            $($declared)*
1721        }
1722    };
1723    (@impl_from $U: ident {$(|)? box $V:ident $($rest:tt)*}) => {
1724        impl From<$V> for $U {
1725            fn from(value: $V) -> Self {
1726                $U::$V(Box::new(value))
1727            }
1728        }
1729        ts_union!(@impl_from $U {$($rest)*});
1730    };
1731    (@impl_from $U: ident {$(|)? $V:ident $($rest:tt)*}) => {
1732        impl From<$V> for $U {
1733            fn from(value: $V) -> Self {
1734                $U::$V(value)
1735            }
1736        }
1737        ts_union!(@impl_from $U {$($rest)*});
1738    };
1739    (@impl_from $U: ident  { ; }) => {};
1740    (@impl_from $U: ident  { }) => {};
1741}
1742
1743ts_union!(
1744    export type ClientRequest =
1745    | PingRequest
1746    | InitializeRequest
1747    | CompleteRequest
1748    | SetLevelRequest
1749    | GetPromptRequest
1750    | ListPromptsRequest
1751    | ListResourcesRequest
1752    | ListResourceTemplatesRequest
1753    | ReadResourceRequest
1754    | SubscribeRequest
1755    | UnsubscribeRequest
1756    | CallToolRequest
1757    | ListToolsRequest;
1758);
1759
1760impl ClientRequest {
1761    pub fn method(&self) -> &'static str {
1762        match &self {
1763            ClientRequest::PingRequest(r) => r.method.as_str(),
1764            ClientRequest::InitializeRequest(r) => r.method.as_str(),
1765            ClientRequest::CompleteRequest(r) => r.method.as_str(),
1766            ClientRequest::SetLevelRequest(r) => r.method.as_str(),
1767            ClientRequest::GetPromptRequest(r) => r.method.as_str(),
1768            ClientRequest::ListPromptsRequest(r) => r.method.as_str(),
1769            ClientRequest::ListResourcesRequest(r) => r.method.as_str(),
1770            ClientRequest::ListResourceTemplatesRequest(r) => r.method.as_str(),
1771            ClientRequest::ReadResourceRequest(r) => r.method.as_str(),
1772            ClientRequest::SubscribeRequest(r) => r.method.as_str(),
1773            ClientRequest::UnsubscribeRequest(r) => r.method.as_str(),
1774            ClientRequest::CallToolRequest(r) => r.method.as_str(),
1775            ClientRequest::ListToolsRequest(r) => r.method.as_str(),
1776        }
1777    }
1778}
1779
1780ts_union!(
1781    export type ClientNotification =
1782    | CancelledNotification
1783    | ProgressNotification
1784    | InitializedNotification
1785    | RootsListChangedNotification
1786    | CustomClientNotification;
1787);
1788
1789ts_union!(
1790    export type ClientResult = box CreateMessageResult | ListRootsResult | CreateElicitationResult | EmptyResult;
1791);
1792
1793impl ClientResult {
1794    pub fn empty(_: ()) -> ClientResult {
1795        ClientResult::EmptyResult(EmptyResult {})
1796    }
1797}
1798
1799pub type ClientJsonRpcMessage = JsonRpcMessage<ClientRequest, ClientResult, ClientNotification>;
1800
1801ts_union!(
1802    export type ServerRequest =
1803    | PingRequest
1804    | CreateMessageRequest
1805    | ListRootsRequest
1806    | CreateElicitationRequest;
1807);
1808
1809ts_union!(
1810    export type ServerNotification =
1811    | CancelledNotification
1812    | ProgressNotification
1813    | LoggingMessageNotification
1814    | ResourceUpdatedNotification
1815    | ResourceListChangedNotification
1816    | ToolListChangedNotification
1817    | PromptListChangedNotification;
1818);
1819
1820ts_union!(
1821    export type ServerResult =
1822    | InitializeResult
1823    | CompleteResult
1824    | GetPromptResult
1825    | ListPromptsResult
1826    | ListResourcesResult
1827    | ListResourceTemplatesResult
1828    | ReadResourceResult
1829    | CallToolResult
1830    | ListToolsResult
1831    | CreateElicitationResult
1832    | EmptyResult
1833    ;
1834);
1835
1836impl ServerResult {
1837    pub fn empty(_: ()) -> ServerResult {
1838        ServerResult::EmptyResult(EmptyResult {})
1839    }
1840}
1841
1842pub type ServerJsonRpcMessage = JsonRpcMessage<ServerRequest, ServerResult, ServerNotification>;
1843
1844impl TryInto<CancelledNotification> for ServerNotification {
1845    type Error = ServerNotification;
1846    fn try_into(self) -> Result<CancelledNotification, Self::Error> {
1847        if let ServerNotification::CancelledNotification(t) = self {
1848            Ok(t)
1849        } else {
1850            Err(self)
1851        }
1852    }
1853}
1854
1855impl TryInto<CancelledNotification> for ClientNotification {
1856    type Error = ClientNotification;
1857    fn try_into(self) -> Result<CancelledNotification, Self::Error> {
1858        if let ClientNotification::CancelledNotification(t) = self {
1859            Ok(t)
1860        } else {
1861            Err(self)
1862        }
1863    }
1864}
1865
1866// =============================================================================
1867// TESTS
1868// =============================================================================
1869
1870#[cfg(test)]
1871mod tests {
1872    use serde_json::json;
1873
1874    use super::*;
1875
1876    #[test]
1877    fn test_notification_serde() {
1878        let raw = json!( {
1879            "jsonrpc": JsonRpcVersion2_0,
1880            "method": InitializedNotificationMethod,
1881        });
1882        let message: ClientJsonRpcMessage =
1883            serde_json::from_value(raw.clone()).expect("invalid notification");
1884        match &message {
1885            ClientJsonRpcMessage::Notification(JsonRpcNotification {
1886                notification: ClientNotification::InitializedNotification(_n),
1887                ..
1888            }) => {}
1889            _ => panic!("Expected Notification"),
1890        }
1891        let json = serde_json::to_value(message).expect("valid json");
1892        assert_eq!(json, raw);
1893    }
1894
1895    #[test]
1896    fn test_custom_client_notification_roundtrip() {
1897        let raw = json!( {
1898            "jsonrpc": JsonRpcVersion2_0,
1899            "method": "notifications/custom",
1900            "params": {"foo": "bar"},
1901        });
1902
1903        let message: ClientJsonRpcMessage =
1904            serde_json::from_value(raw.clone()).expect("invalid notification");
1905        match &message {
1906            ClientJsonRpcMessage::Notification(JsonRpcNotification {
1907                notification: ClientNotification::CustomClientNotification(notification),
1908                ..
1909            }) => {
1910                assert_eq!(notification.method, "notifications/custom");
1911                assert_eq!(
1912                    notification
1913                        .params
1914                        .as_ref()
1915                        .and_then(|p| p.get("foo"))
1916                        .expect("foo present"),
1917                    "bar"
1918                );
1919            }
1920            _ => panic!("Expected custom client notification"),
1921        }
1922
1923        let json = serde_json::to_value(message).expect("valid json");
1924        assert_eq!(json, raw);
1925    }
1926
1927    #[test]
1928    fn test_request_conversion() {
1929        let raw = json!( {
1930            "jsonrpc": JsonRpcVersion2_0,
1931            "id": 1,
1932            "method": "request",
1933            "params": {"key": "value"},
1934        });
1935        let message: JsonRpcMessage = serde_json::from_value(raw.clone()).expect("invalid request");
1936
1937        match &message {
1938            JsonRpcMessage::Request(r) => {
1939                assert_eq!(r.id, RequestId::Number(1));
1940                assert_eq!(r.request.method, "request");
1941                assert_eq!(
1942                    &r.request.params,
1943                    json!({"key": "value"})
1944                        .as_object()
1945                        .expect("should be an object")
1946                );
1947            }
1948            _ => panic!("Expected Request"),
1949        }
1950        let json = serde_json::to_value(&message).expect("valid json");
1951        assert_eq!(json, raw);
1952    }
1953
1954    #[test]
1955    fn test_initial_request_response_serde() {
1956        let request = json!({
1957          "jsonrpc": "2.0",
1958          "id": 1,
1959          "method": "initialize",
1960          "params": {
1961            "protocolVersion": "2024-11-05",
1962            "capabilities": {
1963              "roots": {
1964                "listChanged": true
1965              },
1966              "sampling": {}
1967            },
1968            "clientInfo": {
1969              "name": "ExampleClient",
1970              "version": "1.0.0"
1971            }
1972          }
1973        });
1974        let raw_response_json = json!({
1975          "jsonrpc": "2.0",
1976          "id": 1,
1977          "result": {
1978            "protocolVersion": "2024-11-05",
1979            "capabilities": {
1980              "logging": {},
1981              "prompts": {
1982                "listChanged": true
1983              },
1984              "resources": {
1985                "subscribe": true,
1986                "listChanged": true
1987              },
1988              "tools": {
1989                "listChanged": true
1990              }
1991            },
1992            "serverInfo": {
1993              "name": "ExampleServer",
1994              "version": "1.0.0"
1995            }
1996          }
1997        });
1998        let request: ClientJsonRpcMessage =
1999            serde_json::from_value(request.clone()).expect("invalid request");
2000        let (request, id) = request.into_request().expect("should be a request");
2001        assert_eq!(id, RequestId::Number(1));
2002        match request {
2003            ClientRequest::InitializeRequest(Request {
2004                method: _,
2005                params:
2006                    InitializeRequestParam {
2007                        protocol_version: _,
2008                        capabilities,
2009                        client_info,
2010                    },
2011                ..
2012            }) => {
2013                assert_eq!(capabilities.roots.unwrap().list_changed, Some(true));
2014                assert_eq!(capabilities.sampling.unwrap().len(), 0);
2015                assert_eq!(client_info.name, "ExampleClient");
2016                assert_eq!(client_info.version, "1.0.0");
2017            }
2018            _ => panic!("Expected InitializeRequest"),
2019        }
2020        let server_response: ServerJsonRpcMessage =
2021            serde_json::from_value(raw_response_json.clone()).expect("invalid response");
2022        let (response, id) = server_response
2023            .clone()
2024            .into_response()
2025            .expect("expect response");
2026        assert_eq!(id, RequestId::Number(1));
2027        match response {
2028            ServerResult::InitializeResult(InitializeResult {
2029                protocol_version: _,
2030                capabilities,
2031                server_info,
2032                instructions,
2033            }) => {
2034                assert_eq!(capabilities.logging.unwrap().len(), 0);
2035                assert_eq!(capabilities.prompts.unwrap().list_changed, Some(true));
2036                assert_eq!(
2037                    capabilities.resources.as_ref().unwrap().subscribe,
2038                    Some(true)
2039                );
2040                assert_eq!(capabilities.resources.unwrap().list_changed, Some(true));
2041                assert_eq!(capabilities.tools.unwrap().list_changed, Some(true));
2042                assert_eq!(server_info.name, "ExampleServer");
2043                assert_eq!(server_info.version, "1.0.0");
2044                assert_eq!(server_info.icons, None);
2045                assert_eq!(instructions, None);
2046            }
2047            other => panic!("Expected InitializeResult, got {other:?}"),
2048        }
2049
2050        let server_response_json: Value = serde_json::to_value(&server_response).expect("msg");
2051
2052        assert_eq!(server_response_json, raw_response_json);
2053    }
2054
2055    #[test]
2056    fn test_negative_and_large_request_ids() {
2057        // Test negative ID
2058        let negative_id_json = json!({
2059            "jsonrpc": "2.0",
2060            "id": -1,
2061            "method": "test",
2062            "params": {}
2063        });
2064
2065        let message: JsonRpcMessage =
2066            serde_json::from_value(negative_id_json.clone()).expect("Should parse negative ID");
2067
2068        match &message {
2069            JsonRpcMessage::Request(r) => {
2070                assert_eq!(r.id, RequestId::Number(-1));
2071            }
2072            _ => panic!("Expected Request"),
2073        }
2074
2075        // Test roundtrip serialization
2076        let serialized = serde_json::to_value(&message).expect("Should serialize");
2077        assert_eq!(serialized, negative_id_json);
2078
2079        // Test large negative ID
2080        let large_negative_json = json!({
2081            "jsonrpc": "2.0",
2082            "id": -9007199254740991i64,  // JavaScript's MIN_SAFE_INTEGER
2083            "method": "test",
2084            "params": {}
2085        });
2086
2087        let message: JsonRpcMessage = serde_json::from_value(large_negative_json.clone())
2088            .expect("Should parse large negative ID");
2089
2090        match &message {
2091            JsonRpcMessage::Request(r) => {
2092                assert_eq!(r.id, RequestId::Number(-9007199254740991i64));
2093            }
2094            _ => panic!("Expected Request"),
2095        }
2096
2097        // Test large positive ID (JavaScript's MAX_SAFE_INTEGER)
2098        let large_positive_json = json!({
2099            "jsonrpc": "2.0",
2100            "id": 9007199254740991i64,
2101            "method": "test",
2102            "params": {}
2103        });
2104
2105        let message: JsonRpcMessage = serde_json::from_value(large_positive_json.clone())
2106            .expect("Should parse large positive ID");
2107
2108        match &message {
2109            JsonRpcMessage::Request(r) => {
2110                assert_eq!(r.id, RequestId::Number(9007199254740991i64));
2111            }
2112            _ => panic!("Expected Request"),
2113        }
2114
2115        // Test zero ID
2116        let zero_id_json = json!({
2117            "jsonrpc": "2.0",
2118            "id": 0,
2119            "method": "test",
2120            "params": {}
2121        });
2122
2123        let message: JsonRpcMessage =
2124            serde_json::from_value(zero_id_json.clone()).expect("Should parse zero ID");
2125
2126        match &message {
2127            JsonRpcMessage::Request(r) => {
2128                assert_eq!(r.id, RequestId::Number(0));
2129            }
2130            _ => panic!("Expected Request"),
2131        }
2132    }
2133
2134    #[test]
2135    fn test_protocol_version_order() {
2136        let v1 = ProtocolVersion::V_2024_11_05;
2137        let v2 = ProtocolVersion::V_2025_03_26;
2138        assert!(v1 < v2);
2139    }
2140
2141    #[test]
2142    fn test_icon_serialization() {
2143        let icon = Icon {
2144            src: "https://example.com/icon.png".to_string(),
2145            mime_type: Some("image/png".to_string()),
2146            sizes: Some(vec!["48x48".to_string()]),
2147        };
2148
2149        let json = serde_json::to_value(&icon).unwrap();
2150        assert_eq!(json["src"], "https://example.com/icon.png");
2151        assert_eq!(json["mimeType"], "image/png");
2152        assert_eq!(json["sizes"][0], "48x48");
2153
2154        // Test deserialization
2155        let deserialized: Icon = serde_json::from_value(json).unwrap();
2156        assert_eq!(deserialized, icon);
2157    }
2158
2159    #[test]
2160    fn test_icon_minimal() {
2161        let icon = Icon {
2162            src: "data:image/svg+xml;base64,PHN2Zy8+".to_string(),
2163            mime_type: None,
2164            sizes: None,
2165        };
2166
2167        let json = serde_json::to_value(&icon).unwrap();
2168        assert_eq!(json["src"], "data:image/svg+xml;base64,PHN2Zy8+");
2169        assert!(json.get("mimeType").is_none());
2170        assert!(json.get("sizes").is_none());
2171    }
2172
2173    #[test]
2174    fn test_implementation_with_icons() {
2175        let implementation = Implementation {
2176            name: "test-server".to_string(),
2177            title: Some("Test Server".to_string()),
2178            version: "1.0.0".to_string(),
2179            icons: Some(vec![
2180                Icon {
2181                    src: "https://example.com/icon.png".to_string(),
2182                    mime_type: Some("image/png".to_string()),
2183                    sizes: Some(vec!["48x48".to_string()]),
2184                },
2185                Icon {
2186                    src: "https://example.com/icon.svg".to_string(),
2187                    mime_type: Some("image/svg+xml".to_string()),
2188                    sizes: Some(vec!["any".to_string()]),
2189                },
2190            ]),
2191            website_url: Some("https://example.com".to_string()),
2192        };
2193
2194        let json = serde_json::to_value(&implementation).unwrap();
2195        assert_eq!(json["name"], "test-server");
2196        assert_eq!(json["websiteUrl"], "https://example.com");
2197        assert!(json["icons"].is_array());
2198        assert_eq!(json["icons"][0]["src"], "https://example.com/icon.png");
2199        assert_eq!(json["icons"][0]["sizes"][0], "48x48");
2200        assert_eq!(json["icons"][1]["mimeType"], "image/svg+xml");
2201        assert_eq!(json["icons"][1]["sizes"][0], "any");
2202    }
2203
2204    #[test]
2205    fn test_backward_compatibility() {
2206        // Test that old JSON without icons still deserializes correctly
2207        let old_json = json!({
2208            "name": "legacy-server",
2209            "version": "0.9.0"
2210        });
2211
2212        let implementation: Implementation = serde_json::from_value(old_json).unwrap();
2213        assert_eq!(implementation.name, "legacy-server");
2214        assert_eq!(implementation.version, "0.9.0");
2215        assert_eq!(implementation.icons, None);
2216        assert_eq!(implementation.website_url, None);
2217    }
2218
2219    #[test]
2220    fn test_initialize_with_icons() {
2221        let init_result = InitializeResult {
2222            protocol_version: ProtocolVersion::default(),
2223            capabilities: ServerCapabilities::default(),
2224            server_info: Implementation {
2225                name: "icon-server".to_string(),
2226                title: None,
2227                version: "2.0.0".to_string(),
2228                icons: Some(vec![Icon {
2229                    src: "https://example.com/server.png".to_string(),
2230                    mime_type: Some("image/png".to_string()),
2231                    sizes: Some(vec!["48x48".to_string()]),
2232                }]),
2233                website_url: Some("https://docs.example.com".to_string()),
2234            },
2235            instructions: None,
2236        };
2237
2238        let json = serde_json::to_value(&init_result).unwrap();
2239        assert!(json["serverInfo"]["icons"].is_array());
2240        assert_eq!(
2241            json["serverInfo"]["icons"][0]["src"],
2242            "https://example.com/server.png"
2243        );
2244        assert_eq!(json["serverInfo"]["icons"][0]["sizes"][0], "48x48");
2245        assert_eq!(json["serverInfo"]["websiteUrl"], "https://docs.example.com");
2246    }
2247}