1use crate::{
3 content::Content,
4 prompt::{Prompt, PromptMessage},
5 resource::Resource,
6 resource::ResourceContents,
7 tool::Tool,
8};
9use serde::{Deserialize, Serialize};
10use serde_json::Value;
11
12#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
13pub struct JsonRpcRequest {
14 pub jsonrpc: String,
15 #[serde(skip_serializing_if = "Option::is_none")]
16 pub id: Option<u64>,
17 pub method: String,
18 #[serde(skip_serializing_if = "Option::is_none")]
19 pub params: Option<Value>,
20}
21
22#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
23pub struct JsonRpcResponse {
24 pub jsonrpc: String,
25 #[serde(skip_serializing_if = "Option::is_none")]
26 pub id: Option<u64>,
27 #[serde(skip_serializing_if = "Option::is_none")]
28 pub result: Option<Value>,
29 #[serde(skip_serializing_if = "Option::is_none")]
30 pub error: Option<ErrorData>,
31}
32
33#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
34pub struct JsonRpcNotification {
35 pub jsonrpc: String,
36 pub method: String,
37 #[serde(skip_serializing_if = "Option::is_none")]
38 pub params: Option<Value>,
39}
40
41#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
42pub struct JsonRpcError {
43 pub jsonrpc: String,
44 #[serde(skip_serializing_if = "Option::is_none")]
45 pub id: Option<u64>,
46 pub error: ErrorData,
47}
48
49#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
50#[serde(untagged, try_from = "JsonRpcRaw")]
51pub enum JsonRpcMessage {
52 Request(JsonRpcRequest),
53 Response(JsonRpcResponse),
54 Notification(JsonRpcNotification),
55 Error(JsonRpcError),
56 Nil, }
58
59#[derive(Debug, Serialize, Deserialize)]
60struct JsonRpcRaw {
61 jsonrpc: String,
62 #[serde(skip_serializing_if = "Option::is_none")]
63 id: Option<u64>,
64 #[serde(skip_serializing_if = "Option::is_none")]
65 method: Option<String>,
66 #[serde(skip_serializing_if = "Option::is_none")]
67 params: Option<Value>,
68 #[serde(skip_serializing_if = "Option::is_none")]
69 result: Option<Value>,
70 #[serde(skip_serializing_if = "Option::is_none")]
71 error: Option<ErrorData>,
72}
73
74impl TryFrom<JsonRpcRaw> for JsonRpcMessage {
75 type Error = String;
76
77 fn try_from(raw: JsonRpcRaw) -> Result<Self, <Self as TryFrom<JsonRpcRaw>>::Error> {
78 if raw.error.is_some() {
80 return Ok(JsonRpcMessage::Error(JsonRpcError {
81 jsonrpc: raw.jsonrpc,
82 id: raw.id,
83 error: raw.error.unwrap(),
84 }));
85 }
86
87 if raw.result.is_some() {
89 return Ok(JsonRpcMessage::Response(JsonRpcResponse {
90 jsonrpc: raw.jsonrpc,
91 id: raw.id,
92 result: raw.result,
93 error: None,
94 }));
95 }
96
97 if let Some(method) = raw.method {
99 if raw.id.is_none() {
100 return Ok(JsonRpcMessage::Notification(JsonRpcNotification {
101 jsonrpc: raw.jsonrpc,
102 method,
103 params: raw.params,
104 }));
105 }
106
107 return Ok(JsonRpcMessage::Request(JsonRpcRequest {
108 jsonrpc: raw.jsonrpc,
109 id: raw.id,
110 method,
111 params: raw.params,
112 }));
113 }
114
115 if raw.id.is_none() && raw.result.is_none() && raw.error.is_none() {
117 return Ok(JsonRpcMessage::Nil);
118 }
119
120 Err(format!(
122 "Invalid JSON-RPC message format: id={:?}, method={:?}, result={:?}, error={:?}",
123 raw.id, raw.method, raw.result, raw.error
124 ))
125 }
126}
127
128pub const PARSE_ERROR: i32 = -32700;
130pub const INVALID_REQUEST: i32 = -32600;
131pub const METHOD_NOT_FOUND: i32 = -32601;
132pub const INVALID_PARAMS: i32 = -32602;
133pub const INTERNAL_ERROR: i32 = -32603;
134
135#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
137pub struct ErrorData {
138 pub code: i32,
140
141 pub message: String,
143
144 #[serde(skip_serializing_if = "Option::is_none")]
147 pub data: Option<Value>,
148}
149
150#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
151#[serde(rename_all = "camelCase")]
152pub struct InitializeResult {
153 pub protocol_version: String,
154 pub capabilities: ServerCapabilities,
155 pub server_info: Implementation,
156 #[serde(skip_serializing_if = "Option::is_none")]
157 pub instructions: Option<String>,
158}
159
160#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
161pub struct Implementation {
162 pub name: String,
163 pub version: String,
164}
165
166#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
167pub struct ServerCapabilities {
168 #[serde(skip_serializing_if = "Option::is_none")]
169 pub prompts: Option<PromptsCapability>,
170 #[serde(skip_serializing_if = "Option::is_none")]
171 pub resources: Option<ResourcesCapability>,
172 #[serde(skip_serializing_if = "Option::is_none")]
173 pub tools: Option<ToolsCapability>,
174 }
176
177#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
178#[serde(rename_all = "camelCase")]
179pub struct PromptsCapability {
180 pub list_changed: Option<bool>,
181}
182
183#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
184#[serde(rename_all = "camelCase")]
185pub struct ResourcesCapability {
186 pub subscribe: Option<bool>,
187 pub list_changed: Option<bool>,
188}
189
190#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
191#[serde(rename_all = "camelCase")]
192pub struct ToolsCapability {
193 pub list_changed: Option<bool>,
194}
195
196#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
197#[serde(rename_all = "camelCase")]
198pub struct ListResourcesResult {
199 pub resources: Vec<Resource>,
200 #[serde(skip_serializing_if = "Option::is_none")]
201 pub next_cursor: Option<String>,
202}
203
204#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
205pub struct ReadResourceResult {
206 pub contents: Vec<ResourceContents>,
207}
208
209#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
210#[serde(rename_all = "camelCase")]
211pub struct ListToolsResult {
212 pub tools: Vec<Tool>,
213 #[serde(skip_serializing_if = "Option::is_none")]
214 pub next_cursor: Option<String>,
215}
216
217#[derive(Debug, Serialize, Deserialize)]
218#[serde(rename_all = "camelCase")]
219pub struct CallToolResult {
220 pub content: Vec<Content>,
221 #[serde(skip_serializing_if = "Option::is_none")]
222 pub is_error: Option<bool>,
223}
224
225#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
226pub struct ListPromptsResult {
227 pub prompts: Vec<Prompt>,
228}
229
230#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
231pub struct GetPromptResult {
232 #[serde(skip_serializing_if = "Option::is_none")]
233 pub description: Option<String>,
234 pub messages: Vec<PromptMessage>,
235}
236
237#[derive(Debug, Serialize, Deserialize)]
238pub struct EmptyResult {}
239
240#[cfg(test)]
241mod tests {
242 use super::*;
243 use serde_json::json;
244
245 #[test]
246 fn test_notification_conversion() {
247 let raw = JsonRpcRaw {
248 jsonrpc: "2.0".to_string(),
249 id: None,
250 method: Some("notify".to_string()),
251 params: Some(json!({"key": "value"})),
252 result: None,
253 error: None,
254 };
255
256 let message = JsonRpcMessage::try_from(raw).unwrap();
257 match message {
258 JsonRpcMessage::Notification(n) => {
259 assert_eq!(n.jsonrpc, "2.0");
260 assert_eq!(n.method, "notify");
261 assert_eq!(n.params.unwrap(), json!({"key": "value"}));
262 }
263 _ => panic!("Expected Notification"),
264 }
265 }
266
267 #[test]
268 fn test_request_conversion() {
269 let raw = JsonRpcRaw {
270 jsonrpc: "2.0".to_string(),
271 id: Some(1),
272 method: Some("request".to_string()),
273 params: Some(json!({"key": "value"})),
274 result: None,
275 error: None,
276 };
277
278 let message = JsonRpcMessage::try_from(raw).unwrap();
279 match message {
280 JsonRpcMessage::Request(r) => {
281 assert_eq!(r.jsonrpc, "2.0");
282 assert_eq!(r.id, Some(1));
283 assert_eq!(r.method, "request");
284 assert_eq!(r.params.unwrap(), json!({"key": "value"}));
285 }
286 _ => panic!("Expected Request"),
287 }
288 }
289}