1use serde::{Deserialize, Serialize};
7
8#[derive(Debug, Clone, Serialize, Deserialize)]
10pub struct JsonRpcRequest {
11 pub jsonrpc: String,
13 pub id: Option<JsonRpcId>,
15 pub method: String,
17 #[serde(default, skip_serializing_if = "Option::is_none")]
19 pub params: Option<serde_json::Value>,
20}
21
22#[derive(Debug, Clone, Serialize, Deserialize)]
24pub struct JsonRpcResponse {
25 pub jsonrpc: String,
27 pub id: Option<JsonRpcId>,
29 #[serde(skip_serializing_if = "Option::is_none")]
31 pub result: Option<serde_json::Value>,
32 #[serde(skip_serializing_if = "Option::is_none")]
34 pub error: Option<JsonRpcError>,
35}
36
37impl JsonRpcResponse {
38 pub fn success(id: Option<JsonRpcId>, result: impl Serialize) -> Self {
40 Self {
41 jsonrpc: "2.0".into(),
42 id,
43 result: Some(serde_json::to_value(result).unwrap_or(serde_json::Value::Null)),
44 error: None,
45 }
46 }
47
48 pub fn error(id: Option<JsonRpcId>, code: i32, message: impl Into<String>) -> Self {
50 Self {
51 jsonrpc: "2.0".into(),
52 id,
53 result: None,
54 error: Some(JsonRpcError {
55 code,
56 message: message.into(),
57 data: None,
58 }),
59 }
60 }
61
62 pub fn error_with_data(
64 id: Option<JsonRpcId>,
65 code: i32,
66 message: impl Into<String>,
67 data: serde_json::Value,
68 ) -> Self {
69 Self {
70 jsonrpc: "2.0".into(),
71 id,
72 result: None,
73 error: Some(JsonRpcError {
74 code,
75 message: message.into(),
76 data: Some(data),
77 }),
78 }
79 }
80}
81
82#[derive(Debug, Clone, Serialize, Deserialize)]
84pub struct JsonRpcError {
85 pub code: i32,
87 pub message: String,
89 #[serde(skip_serializing_if = "Option::is_none")]
91 pub data: Option<serde_json::Value>,
92}
93
94#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Hash)]
96#[serde(untagged)]
97pub enum JsonRpcId {
98 String(String),
100 Number(i64),
102}
103
104#[derive(Debug, Clone, Serialize, Deserialize)]
106#[serde(untagged)]
107pub enum McpMessage {
108 Request(JsonRpcRequest),
110 Response(JsonRpcResponse),
112 Notification(JsonRpcRequest),
114}
115
116impl McpMessage {
117 pub fn parse(json: &str) -> crate::Result<Self> {
119 let value: serde_json::Value = serde_json::from_str(json)?;
120
121 if value.get("method").is_some() {
123 let request: JsonRpcRequest = serde_json::from_value(value)?;
124 if request.id.is_some() {
125 Ok(McpMessage::Request(request))
126 } else {
127 Ok(McpMessage::Notification(request))
128 }
129 } else if value.get("result").is_some() || value.get("error").is_some() {
130 let response: JsonRpcResponse = serde_json::from_value(value)?;
131 Ok(McpMessage::Response(response))
132 } else {
133 Err(crate::Error::InvalidParams("invalid MCP message".into()))
134 }
135 }
136
137 pub fn to_json(&self) -> crate::Result<String> {
139 Ok(serde_json::to_string(self)?)
140 }
141}
142
143#[derive(Debug, Clone, Serialize, Deserialize)]
149pub struct InitializeParams {
150 #[serde(rename = "protocolVersion")]
152 pub protocol_version: String,
153 pub capabilities: ClientCapabilities,
155 #[serde(rename = "clientInfo")]
157 pub client_info: ClientInfo,
158}
159
160#[derive(Debug, Clone, Serialize, Deserialize)]
162pub struct InitializeResult {
163 #[serde(rename = "protocolVersion")]
165 pub protocol_version: String,
166 pub capabilities: ServerCapabilities,
168 #[serde(rename = "serverInfo")]
170 pub server_info: ServerInfo,
171}
172
173#[derive(Debug, Clone, Default, Serialize, Deserialize)]
175pub struct ClientCapabilities {
176 #[serde(default)]
178 pub roots: Option<RootsCapability>,
179 #[serde(default)]
181 pub sampling: Option<serde_json::Value>,
182}
183
184#[derive(Debug, Clone, Serialize, Deserialize)]
186pub struct RootsCapability {
187 #[serde(rename = "listChanged", default)]
189 pub list_changed: bool,
190}
191
192#[derive(Debug, Clone, Default, Serialize, Deserialize)]
194pub struct ServerCapabilities {
195 #[serde(default, skip_serializing_if = "Option::is_none")]
197 pub tools: Option<ToolsCapability>,
198 #[serde(default, skip_serializing_if = "Option::is_none")]
200 pub resources: Option<ResourcesCapability>,
201 #[serde(default, skip_serializing_if = "Option::is_none")]
203 pub prompts: Option<PromptsCapability>,
204 #[serde(default, skip_serializing_if = "Option::is_none")]
206 pub logging: Option<serde_json::Value>,
207}
208
209#[derive(Debug, Clone, Default, Serialize, Deserialize)]
211pub struct ToolsCapability {
212 #[serde(rename = "listChanged", default)]
214 pub list_changed: bool,
215}
216
217#[derive(Debug, Clone, Default, Serialize, Deserialize)]
219pub struct ResourcesCapability {
220 #[serde(default)]
222 pub subscribe: bool,
223 #[serde(rename = "listChanged", default)]
225 pub list_changed: bool,
226}
227
228#[derive(Debug, Clone, Default, Serialize, Deserialize)]
230pub struct PromptsCapability {
231 #[serde(rename = "listChanged", default)]
233 pub list_changed: bool,
234}
235
236#[derive(Debug, Clone, Serialize, Deserialize)]
238pub struct ClientInfo {
239 pub name: String,
241 pub version: String,
243}
244
245#[derive(Debug, Clone, Serialize, Deserialize)]
247pub struct ServerInfo {
248 pub name: String,
250 pub version: String,
252}
253
254#[derive(Debug, Clone, Serialize, Deserialize)]
256pub struct ToolDefinition {
257 pub name: String,
259 pub description: String,
261 #[serde(rename = "inputSchema")]
263 pub input_schema: serde_json::Value,
264}
265
266#[derive(Debug, Clone, Serialize, Deserialize)]
268pub struct ToolCallParams {
269 pub name: String,
271 #[serde(default)]
273 pub arguments: serde_json::Value,
274}
275
276#[derive(Debug, Clone, Serialize, Deserialize)]
278pub struct ToolCallResult {
279 pub content: Vec<ContentItem>,
281 #[serde(rename = "isError", default)]
283 pub is_error: bool,
284}
285
286#[derive(Debug, Clone, Serialize, Deserialize)]
288#[serde(tag = "type")]
289pub enum ContentItem {
290 #[serde(rename = "text")]
292 Text {
293 text: String,
295 },
296 #[serde(rename = "image")]
298 Image {
299 data: String,
301 #[serde(rename = "mimeType")]
303 mime_type: String,
304 },
305 #[serde(rename = "resource")]
307 Resource {
308 uri: String,
310 #[serde(rename = "mimeType", skip_serializing_if = "Option::is_none")]
312 mime_type: Option<String>,
313 #[serde(skip_serializing_if = "Option::is_none")]
315 text: Option<String>,
316 },
317}
318
319impl ContentItem {
320 pub fn text(text: impl Into<String>) -> Self {
322 ContentItem::Text { text: text.into() }
323 }
324
325 pub fn image(data: impl Into<String>, mime_type: impl Into<String>) -> Self {
327 ContentItem::Image {
328 data: data.into(),
329 mime_type: mime_type.into(),
330 }
331 }
332}
333
334#[derive(Debug, Clone, Serialize, Deserialize)]
336pub struct ListToolsResult {
337 pub tools: Vec<ToolDefinition>,
339}