mcpkit_axum/
lib.rs

1//! Axum integration for the Rust MCP SDK.
2//!
3//! This crate provides integration between the MCP SDK and the Axum web framework,
4//! making it easy to expose MCP servers over HTTP.
5//!
6//! # Features
7//!
8//! - HTTP POST endpoint for JSON-RPC messages
9//! - Server-Sent Events (SSE) streaming for notifications
10//! - Session management with automatic cleanup
11//! - Protocol version validation
12//! - CORS support
13//!
14//! # HTTP Protocol Requirements
15//!
16//! Clients must include the `Mcp-Protocol-Version` header in all requests:
17//!
18//! ```text
19//! POST /mcp HTTP/1.1
20//! Content-Type: application/json
21//! Mcp-Protocol-Version: 2025-11-25
22//!
23//! {"jsonrpc":"2.0","id":1,"method":"initialize","params":{...}}
24//! ```
25//!
26//! Supported protocol versions: `2024-11-05`, `2025-03-26`, `2025-06-18`, `2025-11-25`
27//!
28//! # Quick Start
29//!
30//! ```ignore
31//! use mcpkit::prelude::*;
32//! use mcpkit_axum::McpRouter;
33//!
34//! // Your MCP server handler (use #[mcp_server] macro)
35//! #[mcp_server(name = "my-server", version = "1.0.0")]
36//! impl MyServer {
37//!     #[tool(description = "Say hello")]
38//!     async fn hello(&self, name: String) -> ToolOutput {
39//!         ToolOutput::text(format!("Hello, {name}!"))
40//!     }
41//! }
42//!
43//! #[tokio::main]
44//! async fn main() -> std::io::Result<()> {
45//!     // Simple one-liner (similar to stdio transport):
46//!     McpRouter::new(MyServer::new())
47//!         .serve("0.0.0.0:3000")
48//!         .await
49//! }
50//! ```
51//!
52//! # Advanced Usage
53//!
54//! For more control, use `into_router()` to integrate with an existing app:
55//!
56//! ```ignore
57//! use mcpkit_axum::McpRouter;
58//! use axum::Router;
59//!
60//! let mcp_router = McpRouter::new(MyServer::new())
61//!     .with_cors()      // Enable CORS
62//!     .with_tracing();  // Enable request tracing
63//!
64//! let app = Router::new()
65//!     .nest("/mcp", mcp_router.into_router())
66//!     .route("/health", axum::routing::get(|| async { "OK" }));
67//!
68//! let listener = tokio::net::TcpListener::bind("0.0.0.0:3000").await?;
69//! axum::serve(listener, app).await?;
70//! ```
71//!
72//! # Client Example (curl)
73//!
74//! ```bash
75//! # Initialize the connection
76//! curl -X POST http://localhost:3000/mcp \
77//!   -H "Content-Type: application/json" \
78//!   -H "Mcp-Protocol-Version: 2025-11-25" \
79//!   -d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-11-25","clientInfo":{"name":"test","version":"1.0"},"capabilities":{}}}'
80//!
81//! # List available tools
82//! curl -X POST http://localhost:3000/mcp \
83//!   -H "Content-Type: application/json" \
84//!   -H "Mcp-Protocol-Version: 2025-11-25" \
85//!   -d '{"jsonrpc":"2.0","id":2,"method":"tools/list"}'
86//!
87//! # Call a tool
88//! curl -X POST http://localhost:3000/mcp \
89//!   -H "Content-Type: application/json" \
90//!   -H "Mcp-Protocol-Version: 2025-11-25" \
91//!   -d '{"jsonrpc":"2.0","id":3,"method":"tools/call","params":{"name":"hello","arguments":{"name":"World"}}}'
92//! ```
93
94#![deny(missing_docs)]
95
96mod error;
97mod handler;
98mod router;
99mod session;
100mod state;
101
102pub use error::ExtensionError;
103pub use handler::{handle_mcp_post, handle_oauth_protected_resource, handle_sse};
104pub use router::McpRouter;
105pub use session::{
106    EventStore, EventStoreConfig, Session, SessionManager, SessionStore, StoredEvent,
107};
108pub use state::{McpState, OAuthState};
109
110/// Prelude module for convenient imports.
111///
112/// # Example
113///
114/// ```ignore
115/// use mcpkit_axum::prelude::*;
116/// ```
117pub mod prelude {
118    pub use crate::error::ExtensionError;
119    pub use crate::handler::{handle_mcp_post, handle_oauth_protected_resource, handle_sse};
120    pub use crate::router::McpRouter;
121    pub use crate::session::{
122        EventStore, EventStoreConfig, Session, SessionManager, SessionStore, StoredEvent,
123    };
124    pub use crate::state::{McpState, OAuthState};
125}
126
127/// Protocol versions supported by this extension.
128pub const SUPPORTED_VERSIONS: &[&str] = &["2024-11-05", "2025-03-26", "2025-06-18", "2025-11-25"];
129
130/// Check if a protocol version is supported.
131#[must_use]
132pub fn is_supported_version(version: Option<&str>) -> bool {
133    version.is_some_and(|v| SUPPORTED_VERSIONS.contains(&v))
134}