Skip to main content

tower_mcp/client/
transport.rs

1//! Client transport trait for raw JSON message I/O.
2//!
3//! This module defines the [`ClientTransport`] trait, the low-level abstraction
4//! for sending and receiving JSON-RPC messages over a transport mechanism.
5//!
6//! Unlike the previous `ClientTransport` which bundled request/response
7//! correlation, this trait provides raw message I/O. The [`McpClient`](super::McpClient)
8//! handles correlation, multiplexing, and dispatch in its background task.
9
10use async_trait::async_trait;
11
12use crate::error::Result;
13
14/// Low-level transport for sending and receiving raw JSON-RPC messages.
15///
16/// Implementations handle the physical I/O (stdio, HTTP, WebSocket) while
17/// the [`McpClient`](super::McpClient) handles JSON-RPC framing, request/response
18/// correlation, and server-initiated request dispatch.
19///
20/// # Implementing a Custom Transport
21///
22/// ```rust,ignore
23/// use async_trait::async_trait;
24/// use tower_mcp::client::ClientTransport;
25/// use tower_mcp::error::Result;
26///
27/// struct MyTransport { /* ... */ }
28///
29/// #[async_trait]
30/// impl ClientTransport for MyTransport {
31///     async fn send(&mut self, message: &str) -> Result<()> {
32///         // Write message to the transport
33///         Ok(())
34///     }
35///
36///     async fn recv(&mut self) -> Result<Option<String>> {
37///         // Read next message, None on EOF
38///         Ok(None)
39///     }
40///
41///     fn is_connected(&self) -> bool { true }
42///
43///     async fn close(&mut self) -> Result<()> { Ok(()) }
44/// }
45/// ```
46#[async_trait]
47pub trait ClientTransport: Send + 'static {
48    /// Send a raw JSON message to the server.
49    ///
50    /// The message is a complete JSON-RPC request, response, or notification
51    /// serialized as a string. The transport adds any necessary framing
52    /// (e.g., newline for stdio).
53    async fn send(&mut self, message: &str) -> Result<()>;
54
55    /// Receive the next raw JSON message from the server.
56    ///
57    /// Returns `Ok(Some(json))` for a message, `Ok(None)` for clean EOF/close,
58    /// or `Err(...)` for transport errors.
59    async fn recv(&mut self) -> Result<Option<String>>;
60
61    /// Check if the transport is still connected.
62    fn is_connected(&self) -> bool;
63
64    /// Close the transport gracefully.
65    ///
66    /// After calling this, `recv()` should return `Ok(None)`.
67    async fn close(&mut self) -> Result<()>;
68
69    /// Reset the transport's session state for re-initialization.
70    ///
71    /// Called when the server indicates the session has expired. The
72    /// transport should clear its session ID, stop any SSE streams,
73    /// and prepare for a new `initialize` handshake.
74    ///
75    /// The default implementation is a no-op (for transports like stdio
76    /// that don't have sessions).
77    async fn reset_session(&mut self) {}
78
79    /// Whether this transport supports automatic session recovery.
80    ///
81    /// When true, the client will attempt to re-initialize and retry
82    /// failed operations when the server returns a session expired error.
83    ///
84    /// Default: `false`.
85    fn supports_session_recovery(&self) -> bool {
86        false
87    }
88}