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}