Skip to main content

mcp_postgres/
protocol.rs

1use serde::{Deserialize, Serialize};
2use serde_json::Value;
3
4#[derive(Debug, Clone, Serialize, Deserialize)]
5pub struct JsonRpcRequest {
6    pub jsonrpc: String,
7    pub method: String,
8    pub params: Option<Value>,
9    pub id: Option<Value>,
10}
11
12#[derive(Debug, Clone, Serialize, Deserialize)]
13pub struct JsonRpcResponse {
14    pub jsonrpc: String,
15    #[serde(skip_serializing_if = "Option::is_none")]
16    pub result: Option<Value>,
17    #[serde(skip_serializing_if = "Option::is_none")]
18    pub error: Option<JsonRpcError>,
19    pub id: Option<Value>,
20}
21
22#[derive(Debug, Clone, Serialize, Deserialize)]
23pub struct JsonRpcError {
24    pub code: i64,
25    pub message: String,
26    #[serde(skip_serializing_if = "Option::is_none")]
27    pub data: Option<Value>,
28}
29
30impl JsonRpcRequest {}
31
32impl JsonRpcResponse {
33    pub fn success(id: Option<Value>, result: Value) -> Self {
34        Self {
35            jsonrpc: "2.0".into(),
36            result: Some(result),
37            error: None,
38            id,
39        }
40    }
41
42    pub fn error(id: Option<Value>, code: i64, message: String) -> Self {
43        Self {
44            jsonrpc: "2.0".into(),
45            result: None,
46            error: Some(JsonRpcError {
47                code,
48                message,
49                data: None,
50            }),
51            id,
52        }
53    }
54}
55
56#[cfg(test)]
57mod tests {
58    use super::*;
59    use serde_json::json;
60
61    #[test]
62    fn test_request_serialize_deserialize() {
63        let req = JsonRpcRequest {
64            jsonrpc: "2.0".to_string(),
65            method: "test_method".to_string(),
66            params: Some(json!({"key": "value"})),
67            id: Some(Value::Number(1.into())),
68        };
69        let json = serde_json::to_string(&req).unwrap();
70        let deserialized: JsonRpcRequest = serde_json::from_str(&json).unwrap();
71        assert_eq!(deserialized.jsonrpc, "2.0");
72        assert_eq!(deserialized.method, "test_method");
73        assert_eq!(deserialized.params, Some(json!({"key": "value"})));
74        assert_eq!(deserialized.id, Some(Value::Number(1.into())));
75    }
76
77    #[test]
78    fn test_request_without_params() {
79        let req = JsonRpcRequest {
80            jsonrpc: "2.0".to_string(),
81            method: "initialize".to_string(),
82            params: None,
83            id: Some(Value::Number(1.into())),
84        };
85        let json = serde_json::to_string(&req).unwrap();
86        let deserialized: JsonRpcRequest = serde_json::from_str(&json).unwrap();
87        assert!(deserialized.params.is_none());
88    }
89
90    #[test]
91    fn test_request_with_string_id() {
92        let req = JsonRpcRequest {
93            jsonrpc: "2.0".to_string(),
94            method: "tools/list".to_string(),
95            params: None,
96            id: Some(Value::String("req-1".into())),
97        };
98        let json = serde_json::to_string(&req).unwrap();
99        let deserialized: JsonRpcRequest = serde_json::from_str(&json).unwrap();
100        assert_eq!(deserialized.id, Some(Value::String("req-1".into())));
101    }
102
103    #[test]
104    fn test_response_success() {
105        let resp = JsonRpcResponse::success(Some(Value::Number(1.into())), json!({"result": "ok"}));
106        assert_eq!(resp.jsonrpc, "2.0");
107        assert_eq!(resp.result, Some(json!({"result": "ok"})));
108        assert!(resp.error.is_none());
109        assert_eq!(resp.id, Some(Value::Number(1.into())));
110    }
111
112    #[test]
113    fn test_response_success_null_id() {
114        let resp = JsonRpcResponse::success(None, json!("ok"));
115        assert!(resp.id.is_none());
116    }
117
118    #[test]
119    fn test_response_error() {
120        let resp =
121            JsonRpcResponse::error(Some(Value::Number(1.into())), -32700, "Parse error".into());
122        assert_eq!(resp.jsonrpc, "2.0");
123        assert!(resp.result.is_none());
124        let err = resp.error.unwrap();
125        assert_eq!(err.code, -32700);
126        assert_eq!(err.message, "Parse error");
127        assert!(err.data.is_none());
128    }
129
130    #[test]
131    fn test_response_error_with_null_id() {
132        let resp = JsonRpcResponse::error(None, -32601, "Not found".into());
133        assert!(resp.id.is_none());
134    }
135
136    #[test]
137    fn test_response_serde_roundtrip() {
138        let resp = JsonRpcResponse::success(Some(Value::Number(42.into())), json!([1, 2, 3]));
139        let json = serde_json::to_string(&resp).unwrap();
140        let deserialized: JsonRpcResponse = serde_json::from_str(&json).unwrap();
141        assert_eq!(deserialized.jsonrpc, "2.0");
142        assert_eq!(deserialized.result, Some(json!([1, 2, 3])));
143        assert_eq!(deserialized.id, Some(Value::Number(42.into())));
144    }
145
146    #[test]
147    fn test_error_serde_roundtrip() {
148        let resp = JsonRpcResponse::error(Some(json!("abc")), -32000, "DB error".into());
149        let json = serde_json::to_string(&resp).unwrap();
150        let deserialized: JsonRpcResponse = serde_json::from_str(&json).unwrap();
151        let err = deserialized.error.unwrap();
152        assert_eq!(err.code, -32000);
153        assert_eq!(err.message, "DB error");
154    }
155
156    #[test]
157    fn test_minimal_request() {
158        let json = r#"{"jsonrpc":"2.0","method":"ping","id":1}"#;
159        let req: JsonRpcRequest = serde_json::from_str(json).unwrap();
160        assert_eq!(req.jsonrpc, "2.0");
161        assert_eq!(req.method, "ping");
162        assert!(req.params.is_none());
163    }
164
165    #[test]
166    fn test_request_with_null_params() {
167        let json = r#"{"jsonrpc":"2.0","method":"ping","params":null,"id":1}"#;
168        let req: JsonRpcRequest = serde_json::from_str(json).unwrap();
169        assert!(req.params.is_none());
170    }
171
172    #[test]
173    fn test_request_with_num_id_zero() {
174        let json = r#"{"jsonrpc":"2.0","method":"initialize","id":0}"#;
175        let req: JsonRpcRequest = serde_json::from_str(json).unwrap();
176        assert_eq!(req.id, Some(Value::Number(0.into())));
177    }
178
179    #[test]
180    fn test_response_with_error_data() {
181        let resp = JsonRpcResponse {
182            jsonrpc: "2.0".to_string(),
183            result: None,
184            error: Some(JsonRpcError {
185                code: -32000,
186                message: "custom error".into(),
187                data: Some(json!({"detail": "something broke"})),
188            }),
189            id: Some(Value::Number(1.into())),
190        };
191        let json = serde_json::to_string(&resp).unwrap();
192        let deserialized: JsonRpcResponse = serde_json::from_str(&json).unwrap();
193        let err = deserialized.error.unwrap();
194        assert_eq!(err.data, Some(json!({"detail": "something broke"})));
195    }
196}