Rmcp Server Kit
Reusable Rust framework for building authenticated, observable MCP (Model Context Protocol) servers over Streamable HTTP.
Ask AI about Rmcp Server Kit
Powered by Claude · Grounded in docs
I know everything about Rmcp Server Kit. Ask me about installation, configuration, usage, or troubleshooting.
0/500
Reviews
Documentation
rmcp-server-kit
rmcp-server-kit is a production-grade, reusable framework for building Model Context Protocol servers in Rust. It provides a Streamable HTTP transport with TLS/mTLS, structured observability, authentication (Bearer / mTLS / OAuth 2.1 JWT), role-based access control (RBAC), per-IP rate limiting, and optional Prometheus metrics -- all wired up and ready to go.
You supply a rmcp::handler::server::ServerHandler implementation; rmcp-server-kit
handles everything else.
Quick Start
[dependencies]
rmcp-server-kit = "1"
rmcp = { version = "1.5", features = ["server", "macros"] }
tokio = { version = "1", features = ["rt-multi-thread", "macros", "signal"] }
The minimal example below uses default features only. Enable the
oauthfeature (features = ["oauth"]) to validate JWTs against a JWKS, ormetricsfor the Prometheus/metricsendpoint -- see the Cargo features table below.
use rmcp_server_kit::transport::{McpServerConfig, serve};
use rmcp::handler::server::ServerHandler;
use rmcp::model::{ServerCapabilities, ServerInfo};
#[derive(Clone)]
struct MyHandler;
impl ServerHandler for MyHandler {
fn get_info(&self) -> ServerInfo {
ServerInfo::new(ServerCapabilities::builder().enable_tools().build())
}
}
#[tokio::main]
async fn main() -> rmcp_server_kit::Result<()> {
let _ = rmcp_server_kit::observability::init_tracing("info,my_server=debug");
let config = McpServerConfig::new("127.0.0.1:8080", "my-server", "0.1.0")
.with_request_timeout(std::time::Duration::from_secs(30))
.enable_request_header_logging();
serve(config.validate()?, || MyHandler).await
}
Full API documentation and worked examples live in docs/GUIDE.md. Two runnable end-to-end examples ship in the repository:
cargo run --example minimal_server
cargo run --example api_key_rbac
cargo run --example oauth_server --features oauth
Common configurations
API key + RBAC + per-tool argument allowlist:
use rmcp_server_kit::auth::{ApiKeyEntry, AuthConfig, generate_api_key};
use rmcp_server_kit::rbac::{ArgumentAllowlist, RbacConfig, RbacPolicy, RoleConfig};
use std::sync::Arc;
let (token, hash) = generate_api_key()?;
let auth = AuthConfig::with_keys(vec![
ApiKeyEntry::new("viewer-key", hash, "viewer"),
]);
let viewer = RoleConfig::new("viewer", vec!["echo".into()], vec!["*".into()])
.with_argument_allowlists(vec![ArgumentAllowlist::new(
"echo", "message", vec!["hello".into(), "ping".into()],
)]);
let rbac = Arc::new(RbacPolicy::new(&RbacConfig::with_roles(vec![viewer])));
OAuth 2.1 resource server (JWT validation against JWKS):
use rmcp_server_kit::auth::AuthConfig;
use rmcp_server_kit::oauth::OAuthConfig;
let oauth = OAuthConfig::builder(
"https://auth.example.com/",
"my-mcp-server",
"https://auth.example.com/.well-known/jwks.json",
)
.scope("mcp:admin", "admin")
.scope("mcp:read", "viewer")
.build();
let mut auth = AuthConfig::with_keys(vec![]);
auth.oauth = Some(oauth);
The OAuth fetcher and the shared
OauthHttpClientenforce a strict per-hop SSRF guard and a fail-closed cap on JWKS key counts. Construct the client viaOauthHttpClient::with_config(&oauth_config)so the configured CA bundle, the SSRF guard, and the HTTPS-downgrade-rejecting redirect policy are all wired in one call. SeeSECURITY.mdfor the trust model.
OAuth in-cluster IdP (private/loopback IdP target, opt-in):
use rmcp_server_kit::oauth::{OAuthConfig, OAuthSsrfAllowlist};
// `OAuthSsrfAllowlist` is `#[non_exhaustive]`; build it via
// `Default::default()` and push into the public fields.
let mut allowlist = OAuthSsrfAllowlist::default();
allowlist.hosts.push("rhbk.ops.example.com".into());
allowlist.cidrs.push("10.0.0.0/8".into());
let oauth = OAuthConfig::builder(
"https://rhbk.ops.example.com/realms/main",
"my-mcp-server",
"https://rhbk.ops.example.com/realms/main/protocol/openid-connect/certs",
)
.ssrf_allowlist(allowlist)
.build();
The default fail-closed SSRF guard blocks targets that resolve into private (RFC 1918), loopback, CGNAT, or unique-local space. Use
ssrf_allowlistonly when the IdP legitimately lives there (e.g. a KeycloakServiceClusterIP). Cloud-metadata addresses (AWS / GCP / Alibaba) remain unbypassable regardless of the allowlist contents. Seedocs/GUIDE.mdand the "Operator allowlist" subsection ofSECURITY.mdfor the full trust model.
Prometheus metrics on a separate listener:
let config = McpServerConfig::new("127.0.0.1:8080", "my-server", "0.1.0")
.with_metrics("127.0.0.1:9090".parse().unwrap());
TLS:
let config = McpServerConfig::new("127.0.0.1:8443", "my-server", "0.1.0")
.with_tls("/etc/certs/server.crt", "/etc/certs/server.key");
Features
- Transport: Streamable HTTP (
/mcp), health (/healthz,/readyz), admin diagnostics, graceful shutdown, configurable TLS and mTLS. - Auth: API-key (Argon2 hashed), mTLS client certs, OAuth 2.1 JWT validation against JWKS (feature-gated).
- RBAC: Tool-scoped allow-lists with per-role argument constraints and
task-local
current_role()/current_identity()accessors. - Observability: Tracing, JSON logs, optional audit-file sink.
- Hardening: Per-IP rate limiting (governor), request-body caps, OWASP security headers, configurable CORS and Host allow-lists.
- Metrics: Prometheus
/metricsendpoint (opt-in viametricsfeature).
Cargo features
| Feature | Default | Description |
|---|---|---|
oauth | No | OAuth 2.1 JWT validation via JWKS. |
metrics | No | Prometheus metrics registry and /metrics. |
Minimum supported Rust
rmcp-server-kit targets stable Rust 1.95 or newer (tracks edition = "2024").
Repository
- GitHub (canonical): https://github.com/andrico21/rmcp-server-kit
The canonical release artifact is the rmcp-server-kit crate on crates.io.
License
Dual-licensed under either of:
- Apache License, Version 2.0 (LICENSE-APACHE or https://www.apache.org/licenses/LICENSE-2.0)
- MIT license (LICENSE-MIT or https://opensource.org/licenses/MIT)
at your option.
Contribution
Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual-licensed as above, without any additional terms or conditions.
