1use serde::{Deserialize, Serialize};
2use serde_json::Value;
3use thiserror::Error;
4
5#[derive(Debug, Clone, Serialize, Deserialize)]
6pub struct JsonRpcRequest {
7 pub jsonrpc: String,
8 pub method: String,
9 #[serde(skip_serializing_if = "Option::is_none")]
10 pub params: Option<Value>,
11 #[serde(skip_serializing_if = "Option::is_none")]
12 pub id: Option<Value>,
13}
14
15#[derive(Debug, Serialize, Deserialize)]
16pub struct JsonRpcResponse {
17 pub jsonrpc: String,
18 #[serde(skip_serializing_if = "Option::is_none")]
19 pub result: Option<Value>,
20 #[serde(skip_serializing_if = "Option::is_none")]
21 pub error: Option<JsonRpcError>,
22 pub id: Value,
23}
24
25#[derive(Debug, Serialize, Deserialize)]
26pub struct JsonRpcError {
27 pub code: i32,
28 pub message: String,
29 #[serde(skip_serializing_if = "Option::is_none")]
30 pub data: Option<Value>,
31}
32
33#[derive(Debug, Error)]
34pub enum McpError {
35 #[error("Invalid request: {0}")]
36 InvalidRequest(String),
37
38 #[error("Method not found: {0}")]
39 MethodNotFound(String),
40
41 #[error("Tool error: {0}")]
42 ToolError(#[from] ToolError),
43
44 #[error("JSON error: {0}")]
45 JsonError(#[from] serde_json::Error),
46}
47
48#[derive(Debug, Error)]
49pub enum ToolError {
50 #[error("Invalid arguments: {0}")]
51 InvalidArguments(String),
52
53 #[error("Execution error: {0}")]
54 ExecutionError(String),
55
56 #[error("Network error: {0}")]
57 NetworkError(String),
58
59 #[error("Timeout")]
60 Timeout,
61}
62
63#[derive(Debug, Clone, Serialize, Deserialize)]
64pub struct ToolResult {
65 #[serde(rename = "type")]
66 pub result_type: String,
67 pub content: Vec<TextContent>,
68}
69
70#[derive(Debug, Clone, Serialize, Deserialize)]
71pub struct TextContent {
72 #[serde(rename = "type")]
73 pub content_type: String,
74 pub text: String,
75}
76
77impl ToolResult {
78 pub fn text(content: String) -> Self {
79 Self {
80 result_type: "content".to_string(),
81 content: vec![TextContent {
82 content_type: "text".to_string(),
83 text: content,
84 }],
85 }
86 }
87}
88
89impl JsonRpcError {
90 pub fn invalid_request(message: String) -> Self {
91 Self {
92 code: -32600,
93 message,
94 data: None,
95 }
96 }
97
98 pub fn method_not_found(method: String) -> Self {
99 Self {
100 code: -32601,
101 message: format!("Method not found: {method}"),
102 data: None,
103 }
104 }
105
106 pub fn internal_error(message: String) -> Self {
107 Self {
108 code: -32603,
109 message,
110 data: None,
111 }
112 }
113}
114
115impl JsonRpcResponse {
116 pub fn error(id: Option<Value>, code: i32, message: &str) -> Self {
117 Self {
118 jsonrpc: "2.0".to_string(),
119 result: None,
120 error: Some(JsonRpcError {
121 code,
122 message: message.to_string(),
123 data: None,
124 }),
125 id: id.unwrap_or(serde_json::Value::Null),
126 }
127 }
128}
129
130#[cfg(test)]
131mod tests {
132 use serde_json::json;
133
134 use super::*;
135
136 #[test]
137 fn test_jsonrpc_request_serialization() {
138 let request = JsonRpcRequest {
139 jsonrpc: "2.0".to_string(),
140 method: "test".to_string(),
141 params: Some(json!({"key": "value"})),
142 id: Some(json!(1)),
143 };
144
145 let serialized = serde_json::to_string(&request).unwrap();
146 let deserialized: JsonRpcRequest = serde_json::from_str(&serialized).unwrap();
147
148 assert_eq!(deserialized.jsonrpc, "2.0");
149 assert_eq!(deserialized.method, "test");
150 assert_eq!(deserialized.params, Some(json!({"key": "value"})));
151 assert_eq!(deserialized.id, Some(json!(1)));
152 }
153
154 #[test]
155 fn test_jsonrpc_response_with_result() {
156 let response = JsonRpcResponse {
157 jsonrpc: "2.0".to_string(),
158 result: Some(json!({"status": "ok"})),
159 error: None,
160 id: json!(1),
161 };
162
163 let serialized = serde_json::to_string(&response).unwrap();
164 assert!(!serialized.contains("\"error\""));
165 assert!(serialized.contains("\"result\""));
166 }
167
168 #[test]
169 fn test_jsonrpc_response_with_error() {
170 let response = JsonRpcResponse {
171 jsonrpc: "2.0".to_string(),
172 result: None,
173 error: Some(JsonRpcError::method_not_found("unknown".to_string())),
174 id: json!(1),
175 };
176
177 let serialized = serde_json::to_string(&response).unwrap();
178 assert!(serialized.contains("\"error\""));
179 assert!(!serialized.contains("\"result\""));
180 }
181
182 #[test]
183 fn test_tool_result_creation() {
184 let result = ToolResult::text("Hello, world!".to_string());
185
186 assert_eq!(result.result_type, "content");
187 assert_eq!(result.content.len(), 1);
188 assert_eq!(result.content[0].content_type, "text");
189 assert_eq!(result.content[0].text, "Hello, world!");
190 }
191
192 #[test]
193 fn test_jsonrpc_error_codes() {
194 let invalid_request = JsonRpcError::invalid_request("bad request".to_string());
195 assert_eq!(invalid_request.code, -32600);
196
197 let method_not_found = JsonRpcError::method_not_found("unknown".to_string());
198 assert_eq!(method_not_found.code, -32601);
199
200 let internal_error = JsonRpcError::internal_error("server error".to_string());
201 assert_eq!(internal_error.code, -32603);
202 }
203
204 #[test]
205 fn test_tool_error_display() {
206 let error = ToolError::InvalidArguments("missing field".to_string());
207 assert_eq!(error.to_string(), "Invalid arguments: missing field");
208
209 let error = ToolError::ExecutionError("failed to process".to_string());
210 assert_eq!(error.to_string(), "Execution error: failed to process");
211
212 let error = ToolError::Timeout;
213 assert_eq!(error.to_string(), "Timeout");
214 }
215}