1use serde::{Deserialize, Serialize};
7
8#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
10pub struct ServerInfo {
11 pub name: String,
13 pub version: String,
15}
16
17#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
19pub struct ClientInfo {
20 pub name: String,
22 pub version: String,
24}
25
26#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Default)]
28pub struct ServerCapabilities {
29 #[serde(skip_serializing_if = "Option::is_none")]
31 pub prompts: Option<PromptsCapability>,
32 #[serde(skip_serializing_if = "Option::is_none")]
34 pub resources: Option<ResourcesCapability>,
35 #[serde(skip_serializing_if = "Option::is_none")]
37 pub tools: Option<ToolsCapability>,
38 #[serde(skip_serializing_if = "Option::is_none")]
40 pub sampling: Option<SamplingCapability>,
41}
42
43#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Default)]
45pub struct ClientCapabilities {
46 #[serde(skip_serializing_if = "Option::is_none")]
48 pub sampling: Option<SamplingCapability>,
49}
50
51#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
53pub struct PromptsCapability {
54 #[serde(rename = "listChanged", skip_serializing_if = "Option::is_none")]
56 pub list_changed: Option<bool>,
57}
58
59#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
61pub struct ResourcesCapability {
62 #[serde(skip_serializing_if = "Option::is_none")]
64 pub subscribe: Option<bool>,
65 #[serde(rename = "listChanged", skip_serializing_if = "Option::is_none")]
67 pub list_changed: Option<bool>,
68}
69
70#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
72pub struct ToolsCapability {
73 #[serde(rename = "listChanged", skip_serializing_if = "Option::is_none")]
75 pub list_changed: Option<bool>,
76}
77
78#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
80pub struct SamplingCapability {}
81
82#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
84#[serde(tag = "type")]
85pub enum Content {
86 #[serde(rename = "text")]
88 Text {
89 text: String,
91 },
92 #[serde(rename = "image")]
94 Image {
95 data: String,
97 #[serde(rename = "mimeType")]
99 mime_type: String,
100 },
101}
102
103#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
105pub struct ResourceContent {
106 pub uri: String,
108 #[serde(rename = "mimeType", skip_serializing_if = "Option::is_none")]
110 pub mime_type: Option<String>,
111 #[serde(skip_serializing_if = "Option::is_none")]
113 pub text: Option<String>,
114 #[serde(skip_serializing_if = "Option::is_none")]
116 pub blob: Option<String>,
117}
118
119#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
121pub struct ToolResult {
122 pub content: Vec<Content>,
124 #[serde(rename = "isError", skip_serializing_if = "Option::is_none")]
126 pub is_error: Option<bool>,
127}
128
129#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
131pub struct ToolInfo {
132 pub name: String,
134 #[serde(skip_serializing_if = "Option::is_none")]
136 pub description: Option<String>,
137 #[serde(rename = "inputSchema")]
139 pub input_schema: serde_json::Value,
140}
141
142#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
144pub struct ResourceInfo {
145 pub uri: String,
147 pub name: String,
149 #[serde(skip_serializing_if = "Option::is_none")]
151 pub description: Option<String>,
152 #[serde(rename = "mimeType", skip_serializing_if = "Option::is_none")]
154 pub mime_type: Option<String>,
155}
156
157#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
159pub struct PromptInfo {
160 pub name: String,
162 #[serde(skip_serializing_if = "Option::is_none")]
164 pub description: Option<String>,
165 #[serde(skip_serializing_if = "Option::is_none")]
167 pub arguments: Option<Vec<PromptArgument>>,
168}
169
170#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
172pub struct PromptArgument {
173 pub name: String,
175 #[serde(skip_serializing_if = "Option::is_none")]
177 pub description: Option<String>,
178 pub required: bool,
180}
181
182#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
184pub struct PromptMessage {
185 pub role: String,
187 pub content: PromptContent,
189}
190
191#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
193#[serde(untagged)]
194pub enum PromptContent {
195 Text {
197 #[serde(rename = "type")]
199 content_type: String,
200 text: String,
202 },
203 Image {
205 #[serde(rename = "type")]
207 content_type: String,
208 data: String,
210 #[serde(rename = "mimeType")]
212 mime_type: String,
213 },
214}
215
216#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
218pub struct PromptResult {
219 #[serde(skip_serializing_if = "Option::is_none")]
221 pub description: Option<String>,
222 pub messages: Vec<PromptMessage>,
224}
225
226#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
230pub struct JsonRpcRequest {
231 pub jsonrpc: String,
233 pub id: serde_json::Value,
235 pub method: String,
237 #[serde(skip_serializing_if = "Option::is_none")]
239 pub params: Option<serde_json::Value>,
240}
241
242#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
244pub struct JsonRpcResponse {
245 pub jsonrpc: String,
247 pub id: serde_json::Value,
249 #[serde(skip_serializing_if = "Option::is_none")]
251 pub result: Option<serde_json::Value>,
252 #[serde(skip_serializing_if = "Option::is_none")]
254 pub error: Option<JsonRpcError>,
255}
256
257#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
259pub struct JsonRpcError {
260 pub code: i32,
262 pub message: String,
264 #[serde(skip_serializing_if = "Option::is_none")]
266 pub data: Option<serde_json::Value>,
267}
268
269#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
271pub struct JsonRpcNotification {
272 pub jsonrpc: String,
274 pub method: String,
276 #[serde(skip_serializing_if = "Option::is_none")]
278 pub params: Option<serde_json::Value>,
279}
280
281pub const PARSE_ERROR: i32 = -32700;
284pub const INVALID_REQUEST: i32 = -32600;
286pub const METHOD_NOT_FOUND: i32 = -32601;
288pub const INVALID_PARAMS: i32 = -32602;
290pub const INTERNAL_ERROR: i32 = -32603;
292
293pub const TOOL_NOT_FOUND: i32 = -32000;
296pub const RESOURCE_NOT_FOUND: i32 = -32001;
298pub const PROMPT_NOT_FOUND: i32 = -32002;
300
301impl JsonRpcRequest {
302 pub fn new<T: Serialize>(
304 id: serde_json::Value,
305 method: String,
306 params: Option<T>,
307 ) -> Result<Self, serde_json::Error> {
308 let params = match params {
309 Some(p) => Some(serde_json::to_value(p)?),
310 None => None,
311 };
312
313 Ok(Self {
314 jsonrpc: "2.0".to_string(),
315 id,
316 method,
317 params,
318 })
319 }
320}
321
322impl JsonRpcResponse {
323 pub fn success<T: Serialize>(
325 id: serde_json::Value,
326 result: T,
327 ) -> Result<Self, serde_json::Error> {
328 Ok(Self {
329 jsonrpc: "2.0".to_string(),
330 id,
331 result: Some(serde_json::to_value(result)?),
332 error: None,
333 })
334 }
335
336 pub fn error(
338 id: serde_json::Value,
339 code: i32,
340 message: String,
341 data: Option<serde_json::Value>,
342 ) -> Self {
343 Self {
344 jsonrpc: "2.0".to_string(),
345 id,
346 result: None,
347 error: Some(JsonRpcError {
348 code,
349 message,
350 data,
351 }),
352 }
353 }
354}
355
356impl JsonRpcNotification {
357 pub fn new<T: Serialize>(method: String, params: Option<T>) -> Result<Self, serde_json::Error> {
359 let params = match params {
360 Some(p) => Some(serde_json::to_value(p)?),
361 None => None,
362 };
363
364 Ok(Self {
365 jsonrpc: "2.0".to_string(),
366 method,
367 params,
368 })
369 }
370}
371
372impl Content {
375 pub fn text<S: Into<String>>(text: S) -> Self {
377 Self::Text { text: text.into() }
378 }
379
380 pub fn image<S: Into<String>>(data: S, mime_type: S) -> Self {
382 Self::Image {
383 data: data.into(),
384 mime_type: mime_type.into(),
385 }
386 }
387}
388
389impl PromptContent {
390 pub fn text<S: Into<String>>(text: S) -> Self {
392 Self::Text {
393 content_type: "text".to_string(),
394 text: text.into(),
395 }
396 }
397
398 pub fn image<S: Into<String>>(data: S, mime_type: S) -> Self {
400 Self::Image {
401 content_type: "image".to_string(),
402 data: data.into(),
403 mime_type: mime_type.into(),
404 }
405 }
406}
407
408#[cfg(test)]
409mod tests {
410 use super::*;
411 use serde_json::json;
412
413 #[test]
414 fn test_content_serialization() {
415 let text_content = Content::text("Hello, world!");
416 let json = serde_json::to_value(&text_content).unwrap();
417 assert_eq!(
418 json,
419 json!({
420 "type": "text",
421 "text": "Hello, world!"
422 })
423 );
424
425 let image_content = Content::image("data", "image/png");
426 let json = serde_json::to_value(&image_content).unwrap();
427 assert_eq!(
428 json,
429 json!({
430 "type": "image",
431 "data": "data",
432 "mimeType": "image/png"
433 })
434 );
435 }
436
437 #[test]
438 fn test_jsonrpc_request() {
439 let request = JsonRpcRequest::new(
440 json!(1),
441 "test_method".to_string(),
442 Some(json!({"param": "value"})),
443 )
444 .unwrap();
445
446 assert_eq!(request.jsonrpc, "2.0");
447 assert_eq!(request.method, "test_method");
448 assert_eq!(request.id, json!(1));
449 }
450
451 #[test]
452 fn test_jsonrpc_response() {
453 let response = JsonRpcResponse::success(json!(1), json!({"result": "success"})).unwrap();
454 assert_eq!(response.jsonrpc, "2.0");
455 assert_eq!(response.id, json!(1));
456 assert!(response.result.is_some());
457 assert!(response.error.is_none());
458
459 let error_response = JsonRpcResponse::error(
460 json!(1),
461 INVALID_PARAMS,
462 "Invalid parameters".to_string(),
463 None,
464 );
465 assert!(error_response.result.is_none());
466 assert!(error_response.error.is_some());
467 }
468}