Skip to content

Commit 51eeba4

Browse files
author
Matthew Hawkins
authored
Update to Rust MCP SDK version 2 (#175)
1 parent e35ab81 commit 51eeba4

File tree

5 files changed

+69
-48
lines changed

5 files changed

+69
-48
lines changed

Cargo.lock

Lines changed: 27 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -50,9 +50,3 @@ expect_used = "deny"
5050
indexing_slicing = "deny"
5151
unwrap_used = "deny"
5252
panic = "deny"
53-
54-
[patch.crates-io]
55-
# The Rust MCP SDK has not had a release in a long time, so we need to depend on it through GitHub to pick up things
56-
# like Streamable HTTP support. This particular commit is pinned because it is before a change to the way shutdown is
57-
# handled through Axum which broke the ability to shut down the server with Ctrl-C.
58-
rmcp = { git = 'https://github.com/modelcontextprotocol/rust-sdk.git', rev = '915bc3fb37fe259fba1a853a9dd03566593f3310' }

crates/apollo-mcp-server/Cargo.toml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,14 @@ anyhow = "1.0.98"
1010
apollo-compiler.workspace = true
1111
apollo-federation.workspace = true
1212
apollo-mcp-registry = { path = "../apollo-mcp-registry" }
13+
axum = "0.8.4"
1314
bon = "3.6.3"
1415
clap = { version = "4.5.36", features = ["derive", "env"] }
1516
futures.workspace = true
1617
lz-str = "0.2.1"
1718
regex = "1.11.1"
1819
reqwest.workspace = true
19-
rmcp = { version = "0.1", features = [
20+
rmcp = { version = "0.2", features = [
2021
"server",
2122
"transport-io",
2223
"transport-sse-server",

crates/apollo-mcp-server/src/server/states.rs

Lines changed: 26 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use apollo_compiler::{Schema, validation::Valid};
22
use apollo_federation::{ApiSchemaOptions, Supergraph};
33
use apollo_mcp_registry::uplink::schema::{SchemaState, event::Event as SchemaEvent};
4-
use futures::{FutureExt as _, Stream, StreamExt as _, future, stream};
4+
use futures::{FutureExt as _, Stream, StreamExt as _, stream};
55
use reqwest::header::HeaderMap;
66

77
use crate::{
@@ -144,34 +144,36 @@ impl StateMachine {
144144
}
145145
}
146146

147-
#[allow(clippy::expect_used)]
148147
fn ctrl_c_stream() -> impl Stream<Item = ServerEvent> {
149-
#[cfg(not(unix))]
150-
{
151-
async {
152-
tokio::signal::ctrl_c()
153-
.await
154-
.expect("Failed to install CTRL+C signal handler");
155-
}
148+
shutdown_signal()
156149
.map(|_| ServerEvent::Shutdown)
157150
.into_stream()
158151
.boxed()
159-
}
152+
}
153+
}
160154

161-
#[cfg(unix)]
162-
future::select(
163-
tokio::signal::ctrl_c().map(|s| s.ok()).boxed(),
164-
async {
165-
tokio::signal::unix::signal(tokio::signal::unix::SignalKind::terminate())
166-
.expect("Failed to install SIGTERM signal handler")
167-
.recv()
168-
.await
169-
}
170-
.boxed(),
171-
)
172-
.map(|_| ServerEvent::Shutdown)
173-
.into_stream()
174-
.boxed()
155+
#[allow(clippy::expect_used)]
156+
async fn shutdown_signal() {
157+
let ctrl_c = async {
158+
tokio::signal::ctrl_c()
159+
.await
160+
.expect("Failed to install CTRL+C signal handler");
161+
};
162+
163+
#[cfg(unix)]
164+
let terminate = async {
165+
tokio::signal::unix::signal(tokio::signal::unix::SignalKind::terminate())
166+
.expect("Failed to install SIGTERM signal handler")
167+
.recv()
168+
.await;
169+
};
170+
171+
#[cfg(not(unix))]
172+
let terminate = std::future::pending::<()>();
173+
174+
tokio::select! {
175+
_ = ctrl_c => {},
176+
_ = terminate => {},
175177
}
176178
}
177179

crates/apollo-mcp-server/src/server/states/starting.rs

Lines changed: 14 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,11 @@
11
use std::{net::SocketAddr, sync::Arc};
22

33
use apollo_compiler::{Name, Schema, ast::OperationType, validation::Valid};
4+
use rmcp::transport::StreamableHttpService;
5+
use rmcp::transport::streamable_http_server::session::local::LocalSessionManager;
46
use rmcp::{
57
ServiceExt as _,
6-
transport::{
7-
SseServer, StreamableHttpServer, sse_server::SseServerConfig, stdio,
8-
streamable_http_server::axum::StreamableHttpServerConfig,
9-
},
8+
transport::{SseServer, sse_server::SseServerConfig, stdio},
109
};
1110
use tokio::sync::{Mutex, RwLock};
1211
use tokio_util::sync::CancellationToken;
@@ -20,7 +19,7 @@ use crate::{
2019
server::Transport,
2120
};
2221

23-
use super::{Config, Running};
22+
use super::{Config, Running, shutdown_signal};
2423

2524
pub(super) struct Starting {
2625
pub(super) config: Config,
@@ -118,14 +117,16 @@ impl Starting {
118117
info!(port = ?port, address = ?address, "Starting MCP server in Streamable HTTP mode");
119118
let running = running.clone();
120119
let listen_address = SocketAddr::new(address, port);
121-
StreamableHttpServer::serve_with_config(StreamableHttpServerConfig {
122-
bind: listen_address,
123-
path: "/mcp".to_string(),
124-
ct: cancellation_token,
125-
sse_keep_alive: None,
126-
})
127-
.await?
128-
.with_service(move || running.clone());
120+
let service = StreamableHttpService::new(
121+
move || Ok(running.clone()),
122+
LocalSessionManager::default().into(),
123+
Default::default(),
124+
);
125+
let router = axum::Router::new().nest_service("/mcp", service);
126+
let tcp_listener = tokio::net::TcpListener::bind(listen_address).await?;
127+
axum::serve(tcp_listener, router)
128+
.with_graceful_shutdown(shutdown_signal())
129+
.await?;
129130
}
130131
Transport::SSE { address, port } => {
131132
info!(port = ?port, address = ?address, "Starting MCP server in SSE mode");

0 commit comments

Comments
 (0)