refactor: provide http server as tower service (#228)
* refactor: streamable http server as tower service
This commit is contained in:
parent
915bc3fb37
commit
209be7bdb8
4 changed files with 1828 additions and 1180 deletions
|
|
@ -7,8 +7,20 @@ edition = "2024"
|
|||
publish = false
|
||||
|
||||
[dependencies]
|
||||
rmcp= { path = "../../crates/rmcp", features = ["server", "transport-sse-server", "transport-io", "transport-streamable-http-server", "auth"] }
|
||||
tokio = { version = "1", features = ["macros", "rt", "rt-multi-thread", "io-std", "signal"] }
|
||||
rmcp = { path = "../../crates/rmcp", features = [
|
||||
"server",
|
||||
"transport-sse-server",
|
||||
"transport-io",
|
||||
"transport-streamable-http-server",
|
||||
"auth",
|
||||
] }
|
||||
tokio = { version = "1", features = [
|
||||
"macros",
|
||||
"rt",
|
||||
"rt-multi-thread",
|
||||
"io-std",
|
||||
"signal",
|
||||
] }
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
serde_json = "1.0"
|
||||
anyhow = "1.0"
|
||||
|
|
@ -26,9 +38,10 @@ reqwest = { version = "0.12", features = ["json"] }
|
|||
chrono = "0.4"
|
||||
uuid = { version = "1.6", features = ["v4", "serde"] }
|
||||
serde_urlencoded = "0.7"
|
||||
askama = { version = "0.14"}
|
||||
askama = { version = "0.14" }
|
||||
tower-http = { version = "0.6", features = ["cors"] }
|
||||
|
||||
hyper = { version = "1" }
|
||||
hyper-util = { version = "0", features = ["server"] }
|
||||
|
||||
[dev-dependencies]
|
||||
tokio-stream = { version = "0.1" }
|
||||
|
|
@ -60,4 +73,8 @@ path = "src/complex_auth_sse.rs"
|
|||
|
||||
[[example]]
|
||||
name = "servers_simple_auth_sse"
|
||||
path = "src/simple_auth_sse.rs"
|
||||
path = "src/simple_auth_sse.rs"
|
||||
|
||||
[[example]]
|
||||
name = "counter_hyper_streamable_http"
|
||||
path = "src/counter_hyper_streamable_http.rs"
|
||||
|
|
|
|||
|
|
@ -38,12 +38,19 @@ A minimal server example using stdio transport.
|
|||
|
||||
### Counter Streamable HTTP Server (`counter_streamhttp.rs`)
|
||||
|
||||
A server using streamable HTTP transport for MCP communication.
|
||||
A server using streamable HTTP transport for MCP communication, with axum.
|
||||
|
||||
- Runs on HTTP with streaming capabilities
|
||||
- Provides counter tools via HTTP streaming
|
||||
- Demonstrates streamable HTTP transport configuration
|
||||
|
||||
### Counter Streamable HTTP Server with Hyper (`counter_hyper_streamable_http.rs`)
|
||||
|
||||
A server using streamable HTTP transport for MCP communication, with hyper.
|
||||
- Runs on HTTP with streaming capabilities
|
||||
- Provides counter tools via HTTP streaming
|
||||
- Demonstrates streamable HTTP transport configuration
|
||||
|
||||
### Complex OAuth SSE Server (`complex_auth_sse.rs`)
|
||||
|
||||
A comprehensive example demonstrating OAuth 2.0 integration with MCP servers.
|
||||
|
|
|
|||
35
examples/servers/src/counter_hyper_streamable_http.rs
Normal file
35
examples/servers/src/counter_hyper_streamable_http.rs
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
mod common;
|
||||
use common::counter::Counter;
|
||||
use hyper_util::{
|
||||
rt::{TokioExecutor, TokioIo},
|
||||
server::conn::auto::Builder,
|
||||
service::TowerToHyperService,
|
||||
};
|
||||
use rmcp::transport::streamable_http_server::{
|
||||
StreamableHttpService, session::local::LocalSessionManager,
|
||||
};
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() -> anyhow::Result<()> {
|
||||
let service = TowerToHyperService::new(StreamableHttpService::new(
|
||||
Counter::new,
|
||||
LocalSessionManager::default().into(),
|
||||
Default::default(),
|
||||
));
|
||||
let listener = tokio::net::TcpListener::bind("[::1]:8080").await?;
|
||||
loop {
|
||||
let io = tokio::select! {
|
||||
_ = tokio::signal::ctrl_c() => break,
|
||||
accept = listener.accept() => {
|
||||
TokioIo::new(accept?.0)
|
||||
}
|
||||
};
|
||||
let service = service.clone();
|
||||
tokio::spawn(async move {
|
||||
let _result = Builder::new(TokioExecutor::default())
|
||||
.serve_connection(io, service)
|
||||
.await;
|
||||
});
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
|
@ -1,4 +1,6 @@
|
|||
use rmcp::transport::streamable_http_server::axum::StreamableHttpServer;
|
||||
use rmcp::transport::streamable_http_server::{
|
||||
StreamableHttpService, session::local::LocalSessionManager,
|
||||
};
|
||||
use tracing_subscriber::{
|
||||
layer::SubscriberExt,
|
||||
util::SubscriberInitExt,
|
||||
|
|
@ -19,11 +21,16 @@ async fn main() -> anyhow::Result<()> {
|
|||
.with(tracing_subscriber::fmt::layer())
|
||||
.init();
|
||||
|
||||
let ct = StreamableHttpServer::serve(BIND_ADDRESS.parse()?)
|
||||
.await?
|
||||
.with_service(Counter::new);
|
||||
let service = StreamableHttpService::new(
|
||||
Counter::new,
|
||||
LocalSessionManager::default().into(),
|
||||
Default::default(),
|
||||
);
|
||||
|
||||
tokio::signal::ctrl_c().await?;
|
||||
ct.cancel();
|
||||
let router = axum::Router::new().nest_service("/mcp", service);
|
||||
let tcp_listener = tokio::net::TcpListener::bind(BIND_ADDRESS).await?;
|
||||
let _ = axum::serve(tcp_listener, router)
|
||||
.with_graceful_shutdown(async { tokio::signal::ctrl_c().await.unwrap() })
|
||||
.await;
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue