Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 20 additions & 3 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ members = [
"crates/rust-mcp-sdk",
"crates/rust-mcp-transport",
"crates/rust-mcp-extra",
"crates/rust-mcp-axum",
]

[workspace.package]
Expand All @@ -16,6 +17,7 @@ rust-mcp-transport = { version = "0.9.0", path = "crates/rust-mcp-transport", de
rust-mcp-sdk = { path = "crates/rust-mcp-sdk", default-features = false }
rust-mcp-macros = { version = "0.9.0", path = "crates/rust-mcp-macros", default-features = false }
rust-mcp-extra = { version="0.1.0", path = "crates/rust-mcp-extra", default-features = false }
rust-mcp-axum = { version = "0.1.0", path = "crates/rust-mcp-axum" }

# External crates
rust-mcp-schema = { version="0.10", default-features = false }
Expand Down
4 changes: 2 additions & 2 deletions Makefile.toml
Original file line number Diff line number Diff line change
Expand Up @@ -54,8 +54,8 @@ set -e
cargo build --lib -p rust-mcp-sdk --no-default-features --features "client,stdio"
cargo build --lib -p rust-mcp-sdk --no-default-features --features "server,stdio"
cargo build --lib -p rust-mcp-sdk --no-default-features --features "hyper-server,streamable-http"
cargo build --lib -p rust-mcp-sdk --no-default-features --features "hyper-server,sse"
cargo build --lib -p rust-mcp-sdk --no-default-features --features "server,streamable-http"
cargo build --lib -p rust-mcp-sdk --no-default-features --features "server,sse"
'''


Expand Down
41 changes: 20 additions & 21 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ This SDK fully implements the latest MCP protocol version ([2025-11-25](https://
- [Authentication](#authentication)
- [RemoteAuthProvider](#remoteauthprovider)
- [OAuthProxy](#oauthproxy)
- [HyperServerOptions](#hyperserveroptions)
- [AxumServerOptions](#axumserveroptions)
- [Security Considerations](#security-considerations)
- [Cargo features](#cargo-features)
- [Available Features](#available-features)
Expand Down Expand Up @@ -164,14 +164,15 @@ async fn main() -> SdkResult<()> {

## Minimal MCP Server (Streamable HTTP)
Creating an MCP server in `rust-mcp-sdk` allows multiple clients to connect simultaneously with no additional setup.
The setup is nearly identical to the stdio example shown above. You only need to create a Hyper server via `hyper_server::create_server()` and pass in the same handler and `HyperServerOptions`.
The setup is nearly identical to the stdio example shown above. You only need to install the `rust-mcp-axum` crate and use `create_axum_server()` with `AxumServerOptions`.

πŸ’‘ If backward compatibility is required, you can enable **SSE** transport by setting `sse_support` to true in `HyperServerOptions`.
πŸ’‘ If backward compatibility is required, you can enable **SSE** transport by setting `sse_support` to true in `AxumServerOptions`.

```rust
use async_trait::async_trait;
use rust_mcp_axum::{create_axum_server, AxumServerOptions};
use rust_mcp_sdk::{*,error::SdkResult,event_store::InMemoryEventStore,macros,
mcp_server::{hyper_server, HyperServerOptions, ServerHandler},schema::*,
mcp_server::ServerHandler,schema::*,
};

// Define a mcp tool
Expand Down Expand Up @@ -232,10 +233,10 @@ async fn main() -> SdkResult<()> {
};

let handler = HelloHandler::default().to_mcp_server_handler();
let server = hyper_server::create_server(
let server = create_axum_server(
server_info,
handler,
HyperServerOptions {
AxumServerOptions {
host: "127.0.0.1".to_string(),
event_store: Some(std::sync::Arc::new(InMemoryEventStore::default())), // enable resumability
..Default::default()
Expand Down Expand Up @@ -442,20 +443,20 @@ MCP server can verify tokens issued by other systems, integrate with external id



## HyperServerOptions
## AxumServerOptions

HyperServer is a lightweight Axum-based server that streamlines MCP servers by supporting **Streamable HTTP** and **SSE** transports. It supports simultaneous client connections, internal session management, and includes built-in security features like DNS rebinding protection and more.
AxumServer is a lightweight Axum-based server provided by the `rust-mcp-axum` crate that streamlines MCP servers by supporting **Streamable HTTP** and **SSE** transports. It supports simultaneous client connections, internal session management, and includes built-in security features like DNS rebinding protection and more.

HyperServer is highly customizable through HyperServerOptions provided during initialization.
AxumServer is highly customizable through AxumServerOptions provided during initialization.

A typical example of creating a HyperServer that exposes the MCP server via Streamable HTTP and SSE transports at:
A typical example of creating an AxumServer that exposes the MCP server via Streamable HTTP and SSE transports at:

```rs

let server = hyper_server::create_server(
let server = create_axum_server(
server_details,
handler.to_mcp_server_handler(),
HyperServerOptions {
AxumServerOptions {
host: "127.0.0.1".to_string(),
port: 8080,
event_store: Some(std::sync::Arc::new(InMemoryEventStore::default())), // enable resumability
Expand All @@ -468,7 +469,7 @@ let server = hyper_server::create_server(
server.start().await?;
```

πŸ“ Refer to [HyperServerOptions](https://github.com/rust-mcp-stack/rust-mcp-sdk/blob/main/crates/rust-mcp-sdk/src/hyper_servers/server.rs#L43) for a complete overview of HyperServerOptions attributes and options.
πŸ“ Refer to [AxumServerOptions](https://github.com/rust-mcp-stack/rust-mcp-sdk/blob/main/crates/rust-mcp-axum/src/server.rs#L43) for a complete overview of AxumServerOptions attributes and options.


### Security Considerations
Expand All @@ -488,8 +489,6 @@ The `rust-mcp-sdk` crate provides several features that can be enabled or disabl

- `server`: Activates MCP server capabilities in `rust-mcp-sdk`, providing modules and APIs for building and managing MCP servers.
- `client`: Activates MCP client capabilities, offering modules and APIs for client development and communicating with MCP servers.
- `hyper-server`: This feature is necessary to enable `Streamable HTTP` or `Server-Sent Events (SSE)` transports for MCP servers. It must be used alongside the server feature to support the required server functionalities.
- `ssl`: This feature enables TLS/SSL support for the `Streamable HTTP` or `Server-Sent Events (SSE)` transport when used with the `hyper-server`.
- `macros`: Provides procedural macros for simplifying the creation and manipulation of MCP Tool structures.
- `sse`: Enables support for the `Server-Sent Events (SSE)` transport.
- `streamable-http`: Enables support for the `Streamable HTTP` transport.
Expand Down Expand Up @@ -520,7 +519,7 @@ If you only need the MCP Server functionality, you can disable the default featu
[dependencies]
rust-mcp-sdk = { version = "0.2.0", default-features = false, features = ["server","macros","stdio"] }
```
Optionally add `hyper-server` and `streamable-http` for **Streamable HTTP** transport, and `ssl` feature for tls/ssl support of the `hyper-server`
Optionally add [`rust-mcp-axum`](https://crates.io/crates/rust-mcp-axum) and the `streamable-http` feature for **Streamable HTTP** transport, and use `rust-mcp-axum`'s `ssl` feature for TLS/SSL support.

<!-- x-release-please-end -->

Expand Down Expand Up @@ -557,11 +556,11 @@ Learn when to use the `mcp_*_handler` traits versus the lower-level `mcp_*_hand

- For `ServerHandler`:
- Use `server_runtime::create_server()` for servers with stdio transport
- Use `hyper_server::create_server()` for servers with sse transport
- Use `rust_mcp_axum::create_axum_server()` for servers with Streamable HTTP/SSE transport

- For `ServerHandlerCore`:
- Use `server_runtime_core::create_server()` for servers with stdio transport
- Use `hyper_server_core::create_server()` for servers with sse transport
- Use `rust_mcp_axum::create_axum_server()` for servers with Streamable HTTP/SSE transport

---

Expand Down Expand Up @@ -609,13 +608,13 @@ While not part of the official MCP spec, `rust-mcp-sdk` provides an optional HTT
- Exposed behind load balancers or reverse proxies (e.g., NGINX, HAProxy, Cloudflare).
- Running in container orchestration environments (e.g., Kubernetes, Docker Swarm, AWS ECS).

The health check endpoint is disabled by default. You can enable it and optionally provide your own custom handler (to return specific metrics or metadata) via `HyperServerOptions`:
The health check endpoint is disabled by default. You can enable it and optionally provide your own custom handler (to return specific metrics or metadata) via `AxumServerOptions`:

```rs
let server = hyper_server::create_server(
let server = create_axum_server(
server_details,
handler.to_mcp_server_handler(),
HyperServerOptions {
AxumServerOptions {
host: "127.0.0.1".into(),
health_endpoint: Some("/health".into()), // enables the endpoint
health_handler: Some(Arc::new(CustomHealth {})), // optional: overrides default 200 OK
Expand Down
35 changes: 35 additions & 0 deletions crates/rust-mcp-axum/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
[package]
name = "rust-mcp-axum"
version = "0.1.0"
authors = ["Ali Hashemi"]
categories = ["data-structures", "parser-implementations", "parsing"]
description = "Axum HTTP server integration for rust-mcp-sdk"
repository = "https://github.com/rust-mcp-stack/rust-mcp-sdk"
documentation = "https://docs.rs/rust-mcp-axum"
keywords = ["rust-mcp-stack", "model", "context", "protocol", "sdk", "axum"]
license = "MIT"
edition = "2021"
rust-version = { workspace = true }

[dependencies]
rust-mcp-sdk = { workspace = true, features = ["server", "streamable-http", "sse", "auth"] }
thiserror = { workspace = true }
axum = { workspace = true }
axum-server = { workspace = true, features = [] }
tokio = { workspace = true }
futures = { workspace = true }
tracing = { workspace = true }
http = { workspace = true }

[dev-dependencies]
tempfile = "3.23.0"
tower = "0.5"
serde_json = { workspace = true }
http-body-util = { workspace = true }

[features]
ssl = ["axum-server/tls-rustls"]
tls-no-provider = ["axum-server/tls-rustls-no-provider"]

[lints]
workspace = true
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,9 @@ use std::net::AddrParseError;
use axum::{http::StatusCode, response::IntoResponse};
use thiserror::Error;

use crate::mcp_http::McpHttpError;
use rust_mcp_sdk::mcp_http::McpHttpError;

#[cfg(feature = "auth")]
use crate::auth::AuthenticationError;
use rust_mcp_sdk::auth::AuthenticationError;

pub type TransportServerResult<T> = core::result::Result<T, TransportServerError>;

Expand All @@ -30,13 +29,11 @@ pub enum TransportServerError {
SslCertError(String),
#[error("{0}")]
TransportError(String),
#[cfg(feature = "auth")]
#[error("{0}")]
AuthenticationError(#[from] AuthenticationError),
}

impl IntoResponse for TransportServerError {
//consume self and returns a Response
fn into_response(self) -> axum::response::Response {
let mut response = StatusCode::INTERNAL_SERVER_ERROR.into_response();
response.extensions_mut().insert(self);
Expand Down Expand Up @@ -65,7 +62,6 @@ impl From<TransportServerError> for McpHttpError {
TransportServerError::HttpError(s) => McpHttpError::HttpError(s),
TransportServerError::TransportError(s) => McpHttpError::TransportError(s),

#[cfg(feature = "auth")]
TransportServerError::AuthenticationError(e) => McpHttpError::HttpError(e.to_string()),

TransportServerError::AddrParseError(e) => McpHttpError::HttpError(e.to_string()),
Expand All @@ -76,10 +72,18 @@ impl From<TransportServerError> for McpHttpError {
}
}

impl From<TransportServerError> for rust_mcp_sdk::error::McpSdkError {
fn from(err: TransportServerError) -> Self {
rust_mcp_sdk::error::McpSdkError::Internal {
description: err.to_string(),
}
}
}

#[cfg(test)]
mod tests {
use super::*;
use crate::mcp_http::McpHttpResult;
use rust_mcp_sdk::mcp_http::{McpHttpError, McpHttpResult};

// McpHttpError to TransportServerError

Expand Down Expand Up @@ -189,7 +193,6 @@ mod tests {
assert!(matches!(m, McpHttpError::HttpError(ref s) if s == "cert expired"));
}

#[cfg(feature = "auth")]
#[test]
fn transport_to_mcp_authentication_lossy() {
let auth_err = AuthenticationError::InactiveToken;
Expand All @@ -198,7 +201,7 @@ mod tests {
assert!(matches!(m, McpHttpError::HttpError(ref s) if s.contains("Inactive")));
}

// Round-trip: McpHttpError to TransportServerError to McpHttpError
// Round-trip

#[test]
fn round_trip_session_id_missing() {
Expand Down Expand Up @@ -240,7 +243,7 @@ mod tests {
assert_eq!(format!("{}", m), format!("{}", back));
}

// Round-trip: TransportServerError > McpHttpError > TransportServerError
// Reverse round-trip

#[test]
fn reverse_round_trip_session_id_missing() {
Expand Down Expand Up @@ -296,9 +299,6 @@ mod tests {
fn mcp_http_result_from_transport_error() {
let r: TransportServerResult<()> = Err(TransportServerError::SessionIdInvalid("x".into()));
let m: McpHttpResult<()> = r.map_err(Into::into);
assert!(matches!(
m.unwrap_err(),
McpHttpError::SessionIdInvalid(ref s) if s == "x"
));
assert!(matches!(m.unwrap_err(), McpHttpError::SessionIdInvalid(ref s) if s == "x"));
}
}
22 changes: 22 additions & 0 deletions crates/rust-mcp-axum/src/factory.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
use super::{AxumServer, AxumServerOptions};
use rust_mcp_sdk::schema::InitializeResult;
use rust_mcp_sdk::McpServerHandler;
use std::sync::Arc;

/// Creates a new AxumServer instance with the provided handler and options
/// The handler must implement ServerHandler.
///
/// # Arguments
/// * `server_details` - Initialization result from the MCP schema
/// * `handler` - Implementation of the ServerHandlerCore trait
/// * `server_options` - Configuration options for the AxumServer
///
/// # Returns
/// * `AxumServer` - A configured AxumServer instance ready to start
pub fn create_axum_server(
server_details: InitializeResult,
handler: Arc<dyn McpServerHandler + 'static>,
server_options: AxumServerOptions,
) -> AxumServer {
AxumServer::new(server_details, handler, server_options)
}
14 changes: 14 additions & 0 deletions crates/rust-mcp-axum/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
mod error;
mod factory;
pub mod routes;
mod runtime;
mod server;
mod utils;

pub use error::*;
pub use factory::*;
pub use routes::mcp_routes;
pub use runtime::*;
pub use server::*;

pub use axum;
Loading
Loading