mcp_core/transport/mod.rs
1//! # MCP Transport Layer
2//!
3//! This module implements the transport layer for the Model Context Protocol (MCP).
4//! It provides abstractions for sending and receiving JSON-RPC messages between
5//! clients and servers using different transport mechanisms.
6//!
7//! The transport layer:
8//! - Handles serialization and deserialization of messages
9//! - Provides interfaces for sending and receiving messages
10//! - Defines transport-specific implementations (SSE, stdio)
11//! - Abstracts the underlying communication protocol
12//!
13//! The core component is the `Transport` trait, which defines the operations that
14//! any MCP transport must support, regardless of the underlying mechanism.
15
16use std::{future::Future, pin::Pin};
17
18use anyhow::Result;
19use async_trait::async_trait;
20use serde::{Deserialize, Serialize};
21
22mod client;
23pub use client::*;
24
25mod server;
26pub use server::*;
27
28use crate::protocol::RequestOptions;
29
30/// A message in the MCP protocol.
31///
32/// Currently, only JSON-RPC messages are supported, as defined in the
33/// [MCP specification](https://spec.modelcontextprotocol.io/specification/basic/messages/).
34pub type Message = JsonRpcMessage;
35
36/// Core trait that defines operations for MCP transports.
37///
38/// This trait abstracts the transport layer, allowing the protocol to work
39/// with different communication mechanisms (SSE, stdio, etc.).
40#[async_trait()]
41pub trait Transport: Send + Sync + 'static {
42 /// Opens the transport connection.
43 ///
44 /// This initializes the transport and prepares it for communication.
45 ///
46 /// # Returns
47 ///
48 /// A `Result` indicating success or failure
49 async fn open(&self) -> Result<()>;
50
51 /// Closes the transport connection.
52 ///
53 /// This terminates the transport and releases any resources.
54 ///
55 /// # Returns
56 ///
57 /// A `Result` indicating success or failure
58 async fn close(&self) -> Result<()>;
59
60 /// Polls for incoming messages.
61 ///
62 /// This checks for any new messages from the other endpoint.
63 ///
64 /// # Returns
65 ///
66 /// A `Result` containing an `Option<Message>` if a message is available
67 async fn poll_message(&self) -> Result<Option<Message>>;
68
69 /// Sends a request and waits for the response.
70 ///
71 /// # Arguments
72 ///
73 /// * `method` - The method name for the request
74 /// * `params` - Optional parameters for the request
75 /// * `options` - Request options (like timeout)
76 ///
77 /// # Returns
78 ///
79 /// A `Future` that resolves to a `Result` containing the response
80 fn request(
81 &self,
82 method: &str,
83 params: Option<serde_json::Value>,
84 options: RequestOptions,
85 ) -> Pin<Box<dyn Future<Output = Result<JsonRpcResponse>> + Send + Sync>>;
86
87 /// Sends a notification.
88 ///
89 /// Unlike requests, notifications do not expect a response.
90 ///
91 /// # Arguments
92 ///
93 /// * `method` - The method name for the notification
94 /// * `params` - Optional parameters for the notification
95 ///
96 /// # Returns
97 ///
98 /// A `Result` indicating success or failure
99 async fn send_notification(
100 &self,
101 method: &str,
102 params: Option<serde_json::Value>,
103 ) -> Result<()>;
104
105 /// Sends a response to a request.
106 ///
107 /// # Arguments
108 ///
109 /// * `id` - The ID of the request being responded to
110 /// * `result` - Optional successful result
111 /// * `error` - Optional error information
112 ///
113 /// # Returns
114 ///
115 /// A `Result` indicating success or failure
116 async fn send_response(
117 &self,
118 id: RequestId,
119 result: Option<serde_json::Value>,
120 error: Option<JsonRpcError>,
121 ) -> Result<()>;
122}
123
124/// Type representing a JSON-RPC request ID.
125///
126/// Request IDs are used to match responses to their corresponding requests.
127pub type RequestId = u64;
128
129/// Represents a JSON-RPC protocol version.
130///
131/// The JSON-RPC version is included in all JSON-RPC messages and
132/// is typically "2.0" for the current version of the protocol.
133#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
134#[serde(transparent)]
135pub struct JsonRpcVersion(String);
136
137impl Default for JsonRpcVersion {
138 /// Creates a default JSON-RPC version (2.0).
139 ///
140 /// # Returns
141 ///
142 /// A new `JsonRpcVersion` with value "2.0"
143 fn default() -> Self {
144 JsonRpcVersion("2.0".to_owned())
145 }
146}
147
148impl JsonRpcVersion {
149 /// Returns the version as a string slice.
150 ///
151 /// # Returns
152 ///
153 /// A string slice containing the version
154 pub fn as_str(&self) -> &str {
155 &self.0
156 }
157}
158
159/// Represents a JSON-RPC message.
160///
161/// This enum can be a request, a response, or a notification.
162#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
163#[serde(deny_unknown_fields)]
164#[serde(untagged)]
165pub enum JsonRpcMessage {
166 /// A response to a request
167 Response(JsonRpcResponse),
168 /// A request that expects a response
169 Request(JsonRpcRequest),
170 /// A notification that does not expect a response
171 Notification(JsonRpcNotification),
172}
173
174/// Represents a JSON-RPC request.
175///
176/// A request is a message that expects a response with the same ID.
177#[derive(Debug, Clone, Serialize, Deserialize, Default, PartialEq, Eq)]
178#[serde(deny_unknown_fields)]
179pub struct JsonRpcRequest {
180 /// The request ID, used to match with the response
181 pub id: RequestId,
182 /// The method name to call
183 pub method: String,
184 /// Optional parameters for the method
185 #[serde(skip_serializing_if = "Option::is_none")]
186 pub params: Option<serde_json::Value>,
187 /// The JSON-RPC version
188 pub jsonrpc: JsonRpcVersion,
189}
190
191/// Represents a JSON-RPC notification.
192///
193/// A notification is a message that does not expect a response.
194#[derive(Debug, Clone, Serialize, Deserialize, Default, PartialEq, Eq)]
195#[serde(rename_all = "camelCase")]
196#[serde(deny_unknown_fields)]
197#[serde(default)]
198pub struct JsonRpcNotification {
199 /// The method name for the notification
200 pub method: String,
201 /// Optional parameters for the notification
202 #[serde(skip_serializing_if = "Option::is_none")]
203 pub params: Option<serde_json::Value>,
204 /// The JSON-RPC version
205 pub jsonrpc: JsonRpcVersion,
206}
207
208/// Represents a JSON-RPC response.
209///
210/// A response is a message sent in reply to a request with the same ID.
211#[derive(Debug, Clone, Serialize, Deserialize, Default, PartialEq, Eq)]
212#[serde(deny_unknown_fields)]
213#[serde(rename_all = "camelCase")]
214#[serde(default)]
215pub struct JsonRpcResponse {
216 /// The request ID this response corresponds to
217 pub id: RequestId,
218 /// The result of the request, if successful
219 #[serde(skip_serializing_if = "Option::is_none")]
220 pub result: Option<serde_json::Value>,
221 /// The error, if the request failed
222 #[serde(skip_serializing_if = "Option::is_none")]
223 pub error: Option<JsonRpcError>,
224 /// The JSON-RPC version
225 pub jsonrpc: JsonRpcVersion,
226}
227
228/// Represents a JSON-RPC error.
229///
230/// An error is included in a response when the request fails.
231#[derive(Debug, Clone, Serialize, Deserialize, Default, PartialEq, Eq)]
232#[serde(rename_all = "camelCase")]
233#[serde(default)]
234pub struct JsonRpcError {
235 /// Error code
236 pub code: i32,
237 /// Error message
238 pub message: String,
239 /// Optional additional error data
240 #[serde(skip_serializing_if = "Option::is_none")]
241 pub data: Option<serde_json::Value>,
242}