1use serde::{Deserialize, Serialize};
8use serde_json::Value;
9
10#[cfg(feature = "native")]
12pub use rmcp::model::{
13 CallToolRequestParams, CallToolResult, Content, Prompt as RmcpPrompt, ProtocolVersion,
14 Resource as RmcpResource, Tool as RmcpTool,
15};
16
17#[cfg(feature = "native")]
19pub use rmcp::model::{
20 ClientCapabilities as RmcpClientCapabilities, PromptsCapability, ResourcesCapability,
21 ServerCapabilities as RmcpServerCapabilities, ToolsCapability,
22};
23
24#[cfg(feature = "native")]
29pub type McpTool = RmcpTool;
31
32#[cfg(feature = "native")]
33pub type McpResource = RmcpResource;
35
36#[cfg(feature = "native")]
37pub type McpPrompt = RmcpPrompt;
39
40#[cfg(feature = "native")]
41pub type CallToolParams = CallToolRequestParams;
43
44#[cfg(feature = "native")]
45pub type ServerCapabilities = RmcpServerCapabilities;
47
48#[cfg(feature = "native")]
49pub type ClientCapabilities = RmcpClientCapabilities;
51
52#[derive(Debug, Clone, Serialize, Deserialize)]
60pub struct JsonRpcRequest {
61 pub jsonrpc: String,
63 pub id: serde_json::Value,
65 pub method: String,
67 #[serde(skip_serializing_if = "Option::is_none")]
69 pub params: Option<Value>,
70}
71
72impl JsonRpcRequest {
73 pub fn new<T: Serialize>(
76 id: impl Into<Value>,
77 method: String,
78 params: Option<T>,
79 ) -> Result<Self, serde_json::Error> {
80 let params_value = match params {
81 Some(p) => Some(serde_json::to_value(p)?),
82 None => None,
83 };
84 Ok(Self {
85 jsonrpc: "2.0".to_string(),
86 id: id.into(),
87 method,
88 params: params_value,
89 })
90 }
91
92 pub fn new_unchecked<T: Serialize>(
95 id: impl Into<Value>,
96 method: String,
97 params: Option<T>,
98 ) -> Self {
99 Self::new(id, method, params).expect("Failed to serialize JSON-RPC request params")
100 }
101}
102
103#[derive(Debug, Clone, Serialize, Deserialize)]
105pub struct JsonRpcResponse {
106 pub jsonrpc: String,
108 pub id: serde_json::Value,
110 #[serde(skip_serializing_if = "Option::is_none")]
112 pub result: Option<Value>,
113 #[serde(skip_serializing_if = "Option::is_none")]
115 pub error: Option<JsonRpcError>,
116}
117
118#[derive(Debug, Clone, Serialize, Deserialize)]
120pub struct JsonRpcError {
121 pub code: i32,
123 pub message: String,
125 #[serde(skip_serializing_if = "Option::is_none")]
127 pub data: Option<Value>,
128}
129
130#[derive(Debug, Clone, Serialize, Deserialize)]
132pub struct JsonRpcNotification {
133 pub jsonrpc: String,
135 pub method: String,
137 #[serde(skip_serializing_if = "Option::is_none")]
139 pub params: Option<Value>,
140}
141
142impl JsonRpcNotification {
143 pub fn new<T: Serialize>(
146 method: impl Into<String>,
147 params: Option<T>,
148 ) -> Result<Self, serde_json::Error> {
149 let params_value = match params {
150 Some(p) => Some(serde_json::to_value(p)?),
151 None => None,
152 };
153 Ok(Self {
154 jsonrpc: "2.0".to_string(),
155 method: method.into(),
156 params: params_value,
157 })
158 }
159
160 pub fn new_unchecked<T: Serialize>(method: impl Into<String>, params: Option<T>) -> Self {
163 Self::new(method, params).expect("Failed to serialize JSON-RPC notification params")
164 }
165}
166
167#[derive(Debug, Clone)]
170pub enum JsonRpcMessage {
171 Response(JsonRpcResponse),
173 Notification(JsonRpcNotification),
175}
176
177impl JsonRpcMessage {
178 pub fn is_response(&self) -> bool {
180 matches!(self, JsonRpcMessage::Response(_))
181 }
182
183 pub fn is_notification(&self) -> bool {
185 matches!(self, JsonRpcMessage::Notification(_))
186 }
187
188 pub fn as_response(self) -> Option<JsonRpcResponse> {
190 match self {
191 JsonRpcMessage::Response(r) => Some(r),
192 _ => None,
193 }
194 }
195
196 pub fn as_notification(self) -> Option<JsonRpcNotification> {
198 match self {
199 JsonRpcMessage::Notification(n) => Some(n),
200 _ => None,
201 }
202 }
203}
204
205#[derive(Debug, Clone, Serialize, Deserialize)]
211pub struct ProgressParams {
212 #[serde(rename = "progressToken")]
214 pub progress_token: String,
215 pub progress: f64,
217 pub total: Option<f64>,
219 pub message: Option<String>,
221}
222
223#[derive(Debug, Clone)]
225pub enum McpNotification {
226 Progress(ProgressParams),
228 Unknown {
230 method: String,
232 params: Option<Value>,
234 },
235}
236
237impl McpNotification {
238 pub fn from_notification(notif: &JsonRpcNotification) -> Self {
240 match notif.method.as_str() {
241 "notifications/progress" => {
242 if let Some(ref params) = notif.params
243 && let Ok(progress) = serde_json::from_value::<ProgressParams>(params.clone())
244 {
245 return McpNotification::Progress(progress);
246 }
247 McpNotification::Unknown {
248 method: notif.method.clone(),
249 params: notif.params.clone(),
250 }
251 }
252 _ => McpNotification::Unknown {
253 method: notif.method.clone(),
254 params: notif.params.clone(),
255 },
256 }
257 }
258}
259
260#[cfg(feature = "native")]
269#[derive(Debug, Clone, Serialize, Deserialize)]
271pub struct InitializeParams {
272 #[serde(rename = "protocolVersion")]
274 pub protocol_version: String,
275 pub capabilities: ClientCapabilities,
277 #[serde(rename = "clientInfo")]
279 pub client_info: ClientInfo,
280}
281
282#[cfg(feature = "native")]
284#[derive(Debug, Clone, Serialize, Deserialize)]
285pub struct ClientInfo {
286 pub name: String,
288 pub version: String,
290}
291
292#[cfg(feature = "native")]
293#[derive(Debug, Clone, Serialize, Deserialize)]
295pub struct InitializeResult {
296 #[serde(rename = "protocolVersion")]
298 pub protocol_version: String,
299 pub capabilities: ServerCapabilities,
301 #[serde(rename = "serverInfo")]
303 pub server_info: ServerInfo,
304}
305
306#[cfg(feature = "native")]
308#[derive(Debug, Clone, Serialize, Deserialize)]
309pub struct ServerInfo {
310 pub name: String,
312 pub version: String,
314}
315
316#[cfg(feature = "native")]
317#[derive(Debug, Clone, Serialize, Deserialize)]
319pub struct ListToolsResult {
320 pub tools: Vec<McpTool>,
322}
323
324#[cfg(feature = "native")]
325#[derive(Debug, Clone, Serialize, Deserialize)]
327pub struct ListResourcesResult {
328 pub resources: Vec<McpResource>,
330}
331
332#[cfg(feature = "native")]
333#[derive(Debug, Clone, Serialize, Deserialize)]
335pub struct ListPromptsResult {
336 pub prompts: Vec<McpPrompt>,
338}
339
340#[cfg(feature = "native")]
341#[derive(Debug, Clone, Serialize, Deserialize)]
343pub struct ReadResourceParams {
344 pub uri: String,
346}
347
348#[cfg(feature = "native")]
349#[derive(Debug, Clone, Serialize, Deserialize)]
351pub struct ReadResourceResult {
352 pub contents: Vec<ResourceContent>,
354}
355
356#[cfg(feature = "native")]
358#[derive(Debug, Clone, Serialize, Deserialize)]
359#[serde(tag = "type", rename_all = "lowercase")]
360pub enum ResourceContent {
361 Text {
363 uri: String,
365 mime_type: Option<String>,
367 text: String,
369 },
370 Blob {
372 uri: String,
374 mime_type: Option<String>,
376 blob: String,
378 },
379}
380
381#[cfg(feature = "native")]
382#[derive(Debug, Clone, Serialize, Deserialize)]
384pub struct GetPromptParams {
385 pub name: String,
387 #[serde(skip_serializing_if = "Option::is_none")]
389 pub arguments: Option<Value>,
390}
391
392#[cfg(feature = "native")]
393#[derive(Debug, Clone, Serialize, Deserialize)]
395pub struct GetPromptResult {
396 pub description: String,
398 pub messages: Vec<PromptMessage>,
400}
401
402#[cfg(feature = "native")]
404#[derive(Debug, Clone, Serialize, Deserialize)]
405pub struct PromptMessage {
406 pub role: String,
408 pub content: PromptContent,
410}
411
412#[cfg(feature = "native")]
414#[derive(Debug, Clone, Serialize, Deserialize)]
415#[serde(tag = "type", rename_all = "lowercase")]
416pub enum PromptContent {
417 Text {
419 text: String,
421 },
422 Image {
424 data: String,
426 mime_type: String,
428 },
429 Resource {
431 resource: McpResource,
433 },
434}
435
436#[cfg(feature = "native")]
437#[derive(Debug, Clone, Serialize, Deserialize)]
439pub struct PromptArgument {
440 pub name: String,
442 pub description: String,
444 pub required: bool,
446}
447
448#[cfg(feature = "native")]
450#[derive(Debug, Clone, Serialize, Deserialize)]
451#[serde(tag = "type", rename_all = "lowercase")]
452pub enum ToolResultContent {
453 Text {
455 text: String,
457 },
458 Image {
460 data: String,
462 mime_type: String,
464 },
465 Resource {
467 resource: McpResource,
469 },
470}
471
472#[cfg(test)]
477mod tests {
478 use super::*;
479 use serde_json::json;
480
481 #[test]
482 fn test_json_rpc_request_new() {
483 let request =
484 JsonRpcRequest::new(1, "test_method".to_string(), Some(json!({"key": "value"})))
485 .unwrap();
486
487 assert_eq!(request.jsonrpc, "2.0");
488 assert_eq!(request.id, json!(1));
489 assert_eq!(request.method, "test_method");
490 assert!(request.params.is_some());
491 }
492
493 #[test]
494 fn test_json_rpc_request_serialization() {
495 let request = JsonRpcRequest::new(1, "test".to_string(), None::<()>).unwrap();
496 let json = serde_json::to_string(&request).unwrap();
497
498 assert!(json.contains("jsonrpc"));
499 assert!(json.contains("2.0"));
500 assert!(json.contains("test"));
501 }
502
503 #[test]
504 fn test_json_rpc_response_success() {
505 let response = JsonRpcResponse {
506 jsonrpc: "2.0".to_string(),
507 id: json!(1),
508 result: Some(json!({"status": "ok"})),
509 error: None,
510 };
511
512 assert!(response.result.is_some());
513 assert!(response.error.is_none());
514 }
515
516 #[test]
517 fn test_json_rpc_response_error() {
518 let response = JsonRpcResponse {
519 jsonrpc: "2.0".to_string(),
520 id: json!(1),
521 result: None,
522 error: Some(JsonRpcError {
523 code: -32600,
524 message: "Invalid Request".to_string(),
525 data: None,
526 }),
527 };
528
529 assert!(response.result.is_none());
530 assert!(response.error.is_some());
531 }
532
533 #[cfg(feature = "native")]
534 #[test]
535 fn test_type_aliases_work() {
536 let _tool: McpTool;
538 let _resource: McpResource;
539 let _prompt: McpPrompt;
540 }
542}