//! MCP JSON-RPC 2.0 protocol types for the Streamable HTTP transport. //! //! Only the subset needed for `initialize`, `tools/list`, and `tools/call`. use serde::{Deserialize, Serialize}; use serde_json::Value; pub const MCP_PROTOCOL_VERSION: &str = "2025-06-18"; #[derive(Debug, Deserialize)] pub struct JsonRpcRequest { #[allow(dead_code)] pub jsonrpc: String, #[serde(default)] pub id: Option, pub method: String, #[serde(default)] pub params: Option, } #[derive(Debug, Serialize)] pub struct JsonRpcResponse { pub jsonrpc: &'static str, pub id: Value, #[serde(skip_serializing_if = "Option::is_none")] pub result: Option, #[serde(skip_serializing_if = "Option::is_none")] pub error: Option, } impl JsonRpcResponse { pub fn ok(id: Value, result: Value) -> Self { Self { jsonrpc: "2.0", id, result: Some(result), error: None, } } pub fn err(id: Value, code: i32, message: impl Into) -> Self { Self { jsonrpc: "2.0", id, result: None, error: Some(JsonRpcError { code, message: message.into(), data: None, }), } } } #[derive(Debug, Serialize)] pub struct JsonRpcError { pub code: i32, pub message: String, #[serde(skip_serializing_if = "Option::is_none")] pub data: Option, } pub mod codes { pub const PARSE_ERROR: i32 = -32700; pub const METHOD_NOT_FOUND: i32 = -32601; pub const INVALID_PARAMS: i32 = -32602; pub const INTERNAL_ERROR: i32 = -32603; /// MCP-defined: a `resources/read` (or subscribe) named an unknown uri. pub const RESOURCE_NOT_FOUND: i32 = -32002; /// An in-flight request was cancelled before it completed. Same code LSP /// uses for `ContentModified`/cancellation. pub const REQUEST_CANCELLED: i32 = -32800; } #[derive(Debug, Serialize)] pub struct InitializeResult { #[serde(rename = "protocolVersion")] pub protocol_version: &'static str, pub capabilities: ServerCapabilities, #[serde(rename = "serverInfo")] pub server_info: ServerInfo, } #[derive(Debug, Serialize)] pub struct ServerCapabilities { pub tools: ToolsCapability, /// Only advertised when the server was configured with a resource /// registry. `subscribe` stays `false` until the push layer lands. #[serde(skip_serializing_if = "Option::is_none")] pub resources: Option, } #[derive(Debug, Serialize)] pub struct ToolsCapability { #[serde(rename = "listChanged")] pub list_changed: bool, } #[derive(Debug, Serialize)] pub struct ResourcesCapability { pub subscribe: bool, #[serde(rename = "listChanged")] pub list_changed: bool, } #[derive(Debug, Serialize)] pub struct ServerInfo { pub name: String, pub version: String, } #[derive(Debug, Deserialize)] pub struct CallToolParams { pub name: String, #[serde(default)] pub arguments: Value, } /// `resources/subscribe` and `resources/unsubscribe` param object. #[derive(Debug, Deserialize)] pub struct SubscribeParams { pub uri: String, } /// `notifications/cancelled` param object (client → server). `requestId` is the /// id of the request being cancelled; `reason` is optional free text. #[derive(Debug, Deserialize)] pub struct CancelledParams { #[serde(rename = "requestId")] pub request_id: Value, #[serde(default)] #[allow(dead_code)] pub reason: Option, }