feat: add subscription listen streams (SEP-2575) (#1000)
* feat: add subscription listen streams * refactor: reuse legacy request helper
This commit is contained in:
parent
8ee9ee68f1
commit
ff1a715b6e
1 changed files with 3617 additions and 223 deletions
83
examples/servers/src/subscriptions_streamhttp.rs
Normal file
83
examples/servers/src/subscriptions_streamhttp.rs
Normal file
|
|
@ -0,0 +1,83 @@
|
|||
use std::{borrow::Cow, time::Duration};
|
||||
|
||||
use rmcp::{
|
||||
ErrorData, ServerHandler,
|
||||
model::{ProtocolVersion, ServerCapabilities, ServerInfo, SubscriptionFilter},
|
||||
service::SubscriptionContext,
|
||||
transport::streamable_http_server::{
|
||||
StreamableHttpServerConfig, StreamableHttpService, session::local::LocalSessionManager,
|
||||
},
|
||||
};
|
||||
use tokio_util::sync::CancellationToken;
|
||||
|
||||
#[derive(Clone)]
|
||||
struct SubscriptionServer;
|
||||
|
||||
impl ServerHandler for SubscriptionServer {
|
||||
fn supported_protocol_versions(&self) -> Cow<'static, [ProtocolVersion]> {
|
||||
Cow::Borrowed(&[ProtocolVersion::V_2026_07_28])
|
||||
}
|
||||
|
||||
fn get_info(&self) -> ServerInfo {
|
||||
ServerInfo::new(
|
||||
ServerCapabilities::builder()
|
||||
.enable_tools()
|
||||
.enable_tool_list_changed()
|
||||
.build(),
|
||||
)
|
||||
}
|
||||
|
||||
fn accepted_subscription_filter(
|
||||
&self,
|
||||
requested: &SubscriptionFilter,
|
||||
) -> Option<SubscriptionFilter> {
|
||||
Some(requested.supported_by(&self.get_info().capabilities))
|
||||
}
|
||||
|
||||
async fn listen(&self, context: SubscriptionContext) -> Result<(), ErrorData> {
|
||||
loop {
|
||||
tokio::select! {
|
||||
() = context.cancelled() => return Ok(()),
|
||||
() = tokio::time::sleep(Duration::from_secs(2)) => {
|
||||
context
|
||||
.sink()
|
||||
.notify_tool_list_changed()
|
||||
.await
|
||||
.map_err(|error| {
|
||||
ErrorData::internal_error(error.to_string(), None)
|
||||
})?;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[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 cancellation_token = CancellationToken::new();
|
||||
let service: StreamableHttpService<SubscriptionServer, LocalSessionManager> =
|
||||
StreamableHttpService::new(
|
||||
|| Ok(SubscriptionServer),
|
||||
Default::default(),
|
||||
StreamableHttpServerConfig::default()
|
||||
.with_legacy_session_mode(false)
|
||||
.with_sse_keep_alive(Some(Duration::from_secs(10)))
|
||||
.with_cancellation_token(cancellation_token.child_token()),
|
||||
);
|
||||
let router = axum::Router::new().nest_service("/mcp", service);
|
||||
let listener = tokio::net::TcpListener::bind("127.0.0.1:8000").await?;
|
||||
|
||||
axum::serve(listener, router)
|
||||
.with_graceful_shutdown(async move {
|
||||
let _ = tokio::signal::ctrl_c().await;
|
||||
cancellation_token.cancel();
|
||||
})
|
||||
.await?;
|
||||
Ok(())
|
||||
}
|
||||
Loading…
Reference in a new issue