1use serde::{Deserialize, Serialize};
4use serde_json::Value;
5
6pub const SUPPORTED_PROTOCOL_VERSIONS: [&str; 3] = ["2025-11-25", "2025-06-18", "2024-11-05"];
13
14pub const LATEST_PROTOCOL_VERSION: &str = SUPPORTED_PROTOCOL_VERSIONS[0];
16
17#[derive(Debug, Clone, Serialize, Deserialize)]
19pub struct JsonRpcRequest {
20 pub jsonrpc: String,
22 #[serde(default, skip_serializing_if = "Option::is_none")]
24 pub id: Option<Value>,
25 pub method: String,
27 #[serde(default, skip_serializing_if = "Option::is_none")]
29 pub params: Option<Value>,
30}
31
32#[derive(Debug, Clone, Serialize)]
35pub struct JsonRpcResponse {
36 pub jsonrpc: String,
38 pub id: Value,
40 #[serde(skip_serializing_if = "Option::is_none")]
42 pub result: Option<JsonRpcResult>,
43 #[serde(skip_serializing_if = "Option::is_none")]
45 pub error: Option<McpError>,
46}
47
48impl JsonRpcResponse {
49 pub fn success(id: Value, result: JsonRpcResult) -> Self {
51 Self { jsonrpc: "2.0".into(), id, result: Some(result), error: None }
52 }
53
54 pub fn error(id: Value, error: McpError) -> Self {
56 Self { jsonrpc: "2.0".into(), id, result: None, error: Some(error) }
57 }
58}
59
60#[derive(Debug, Clone, Serialize)]
64#[serde(untagged)]
65pub enum JsonRpcResult {
66 Initialize {
68 #[serde(rename = "protocolVersion")]
70 protocol_version: String,
71 capabilities: Value,
73 #[serde(rename = "serverInfo")]
75 server_info: ServerInfo,
76 #[serde(skip_serializing_if = "Option::is_none")]
80 instructions: Option<String>,
81 },
82 ToolsList {
84 tools: Vec<ToolDescription>,
86 },
87 ToolsCall {
89 content: Vec<Value>,
91 #[serde(rename = "isError", skip_serializing_if = "std::ops::Not::not")]
93 is_error: bool,
94 },
95 Empty {},
97}
98
99#[derive(Debug, Clone, Serialize)]
101pub struct ServerInfo {
102 pub name: String,
104 pub version: String,
106}
107
108#[derive(Debug, Clone, Serialize)]
110pub struct McpError {
111 pub code: i32,
114 pub message: String,
116 #[serde(skip_serializing_if = "Option::is_none")]
118 pub data: Option<Value>,
119}
120
121#[derive(Debug, Clone, Serialize)]
123pub struct ToolDescription {
124 pub name: String,
127 pub description: String,
129 #[serde(rename = "inputSchema")]
131 pub input_schema: Value,
132}
133
134#[cfg(test)]
135mod tests_mcp_protocol {
136 #[allow(unused_imports)]
138 use super::*;
139
140 use crate::mcp::McpError;
141 use crate::mcp::protocol::{
142 JsonRpcRequest, JsonRpcResponse, JsonRpcResult, ServerInfo, ToolDescription,
143 };
144 use serde_json::json;
145
146 #[test]
147 fn initialize_request_parse() {
148 let raw = json!({
149 "jsonrpc": "2.0",
150 "id": 1,
151 "method": "initialize",
152 "params": {"protocolVersion": "2024-11-05"}
153 });
154 let req: JsonRpcRequest = serde_json::from_value(raw).expect("parse");
155 assert_eq!(req.jsonrpc, "2.0");
156 assert_eq!(req.method, "initialize");
157 assert_eq!(req.id, Some(json!(1)));
158 }
159
160 #[test]
161 fn tools_list_response_shape() {
162 let tools = vec![ToolDescription {
163 name: "greet".into(),
164 description: "Greet by name".into(),
165 input_schema: json!({"type": "object", "properties": {"name": {"type": "string"}}}),
166 }];
167 let resp = JsonRpcResponse::success(json!(1), JsonRpcResult::ToolsList { tools });
168 let raw = serde_json::to_value(&resp).expect("ser");
169 assert_eq!(raw["jsonrpc"], "2.0");
170 assert_eq!(raw["id"], 1);
171 assert!(raw["result"]["tools"].is_array());
172 assert_eq!(raw["result"]["tools"][0]["name"], "greet");
173 }
174
175 #[test]
176 fn error_response_shape() {
177 let resp = JsonRpcResponse::error(
178 json!(2),
179 McpError { code: -32601, message: "Method not found".into(), data: None },
180 );
181 let raw = serde_json::to_value(&resp).expect("ser");
182 assert_eq!(raw["error"]["code"], -32601);
183 assert_eq!(raw["error"]["message"], "Method not found");
184 assert!(raw["result"].is_null());
185 }
186
187 #[test]
190 fn each_result_variant_serialises_to_its_own_shape() {
191 let call = JsonRpcResult::ToolsCall {
192 content: vec![json!({"type": "text", "text": "hi"})],
193 is_error: true,
194 };
195 let raw = serde_json::to_value(&call).expect("ser");
196 assert_eq!(raw["content"][0]["text"], "hi");
197 assert_eq!(raw["isError"], true);
198 }
199
200 #[test]
201 fn ping_result_serialises_to_an_empty_object() {
202 let resp = JsonRpcResponse::success(json!(9), JsonRpcResult::Empty {});
203 let raw = serde_json::to_value(&resp).expect("ser");
204 assert_eq!(raw["result"], json!({}));
205 }
206
207 #[test]
208 fn initialize_response_shape() {
209 let resp = JsonRpcResponse::success(
210 json!(1),
211 JsonRpcResult::Initialize {
212 protocol_version: "2024-11-05".into(),
213 capabilities: json!({"tools": {}}),
214 server_info: ServerInfo { name: "probe".into(), version: "0.0.1".into() },
215 instructions: None,
216 },
217 );
218 let raw = serde_json::to_value(&resp).expect("ser");
219 assert_eq!(raw["result"]["protocolVersion"], "2024-11-05");
220 assert_eq!(raw["result"]["serverInfo"]["name"], "probe");
221 }
222}