Skip to main content

mcpkit_core/error/
jsonrpc.rs

1//! JSON-RPC error response type and conversions.
2//!
3//! This module provides the `JsonRpcError` type for wire format
4//! and conversions from `McpError`.
5
6use serde::{Deserialize, Serialize};
7
8use super::types::McpError;
9
10/// A JSON-RPC error response object.
11#[derive(Debug, Clone, Serialize, Deserialize)]
12pub struct JsonRpcError {
13    /// Error code.
14    pub code: i32,
15    /// Error message.
16    pub message: String,
17    /// Additional error data.
18    #[serde(skip_serializing_if = "Option::is_none")]
19    pub data: Option<serde_json::Value>,
20}
21
22impl JsonRpcError {
23    /// Create an "invalid params" error (-32602).
24    pub fn invalid_params(message: impl Into<String>) -> Self {
25        Self {
26            code: -32602,
27            message: message.into(),
28            data: None,
29        }
30    }
31
32    /// Create an "internal error" (-32603).
33    pub fn internal_error(message: impl Into<String>) -> Self {
34        Self {
35            code: -32603,
36            message: message.into(),
37            data: None,
38        }
39    }
40
41    /// Create a "method not found" error (-32601).
42    pub fn method_not_found(message: impl Into<String>) -> Self {
43        Self {
44            code: -32601,
45            message: message.into(),
46            data: None,
47        }
48    }
49
50    /// Create a "parse error" (-32700).
51    pub fn parse_error(message: impl Into<String>) -> Self {
52        Self {
53            code: -32700,
54            message: message.into(),
55            data: None,
56        }
57    }
58
59    /// Create an "invalid request" error (-32600).
60    pub fn invalid_request(message: impl Into<String>) -> Self {
61        Self {
62            code: -32600,
63            message: message.into(),
64            data: None,
65        }
66    }
67}
68
69impl From<&McpError> for JsonRpcError {
70    fn from(err: &McpError) -> Self {
71        // A wrapped raw JSON-RPC error passes through verbatim.
72        if let McpError::JsonRpc(e) = err {
73            return e.clone();
74        }
75        let code = err.code();
76        let message = err.to_string();
77        let data = match err {
78            McpError::MethodNotFound {
79                method, available, ..
80            } => Some(serde_json::json!({
81                "method": method,
82                "available": available,
83            })),
84            McpError::InvalidParams(details) => Some(serde_json::json!({
85                "method": details.method,
86                "param_path": details.param_path,
87                "expected": details.expected,
88                "actual": details.actual,
89            })),
90            McpError::Transport(details) => Some(serde_json::json!({
91                "kind": format!("{:?}", details.kind),
92                "context": details.context,
93            })),
94            McpError::ToolExecution(details) => details
95                .data
96                .clone()
97                .or_else(|| Some(serde_json::json!({ "tool": details.tool }))),
98            McpError::HandshakeFailed(details) => Some(serde_json::json!({
99                "client_version": details.client_version,
100                "server_version": details.server_version,
101            })),
102            McpError::UrlElicitationRequired { elicitations } => Some(serde_json::json!({
103                "elicitations": elicitations,
104            })),
105            McpError::WithContext { source, .. } => {
106                let inner: Self = source.as_ref().into();
107                inner.data
108            }
109            _ => None,
110        };
111
112        Self {
113            code,
114            message,
115            data,
116        }
117    }
118}
119
120impl From<McpError> for JsonRpcError {
121    fn from(err: McpError) -> Self {
122        Self::from(&err)
123    }
124}