feat!: remove SSE transport support (#562)

SSE transport has been removed from the MCP specification in favor of
streamable HTTP. This removes all SSE-specific transport code:

- Remove `transport-sse-client` and `transport-sse-server` features
- Remove `SseClientTransport` and `SseServer` types
- Remove SSE-specific examples (`counter_sse`, `counter_sse_directly`)
- Migrate auth examples from SSE to streamable HTTP
- Update tests to remove SSE transport usage
- Update documentation

BREAKING CHANGE: The following have been removed:
- `transport-sse-client` feature
- `transport-sse-client-reqwest` feature
- `transport-sse-server` feature
- `SseClientTransport` type
- `SseServer` type
- `sse_client` and `sse_server` modules

Users should migrate to streamable HTTP transport which provides
equivalent functionality. See `StreamableHttpClientTransport` and
`StreamableHttpService` for the replacement APIs.

Ref: https://github.com/modelcontextprotocol/rust-sdk/pull/561#issuecomment-3576551699
This commit is contained in:
adam jones 2025-12-02 01:40:13 +00:00 • committed by GitHub
commit eb5a7f7408
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 164 additions and 1688 deletions

View file

@ -11,9 +11,9 @@ use rmcp::{
ServiceExt,
model::ClientInfo,
transport::{
SseClientTransport,
StreamableHttpClientTransport,
auth::{AuthClient, OAuthState},
sse_client::SseClientConfig,
streamable_http_client::StreamableHttpClientTransportConfig,
},
};
use serde::Deserialize;
@ -25,7 +25,6 @@ use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt};
const MCP_SERVER_URL: &str = "http://localhost:3000/mcp";
const MCP_REDIRECT_URI: &str = "http://localhost:8080/callback";
const MCP_SSE_URL: &str = "http://localhost:3000/mcp/sse";
const CALLBACK_PORT: u16 = 8080;
const CALLBACK_HTML: &str = include_str!("callback.html");
@ -150,14 +149,10 @@ async fn main() -> Result<()> {
.into_authorization_manager()
.ok_or_else(|| anyhow::anyhow!("Failed to get authorization manager"))?;
let client = AuthClient::new(reqwest::Client::default(), am);
let transport = SseClientTransport::start_with_client(
let transport = StreamableHttpClientTransport::with_client(
client,
SseClientConfig {
sse_endpoint: MCP_SSE_URL.into(),
..Default::default()
},
)
.await?;
StreamableHttpClientTransportConfig::with_uri(MCP_SERVER_URL),
);
// Create client and connect to MCP server
let client_service = ClientInfo::default();

View file

@ -12,7 +12,7 @@ use rmcp::{
ProgressNotificationParam,
},
service::{NotificationContext, RoleClient},
transport::{SseClientTransport, StreamableHttpClientTransport, TokioChildProcess},
transport::{StreamableHttpClientTransport, TokioChildProcess},
};
use tokio::{process::Command, time::sleep};
use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt};
@ -20,7 +20,6 @@ use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt};
#[derive(Debug, Clone, ValueEnum)]
enum TransportType {
Stdio,
Sse,
Http,
All,
}
@ -37,10 +36,6 @@ struct Args {
#[arg(short, long, default_value_t = 10)]
records: u32,
/// SSE server URL
#[arg(long, default_value = "http://127.0.0.1:8000/sse")]
sse_url: String,
/// HTTP server URL
#[arg(long, default_value = "http://127.0.0.1:8001/mcp")]
http_url: String,
@ -203,59 +198,7 @@ async fn test_stdio_transport(records: u32) -> Result<()> {
tracing::info!("STDIO transport test completed successfully!");
Ok(())
}
// Test SSE transport, must run the server with `cargo run --example servers_progress_demo -- sse` in the servers directory
async fn test_sse_transport(sse_url: &str, records: u32) -> Result<()> {
tracing::info!("Testing SSE Transport");
tracing::info!("=========================");
tracing::info!("SSE URL: {}", sse_url);
// Wait a bit for server to be ready
sleep(Duration::from_secs(1)).await;
let transport = SseClientTransport::start(sse_url).await?;
// Create progress-aware client handler
let client_handler = ProgressAwareClient::new();
client_handler.start_tracking();
let client_handler_clone = client_handler.clone();
let client = client_handler.serve(transport).await.inspect_err(|e| {
tracing::error!("SSE client error: {:?}", e);
})?;
// Initialize
let server_info = client.peer_info();
if let Some(info) = server_info {
tracing::info!("Connected to server: {:?}", info.server_info.name);
}
// List tools
let tools = client.list_tools(Default::default()).await?;
tracing::info!(
"Available tools: {:?}",
tools.tools.iter().map(|t| &t.name).collect::<Vec<_>>()
);
// Call stream processor tool
tracing::info!("Starting to process {} records...", records);
let tool_result = client
.call_tool(CallToolRequestParam {
name: "stream_processor".into(),
arguments: None,
})
.await?;
if let Some(content) = tool_result.content.first() {
if let Some(text) = content.as_text() {
tracing::info!("Processing completed: {}", text.text);
}
}
client.cancel().await?;
client_handler_clone.stop_tracking();
tracing::info!("SSE transport test completed successfully!");
Ok(())
}
// Test HTTP transport, must run the server with `cargo run --example servers_progress_demo -- http` in the servers directory
async fn test_http_transport(http_url: &str, records: u32) -> Result<()> {
tracing::info!("Testing HTTP Streaming Transport");
@ -316,13 +259,6 @@ async fn run_single_test(transport_type: &TransportType, args: &Args) -> Result<
test_stdio_transport(args.records).await?;
Ok(true)
}
TransportType::Sse => match test_sse_transport(&args.sse_url, args.records).await {
Ok(_) => Ok(true),
Err(e) => {
tracing::error!("SSE test failed: {}", e);
Ok(false)
}
},
TransportType::Http => match test_http_transport(&args.http_url, args.records).await {
Ok(_) => Ok(true),
Err(e) => {
@ -357,11 +293,7 @@ async fn main() -> Result<()> {
// Test all transport types
let mut results = std::collections::HashMap::new();
for transport_type in [
TransportType::Stdio,
TransportType::Sse,
TransportType::Http,
] {
for transport_type in [TransportType::Stdio, TransportType::Http] {
let transport_name = format!("{:?}", transport_type).to_uppercase();
tracing::info!("\n");

View file

@ -1,52 +0,0 @@
use anyhow::Result;
use rmcp::{
ServiceExt,
model::{CallToolRequestParam, ClientCapabilities, ClientInfo, Implementation},
transport::SseClientTransport,
};
use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt};
#[tokio::main]
async fn main() -> Result<()> {
// Initialize logging
tracing_subscriber::registry()
.with(
tracing_subscriber::EnvFilter::try_from_default_env()
.unwrap_or_else(|_| format!("info,{}=debug", env!("CARGO_CRATE_NAME")).into()),
)
.with(tracing_subscriber::fmt::layer())
.init();
let transport = SseClientTransport::start("http://localhost:8000/sse").await?;
let client_info = ClientInfo {
protocol_version: Default::default(),
capabilities: ClientCapabilities::default(),
client_info: Implementation {
name: "test sse client".to_string(),
title: None,
version: "0.0.1".to_string(),
website_url: None,
icons: None,
},
};
let client = client_info.serve(transport).await.inspect_err(|e| {
tracing::error!("client error: {:?}", e);
})?;
// Initialize
let server_info = client.peer_info();
tracing::info!("Connected to server: {server_info:#?}");
// List tools
let tools = client.list_tools(Default::default()).await?;
tracing::info!("Available tools: {tools:#?}");
let tool_result = client
.call_tool(CallToolRequestParam {
name: "increment".into(),
arguments: serde_json::json!({}).as_object().cloned(),
})
.await?;
tracing::info!("Tool result: {tool_result:#?}");
client.cancel().await?;
Ok(())
}