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")]
416#[allow(clippy::large_enum_variant)]
419pub enum PromptContent {
420 Text {
422 text: String,
424 },
425 Image {
427 data: String,
429 mime_type: String,
431 },
432 Resource {
434 resource: McpResource,
436 },
437}
438
439#[cfg(feature = "native")]
440#[derive(Debug, Clone, Serialize, Deserialize)]
442pub struct PromptArgument {
443 pub name: String,
445 pub description: String,
447 pub required: bool,
449}
450
451#[cfg(feature = "native")]
453#[derive(Debug, Clone, Serialize, Deserialize)]
454#[serde(tag = "type", rename_all = "lowercase")]
455#[allow(clippy::large_enum_variant)]
458pub enum ToolResultContent {
459 Text {
461 text: String,
463 },
464 Image {
466 data: String,
468 mime_type: String,
470 },
471 Resource {
473 resource: McpResource,
475 },
476}
477
478#[cfg(test)]
483mod tests {
484 use super::*;
485 use serde_json::json;
486
487 #[test]
488 fn test_json_rpc_request_new() {
489 let request =
490 JsonRpcRequest::new(1, "test_method".to_string(), Some(json!({"key": "value"})))
491 .unwrap();
492
493 assert_eq!(request.jsonrpc, "2.0");
494 assert_eq!(request.id, json!(1));
495 assert_eq!(request.method, "test_method");
496 assert!(request.params.is_some());
497 }
498
499 #[test]
500 fn test_json_rpc_request_serialization() {
501 let request = JsonRpcRequest::new(1, "test".to_string(), None::<()>).unwrap();
502 let json = serde_json::to_string(&request).unwrap();
503
504 assert!(json.contains("jsonrpc"));
505 assert!(json.contains("2.0"));
506 assert!(json.contains("test"));
507 }
508
509 #[test]
510 fn test_json_rpc_response_success() {
511 let response = JsonRpcResponse {
512 jsonrpc: "2.0".to_string(),
513 id: json!(1),
514 result: Some(json!({"status": "ok"})),
515 error: None,
516 };
517
518 assert!(response.result.is_some());
519 assert!(response.error.is_none());
520 }
521
522 #[test]
523 fn test_json_rpc_response_error() {
524 let response = JsonRpcResponse {
525 jsonrpc: "2.0".to_string(),
526 id: json!(1),
527 result: None,
528 error: Some(JsonRpcError {
529 code: -32600,
530 message: "Invalid Request".to_string(),
531 data: None,
532 }),
533 };
534
535 assert!(response.result.is_none());
536 assert!(response.error.is_some());
537 }
538
539 #[cfg(feature = "native")]
540 #[test]
541 fn test_type_aliases_work() {
542 let _tool: McpTool;
544 let _resource: McpResource;
545 let _prompt: McpPrompt;
546 }
548}