1use serde::{Deserialize, Serialize};
6use std::collections::HashMap;
7
8pub const PROTOCOL_VERSION: &str = "2024-11-05";
10
11#[derive(Debug, Clone, Serialize, Deserialize)]
17pub struct JsonRpcRequest {
18 pub jsonrpc: String,
19 pub id: RequestId,
20 pub method: String,
21 #[serde(skip_serializing_if = "Option::is_none")]
22 pub params: Option<serde_json::Value>,
23}
24
25impl JsonRpcRequest {
26 pub fn new(id: impl Into<RequestId>, method: impl Into<String>) -> Self {
27 Self {
28 jsonrpc: "2.0".to_string(),
29 id: id.into(),
30 method: method.into(),
31 params: None,
32 }
33 }
34
35 pub fn with_params(mut self, params: serde_json::Value) -> Self {
36 self.params = Some(params);
37 self
38 }
39}
40
41#[derive(Debug, Clone, Serialize, Deserialize)]
43pub struct JsonRpcResponse {
44 pub jsonrpc: String,
45 pub id: RequestId,
46 #[serde(skip_serializing_if = "Option::is_none")]
47 pub result: Option<serde_json::Value>,
48 #[serde(skip_serializing_if = "Option::is_none")]
49 pub error: Option<JsonRpcError>,
50}
51
52#[derive(Debug, Clone, Serialize, Deserialize)]
54pub struct JsonRpcError {
55 pub code: i32,
56 pub message: String,
57 #[serde(skip_serializing_if = "Option::is_none")]
58 pub data: Option<serde_json::Value>,
59}
60
61#[derive(Debug, Clone, Serialize, Deserialize)]
63pub struct JsonRpcNotification {
64 pub jsonrpc: String,
65 pub method: String,
66 #[serde(skip_serializing_if = "Option::is_none")]
67 pub params: Option<serde_json::Value>,
68}
69
70impl JsonRpcNotification {
71 pub fn new(method: impl Into<String>) -> Self {
72 Self {
73 jsonrpc: "2.0".to_string(),
74 method: method.into(),
75 params: None,
76 }
77 }
78
79 pub fn with_params(mut self, params: serde_json::Value) -> Self {
80 self.params = Some(params);
81 self
82 }
83}
84
85#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Hash)]
87#[serde(untagged)]
88pub enum RequestId {
89 String(String),
90 Number(i64),
91}
92
93impl From<i64> for RequestId {
94 fn from(n: i64) -> Self {
95 RequestId::Number(n)
96 }
97}
98
99impl From<String> for RequestId {
100 fn from(s: String) -> Self {
101 RequestId::String(s)
102 }
103}
104
105impl From<&str> for RequestId {
106 fn from(s: &str) -> Self {
107 RequestId::String(s.to_string())
108 }
109}
110
111#[derive(Debug, Clone, Serialize, Deserialize)]
117#[serde(rename_all = "camelCase")]
118pub struct InitializeParams {
119 pub protocol_version: String,
120 pub capabilities: ClientCapabilities,
121 pub client_info: Implementation,
122}
123
124#[derive(Debug, Clone, Serialize, Deserialize)]
126#[serde(rename_all = "camelCase")]
127pub struct InitializeResult {
128 pub protocol_version: String,
129 pub capabilities: ServerCapabilities,
130 pub server_info: Implementation,
131 #[serde(skip_serializing_if = "Option::is_none")]
132 pub instructions: Option<String>,
133}
134
135#[derive(Debug, Clone, Default, Serialize, Deserialize)]
137pub struct ClientCapabilities {
138 #[serde(skip_serializing_if = "Option::is_none")]
139 pub roots: Option<RootsCapability>,
140 #[serde(skip_serializing_if = "Option::is_none")]
141 pub sampling: Option<SamplingCapability>,
142 #[serde(skip_serializing_if = "Option::is_none")]
143 pub experimental: Option<HashMap<String, serde_json::Value>>,
144}
145
146#[derive(Debug, Clone, Default, Serialize, Deserialize)]
148#[serde(rename_all = "camelCase")]
149pub struct ServerCapabilities {
150 #[serde(skip_serializing_if = "Option::is_none")]
151 pub prompts: Option<PromptsCapability>,
152 #[serde(skip_serializing_if = "Option::is_none")]
153 pub resources: Option<ResourcesCapability>,
154 #[serde(skip_serializing_if = "Option::is_none")]
155 pub tools: Option<ToolsCapability>,
156 #[serde(skip_serializing_if = "Option::is_none")]
157 pub logging: Option<LoggingCapability>,
158 #[serde(skip_serializing_if = "Option::is_none")]
159 pub experimental: Option<HashMap<String, serde_json::Value>>,
160}
161
162#[derive(Debug, Clone, Serialize, Deserialize)]
164pub struct Implementation {
165 pub name: String,
166 pub version: String,
167}
168
169#[derive(Debug, Clone, Default, Serialize, Deserialize)]
174#[serde(rename_all = "camelCase")]
175pub struct RootsCapability {
176 #[serde(skip_serializing_if = "Option::is_none")]
177 pub list_changed: Option<bool>,
178}
179
180#[derive(Debug, Clone, Default, Serialize, Deserialize)]
181pub struct SamplingCapability {}
182
183#[derive(Debug, Clone, Default, Serialize, Deserialize)]
184#[serde(rename_all = "camelCase")]
185pub struct PromptsCapability {
186 #[serde(skip_serializing_if = "Option::is_none")]
187 pub list_changed: Option<bool>,
188}
189
190#[derive(Debug, Clone, Default, Serialize, Deserialize)]
191#[serde(rename_all = "camelCase")]
192pub struct ResourcesCapability {
193 #[serde(skip_serializing_if = "Option::is_none")]
194 pub subscribe: Option<bool>,
195 #[serde(skip_serializing_if = "Option::is_none")]
196 pub list_changed: Option<bool>,
197}
198
199#[derive(Debug, Clone, Default, Serialize, Deserialize)]
200#[serde(rename_all = "camelCase")]
201pub struct ToolsCapability {
202 #[serde(skip_serializing_if = "Option::is_none")]
203 pub list_changed: Option<bool>,
204}
205
206#[derive(Debug, Clone, Default, Serialize, Deserialize)]
207pub struct LoggingCapability {}
208
209#[derive(Debug, Clone, Serialize, Deserialize)]
215#[serde(rename_all = "camelCase")]
216pub struct McpTool {
217 pub name: String,
218 #[serde(skip_serializing_if = "Option::is_none")]
219 pub description: Option<String>,
220 pub input_schema: serde_json::Value,
221}
222
223#[derive(Debug, Clone, Default, Serialize, Deserialize)]
225pub struct ListToolsParams {
226 #[serde(skip_serializing_if = "Option::is_none")]
227 pub cursor: Option<String>,
228}
229
230#[derive(Debug, Clone, Serialize, Deserialize)]
232#[serde(rename_all = "camelCase")]
233pub struct ListToolsResult {
234 pub tools: Vec<McpTool>,
235 #[serde(skip_serializing_if = "Option::is_none")]
236 pub next_cursor: Option<String>,
237}
238
239#[derive(Debug, Clone, Serialize, Deserialize)]
241pub struct CallToolParams {
242 pub name: String,
243 #[serde(skip_serializing_if = "Option::is_none")]
244 pub arguments: Option<serde_json::Value>,
245}
246
247#[derive(Debug, Clone, Serialize, Deserialize)]
249#[serde(rename_all = "camelCase")]
250pub struct CallToolResult {
251 pub content: Vec<ToolContent>,
252 #[serde(default)]
253 pub is_error: bool,
254}
255
256#[derive(Debug, Clone, Serialize, Deserialize)]
258#[serde(tag = "type", rename_all = "camelCase")]
259pub enum ToolContent {
260 #[serde(rename = "text")]
261 Text { text: String },
262 #[serde(rename = "image")]
263 Image { data: String, mime_type: String },
264 #[serde(rename = "resource")]
265 Resource { resource: ResourceContent },
266}
267
268impl ToolContent {
269 pub fn text(s: impl Into<String>) -> Self {
270 ToolContent::Text { text: s.into() }
271 }
272
273 pub fn as_text(&self) -> Option<&str> {
274 match self {
275 ToolContent::Text { text } => Some(text),
276 _ => None,
277 }
278 }
279}
280
281#[derive(Debug, Clone, Serialize, Deserialize)]
287#[serde(rename_all = "camelCase")]
288pub struct ResourceContent {
289 pub uri: String,
290 #[serde(skip_serializing_if = "Option::is_none")]
291 pub mime_type: Option<String>,
292 #[serde(skip_serializing_if = "Option::is_none")]
293 pub text: Option<String>,
294 #[serde(skip_serializing_if = "Option::is_none")]
295 pub blob: Option<String>,
296}
297
298#[derive(Debug, Clone, Serialize, Deserialize)]
300#[serde(rename_all = "camelCase")]
301pub struct McpResource {
302 pub uri: String,
303 pub name: String,
304 #[serde(skip_serializing_if = "Option::is_none")]
305 pub description: Option<String>,
306 #[serde(skip_serializing_if = "Option::is_none")]
307 pub mime_type: Option<String>,
308}
309
310#[derive(Debug, Clone, Serialize, Deserialize)]
312#[serde(rename_all = "camelCase")]
313pub struct ListResourcesResult {
314 pub resources: Vec<McpResource>,
315 #[serde(skip_serializing_if = "Option::is_none")]
316 pub next_cursor: Option<String>,
317}
318
319#[derive(Debug, Clone, Serialize, Deserialize)]
325pub struct McpPrompt {
326 pub name: String,
327 #[serde(skip_serializing_if = "Option::is_none")]
328 pub description: Option<String>,
329 #[serde(skip_serializing_if = "Option::is_none")]
330 pub arguments: Option<Vec<PromptArgument>>,
331}
332
333#[derive(Debug, Clone, Serialize, Deserialize)]
335pub struct PromptArgument {
336 pub name: String,
337 #[serde(skip_serializing_if = "Option::is_none")]
338 pub description: Option<String>,
339 #[serde(skip_serializing_if = "Option::is_none")]
340 pub required: Option<bool>,
341}
342
343#[derive(Debug, Clone, Serialize, Deserialize)]
345#[serde(rename_all = "camelCase")]
346pub struct ListPromptsResult {
347 pub prompts: Vec<McpPrompt>,
348 #[serde(skip_serializing_if = "Option::is_none")]
349 pub next_cursor: Option<String>,
350}