turul_mcp_protocol_2025_06_18/
json_rpc.rs1use serde::{Deserialize, Serialize};
7use serde_json::Value;
8use std::collections::HashMap;
9
10use crate::meta::{Meta, ProgressToken};
11use crate::traits::{
12 HasData, HasDataParam, HasMeta, HasMetaParam, HasProgressTokenParam, Params, RpcResult,
13};
14
15pub const JSONRPC_VERSION: &str = "2.0";
17
18#[derive(Debug, Clone, Deserialize, Serialize)]
20#[serde(rename_all = "camelCase")]
21pub struct RequestParams {
22 #[serde(default, skip_serializing_if = "Option::is_none", alias = "_meta")]
24 pub meta: Option<Meta>,
25
26 #[serde(flatten)]
28 pub other: HashMap<String, Value>,
29}
30
31impl Params for RequestParams {}
32
33impl HasMeta for RequestParams {
34 fn meta(&self) -> Option<HashMap<String, Value>> {
35 self.meta.as_ref().map(|m| {
36 let mut map = HashMap::new();
37 if let Some(ref token) = m.progress_token {
38 map.insert(
39 "progressToken".to_string(),
40 Value::String(token.as_str().to_string()),
41 );
42 }
43 if let Some(ref cursor) = m.cursor {
44 map.insert(
45 "cursor".to_string(),
46 Value::String(cursor.as_str().to_string()),
47 );
48 }
49 if let Some(total) = m.total {
50 map.insert("total".to_string(), Value::Number(total.into()));
51 }
52 if let Some(has_more) = m.has_more {
53 map.insert("hasMore".to_string(), Value::Bool(has_more));
54 }
55 if let Some(estimated_remaining) = m.estimated_remaining_seconds {
56 map.insert(
57 "estimatedRemainingSeconds".to_string(),
58 Value::Number(serde_json::Number::from_f64(estimated_remaining).unwrap()),
59 );
60 }
61 if let Some(progress) = m.progress {
62 map.insert(
63 "progress".to_string(),
64 Value::Number(serde_json::Number::from_f64(progress).unwrap()),
65 );
66 }
67 if let Some(current_step) = m.current_step {
68 map.insert(
69 "currentStep".to_string(),
70 Value::Number(current_step.into()),
71 );
72 }
73 if let Some(total_steps) = m.total_steps {
74 map.insert("totalSteps".to_string(), Value::Number(total_steps.into()));
75 }
76 map
77 })
78 }
79}
80
81impl HasProgressTokenParam for RequestParams {
82 fn progress_token(&self) -> Option<&ProgressToken> {
83 self.meta.as_ref()?.progress_token.as_ref()
84 }
85}
86
87impl HasDataParam for RequestParams {
88 fn data(&self) -> &HashMap<String, Value> {
89 &self.other
90 }
91}
92
93impl HasMetaParam for RequestParams {
94 fn meta(&self) -> Option<&HashMap<String, Value>> {
95 None
98 }
99}
100
101#[derive(Debug, Clone, Serialize, Deserialize)]
103pub struct ResultWithMeta {
104 #[serde(flatten)]
106 pub data: HashMap<String, Value>,
107
108 #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
110 pub meta: Option<HashMap<String, Value>>,
111}
112
113impl ResultWithMeta {
114 pub fn new(data: HashMap<String, Value>) -> Self {
115 Self { data, meta: None }
116 }
117
118 pub fn with_meta(mut self, meta: HashMap<String, Value>) -> Self {
119 self.meta = Some(meta);
120 self
121 }
122
123 pub fn from_value(value: Value) -> Self {
124 match value {
125 Value::Object(map) => Self {
126 data: map.into_iter().collect(),
127 meta: None,
128 },
129 _ => Self {
130 data: HashMap::new(),
131 meta: None,
132 },
133 }
134 }
135}
136
137impl HasData for ResultWithMeta {
138 fn data(&self) -> HashMap<String, Value> {
139 self.data.clone()
140 }
141}
142
143impl HasMeta for ResultWithMeta {
144 fn meta(&self) -> Option<HashMap<String, Value>> {
145 self.meta.clone()
146 }
147}
148
149impl RpcResult for ResultWithMeta {}
150
151#[derive(Debug, Clone, Serialize, Deserialize)]
153pub struct JsonRpcRequest {
154 pub jsonrpc: String,
155 pub id: Value,
156 pub method: String,
157 #[serde(skip_serializing_if = "Option::is_none")]
158 pub params: Option<RequestParams>,
159}
160
161impl JsonRpcRequest {
162 pub fn new(id: Value, method: String) -> Self {
163 Self {
164 jsonrpc: JSONRPC_VERSION.to_string(),
165 id,
166 method,
167 params: None,
168 }
169 }
170
171 pub fn with_params(mut self, params: RequestParams) -> Self {
172 self.params = Some(params);
173 self
174 }
175}
176
177#[derive(Debug, Clone, Serialize, Deserialize)]
179pub struct JsonRpcResponse {
180 pub jsonrpc: String,
181 pub id: Value,
182 #[serde(skip_serializing_if = "Option::is_none")]
183 pub result: Option<ResultWithMeta>,
184 #[serde(skip_serializing_if = "Option::is_none")]
185 pub error: Option<JsonRpcError>,
186}
187
188impl JsonRpcResponse {
189 pub fn success(id: Value, result: ResultWithMeta) -> Self {
190 Self {
191 jsonrpc: JSONRPC_VERSION.to_string(),
192 id,
193 result: Some(result),
194 error: None,
195 }
196 }
197
198 pub fn error(id: Value, error: JsonRpcError) -> Self {
199 Self {
200 jsonrpc: JSONRPC_VERSION.to_string(),
201 id,
202 result: None,
203 error: Some(error),
204 }
205 }
206}
207
208#[derive(Debug, Clone, Serialize, Deserialize)]
210pub struct JsonRpcError {
211 pub code: i32,
212 pub message: String,
213 #[serde(skip_serializing_if = "Option::is_none")]
214 pub data: Option<Value>,
215}
216
217impl JsonRpcError {
218 pub fn new(code: i32, message: String) -> Self {
219 Self {
220 code,
221 message,
222 data: None,
223 }
224 }
225
226 pub fn with_data(mut self, data: Value) -> Self {
227 self.data = Some(data);
228 self
229 }
230
231 pub fn parse_error() -> Self {
233 Self::new(-32700, "Parse error".to_string())
234 }
235
236 pub fn invalid_request() -> Self {
237 Self::new(-32600, "Invalid Request".to_string())
238 }
239
240 pub fn method_not_found() -> Self {
241 Self::new(-32601, "Method not found".to_string())
242 }
243
244 pub fn invalid_params() -> Self {
245 Self::new(-32602, "Invalid params".to_string())
246 }
247
248 pub fn internal_error() -> Self {
249 Self::new(-32603, "Internal error".to_string())
250 }
251}
252
253#[derive(Debug, Clone, Serialize, Deserialize)]
255pub struct JsonRpcNotification {
256 pub jsonrpc: String,
257 pub method: String,
258 #[serde(skip_serializing_if = "Option::is_none")]
259 pub params: Option<RequestParams>,
260}
261
262impl JsonRpcNotification {
263 pub fn new(method: String) -> Self {
264 Self {
265 jsonrpc: JSONRPC_VERSION.to_string(),
266 method,
267 params: None,
268 }
269 }
270
271 pub fn with_params(mut self, params: RequestParams) -> Self {
272 self.params = Some(params);
273 self
274 }
275}
276
277#[derive(Debug, Clone, Serialize, Deserialize)]
279#[serde(untagged)]
280pub enum JsonRpcMessage {
281 Request(JsonRpcRequest),
282 Response(JsonRpcResponse),
283 Notification(JsonRpcNotification),
284 Error(JsonRpcError),
285}
286
287#[cfg(test)]
288mod tests {
289 use super::*;
290 use serde_json::json;
291
292 #[test]
293 fn test_request_params_with_meta() {
294 let params = RequestParams {
295 meta: Some(Meta {
296 progress_token: Some(ProgressToken::new("test-token")),
297 cursor: Some(crate::meta::Cursor::new("cursor-123")),
298 total: Some(100),
299 has_more: Some(true),
300 ..Default::default()
301 }),
302 other: {
303 let mut map = HashMap::new();
304 map.insert("name".to_string(), json!("test"));
305 map
306 },
307 };
308
309 let json_str = serde_json::to_string(¶ms).unwrap();
311 assert!(json_str.contains("progressToken"));
312 assert!(json_str.contains("test-token"));
313 assert!(json_str.contains("cursor"));
314 assert!(json_str.contains("cursor-123"));
315 assert!(json_str.contains("name"));
316 assert!(json_str.contains("test"));
317
318 let parsed: RequestParams = serde_json::from_str(&json_str).unwrap();
320 assert!(parsed.meta.is_some());
321 assert_eq!(
322 parsed
323 .meta
324 .as_ref()
325 .unwrap()
326 .progress_token
327 .as_ref()
328 .unwrap()
329 .as_str(),
330 "test-token"
331 );
332 }
333
334 #[test]
335 fn test_result_with_meta() {
336 let mut data = HashMap::new();
337 data.insert("result".to_string(), json!("success"));
338
339 let mut meta = HashMap::new();
340 meta.insert("total".to_string(), json!(42));
341
342 let result = ResultWithMeta::new(data).with_meta(meta);
343
344 assert!(result.data().contains_key("result"));
346 assert!(result.meta().unwrap().contains_key("total"));
347
348 let json_str = serde_json::to_string(&result).unwrap();
350 assert!(json_str.contains("result"));
351 assert!(json_str.contains("_meta"));
352 assert!(json_str.contains("total"));
353 }
354}