Skip to content

Commit f4edef4

Browse files
authored
fix(transport): make message channel capacity configurable for all transports (#171)
* merge * Add channel_capacity option to transports * Allow clippy too_many_arguments and simplify doc Add #[allow(clippy::too_many_arguments)] to MCPStream::create and MCPStream::create_with_ack to silence the lint for many parameters. Update TransportOptions doc comment to state "Defaults to 36" instead of referencing the constant name.
1 parent 0f15e56 commit f4edef4

6 files changed

Lines changed: 54 additions & 3 deletions

File tree

crates/rust-mcp-transport/src/client_sse.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ const SHUTDOWN_TIMEOUT_SECONDS: u64 = 5;
3939
pub struct ClientSseTransportOptions {
4040
pub request_timeout: Duration,
4141
pub max_line_length: usize,
42+
pub channel_capacity: usize,
4243
pub retry_delay: Option<Duration>,
4344
pub max_retries: Option<usize>,
4445
pub custom_headers: Option<HashMap<String, String>>,
@@ -50,6 +51,7 @@ impl Default for ClientSseTransportOptions {
5051
Self {
5152
request_timeout: TransportOptions::default().timeout,
5253
max_line_length: TransportOptions::default().max_line_length,
54+
channel_capacity: TransportOptions::default().channel_capacity,
5355
retry_delay: None,
5456
max_retries: None,
5557
custom_headers: None,
@@ -72,6 +74,8 @@ where
7274
request_timeout: Duration,
7375
/// Maximum line length for incoming messages
7476
max_line_length: usize,
77+
/// Capacity of the incoming-message channel buffer
78+
channel_capacity: usize,
7579
/// HTTP client for making requests
7680
client: Client,
7781
/// URL for the SSE endpoint
@@ -134,6 +138,7 @@ where
134138
is_shut_down: Mutex::new(false),
135139
request_timeout: options.request_timeout,
136140
max_line_length: options.max_line_length,
141+
channel_capacity: options.channel_capacity,
137142
custom_headers: headers,
138143
sse_task: tokio::sync::RwLock::new(None),
139144
post_task: tokio::sync::RwLock::new(None),
@@ -330,6 +335,7 @@ where
330335
self.request_timeout,
331336
self.max_line_length,
332337
cancellation_token,
338+
self.channel_capacity,
333339
);
334340

335341
self.set_message_sender(sender).await;

crates/rust-mcp-transport/src/client_streamable_http.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ impl StreamableTransportOptions {
5454
pub struct RequestOptions {
5555
pub request_timeout: Duration,
5656
pub max_line_length: usize,
57+
pub channel_capacity: usize,
5758
pub retry_delay: Option<Duration>,
5859
pub max_retries: Option<usize>,
5960
pub custom_headers: Option<HashMap<String, String>>,
@@ -64,6 +65,7 @@ impl Default for RequestOptions {
6465
Self {
6566
request_timeout: TransportOptions::default().timeout,
6667
max_line_length: TransportOptions::default().max_line_length,
68+
channel_capacity: TransportOptions::default().channel_capacity,
6769
retry_delay: None,
6870
max_retries: None,
6971
custom_headers: None,
@@ -83,6 +85,8 @@ where
8385
request_timeout: Duration,
8486
/// Maximum line length for incoming messages
8587
max_line_length: usize,
88+
/// Capacity of the incoming-message channel buffer
89+
channel_capacity: usize,
8690
/// HTTP client for making requests
8791
client: Client,
8892
/// URL for the SSE endpoint
@@ -124,6 +128,7 @@ where
124128
is_shut_down: Mutex::new(false),
125129
request_timeout: options.request_options.request_timeout,
126130
max_line_length: options.request_options.max_line_length,
131+
channel_capacity: options.request_options.channel_capacity,
127132
client,
128133
mcp_server_url,
129134
retry_delay: options
@@ -294,6 +299,7 @@ where
294299
self.request_timeout,
295300
self.max_line_length,
296301
cancellation_token,
302+
self.channel_capacity,
297303
);
298304

299305
self.set_message_sender(sender).await;
@@ -380,6 +386,7 @@ where
380386
self.request_timeout,
381387
self.max_line_length,
382388
cancellation_token,
389+
self.channel_capacity,
383390
);
384391

385392
self.set_message_sender(sender).await;

crates/rust-mcp-transport/src/mcp_stream.rs

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,9 @@ use tokio::{
1212
sync::Mutex,
1313
};
1414

15-
const CHANNEL_CAPACITY: usize = 36;
15+
/// Default capacity of the incoming-message channel. Used when callers do not
16+
/// override it (see [`crate::TransportOptions::channel_capacity`]).
17+
pub(crate) const DEFAULT_MESSAGE_CHANNEL_CAPACITY: usize = 36;
1618

1719
pub struct MCPStream {}
1820

@@ -25,6 +27,7 @@ impl MCPStream {
2527
/// - A `Pin<Box<dyn Stream<Item = R> + Send>>`: A stream that yields items of type `R`.
2628
/// - A `MessageDispatcher<R>`: A sender that can be used to send messages of type `R`.
2729
/// - An `IoStream`: An error handling stream for managing error I/O (stderr).
30+
#[allow(clippy::too_many_arguments)]
2831
pub fn create<X, R>(
2932
readable: Pin<Box<dyn tokio::io::AsyncRead + Send + Sync>>,
3033
writable: Mutex<Pin<Box<dyn tokio::io::AsyncWrite + Send + Sync>>>,
@@ -33,6 +36,7 @@ impl MCPStream {
3336
request_timeout: Duration,
3437
max_line_length: usize,
3538
cancellation_token: CancellationToken,
39+
channel_capacity: usize,
3640
) -> (
3741
tokio_stream::wrappers::ReceiverStream<X>,
3842
MessageDispatcher<R>,
@@ -42,7 +46,7 @@ impl MCPStream {
4246
R: Clone + Send + Sync + serde::de::DeserializeOwned + 'static,
4347
X: Clone + Send + Sync + serde::de::DeserializeOwned + 'static,
4448
{
45-
let (tx, rx) = tokio::sync::mpsc::channel::<X>(CHANNEL_CAPACITY);
49+
let (tx, rx) = tokio::sync::mpsc::channel::<X>(channel_capacity);
4650
let stream = tokio_stream::wrappers::ReceiverStream::new(rx);
4751

4852
let reader_token = cancellation_token.clone();
@@ -55,6 +59,7 @@ impl MCPStream {
5559
(stream, sender, error_io)
5660
}
5761

62+
#[allow(clippy::too_many_arguments)]
5863
pub fn create_with_ack<X, R>(
5964
readable: Pin<Box<dyn tokio::io::AsyncRead + Send + Sync>>,
6065
writable: tokio::sync::mpsc::Sender<(
@@ -66,6 +71,7 @@ impl MCPStream {
6671
request_timeout: Duration,
6772
max_line_length: usize,
6873
cancellation_token: CancellationToken,
74+
channel_capacity: usize,
6975
) -> (
7076
tokio_stream::wrappers::ReceiverStream<X>,
7177
MessageDispatcher<R>,
@@ -75,7 +81,7 @@ impl MCPStream {
7581
R: Clone + Send + Sync + serde::de::DeserializeOwned + 'static,
7682
X: Clone + Send + Sync + serde::de::DeserializeOwned + 'static,
7783
{
78-
let (tx, rx) = tokio::sync::mpsc::channel::<X>(CHANNEL_CAPACITY);
84+
let (tx, rx) = tokio::sync::mpsc::channel::<X>(channel_capacity);
7985
let stream = tokio_stream::wrappers::ReceiverStream::new(rx);
8086

8187
let reader_token = cancellation_token.clone();

crates/rust-mcp-transport/src/sse.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -190,6 +190,7 @@ impl Transport<ClientMessages, MessageFromServer, ClientMessage, ServerMessages,
190190
self.options.timeout,
191191
self.options.max_line_length,
192192
cancellation_token,
193+
self.options.channel_capacity,
193194
);
194195

195196
if let (Some(session_id), Some(stream_id), Some(event_store)) = (

crates/rust-mcp-transport/src/stdio.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -224,6 +224,7 @@ where
224224
self.options.timeout,
225225
self.options.max_line_length,
226226
cancellation_token,
227+
self.options.channel_capacity,
227228
);
228229

229230
self.set_message_sender(sender).await;
@@ -239,6 +240,7 @@ where
239240
self.options.timeout,
240241
self.options.max_line_length,
241242
cancellation_token,
243+
self.options.channel_capacity,
242244
);
243245

244246
self.set_message_sender(sender).await;

crates/rust-mcp-transport/src/transport.rs

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,12 +44,19 @@ pub struct TransportOptions {
4444
/// large tool results or responses, increase this value.
4545
/// Default: 16 MiB.
4646
pub max_line_length: usize,
47+
48+
/// Capacity of the incoming-message channel buffer.
49+
///
50+
/// A larger value smooths out head-of-line jitter under bursty traffic at
51+
/// the cost of more buffered memory. Defaults to 36.
52+
pub channel_capacity: usize,
4753
}
4854
impl Default for TransportOptions {
4955
fn default() -> Self {
5056
Self {
5157
timeout: Duration::from_millis(DEFAULT_TIMEOUT_MSEC),
5258
max_line_length: DEFAULT_MAX_LINE_LENGTH,
59+
channel_capacity: crate::mcp_stream::DEFAULT_MESSAGE_CHANNEL_CAPACITY,
5360
}
5461
}
5562
}
@@ -197,3 +204,25 @@ where
197204
// Ok(self)
198205
// }
199206
// }
207+
208+
#[cfg(test)]
209+
mod tests {
210+
use super::*;
211+
212+
#[test]
213+
fn default_channel_capacity_matches_constant() {
214+
assert_eq!(
215+
TransportOptions::default().channel_capacity,
216+
crate::mcp_stream::DEFAULT_MESSAGE_CHANNEL_CAPACITY
217+
);
218+
}
219+
220+
#[test]
221+
fn channel_capacity_is_overridable() {
222+
let options = TransportOptions {
223+
channel_capacity: 256,
224+
..Default::default()
225+
};
226+
assert_eq!(options.channel_capacity, 256);
227+
}
228+
}

0 commit comments

Comments
 (0)