feat: add subscription listen streams (SEP-2575) (#1000)

* feat: add subscription listen streams

* refactor: reuse legacy request helper
This commit is contained in:
Dale Seo 2026-07-21 09:53:04 -04:00 • committed by GitHub
commit ff1a715b6e
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 3617 additions and 223 deletions

View file

@ -65,3 +65,7 @@ path = "src/auth/client_credentials.rs"
[[example]]
name = "clients_task_stdio"
path = "src/task_stdio.rs"
[[example]]
name = "clients_subscriptions_streamhttp"
path = "src/subscriptions_streamhttp.rs"

View file

@ -16,6 +16,13 @@ A client that communicates with a Git-related MCP server using standard input/ou
A client that communicates with an MCP server using HTTP streaming transport.
- Connects to an MCP server running at `http://localhost:8000`
### Modern Subscription Client (`subscriptions_streamhttp.rs`)
Uses modern discovery and `subscriptions/listen`, prints the accepted filter,
and consumes tagged notifications until graceful closure or cancellation.
- Run with `cargo run -p mcp-client-examples --example clients_subscriptions_streamhttp`
- Retrieves server information and list of available tools
- Calls a tool named "increment"

View file

@ -0,0 +1,49 @@
use rmcp::{
ClientLifecycleMode, ClientServiceExt,
model::{ClientInfo, ProtocolVersion, SubscriptionFilter},
transport::StreamableHttpClientTransport,
};
#[tokio::main]
async fn main() -> anyhow::Result<()> {
tracing_subscriber::fmt()
.with_env_filter(
tracing_subscriber::EnvFilter::try_from_default_env().unwrap_or_else(|_| "info".into()),
)
.init();
let transport = StreamableHttpClientTransport::from_uri("http://127.0.0.1:8000/mcp");
let client = ClientInfo::default()
.serve_with_lifecycle(
transport,
ClientLifecycleMode::Discover {
preferred_versions: vec![ProtocolVersion::V_2026_07_28],
},
)
.await?;
let mut subscription = client
.listen(SubscriptionFilter::builder().tools_list_changed().build())
.await?;
println!("accepted filter: {:?}", subscription.acknowledged());
loop {
tokio::select! {
result = subscription.next() => {
match result? {
Some(notification) => println!("notification: {notification:?}"),
None => {
println!("subscription ended: {:?}", subscription.end());
break;
}
}
}
_ = tokio::signal::ctrl_c() => {
subscription.cancel().await?;
break;
}
}
}
client.cancel().await?;
Ok(())
}