1use serde_json::Value;
7
8use crate::protocol::{
9 error_codes::*,
10 types::{
11 ErrorObject, JsonRpcError, JsonRpcMessage, JsonRpcNotification, JsonRpcRequest,
12 JsonRpcResponse, RequestId, JSONRPC_VERSION,
13 },
14};
15
16impl JsonRpcError {
17 pub fn new<S: Into<String>>(id: RequestId, code: i32, message: S) -> Self {
32 Self {
33 jsonrpc: JSONRPC_VERSION.to_string(),
34 id,
35 error: ErrorObject {
36 code,
37 message: message.into(),
38 data: None,
39 },
40 }
41 }
42
43 pub fn with_data<S: Into<String>>(
59 id: RequestId,
60 code: i32,
61 message: S,
62 data: Option<Value>,
63 ) -> Self {
64 Self {
65 jsonrpc: JSONRPC_VERSION.to_string(),
66 id,
67 error: ErrorObject {
68 code,
69 message: message.into(),
70 data,
71 },
72 }
73 }
74
75 pub fn parse_error(id: RequestId) -> Self {
79 Self::new(id, PARSE_ERROR, "Parse error")
80 }
81
82 pub fn invalid_request(id: RequestId) -> Self {
86 Self::new(id, INVALID_REQUEST, "Invalid Request")
87 }
88
89 pub fn method_not_found(id: RequestId) -> Self {
93 Self::new(id, METHOD_NOT_FOUND, "Method not found")
94 }
95
96 pub fn method_not_found_with_name<S: Into<String>>(id: RequestId, method: S) -> Self {
98 let method = method.into();
99 Self::with_data(
100 id,
101 METHOD_NOT_FOUND,
102 format!("Method '{}' not found", method),
103 Some(serde_json::json!({ "method": method })),
104 )
105 }
106
107 pub fn invalid_params(id: RequestId) -> Self {
111 Self::new(id, INVALID_PARAMS, "Invalid params")
112 }
113
114 pub fn invalid_params_with_message<S: Into<String>>(id: RequestId, details: S) -> Self {
116 Self::new(id, INVALID_PARAMS, details)
117 }
118
119 pub fn internal_error(id: RequestId) -> Self {
123 Self::new(id, INTERNAL_ERROR, "Internal error")
124 }
125
126 pub fn internal_error_with_message<S: Into<String>>(id: RequestId, details: S) -> Self {
128 Self::new(id, INTERNAL_ERROR, details)
129 }
130
131 pub fn tool_not_found<S: Into<String>>(id: RequestId, tool_name: S) -> Self {
135 let name = tool_name.into();
136 Self::with_data(
137 id,
138 TOOL_NOT_FOUND,
139 format!("Tool '{}' not found", name),
140 Some(serde_json::json!({ "tool": name })),
141 )
142 }
143
144 pub fn resource_not_found<S: Into<String>>(id: RequestId, uri: S) -> Self {
148 let uri = uri.into();
149 Self::with_data(
150 id,
151 RESOURCE_NOT_FOUND,
152 format!("Resource '{}' not found", uri),
153 Some(serde_json::json!({ "uri": uri })),
154 )
155 }
156
157 pub fn prompt_not_found<S: Into<String>>(id: RequestId, prompt_name: S) -> Self {
161 let name = prompt_name.into();
162 Self::with_data(
163 id,
164 PROMPT_NOT_FOUND,
165 format!("Prompt '{}' not found", name),
166 Some(serde_json::json!({ "prompt": name })),
167 )
168 }
169
170 pub fn custom<S: Into<String>>(id: RequestId, code: i32, message: S) -> Self {
172 Self::new(id, code, message)
173 }
174
175 pub fn custom_with_data<S: Into<String>>(
177 id: RequestId,
178 code: i32,
179 message: S,
180 data: Value,
181 ) -> Self {
182 Self::with_data(id, code, message, Some(data))
183 }
184}
185
186impl From<JsonRpcError> for JsonRpcMessage {
188 fn from(error: JsonRpcError) -> Self {
189 JsonRpcMessage::Error(error)
190 }
191}
192
193pub trait IntoJsonRpcMessage {
195 fn into_message(self) -> JsonRpcMessage;
196}
197
198impl IntoJsonRpcMessage for JsonRpcError {
199 fn into_message(self) -> JsonRpcMessage {
200 JsonRpcMessage::Error(self)
201 }
202}
203
204impl From<JsonRpcResponse> for JsonRpcMessage {
206 fn from(response: JsonRpcResponse) -> Self {
207 JsonRpcMessage::Response(response)
208 }
209}
210
211impl From<JsonRpcNotification> for JsonRpcMessage {
212 fn from(notification: JsonRpcNotification) -> Self {
213 JsonRpcMessage::Notification(notification)
214 }
215}
216
217impl From<JsonRpcRequest> for JsonRpcMessage {
218 fn from(request: JsonRpcRequest) -> Self {
219 JsonRpcMessage::Request(request)
220 }
221}
222
223impl TryFrom<JsonRpcMessage> for JsonRpcRequest {
224 type Error = crate::core::error::McpError;
225
226 fn try_from(msg: JsonRpcMessage) -> Result<Self, Self::Error> {
227 match msg {
228 JsonRpcMessage::Request(req) => Ok(req),
229 _ => Err(crate::core::error::McpError::Protocol(
230 "Not a JSON-RPC request".to_string(),
231 )),
232 }
233 }
234}
235
236impl TryFrom<JsonRpcMessage> for JsonRpcResponse {
237 type Error = crate::core::error::McpError;
238
239 fn try_from(msg: JsonRpcMessage) -> Result<Self, Self::Error> {
240 match msg {
241 JsonRpcMessage::Response(resp) => Ok(resp),
242 _ => Err(crate::core::error::McpError::Protocol(
243 "Not a JSON-RPC response".to_string(),
244 )),
245 }
246 }
247}
248
249impl TryFrom<JsonRpcMessage> for JsonRpcError {
250 type Error = crate::core::error::McpError;
251
252 fn try_from(msg: JsonRpcMessage) -> Result<Self, Self::Error> {
253 match msg {
254 JsonRpcMessage::Error(err) => Ok(err),
255 _ => Err(crate::core::error::McpError::Protocol(
256 "Not a JSON-RPC error".to_string(),
257 )),
258 }
259 }
260}
261
262impl TryFrom<JsonRpcMessage> for JsonRpcNotification {
263 type Error = crate::core::error::McpError;
264
265 fn try_from(msg: JsonRpcMessage) -> Result<Self, Self::Error> {
266 match msg {
267 JsonRpcMessage::Notification(notif) => Ok(notif),
268 _ => Err(crate::core::error::McpError::Protocol(
269 "Not a JSON-RPC notification".to_string(),
270 )),
271 }
272 }
273}
274
275#[cfg(test)]
276mod tests {
277 use super::*;
278 use serde_json::json;
279
280 #[test]
281 fn test_error_creation() {
282 let id = json!("test-123");
283
284 let error = JsonRpcError::new(id.clone(), -32601, "Method not found");
286 assert_eq!(error.jsonrpc, "2.0");
287 assert_eq!(error.id, id);
288 assert_eq!(error.error.code, -32601);
289 assert_eq!(error.error.message, "Method not found");
290 assert!(error.error.data.is_none());
291
292 let data = json!({"detail": "extra info"});
294 let error_with_data =
295 JsonRpcError::with_data(id.clone(), -32602, "Invalid params", Some(data.clone()));
296 assert_eq!(error_with_data.error.data, Some(data));
297 }
298
299 #[test]
300 fn test_standard_errors() {
301 let id = json!(123);
302
303 let parse_err = JsonRpcError::parse_error(id.clone());
305 assert_eq!(parse_err.error.code, PARSE_ERROR);
306 assert_eq!(parse_err.error.message, "Parse error");
307
308 let invalid_req = JsonRpcError::invalid_request(id.clone());
310 assert_eq!(invalid_req.error.code, INVALID_REQUEST);
311 assert_eq!(invalid_req.error.message, "Invalid Request");
312
313 let method_err = JsonRpcError::method_not_found(id.clone());
315 assert_eq!(method_err.error.code, METHOD_NOT_FOUND);
316 assert_eq!(method_err.error.message, "Method not found");
317
318 let method_err_with_name =
320 JsonRpcError::method_not_found_with_name(id.clone(), "test_method");
321 assert_eq!(method_err_with_name.error.code, METHOD_NOT_FOUND);
322 assert!(method_err_with_name.error.message.contains("test_method"));
323 assert!(method_err_with_name.error.data.is_some());
324
325 let params_err = JsonRpcError::invalid_params(id.clone());
327 assert_eq!(params_err.error.code, INVALID_PARAMS);
328 assert_eq!(params_err.error.message, "Invalid params");
329
330 let params_err_msg =
332 JsonRpcError::invalid_params_with_message(id.clone(), "Missing required field 'name'");
333 assert_eq!(params_err_msg.error.code, INVALID_PARAMS);
334 assert_eq!(
335 params_err_msg.error.message,
336 "Missing required field 'name'"
337 );
338
339 let internal_err = JsonRpcError::internal_error(id.clone());
341 assert_eq!(internal_err.error.code, INTERNAL_ERROR);
342 assert_eq!(internal_err.error.message, "Internal error");
343
344 let internal_err_msg =
346 JsonRpcError::internal_error_with_message(id.clone(), "Database connection failed");
347 assert_eq!(internal_err_msg.error.code, INTERNAL_ERROR);
348 assert_eq!(internal_err_msg.error.message, "Database connection failed");
349 }
350
351 #[test]
352 fn test_mcp_specific_errors() {
353 let id = json!("req-456");
354
355 let tool_err = JsonRpcError::tool_not_found(id.clone(), "my_tool");
357 assert_eq!(tool_err.error.code, TOOL_NOT_FOUND);
358 assert!(tool_err.error.message.contains("my_tool"));
359 assert_eq!(tool_err.error.data, Some(json!({"tool": "my_tool"})));
360
361 let resource_err = JsonRpcError::resource_not_found(id.clone(), "file:///test.txt");
363 assert_eq!(resource_err.error.code, RESOURCE_NOT_FOUND);
364 assert!(resource_err.error.message.contains("file:///test.txt"));
365 assert_eq!(
366 resource_err.error.data,
367 Some(json!({"uri": "file:///test.txt"}))
368 );
369
370 let prompt_err = JsonRpcError::prompt_not_found(id.clone(), "test_prompt");
372 assert_eq!(prompt_err.error.code, PROMPT_NOT_FOUND);
373 assert!(prompt_err.error.message.contains("test_prompt"));
374 assert_eq!(
375 prompt_err.error.data,
376 Some(json!({"prompt": "test_prompt"}))
377 );
378 }
379
380 #[test]
381 fn test_custom_errors() {
382 let id = json!(789);
383
384 let custom = JsonRpcError::custom(id.clone(), -32099, "Custom error message");
386 assert_eq!(custom.error.code, -32099);
387 assert_eq!(custom.error.message, "Custom error message");
388 assert!(custom.error.data.is_none());
389
390 let custom_data = json!({"field": "value", "count": 42});
392 let custom_with_data = JsonRpcError::custom_with_data(
393 id.clone(),
394 -32098,
395 "Another custom error",
396 custom_data.clone(),
397 );
398 assert_eq!(custom_with_data.error.code, -32098);
399 assert_eq!(custom_with_data.error.message, "Another custom error");
400 assert_eq!(custom_with_data.error.data, Some(custom_data));
401 }
402
403 #[test]
404 fn test_conversion_to_message() {
405 let id = json!("msg-001");
406 let error = JsonRpcError::method_not_found(id);
407
408 let message: JsonRpcMessage = error.clone().into();
410 assert!(matches!(message, JsonRpcMessage::Error(_)));
411
412 let message2 = error.into_message();
414 assert!(matches!(message2, JsonRpcMessage::Error(_)));
415 }
416
417 #[test]
418 fn test_error_serialization() {
419 let id = json!(42);
420 let error = JsonRpcError::invalid_params_with_message(id, "Field 'name' is required");
421
422 let serialized = serde_json::to_value(&error).unwrap();
423 assert_eq!(serialized["jsonrpc"], "2.0");
424 assert_eq!(serialized["id"], 42);
425 assert_eq!(serialized["error"]["code"], INVALID_PARAMS);
426 assert_eq!(serialized["error"]["message"], "Field 'name' is required");
427
428 let deserialized: JsonRpcError = serde_json::from_value(serialized).unwrap();
430 assert_eq!(deserialized, error);
431 }
432}