mcp_core_rs/protocol/
message.rs

1use serde::{Deserialize, Serialize};
2use serde_json::Value;
3
4use crate::protocol::{constants::JSONRPC_VERSION_FIELD, error::ErrorData};
5
6#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
7#[serde(untagged, try_from = "JsonRpcRaw")]
8pub enum JsonRpcMessage {
9    Request(JsonRpcRequest),
10    Response(JsonRpcResponse),
11    Notification(JsonRpcNotification),
12    Error(JsonRpcError),
13    Nil, // used to respond to notifications
14}
15
16#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
17pub struct JsonRpcRequest {
18    pub jsonrpc: String,
19    #[serde(skip_serializing_if = "Option::is_none")]
20    pub id: Option<u64>,
21    pub method: String,
22    #[serde(skip_serializing_if = "Option::is_none")]
23    pub params: Option<Value>,
24}
25
26impl JsonRpcRequest {
27    pub fn new(id: Option<u64>, method: impl Into<String>, params: Option<Value>) -> Self {
28        Self {
29            jsonrpc: JSONRPC_VERSION_FIELD.to_string(),
30            id,
31            method: method.into(),
32            params,
33        }
34    }
35}
36
37#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
38pub struct JsonRpcResponse {
39    pub jsonrpc: String,
40    #[serde(skip_serializing_if = "Option::is_none")]
41    pub id: Option<u64>,
42    #[serde(skip_serializing_if = "Option::is_none")]
43    pub result: Option<Value>,
44    #[serde(skip_serializing_if = "Option::is_none")]
45    pub error: Option<ErrorData>,
46}
47
48impl JsonRpcResponse {
49    pub fn empty(id: Option<u64>) -> Self {
50        Self {
51            jsonrpc: JSONRPC_VERSION_FIELD.to_string(),
52            id,
53            result: None,
54            error: None,
55        }
56    }
57
58    pub fn error(id: Option<u64>, error: ErrorData) -> Self {
59        Self {
60            jsonrpc: JSONRPC_VERSION_FIELD.to_string(),
61            id,
62            result: None,
63            error: Some(error),
64        }
65    }
66
67    pub fn success(id: Option<u64>, result: Value) -> Self {
68        Self {
69            jsonrpc: JSONRPC_VERSION_FIELD.to_string(),
70            id,
71            result: Some(result),
72            error: None,
73        }
74    }
75}
76
77#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
78pub struct JsonRpcNotification {
79    pub jsonrpc: String,
80    pub method: String,
81    #[serde(skip_serializing_if = "Option::is_none")]
82    pub params: Option<Value>,
83}
84
85#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
86pub struct JsonRpcError {
87    pub jsonrpc: String,
88    #[serde(skip_serializing_if = "Option::is_none")]
89    pub id: Option<u64>,
90    pub error: ErrorData,
91}
92
93#[derive(Debug, Serialize, Deserialize)]
94pub struct JsonRpcRaw {
95    pub jsonrpc: String,
96    #[serde(skip_serializing_if = "Option::is_none")]
97    pub id: Option<u64>,
98    #[serde(skip_serializing_if = "Option::is_none")]
99    pub method: Option<String>,
100    #[serde(skip_serializing_if = "Option::is_none")]
101    pub params: Option<Value>,
102    #[serde(skip_serializing_if = "Option::is_none")]
103    pub result: Option<Value>,
104    #[serde(skip_serializing_if = "Option::is_none")]
105    pub error: Option<ErrorData>,
106}
107
108impl TryFrom<JsonRpcRaw> for JsonRpcMessage {
109    type Error = String;
110
111    fn try_from(raw: JsonRpcRaw) -> Result<Self, <Self as TryFrom<JsonRpcRaw>>::Error> {
112        // If it has an error field, it's an error response
113        if raw.error.is_some() {
114            return Ok(JsonRpcMessage::Error(JsonRpcError {
115                jsonrpc: raw.jsonrpc,
116                id: raw.id,
117                error: raw.error.unwrap(),
118            }));
119        }
120
121        // If it has a result field, it's a response
122        if raw.result.is_some() {
123            return Ok(JsonRpcMessage::Response(JsonRpcResponse {
124                jsonrpc: raw.jsonrpc,
125                id: raw.id,
126                result: raw.result,
127                error: None,
128            }));
129        }
130
131        // If we have a method, it's either a notification or request
132        if let Some(method) = raw.method {
133            if raw.id.is_none() {
134                return Ok(JsonRpcMessage::Notification(JsonRpcNotification {
135                    jsonrpc: raw.jsonrpc,
136                    method,
137                    params: raw.params,
138                }));
139            }
140
141            return Ok(JsonRpcMessage::Request(JsonRpcRequest {
142                jsonrpc: raw.jsonrpc,
143                id: raw.id,
144                method,
145                params: raw.params,
146            }));
147        }
148
149        // If we have no method and no result/error, it's a nil response
150        if raw.id.is_none() && raw.result.is_none() && raw.error.is_none() {
151            return Ok(JsonRpcMessage::Nil);
152        }
153
154        // If we get here, something is wrong with the message
155        Err(format!(
156            "Invalid JSON-RPC message format: id={:?}, method={:?}, result={:?}, error={:?}",
157            raw.id, raw.method, raw.result, raw.error
158        ))
159    }
160}