Skip to main content

barbacane_lib/mcp/
jsonrpc.rs

1use serde::{Deserialize, Serialize};
2
3/// JSON-RPC 2.0 request (MCP uses JSON-RPC as its wire format).
4#[derive(Debug, Deserialize)]
5pub struct JsonRpcRequest {
6    pub jsonrpc: String,
7    pub id: Option<serde_json::Value>,
8    pub method: String,
9    #[serde(default)]
10    pub params: Option<serde_json::Value>,
11}
12
13/// JSON-RPC 2.0 response.
14#[derive(Debug, Serialize)]
15pub struct JsonRpcResponse {
16    pub jsonrpc: &'static str,
17    #[serde(skip_serializing_if = "Option::is_none")]
18    pub id: Option<serde_json::Value>,
19    #[serde(skip_serializing_if = "Option::is_none")]
20    pub result: Option<serde_json::Value>,
21    #[serde(skip_serializing_if = "Option::is_none")]
22    pub error: Option<JsonRpcError>,
23}
24
25/// JSON-RPC 2.0 error object.
26#[derive(Debug, Serialize)]
27pub struct JsonRpcError {
28    pub code: i32,
29    pub message: String,
30    #[serde(skip_serializing_if = "Option::is_none")]
31    pub data: Option<serde_json::Value>,
32}
33
34// Standard JSON-RPC error codes
35pub const PARSE_ERROR: i32 = -32700;
36pub const INVALID_REQUEST: i32 = -32600;
37pub const METHOD_NOT_FOUND: i32 = -32601;
38pub const INVALID_PARAMS: i32 = -32602;
39pub const INTERNAL_ERROR: i32 = -32603;
40
41impl JsonRpcResponse {
42    pub fn success(id: Option<serde_json::Value>, result: serde_json::Value) -> Self {
43        Self {
44            jsonrpc: "2.0",
45            id,
46            result: Some(result),
47            error: None,
48        }
49    }
50
51    pub fn error(id: Option<serde_json::Value>, code: i32, message: impl Into<String>) -> Self {
52        Self {
53            jsonrpc: "2.0",
54            id,
55            result: None,
56            error: Some(JsonRpcError {
57                code,
58                message: message.into(),
59                data: None,
60            }),
61        }
62    }
63}
64
65#[cfg(test)]
66mod tests {
67    use super::*;
68
69    #[test]
70    fn parse_valid_request() {
71        let json = r#"{"jsonrpc":"2.0","id":1,"method":"initialize","params":{}}"#;
72        let req: JsonRpcRequest = serde_json::from_str(json).expect("should parse");
73        assert_eq!(req.jsonrpc, "2.0");
74        assert_eq!(req.method, "initialize");
75        assert_eq!(req.id, Some(serde_json::json!(1)));
76    }
77
78    #[test]
79    fn parse_notification_no_id() {
80        let json = r#"{"jsonrpc":"2.0","method":"notifications/initialized"}"#;
81        let req: JsonRpcRequest = serde_json::from_str(json).expect("should parse");
82        assert!(req.id.is_none());
83        assert!(req.params.is_none());
84    }
85
86    #[test]
87    fn parse_request_with_string_id() {
88        let json = r#"{"jsonrpc":"2.0","id":"abc","method":"tools/list"}"#;
89        let req: JsonRpcRequest = serde_json::from_str(json).expect("should parse");
90        assert_eq!(req.id, Some(serde_json::json!("abc")));
91    }
92
93    #[test]
94    fn parse_invalid_json() {
95        let result = serde_json::from_str::<JsonRpcRequest>("not json");
96        assert!(result.is_err());
97    }
98
99    #[test]
100    fn success_response_serialization() {
101        let resp = JsonRpcResponse::success(Some(serde_json::json!(1)), serde_json::json!({}));
102        let json = serde_json::to_value(&resp).expect("should serialize");
103        assert_eq!(json["jsonrpc"], "2.0");
104        assert_eq!(json["id"], 1);
105        assert!(json.get("error").is_none());
106    }
107
108    #[test]
109    fn error_response_serialization() {
110        let resp =
111            JsonRpcResponse::error(Some(serde_json::json!(1)), METHOD_NOT_FOUND, "not found");
112        let json = serde_json::to_value(&resp).expect("should serialize");
113        assert_eq!(json["error"]["code"], METHOD_NOT_FOUND);
114        assert_eq!(json["error"]["message"], "not found");
115        assert!(json.get("result").is_none());
116    }
117}