async_mcp/transport/
mod.rs1use anyhow::Result;
6use async_trait::async_trait;
7use serde::{Deserialize, Serialize};
8
9mod stdio_transport;
10pub use stdio_transport::*;
11mod inmemory_transport;
12pub use inmemory_transport::*;
13mod sse_transport;
14pub use sse_transport::*;
15mod ws_transport;
16pub use ws_transport::*;
17mod http_transport;
18pub use http_transport::*;
19pub type Message = JsonRpcMessage;
22
23#[async_trait]
24pub trait Transport: Send + Sync + 'static {
25 async fn send(&self, message: &Message) -> Result<()>;
27
28 async fn receive(&self) -> Result<Option<Message>>;
31
32 async fn open(&self) -> Result<()>;
34
35 async fn close(&self) -> Result<()>;
37}
38
39pub type RequestId = u64;
41#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
43#[serde(transparent)]
44pub struct JsonRpcVersion(String);
45
46impl Default for JsonRpcVersion {
47 fn default() -> Self {
48 JsonRpcVersion("2.0".to_owned())
49 }
50}
51
52impl JsonRpcVersion {
53 pub fn as_str(&self) -> &str {
54 &self.0
55 }
56}
57
58#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
59#[serde(deny_unknown_fields)]
60#[serde(untagged)]
61pub enum JsonRpcMessage {
62 Response(JsonRpcResponse),
63 Request(JsonRpcRequest),
64 Notification(JsonRpcNotification),
65}
66
67#[derive(Debug, Clone, Serialize, Deserialize, Default, PartialEq, Eq)]
69#[serde(deny_unknown_fields)]
70pub struct JsonRpcRequest {
71 pub id: RequestId,
72 pub method: String,
73 #[serde(skip_serializing_if = "Option::is_none")]
74 pub params: Option<serde_json::Value>,
75 pub jsonrpc: JsonRpcVersion,
76}
77
78#[derive(Debug, Clone, Serialize, Deserialize, Default, PartialEq, Eq)]
79#[serde(rename_all = "camelCase")]
80#[serde(deny_unknown_fields)]
81#[serde(default)]
82pub struct JsonRpcNotification {
83 pub method: String,
84 #[serde(skip_serializing_if = "Option::is_none")]
85 pub params: Option<serde_json::Value>,
86 pub jsonrpc: JsonRpcVersion,
87}
88
89#[derive(Debug, Clone, Serialize, Deserialize, Default, PartialEq, Eq)]
90#[serde(deny_unknown_fields)]
91#[serde(rename_all = "camelCase")]
92#[serde(default)]
93pub struct JsonRpcResponse {
94 pub id: RequestId,
96 #[serde(skip_serializing_if = "Option::is_none")]
98 pub result: Option<serde_json::Value>,
99 #[serde(skip_serializing_if = "Option::is_none")]
101 pub error: Option<JsonRpcError>,
102 pub jsonrpc: JsonRpcVersion,
104}
105
106#[derive(Debug, Clone, Serialize, Deserialize, Default, PartialEq, Eq)]
107#[serde(rename_all = "camelCase")]
108#[serde(default)]
109pub struct JsonRpcError {
110 pub code: i32,
112 pub message: String,
114 #[serde(skip_serializing_if = "Option::is_none")]
116 pub data: Option<serde_json::Value>,
117}
118
119#[cfg(test)]
120mod tests {
121 use super::*;
122 #[test]
123 fn test_deserialize_initialize_request() {
124 let json = r#"{"method":"initialize","params":{"protocolVersion":"2024-11-05","capabilities":{},"clientInfo":{"name":"claude-ai","version":"0.1.0"}},"jsonrpc":"2.0","id":0}"#;
125
126 let message: Message = serde_json::from_str(json).unwrap();
127 match message {
128 JsonRpcMessage::Request(req) => {
129 assert_eq!(req.jsonrpc.as_str(), "2.0");
130 assert_eq!(req.id, 0);
131 assert_eq!(req.method, "initialize");
132
133 let params = req.params.expect("params should exist");
135 assert!(params.is_object());
136
137 let params_obj = params.as_object().unwrap();
138 assert_eq!(params_obj["protocolVersion"], "2024-11-05");
139
140 let client_info = params_obj["clientInfo"].as_object().unwrap();
141 assert_eq!(client_info["name"], "claude-ai");
142 assert_eq!(client_info["version"], "0.1.0");
143 }
144 _ => panic!("Expected Request variant"),
145 }
146 }
147}