axum-mcp
axum-mcp is a comprehensive Model Context Protocol (MCP) implementation built in Rust. It supports AI workflow templates and multiple transport protocols, enabling seamless communication between Large Language Models (LLMs) and Rust applications. With features like session management and authentication, it is well-suited for production environments.
GitHub Stars
1
User Rating
Not Rated
Favorites
0
Views
53
Forks
0
Issues
0
axum-mcp
A comprehensive Model Context Protocol (MCP) implementation for Rust with Axum integration, featuring configurable resource registries, AI workflow templates, and multi-transport support.
Overview
axum-mcp is a production-ready MCP server and client library that enables seamless communication between Large Language Models (LLMs) and Rust applications. It provides a trait-based architecture for building custom MCP servers with support for multiple transport protocols.
Key Features
- π Production Ready - Session management, authentication, monitoring, and error recovery
- π Multiple Transports - stdio, Server-Sent Events (SSE), and StreamableHTTP for Claude Desktop
- ποΈ Configurable Resource Registry - Support for custom URI schemes (
ratchet://,layercake://, etc.) - π€ AI Workflow Templates - Prompt registry with parameter substitution and embedded resources
- π‘οΈ Security First - Built-in authentication, authorization, and rate limiting
- β‘ High Performance - Connection pooling, message batching, and streaming support
- π― Claude Compatible - Full support for Claude Desktop's StreamableHTTP transport
- π§© Trait-Based - Flexible architecture enabling custom tool registries and authentication
- π Observability - Comprehensive logging, metrics, and health monitoring
Architecture
βββββββββββββββββββββββ
β LLM/AI Agent β
β (Claude, GPT-4) β
β βββββββββββββββββ β
β β MCP Client β β
β βββββββββ¬ββββββββ β
ββββββββββββΌβββββββββββ
β
ββββββββ΄βββββββ
β Transport β
β (stdio/SSE) β
ββββββββ¬βββββββ
β
ββββββββββββΌβββββββββββ
β axum-mcp Server β
β βββββββββββββββββ β
β β Tool Registryβ β
β βββββββββ¬ββββββββ β
ββββββββββββΌβββββββββββ
β
ββββββββ΄βββββββββββ
β Your App Logic β
β - Custom Tools β
β - Business Logicβ
β - Data Access β
βββββββββββββββββββ
Quick Start
Add to your Cargo.toml:
[dependencies]
axum-mcp = "0.1"
axum = "0.7"
tokio = { version = "1.0", features = ["full"] }
async-trait = "0.1"
serde_json = "1.0"
Basic Server Example
use axum_mcp::{
prelude::*,
axum_integration::{mcp_routes_with_wrapper, McpServerWrapper},
server::{config::McpServerConfig, service::McpServer},
};
#[derive(Clone)]
struct MyServerState {
tools: InMemoryToolRegistry,
auth: MyAuth,
}
#[derive(Clone)]
struct MyAuth;
#[async_trait]
impl McpAuth for MyAuth {
async fn authenticate(&self, _client: &ClientContext) -> McpResult<SecurityContext> {
Ok(SecurityContext::system())
}
async fn authorize(&self, _context: &SecurityContext, _resource: &str, _action: &str) -> bool {
true
}
}
impl McpServerState for MyServerState {
type ToolRegistry = InMemoryToolRegistry;
type AuthManager = MyAuth;
fn tool_registry(&self) -> &Self::ToolRegistry { &self.tools }
fn auth_manager(&self) -> &Self::AuthManager { &self.auth }
}
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let config = McpServerConfig::default();
// Create tools registry
let mut tools = InMemoryToolRegistry::new();
let echo_tool = McpTool::new(
"echo",
"Echo back a message",
serde_json::json!({
"type": "object",
"properties": {
"message": {"type": "string", "description": "Message to echo"}
},
"required": ["message"]
}),
"utility"
).public();
tools.register_tool(echo_tool);
let state = MyServerState {
tools,
auth: MyAuth,
};
let server = McpServer::new(config, state);
let wrapper = McpServerWrapper::new(server);
let app = axum::Router::new()
.merge(mcp_routes_with_wrapper())
.with_state(wrapper);
let listener = tokio::net::TcpListener::bind("0.0.0.0:3000").await?;
println!("MCP server running on http://0.0.0.0:3000");
axum::serve(listener, app).await?;
Ok(())
}
Claude Desktop Integration
To integrate with Claude Desktop, add this configuration to Claude's settings:
{
"mcpServers": {
"my-rust-server": {
"command": "curl",
"args": [
"-X", "POST",
"http://localhost:3000/mcp",
"-H", "Content-Type: application/json",
"-d", "@-"
],
"transport": "streamable-http"
}
}
}
Core Concepts
Tool Registry
The ToolRegistry trait defines how your application exposes tools to MCP clients:
#[async_trait]
pub trait ToolRegistry: Send + Sync {
async fn list_tools(&self, context: &SecurityContext) -> McpResult<Vec<Tool>>;
async fn execute_tool(&self, name: &str, context: ToolExecutionContext) -> McpResult<ToolsCallResult>;
}
Server State
The McpServerState trait connects your tool registry, authentication, and optional registries:
pub trait McpServerState: Send + Sync + Clone + 'static {
type ToolRegistry: ToolRegistry;
type AuthManager: McpAuth;
fn tool_registry(&self) -> &Self::ToolRegistry;
fn auth_manager(&self) -> &Self::AuthManager;
// Optional: Add resource registry for custom URI schemes
fn resource_registry(&self) -> Option<&dyn ResourceRegistry> { None }
// Optional: Add prompt registry for AI workflow templates
fn prompt_registry(&self) -> Option<&dyn PromptRegistry> { None }
}
Authentication
Implement custom authentication with the McpAuth trait:
#[async_trait]
pub trait McpAuth: Send + Sync {
async fn authenticate(&self, context: &ClientContext) -> McpResult<SecurityContext>;
async fn authorize(&self, context: &SecurityContext, resource: &str, action: &str) -> bool;
}
Transport Types
Standard I/O Transport
For local processes and command-line tools:
use axum_mcp::transport::{StdioTransport, McpTransport};
let transport = StdioTransport::new();
// Use with stdio-based MCP clients
Server-Sent Events (SSE)
For web-based real-time communication:
// SSE endpoints are automatically included in mcp_routes()
let app = Router::new()
.merge(mcp_routes())
.with_state(state);
StreamableHTTP
For Claude Desktop compatibility:
// StreamableHTTP is the default transport in mcp_routes()
// Supports both request/response and streaming modes
Advanced Features
Custom Authentication
#[derive(Clone)]
struct ApiKeyAuth {
valid_keys: HashSet<String>,
}
#[async_trait]
impl McpAuth for ApiKeyAuth {
async fn authenticate(&self, context: &ClientContext) -> McpResult<SecurityContext> {
let api_key = context.headers
.get("authorization")
.and_then(|h| h.to_str().ok())
.and_then(|s| s.strip_prefix("Bearer "))
.ok_or_else(|| McpError::unauthorized("Missing API key"))?;
if self.valid_keys.contains(api_key) {
Ok(SecurityContext::authenticated(api_key.to_string()))
} else {
Err(McpError::unauthorized("Invalid API key"))
}
}
async fn authorize(&self, _context: &SecurityContext, _resource: &str, _action: &str) -> bool {
true // Implement your authorization logic
}
}
Progress Reporting
For long-running operations:
async fn execute_tool(&self, name: &str, context: ToolExecutionContext) -> McpResult<ToolsCallResult> {
match name {
"long_task" => {
let progress = context.progress_reporter();
progress.report(0.0, "Starting task...").await;
// Do work...
progress.report(0.5, "Half way done...").await;
// More work...
progress.report(1.0, "Complete!").await;
Ok(ToolsCallResult::text("Task completed"))
}
_ => Err(McpError::method_not_found(format!("Unknown tool: {}", name)))
}
}
Rate Limiting
use axum_mcp::security::RateLimiter;
let rate_limiter = RateLimiter::new(100, Duration::from_secs(60)); // 100 requests per minute
Resource Registry
The resource registry enables custom URI schemes for project-specific resources:
Basic Resource Registry
use axum_mcp::server::resource::{UriSchemeConfig, InMemoryResourceRegistry, Resource, ResourceContent};
// Configure your project's URI scheme
let scheme = UriSchemeConfig::new("myproject", "My Project Resources")
.with_types(vec!["task".to_string(), "model".to_string()]);
let mut registry = InMemoryResourceRegistry::new(scheme);
// Add resources with your custom URIs
registry.add_resource(Resource {
uri: "myproject://tasks/data-processor".to_string(),
name: "Data Processing Task".to_string(),
description: Some("Processes CSV data files".to_string()),
mime_type: Some("application/json".to_string()),
content: ResourceContent::Text {
text: r#"{"name": "data-processor", "type": "etl"}"#.to_string()
},
metadata: std::collections::HashMap::new(),
});
Multi-Scheme Support
Support multiple URI schemes simultaneously:
use axum_mcp::server::resource::MultiSchemeResourceRegistry;
let mut multi_registry = MultiSchemeResourceRegistry::new();
// Register different schemes for different projects
let ratchet_registry = create_ratchet_registry(); // ratchet:// URIs
let layercake_registry = create_layercake_registry(); // layercake:// URIs
multi_registry.register_scheme(Box::new(ratchet_registry));
multi_registry.register_scheme(Box::new(layercake_registry));
// Now supports both ratchet://tasks/... and layercake://models/...
Resource Templates
Define templates for dynamic resource discovery:
registry.add_template(ResourceTemplate {
uri_template: "myproject://tasks/{task_id}".to_string(),
name: "Task Definition".to_string(),
description: Some("Task configuration and metadata".to_string()),
mime_type: Some("application/json".to_string()),
metadata: {
let mut meta = HashMap::new();
meta.insert("parameters".to_string(), serde_json::json!({
"task_id": "The unique identifier for the task"
}));
meta
},
});
Prompt Registry
Create reusable AI workflow templates with parameter substitution:
Basic Prompt Registry
use axum_mcp::server::prompt::{InMemoryPromptRegistry, PromptParameter};
let mut prompts = InMemoryPromptRegistry::new();
// Add a workflow prompt with parameters
prompts.add_workflow_prompt(
"code_analyzer",
"Analyze code for {{analysis_type}} issues",
"You are an expert code reviewer.",
"Please analyze this code for {{analysis_type}} issues: {{code_content}}",
vec![
PromptParameter {
name: "analysis_type".to_string(),
description: "Type of analysis (security, performance, style)".to_string(),
required: true,
schema: Some(serde_json::json!({
"type": "string",
"enum": ["security", "performance", "style"]
})),
default: None,
},
PromptParameter {
name: "code_content".to_string(),
description: "The code to analyze".to_string(),
required: true,
schema: Some(serde_json::json!({"type": "string"})),
default: None,
},
],
);
Embedded Resources in Prompts
Link prompts to external resources:
// Create a prompt that embeds a code file
prompts.add_code_analysis_prompt(
"security_reviewer",
"Review code for security vulnerabilities",
"myproject://code/auth_handler.py" // Embedded resource URI
);
// When rendered, this automatically includes the code file content
Using Prompts with Parameters
let request = GetPromptRequest {
name: "code_analyzer".to_string(),
arguments: Some({
let mut args = HashMap::new();
args.insert("analysis_type".to_string(),
serde_json::Value::String("security".to_string()));
args.insert("code_content".to_string(),
serde_json::Value::String("def authenticate(user): return True".to_string()));
args
}),
};
let result = prompts.get_prompt_with_args(request, &context).await?;
// Returns rendered prompt with parameters substituted
AI Workflow Categories
Organize prompts by domain:
prompts.add_category(PromptCategory {
id: "development".to_string(),
name: "Software Development".to_string(),
description: "Prompts for software development workflows".to_string(),
prompts: vec![
"code_analyzer".to_string(),
"debug_assistant".to_string(),
"api_designer".to_string(),
],
});
Configuration
Configure your MCP server with various options:
let config = McpServerConfig::sse_with_host(3000, "0.0.0.0")
.with_batch(50) // Enable batch operations with max 50 items
.with_metadata("version", serde_json::json!("1.0.0"))
.with_timeout(std::time::Duration::from_secs(30));
Transport Configuration
Choose your transport type:
// Server-Sent Events (default)
let config = McpServerConfig::sse_with_host(3000, "0.0.0.0");
// StreamableHTTP for Claude Desktop
let config = McpServerConfig::streamable_http_with_host(3000, "0.0.0.0");
// stdio for command-line tools
let config = McpServerConfig::stdio();
Error Handling
Comprehensive error handling with typed errors:
use axum_mcp::{McpError, McpResult};
fn my_tool_function() -> McpResult<String> {
// Tool not found
Err(McpError::ToolNotFound {
name: "invalid_tool".to_string()
})
// Tool execution error
Err(McpError::ToolExecution {
tool: "my_tool".to_string(),
message: "Invalid parameters".to_string()
})
// Resource errors
Err(McpError::ResourceNotFound {
uri: "myproject://invalid/resource".to_string()
})
// Authentication errors
Err(McpError::Authentication {
message: "Invalid credentials".to_string()
})
}
Project Integration Examples
Ratchet Integration
// Ratchet uses ratchet:// URI scheme
let ratchet_scheme = UriSchemeConfig::new("ratchet", "Ratchet task management")
.with_types(vec!["task".to_string(), "execution".to_string()]);
// Resources: ratchet://tasks/web-scraper, ratchet://executions/run-123
// Prompts: Task analysis, execution debugging, workflow optimization
Layercake Integration
// Layercake uses layercake:// URI scheme
let layercake_scheme = UriSchemeConfig::new("layercake", "Layercake ML platform")
.with_types(vec!["model".to_string(), "dataset".to_string()]);
// Resources: layercake://models/sentiment-v2, layercake://datasets/training-data
// Prompts: Model evaluation, hyperparameter tuning, data analysis
Features
Enable specific features in your Cargo.toml:
[dependencies]
axum-mcp = { version = "0.1", features = ["server", "client", "transport-sse"] }
Available features:
server- MCP server implementation (default)client- MCP client implementationtransport-stdio- Standard I/O transport (default)transport-sse- Server-Sent Events transport (default)transport-streamable-http- StreamableHTTP transport for Claude Desktop (default)
Examples
The examples/ directory contains comprehensive examples:
minimal_server.rs- Basic MCP server setup with tool registryresource_registry_example.rs- Custom URI schemes and resource managementprompt_registry_example.rs- AI workflow templates and prompt management
Running Examples
# Basic MCP server
cargo run --example minimal_server
# Resource registry with custom URI schemes
cargo run --example resource_registry_example
# AI workflow templates with prompt registry
cargo run --example prompt_registry_example
Each example includes detailed API usage instructions and curl commands for testing.
Testing
Run the test suite:
cargo test
Run examples:
cargo run --example minimal_server
Contributing
Contributions are welcome! Please see our Contributing Guide for details.
License
This project is licensed under either of
- Apache License, Version 2.0, (LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0)
- MIT license (LICENSE-MIT or http://opensource.org/licenses/MIT)
at your option.
Acknowledgments
This crate was extracted from the Ratchet project and represents a comprehensive, production-ready MCP implementation for the Rust ecosystem.
79
Followers
162
Repositories
107
Gists
0
Total Contributions