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