1use alloc::string::{String, ToString};
6use core::fmt;
7use serde::{Deserialize, Deserializer, Serialize, Serializer};
8use serde_json::Value;
9
10pub const JSONRPC_VERSION: &str = "2.0";
12
13#[derive(Debug, Clone, PartialEq, Eq, Default)]
15pub struct JsonRpcVersion;
16
17impl Serialize for JsonRpcVersion {
18 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
19 where
20 S: Serializer,
21 {
22 serializer.serialize_str(JSONRPC_VERSION)
23 }
24}
25
26impl<'de> Deserialize<'de> for JsonRpcVersion {
27 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
28 where
29 D: Deserializer<'de>,
30 {
31 let version = String::deserialize(deserializer)?;
32 if version == JSONRPC_VERSION {
33 Ok(JsonRpcVersion)
34 } else {
35 Err(serde::de::Error::custom(alloc::format!(
36 "Invalid JSON-RPC version: expected '{}', got '{}'",
37 JSONRPC_VERSION,
38 version
39 )))
40 }
41 }
42}
43
44#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
46#[serde(untagged)]
47pub enum RequestId {
48 String(String),
50 Number(i64),
52}
53
54impl fmt::Display for RequestId {
55 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
56 match self {
57 Self::String(s) => write!(f, "{}", s),
58 Self::Number(n) => write!(f, "{}", n),
59 }
60 }
61}
62
63impl From<String> for RequestId {
64 fn from(s: String) -> Self {
65 Self::String(s)
66 }
67}
68
69impl From<&str> for RequestId {
70 fn from(s: &str) -> Self {
71 Self::String(s.to_string())
72 }
73}
74
75impl From<i64> for RequestId {
76 fn from(n: i64) -> Self {
77 Self::Number(n)
78 }
79}
80
81impl From<i32> for RequestId {
82 fn from(n: i32) -> Self {
83 Self::Number(n as i64)
84 }
85}
86
87#[derive(Debug, Clone, Serialize, Deserialize)]
89pub struct JsonRpcRequest {
90 pub jsonrpc: JsonRpcVersion,
92 pub method: String,
94 #[serde(skip_serializing_if = "Option::is_none")]
96 pub params: Option<Value>,
97 pub id: RequestId,
99}
100
101impl JsonRpcRequest {
102 #[must_use]
104 pub fn new(method: impl Into<String>, params: Option<Value>, id: impl Into<RequestId>) -> Self {
105 Self {
106 jsonrpc: JsonRpcVersion,
107 method: method.into(),
108 params,
109 id: id.into(),
110 }
111 }
112
113 #[must_use]
115 pub fn without_params(method: impl Into<String>, id: impl Into<RequestId>) -> Self {
116 Self::new(method, None, id)
117 }
118}
119
120#[derive(Debug, Clone, Serialize, Deserialize)]
122pub struct JsonRpcNotification {
123 pub jsonrpc: JsonRpcVersion,
125 pub method: String,
127 #[serde(skip_serializing_if = "Option::is_none")]
129 pub params: Option<Value>,
130}
131
132impl JsonRpcNotification {
133 #[must_use]
135 pub fn new(method: impl Into<String>, params: Option<Value>) -> Self {
136 Self {
137 jsonrpc: JsonRpcVersion,
138 method: method.into(),
139 params,
140 }
141 }
142
143 #[must_use]
145 pub fn without_params(method: impl Into<String>) -> Self {
146 Self::new(method, None)
147 }
148}
149
150#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
152pub struct JsonRpcError {
153 pub code: i32,
155 pub message: String,
157 #[serde(skip_serializing_if = "Option::is_none")]
159 pub data: Option<Value>,
160}
161
162impl JsonRpcError {
163 #[must_use]
165 pub fn new(code: i32, message: impl Into<String>) -> Self {
166 Self {
167 code,
168 message: message.into(),
169 data: None,
170 }
171 }
172
173 #[must_use]
175 pub fn with_data(code: i32, message: impl Into<String>, data: Value) -> Self {
176 Self {
177 code,
178 message: message.into(),
179 data: Some(data),
180 }
181 }
182
183 #[must_use]
185 pub fn parse_error() -> Self {
186 Self::new(-32700, "Parse error")
187 }
188
189 #[must_use]
191 pub fn invalid_request() -> Self {
192 Self::new(-32600, "Invalid Request")
193 }
194
195 #[must_use]
197 pub fn method_not_found(method: &str) -> Self {
198 Self::new(-32601, alloc::format!("Method not found: {}", method))
199 }
200
201 #[must_use]
203 pub fn invalid_params(details: &str) -> Self {
204 Self::new(-32602, alloc::format!("Invalid params: {}", details))
205 }
206
207 #[must_use]
209 pub fn internal_error(details: &str) -> Self {
210 Self::new(-32603, alloc::format!("Internal error: {}", details))
211 }
212
213 #[must_use]
215 pub const fn code(&self) -> i32 {
216 self.code
217 }
218
219 #[must_use]
221 pub const fn is_parse_error(&self) -> bool {
222 self.code == -32700
223 }
224
225 #[must_use]
227 pub const fn is_invalid_request(&self) -> bool {
228 self.code == -32600
229 }
230}
231
232impl fmt::Display for JsonRpcError {
233 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
234 write!(f, "[{}] {}", self.code, self.message)
235 }
236}
237
238#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
240#[serde(transparent)]
241pub struct ResponseId(pub Option<RequestId>);
242
243impl ResponseId {
244 #[must_use]
246 pub fn from_request(id: RequestId) -> Self {
247 Self(Some(id))
248 }
249
250 #[must_use]
252 pub fn null() -> Self {
253 Self(None)
254 }
255
256 #[must_use]
258 pub fn as_request_id(&self) -> Option<&RequestId> {
259 self.0.as_ref()
260 }
261
262 #[must_use]
264 pub fn is_null(&self) -> bool {
265 self.0.is_none()
266 }
267}
268
269#[derive(Debug, Clone, Serialize)]
273#[serde(untagged)]
274pub enum JsonRpcResponsePayload {
275 Success {
277 result: Value,
279 },
280 Error {
282 error: JsonRpcError,
284 },
285}
286
287impl<'de> Deserialize<'de> for JsonRpcResponsePayload {
288 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
289 where
290 D: Deserializer<'de>,
291 {
292 let mut object = serde_json::Map::<String, Value>::deserialize(deserializer)?;
293 let result_present = object.contains_key("result");
294 let error_present = object.contains_key("error");
295
296 match (result_present, error_present) {
297 (true, false) => Ok(Self::Success {
298 result: object.remove("result").unwrap_or(Value::Null),
299 }),
300 (false, true) => {
301 let error_value = object.remove("error").unwrap_or(Value::Null);
302 let error =
303 JsonRpcError::deserialize(error_value).map_err(serde::de::Error::custom)?;
304 Ok(Self::Error { error })
305 }
306 (true, true) => Err(serde::de::Error::custom(
307 "JSON-RPC response must contain exactly one of `result` or `error`, not both",
308 )),
309 (false, false) => Err(serde::de::Error::custom(
310 "JSON-RPC response must contain exactly one of `result` or `error`",
311 )),
312 }
313 }
314}
315
316#[derive(Debug, Clone, Serialize, Deserialize)]
318pub struct JsonRpcResponse {
319 pub jsonrpc: JsonRpcVersion,
321 #[serde(flatten)]
323 pub payload: JsonRpcResponsePayload,
324 pub id: ResponseId,
326}
327
328impl JsonRpcResponse {
329 #[must_use]
331 pub fn success(result: Value, id: RequestId) -> Self {
332 Self {
333 jsonrpc: JsonRpcVersion,
334 payload: JsonRpcResponsePayload::Success { result },
335 id: ResponseId::from_request(id),
336 }
337 }
338
339 #[must_use]
341 pub fn error_response(error: JsonRpcError, id: RequestId) -> Self {
342 Self {
343 jsonrpc: JsonRpcVersion,
344 payload: JsonRpcResponsePayload::Error { error },
345 id: ResponseId::from_request(id),
346 }
347 }
348
349 #[must_use]
351 pub fn parse_error(message: Option<String>) -> Self {
352 let error = JsonRpcError {
353 code: -32700,
354 message: message.unwrap_or_else(|| "Parse error".to_string()),
355 data: None,
356 };
357 Self {
358 jsonrpc: JsonRpcVersion,
359 payload: JsonRpcResponsePayload::Error { error },
360 id: ResponseId::null(),
361 }
362 }
363
364 #[must_use]
366 pub fn is_success(&self) -> bool {
367 matches!(self.payload, JsonRpcResponsePayload::Success { .. })
368 }
369
370 #[must_use]
372 pub fn is_error(&self) -> bool {
373 matches!(self.payload, JsonRpcResponsePayload::Error { .. })
374 }
375
376 #[must_use]
378 pub fn result(&self) -> Option<&Value> {
379 match &self.payload {
380 JsonRpcResponsePayload::Success { result } => Some(result),
381 JsonRpcResponsePayload::Error { .. } => None,
382 }
383 }
384
385 #[must_use]
387 pub fn error(&self) -> Option<&JsonRpcError> {
388 match &self.payload {
389 JsonRpcResponsePayload::Success { .. } => None,
390 JsonRpcResponsePayload::Error { error } => Some(error),
391 }
392 }
393}
394
395#[derive(Debug, Clone, Copy, PartialEq, Eq)]
397pub enum JsonRpcErrorCode {
398 ParseError,
400 InvalidRequest,
402 MethodNotFound,
404 InvalidParams,
406 InternalError,
408 ApplicationError(i32),
410}
411
412impl JsonRpcErrorCode {
413 #[must_use]
415 pub const fn code(&self) -> i32 {
416 match self {
417 Self::ParseError => -32700,
418 Self::InvalidRequest => -32600,
419 Self::MethodNotFound => -32601,
420 Self::InvalidParams => -32602,
421 Self::InternalError => -32603,
422 Self::ApplicationError(code) => *code,
423 }
424 }
425
426 #[must_use]
428 pub const fn message(&self) -> &'static str {
429 match self {
430 Self::ParseError => "Parse error",
431 Self::InvalidRequest => "Invalid Request",
432 Self::MethodNotFound => "Method not found",
433 Self::InvalidParams => "Invalid params",
434 Self::InternalError => "Internal error",
435 Self::ApplicationError(_) => "Application error",
436 }
437 }
438}
439
440impl fmt::Display for JsonRpcErrorCode {
441 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
442 write!(f, "{} ({})", self.message(), self.code())
443 }
444}
445
446impl From<i32> for JsonRpcErrorCode {
447 fn from(code: i32) -> Self {
448 match code {
449 -32700 => Self::ParseError,
450 -32600 => Self::InvalidRequest,
451 -32601 => Self::MethodNotFound,
452 -32602 => Self::InvalidParams,
453 -32603 => Self::InternalError,
454 other => Self::ApplicationError(other),
455 }
456 }
457}
458
459impl From<JsonRpcErrorCode> for JsonRpcError {
460 fn from(code: JsonRpcErrorCode) -> Self {
461 Self {
462 code: code.code(),
463 message: code.message().to_string(),
464 data: None,
465 }
466 }
467}
468
469#[derive(Debug, Clone)]
501pub struct JsonRpcIncoming {
502 pub jsonrpc: String,
507 pub id: Option<Value>,
509 pub method: String,
511 pub params: Option<Value>,
513}
514
515impl<'de> Deserialize<'de> for JsonRpcIncoming {
516 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
517 where
518 D: Deserializer<'de>,
519 {
520 let mut object = serde_json::Map::<String, Value>::deserialize(deserializer)?;
521
522 let jsonrpc = match object.remove("jsonrpc") {
523 Some(Value::String(version)) => version,
524 Some(_) => {
525 return Err(serde::de::Error::custom(
526 "JSON-RPC request field `jsonrpc` must be a string",
527 ));
528 }
529 None => return Err(serde::de::Error::missing_field("jsonrpc")),
530 };
531
532 let method = match object.remove("method") {
533 Some(Value::String(method)) => method,
534 Some(_) => {
535 return Err(serde::de::Error::custom(
536 "JSON-RPC request field `method` must be a string",
537 ));
538 }
539 None => return Err(serde::de::Error::missing_field("method")),
540 };
541
542 let id = match object.remove("id") {
543 Some(value) => {
544 Some(validate_incoming_request_id(value).map_err(serde::de::Error::custom)?)
545 }
546 None => None,
547 };
548
549 Ok(Self {
550 jsonrpc,
551 id,
552 method,
553 params: match object.remove("params") {
554 Some(Value::Null) | None => None,
555 Some(params) => Some(params),
556 },
557 })
558 }
559}
560
561fn validate_incoming_request_id(value: Value) -> Result<Value, &'static str> {
562 match &value {
563 Value::String(_) => Ok(value),
564 Value::Number(number) if number.as_i64().is_some() => Ok(value),
565 Value::Null => Err("MCP request `id` must not be null"),
566 Value::Number(_) => Err("MCP request `id` must be an integer"),
567 _ => Err("MCP request `id` must be a string or integer"),
568 }
569}
570
571impl JsonRpcIncoming {
572 #[must_use]
574 pub fn is_request(&self) -> bool {
575 self.id.is_some()
576 }
577
578 #[must_use]
580 pub fn is_notification(&self) -> bool {
581 self.id.is_none()
582 }
583
584 pub fn parse(input: &str) -> Result<Self, serde_json::Error> {
586 serde_json::from_str(input)
587 }
588
589 #[must_use]
594 pub fn is_valid_version(&self) -> bool {
595 self.jsonrpc == "2.0"
596 }
597}
598
599#[derive(Debug, Clone, Serialize)]
622pub struct JsonRpcOutgoing {
623 pub jsonrpc: String,
625 pub id: Option<Value>,
633 #[serde(skip_serializing_if = "Option::is_none")]
635 pub result: Option<Value>,
636 #[serde(skip_serializing_if = "Option::is_none")]
638 pub error: Option<JsonRpcError>,
639}
640
641impl JsonRpcOutgoing {
642 #[must_use]
644 pub fn success(id: Option<Value>, result: Value) -> Self {
645 Self {
646 jsonrpc: "2.0".to_string(),
647 id,
648 result: Some(result),
649 error: None,
650 }
651 }
652
653 #[must_use]
655 pub fn error(id: Option<Value>, error: impl Into<JsonRpcError>) -> Self {
656 Self {
657 jsonrpc: "2.0".to_string(),
658 id,
659 result: None,
660 error: Some(error.into()),
661 }
662 }
663
664 #[must_use]
666 pub fn notification_ack() -> Self {
667 Self {
668 jsonrpc: "2.0".to_string(),
669 id: None,
670 result: None,
671 error: None,
672 }
673 }
674
675 #[must_use]
680 pub fn should_send(&self) -> bool {
681 self.id.is_some() || self.error.is_some()
684 }
685
686 pub fn to_json(&self) -> Result<String, serde_json::Error> {
688 serde_json::to_string(self)
689 }
690}
691
692impl From<crate::error::McpError> for JsonRpcError {
700 fn from(err: crate::error::McpError) -> Self {
701 Self {
702 code: err.jsonrpc_code(),
703 message: err.message.clone(),
704 data: err.data().cloned(),
705 }
706 }
707}
708
709#[cfg(test)]
710mod tests {
711 use super::*;
712
713 #[test]
714 fn test_request_creation() {
715 let req = JsonRpcRequest::new("test", None, "id-1");
716 assert_eq!(req.method, "test");
717 assert!(req.params.is_none());
718 }
719
720 #[test]
721 fn test_response_success() {
722 let resp = JsonRpcResponse::success(serde_json::json!({"ok": true}), "id-1".into());
723 assert!(resp.is_success());
724 assert!(!resp.is_error());
725 }
726
727 #[test]
728 fn test_error_codes() {
729 assert_eq!(JsonRpcErrorCode::ParseError.code(), -32700);
730 assert_eq!(
731 JsonRpcErrorCode::from(-32601),
732 JsonRpcErrorCode::MethodNotFound
733 );
734 }
735
736 #[test]
737 fn test_request_id_conversion() {
738 let id1: RequestId = "test".into();
739 assert!(matches!(id1, RequestId::String(_)));
740
741 let id2: RequestId = 42i32.into();
742 assert!(matches!(id2, RequestId::Number(42)));
743 }
744
745 #[test]
746 fn test_incoming_request() {
747 let input = r#"{"jsonrpc": "2.0", "id": 1, "method": "ping"}"#;
748 let incoming = JsonRpcIncoming::parse(input).unwrap();
749 assert!(incoming.is_request());
750 assert!(!incoming.is_notification());
751 assert_eq!(incoming.method, "ping");
752 }
753
754 #[test]
755 fn test_incoming_notification() {
756 let input = r#"{"jsonrpc": "2.0", "method": "notifications/initialized"}"#;
757 let incoming = JsonRpcIncoming::parse(input).unwrap();
758 assert!(!incoming.is_request());
759 assert!(incoming.is_notification());
760 }
761
762 #[test]
763 fn test_incoming_rejects_null_id() {
764 let input = r#"{"jsonrpc": "2.0", "id": null, "method": "ping"}"#;
765 let err = JsonRpcIncoming::parse(input).unwrap_err();
766 assert!(err.to_string().contains("must not be null"));
767 }
768
769 #[test]
770 fn test_incoming_rejects_non_integer_number_id() {
771 let input = r#"{"jsonrpc": "2.0", "id": 1.25, "method": "ping"}"#;
772 let err = JsonRpcIncoming::parse(input).unwrap_err();
773 assert!(err.to_string().contains("must be an integer"));
774 }
775
776 #[test]
777 fn test_outgoing_success() {
778 let response = JsonRpcOutgoing::success(Some(serde_json::json!(1)), serde_json::json!({}));
779 assert!(response.should_send());
780 assert!(response.result.is_some());
781 assert!(response.error.is_none());
782 }
783
784 #[test]
785 fn test_outgoing_success_without_id_is_not_sent() {
786 let response = JsonRpcOutgoing::success(None, serde_json::json!({}));
787 assert!(!response.should_send());
788 }
789
790 #[test]
791 fn test_outgoing_notification_ack() {
792 let response = JsonRpcOutgoing::notification_ack();
793 assert!(!response.should_send());
794 }
795
796 #[test]
799 fn test_response_payload_rejects_both_result_and_error() {
800 let raw = r#"{"jsonrpc":"2.0","id":1,"result":{},"error":{"code":-32603,"message":"x"}}"#;
801 let err = serde_json::from_str::<JsonRpcResponse>(raw)
802 .expect_err("response with both result and error must be rejected");
803 assert!(err.to_string().contains("exactly one of"));
804 }
805
806 #[test]
807 fn test_response_payload_rejects_neither_result_nor_error() {
808 let raw = r#"{"jsonrpc":"2.0","id":1}"#;
809 let err = serde_json::from_str::<JsonRpcResponse>(raw)
810 .expect_err("response with neither result nor error must be rejected");
811 assert!(err.to_string().contains("exactly one of"));
812 }
813
814 #[test]
815 fn test_response_payload_accepts_error_only() {
816 let raw =
817 r#"{"jsonrpc":"2.0","id":1,"error":{"code":-32601,"message":"Method not found"}}"#;
818 let resp: JsonRpcResponse = serde_json::from_str(raw).unwrap();
819 assert!(resp.is_error());
820 assert_eq!(resp.error().unwrap().code, -32601);
821 }
822
823 #[test]
824 fn test_response_payload_accepts_null_result() {
825 let raw = r#"{"jsonrpc":"2.0","id":1,"result":null}"#;
826 let resp: JsonRpcResponse = serde_json::from_str(raw).unwrap();
827 assert!(resp.is_success());
828 assert_eq!(resp.result(), Some(&Value::Null));
829 }
830}