mcp_protocol_sdk/transport/
traits.rs

1//! Transport layer traits and abstractions
2//!
3//! This module defines the core transport traits that enable MCP communication
4//! over different protocols like STDIO, HTTP, and WebSocket.
5
6use crate::core::error::McpResult;
7use crate::protocol::types::{JsonRpcNotification, JsonRpcRequest, JsonRpcResponse};
8use async_trait::async_trait;
9
10/// Transport trait for MCP clients
11///
12/// This trait defines the interface for sending requests and receiving responses
13/// in a client-side MCP connection.
14#[async_trait]
15pub trait Transport: Send + Sync {
16    /// Send a JSON-RPC request and wait for a response
17    ///
18    /// # Arguments
19    /// * `request` - The JSON-RPC request to send
20    ///
21    /// # Returns
22    /// Result containing the JSON-RPC response or an error
23    async fn send_request(&mut self, request: JsonRpcRequest) -> McpResult<JsonRpcResponse>;
24
25    /// Send a JSON-RPC notification (no response expected)
26    ///
27    /// # Arguments
28    /// * `notification` - The JSON-RPC notification to send
29    ///
30    /// # Returns
31    /// Result indicating success or an error
32    async fn send_notification(&mut self, notification: JsonRpcNotification) -> McpResult<()>;
33
34    /// Receive a notification from the server (non-blocking)
35    ///
36    /// # Returns
37    /// Result containing an optional notification or an error
38    async fn receive_notification(&mut self) -> McpResult<Option<JsonRpcNotification>>;
39
40    /// Close the transport connection
41    ///
42    /// # Returns
43    /// Result indicating success or an error
44    async fn close(&mut self) -> McpResult<()>;
45
46    /// Check if the transport is connected
47    ///
48    /// # Returns
49    /// True if the transport is connected and ready for communication
50    fn is_connected(&self) -> bool {
51        true // Default implementation - assume connected
52    }
53
54    /// Get connection information for debugging
55    ///
56    /// # Returns
57    /// String describing the connection
58    fn connection_info(&self) -> String {
59        "Unknown transport".to_string()
60    }
61}
62
63/// Transport trait for MCP servers
64///
65/// This trait defines the interface for handling incoming requests and
66/// sending responses in a server-side MCP connection.
67#[async_trait]
68pub trait ServerTransport: Send + Sync {
69    /// Start the server transport and begin listening for connections
70    ///
71    /// # Returns
72    /// Result indicating success or an error
73    async fn start(&mut self) -> McpResult<()>;
74
75    /// Handle an incoming JSON-RPC request and return a response
76    ///
77    /// # Arguments
78    /// * `request` - The incoming JSON-RPC request
79    ///
80    /// # Returns
81    /// Result containing the JSON-RPC response or an error
82    async fn handle_request(&mut self, request: JsonRpcRequest) -> McpResult<JsonRpcResponse>;
83
84    /// Send a JSON-RPC notification to the client
85    ///
86    /// # Arguments
87    /// * `notification` - The JSON-RPC notification to send
88    ///
89    /// # Returns
90    /// Result indicating success or an error
91    async fn send_notification(&mut self, notification: JsonRpcNotification) -> McpResult<()>;
92
93    /// Stop the server transport
94    ///
95    /// # Returns
96    /// Result indicating success or an error
97    async fn stop(&mut self) -> McpResult<()>;
98
99    /// Check if the server is running
100    ///
101    /// # Returns
102    /// True if the server is running and accepting connections
103    fn is_running(&self) -> bool {
104        true // Default implementation - assume running
105    }
106
107    /// Get server information for debugging
108    ///
109    /// # Returns
110    /// String describing the server state
111    fn server_info(&self) -> String {
112        "Unknown server transport".to_string()
113    }
114}
115
116/// Transport configuration options
117#[derive(Debug, Clone)]
118pub struct TransportConfig {
119    /// Connection timeout in milliseconds
120    pub connect_timeout_ms: Option<u64>,
121    /// Read timeout in milliseconds
122    pub read_timeout_ms: Option<u64>,
123    /// Write timeout in milliseconds
124    pub write_timeout_ms: Option<u64>,
125    /// Maximum message size in bytes
126    pub max_message_size: Option<usize>,
127    /// Keep-alive interval in milliseconds
128    pub keep_alive_ms: Option<u64>,
129    /// Whether to enable compression
130    pub compression: bool,
131    /// Custom headers for HTTP-based transports
132    pub headers: std::collections::HashMap<String, String>,
133}
134
135impl Default for TransportConfig {
136    fn default() -> Self {
137        Self {
138            connect_timeout_ms: Some(30_000),         // 30 seconds
139            read_timeout_ms: Some(60_000),            // 60 seconds
140            write_timeout_ms: Some(30_000),           // 30 seconds
141            max_message_size: Some(16 * 1024 * 1024), // 16 MB
142            keep_alive_ms: Some(30_000),              // 30 seconds
143            compression: false,
144            headers: std::collections::HashMap::new(),
145        }
146    }
147}
148
149/// Connection state for transports
150#[derive(Debug, Clone, PartialEq)]
151pub enum ConnectionState {
152    /// Transport is disconnected
153    Disconnected,
154    /// Transport is connecting
155    Connecting,
156    /// Transport is connected and ready
157    Connected,
158    /// Transport is reconnecting after an error
159    Reconnecting,
160    /// Transport is closing
161    Closing,
162    /// Transport has encountered an error
163    Error(String),
164}
165
166/// Transport statistics for monitoring
167#[derive(Debug, Clone, Default)]
168pub struct TransportStats {
169    /// Number of requests sent
170    pub requests_sent: u64,
171    /// Number of responses received
172    pub responses_received: u64,
173    /// Number of notifications sent
174    pub notifications_sent: u64,
175    /// Number of notifications received
176    pub notifications_received: u64,
177    /// Number of connection errors
178    pub connection_errors: u64,
179    /// Number of protocol errors
180    pub protocol_errors: u64,
181    /// Total bytes sent
182    pub bytes_sent: u64,
183    /// Total bytes received
184    pub bytes_received: u64,
185    /// Connection uptime in milliseconds
186    pub uptime_ms: u64,
187}
188
189/// Trait for transports that support statistics
190pub trait TransportStats_: Send + Sync {
191    /// Get current transport statistics
192    fn stats(&self) -> TransportStats;
193
194    /// Reset transport statistics
195    fn reset_stats(&mut self);
196}
197
198/// Trait for transports that support reconnection
199#[async_trait]
200pub trait ReconnectableTransport: Transport {
201    /// Attempt to reconnect the transport
202    ///
203    /// # Returns
204    /// Result indicating success or an error
205    async fn reconnect(&mut self) -> McpResult<()>;
206
207    /// Set the reconnection configuration
208    ///
209    /// # Arguments
210    /// * `config` - Reconnection configuration
211    fn set_reconnect_config(&mut self, config: ReconnectConfig);
212
213    /// Get the current connection state
214    fn connection_state(&self) -> ConnectionState;
215}
216
217/// Configuration for automatic reconnection
218#[derive(Debug, Clone)]
219pub struct ReconnectConfig {
220    /// Whether automatic reconnection is enabled
221    pub enabled: bool,
222    /// Maximum number of reconnection attempts
223    pub max_attempts: Option<u32>,
224    /// Initial delay before first reconnection attempt (milliseconds)
225    pub initial_delay_ms: u64,
226    /// Maximum delay between reconnection attempts (milliseconds)
227    pub max_delay_ms: u64,
228    /// Multiplier for exponential backoff
229    pub backoff_multiplier: f64,
230    /// Jitter factor for randomizing delays (0.0 to 1.0)
231    pub jitter_factor: f64,
232}
233
234impl Default for ReconnectConfig {
235    fn default() -> Self {
236        Self {
237            enabled: true,
238            max_attempts: Some(5),
239            initial_delay_ms: 1000, // 1 second
240            max_delay_ms: 30_000,   // 30 seconds
241            backoff_multiplier: 2.0,
242            jitter_factor: 0.1,
243        }
244    }
245}
246
247/// Trait for transports that support message filtering
248pub trait FilterableTransport: Send + Sync {
249    /// Set a message filter function
250    ///
251    /// # Arguments
252    /// * `filter` - Function that returns true if message should be processed
253    fn set_message_filter(&mut self, filter: Box<dyn Fn(&JsonRpcRequest) -> bool + Send + Sync>);
254
255    /// Clear the message filter
256    fn clear_message_filter(&mut self);
257}
258
259/// Transport event for monitoring and debugging
260#[derive(Debug, Clone)]
261pub enum TransportEvent {
262    /// Connection established
263    Connected,
264    /// Connection lost
265    Disconnected,
266    /// Message sent
267    MessageSent {
268        /// Message type
269        message_type: String,
270        /// Message size in bytes
271        size: usize,
272    },
273    /// Message received
274    MessageReceived {
275        /// Message type
276        message_type: String,
277        /// Message size in bytes
278        size: usize,
279    },
280    /// Error occurred
281    Error {
282        /// Error message
283        message: String,
284    },
285}
286
287/// Trait for transports that support event listeners
288pub trait EventEmittingTransport: Send + Sync {
289    /// Add an event listener
290    ///
291    /// # Arguments
292    /// * `listener` - Event listener function
293    fn add_event_listener(&mut self, listener: Box<dyn Fn(TransportEvent) + Send + Sync>);
294
295    /// Remove all event listeners
296    fn clear_event_listeners(&mut self);
297}
298
299#[cfg(test)]
300mod tests {
301    use super::*;
302
303    #[test]
304    fn test_transport_config_default() {
305        let config = TransportConfig::default();
306        assert_eq!(config.connect_timeout_ms, Some(30_000));
307        assert_eq!(config.read_timeout_ms, Some(60_000));
308        assert_eq!(config.max_message_size, Some(16 * 1024 * 1024));
309        assert!(!config.compression);
310    }
311
312    #[test]
313    fn test_reconnect_config_default() {
314        let config = ReconnectConfig::default();
315        assert!(config.enabled);
316        assert_eq!(config.max_attempts, Some(5));
317        assert_eq!(config.initial_delay_ms, 1000);
318        assert_eq!(config.max_delay_ms, 30_000);
319        assert_eq!(config.backoff_multiplier, 2.0);
320        assert_eq!(config.jitter_factor, 0.1);
321    }
322
323    #[test]
324    fn test_connection_state_equality() {
325        assert_eq!(ConnectionState::Connected, ConnectionState::Connected);
326        assert_eq!(ConnectionState::Disconnected, ConnectionState::Disconnected);
327        assert_ne!(ConnectionState::Connected, ConnectionState::Disconnected);
328
329        let error1 = ConnectionState::Error("test".to_string());
330        let error2 = ConnectionState::Error("test".to_string());
331        let error3 = ConnectionState::Error("other".to_string());
332        assert_eq!(error1, error2);
333        assert_ne!(error1, error3);
334    }
335
336    #[test]
337    fn test_transport_stats_default() {
338        let stats = TransportStats::default();
339        assert_eq!(stats.requests_sent, 0);
340        assert_eq!(stats.responses_received, 0);
341        assert_eq!(stats.bytes_sent, 0);
342        assert_eq!(stats.bytes_received, 0);
343    }
344}