Skip to main content

mcp_kit/
protocol.rs

1/// JSON-RPC 2.0 protocol implementation for MCP
2use serde::{Deserialize, Serialize};
3use serde_json::Value;
4
5use crate::error::ErrorData;
6
7pub const JSONRPC_VERSION: &str = "2.0";
8pub const MCP_PROTOCOL_VERSION: &str = "2024-11-05";
9
10/// A JSON-RPC request ID (string or integer, never null)
11#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
12#[serde(untagged)]
13pub enum RequestId {
14    String(String),
15    Number(i64),
16}
17
18impl std::fmt::Display for RequestId {
19    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
20        match self {
21            Self::String(s) => write!(f, "{s}"),
22            Self::Number(n) => write!(f, "{n}"),
23        }
24    }
25}
26
27impl From<i64> for RequestId {
28    fn from(n: i64) -> Self {
29        Self::Number(n)
30    }
31}
32
33impl From<String> for RequestId {
34    fn from(s: String) -> Self {
35        Self::String(s)
36    }
37}
38
39impl From<&str> for RequestId {
40    fn from(s: &str) -> Self {
41        Self::String(s.to_owned())
42    }
43}
44
45/// A JSON-RPC 2.0 request
46#[derive(Debug, Clone, Serialize, Deserialize)]
47pub struct JsonRpcRequest {
48    pub jsonrpc: String,
49    pub id: RequestId,
50    pub method: String,
51    #[serde(default, skip_serializing_if = "Option::is_none")]
52    pub params: Option<Value>,
53}
54
55impl JsonRpcRequest {
56    pub fn new(id: impl Into<RequestId>, method: impl Into<String>, params: Option<Value>) -> Self {
57        Self {
58            jsonrpc: JSONRPC_VERSION.to_owned(),
59            id: id.into(),
60            method: method.into(),
61            params,
62        }
63    }
64}
65
66/// A JSON-RPC 2.0 success response
67#[derive(Debug, Clone, Serialize, Deserialize)]
68pub struct JsonRpcResponse {
69    pub jsonrpc: String,
70    pub id: RequestId,
71    pub result: Value,
72}
73
74impl JsonRpcResponse {
75    pub fn new(id: RequestId, result: impl Serialize) -> Result<Self, serde_json::Error> {
76        Ok(Self {
77            jsonrpc: JSONRPC_VERSION.to_owned(),
78            id,
79            result: serde_json::to_value(result)?,
80        })
81    }
82
83    pub fn ok(id: RequestId) -> Self {
84        Self {
85            jsonrpc: JSONRPC_VERSION.to_owned(),
86            id,
87            result: Value::Object(Default::default()),
88        }
89    }
90}
91
92/// A JSON-RPC 2.0 error response
93#[derive(Debug, Clone, Serialize, Deserialize)]
94pub struct JsonRpcError {
95    pub jsonrpc: String,
96    pub id: RequestId,
97    pub error: ErrorData,
98}
99
100impl JsonRpcError {
101    pub fn new(id: RequestId, error: impl Into<ErrorData>) -> Self {
102        Self {
103            jsonrpc: JSONRPC_VERSION.to_owned(),
104            id,
105            error: error.into(),
106        }
107    }
108}
109
110/// A JSON-RPC 2.0 notification (no id, no response expected)
111#[derive(Debug, Clone, Serialize, Deserialize)]
112pub struct JsonRpcNotification {
113    pub jsonrpc: String,
114    pub method: String,
115    #[serde(default, skip_serializing_if = "Option::is_none")]
116    pub params: Option<Value>,
117}
118
119impl JsonRpcNotification {
120    pub fn new(method: impl Into<String>, params: Option<Value>) -> Self {
121        Self {
122            jsonrpc: JSONRPC_VERSION.to_owned(),
123            method: method.into(),
124            params,
125        }
126    }
127}
128
129/// Any message that can be sent/received over the wire
130#[derive(Debug, Clone, Serialize, Deserialize)]
131#[serde(untagged)]
132pub enum JsonRpcMessage {
133    Request(JsonRpcRequest),
134    Response(JsonRpcResponse),
135    Error(JsonRpcError),
136    Notification(JsonRpcNotification),
137}
138
139impl JsonRpcMessage {
140    pub fn is_request(&self) -> bool {
141        matches!(self, Self::Request(_))
142    }
143
144    pub fn is_notification(&self) -> bool {
145        matches!(self, Self::Notification(_))
146    }
147
148    pub fn method(&self) -> Option<&str> {
149        match self {
150            Self::Request(r) => Some(&r.method),
151            Self::Notification(n) => Some(&n.method),
152            _ => None,
153        }
154    }
155
156    pub fn id(&self) -> Option<&RequestId> {
157        match self {
158            Self::Request(r) => Some(&r.id),
159            Self::Response(r) => Some(&r.id),
160            Self::Error(e) => Some(&e.id),
161            Self::Notification(_) => None,
162        }
163    }
164
165    pub fn into_request(self) -> Option<JsonRpcRequest> {
166        match self {
167            Self::Request(r) => Some(r),
168            _ => None,
169        }
170    }
171}
172
173/// Progress token — used in notifications/progress
174#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
175#[serde(untagged)]
176pub enum ProgressToken {
177    String(String),
178    Number(i64),
179}