rust-mcp-core
A config-driven MCP server core built on the official Rust SDK. Define tools, auth, prompts, resources, and HTTP behavior in YAML or JSON configuration -- the library handles execution, validation, and protocol compliance with minimal Rust code.
Install / Use
claude mcp add nullablevariant -- npx -y github:nullablevariant/rust-mcp-coreIf the server publishes to npm under a different name, use that package instead — check the repo README.
MCP Server
Model Context Protocol server
Quality Score
Category
LegalSupported Platforms
Skill content
View source on GitHubrust-mcp-core
A config-driven MCP server core built on the official Rust SDK (rmcp). Define tools, auth, prompts, resources, and HTTP behavior in YAML or JSON configuration -- the library handles execution, validation, and protocol compliance with minimal Rust code.
Fully implements the Model Context Protocol specification (2025-11-25).
Tested AI CLI compatibility
This library has been tested and verified with:
- Claude Code
- Codex CLI
- Gemini CLI
What this is for
- Reduced boilerplate. Stand up a spec-compliant MCP server by writing configuration instead of protocol plumbing. A working server with HTTP tools needs only a YAML file and a few lines of Rust.
- Built-in HTTP API tooling. Define outbound HTTP tool calls entirely in config with URL templating, header injection, query parameters, and structured response mapping.
- Authentication out of the box. Supports inbound bearer token, JWT/JWKS validation, and OAuth token introspection with scope enforcement and
WWW-Authenticatechallenges. Also supports outbound upstream auth for HTTP tools (none,bearer,basic,oauth2) including OAuth2 client-credentials/refresh-token grants with optional mTLS at the token endpoint. - Extensible plugin system. When config-driven behavior is not enough, register plugins for custom tool logic, auth validation, prompt/resource providers, completion providers, and HTTP router extensions.
- Both transports. Works with stdio and streamable HTTP transports.
- Works with the official SDK. This library builds on rmcp and uses its transport runtime,
ServerHandlertrait, and MCP type definitions directly -- no reimplementation.
What this is not
- Not a toolbox. This library does not include built-in tools like file servers, database connectors, or shell executors. The only built-in execution type is outbound HTTP calls. Any other tool behavior must be provided through a tool plugin.
How this complements the rmcp SDK
The rmcp SDK provides low-level MCP protocol primitives: transport, message framing, the ServerHandler trait, and type definitions. rust-mcp-core builds on top of that to provide a config-driven server framework.
What the SDK provides (used directly, not reimplemented):
- Transport runtime (stdio + streamable HTTP)
ServerHandlertrait and JSON-RPC dispatch- All MCP model types (
Tool,Prompt,Resource,Task, etc.) - Default handler implementations (e.g.,
ping)
What rust-mcp-core adds:
- Config loading with
${env:ENV}expansion and JSON schema validation - Tool execution engine (HTTP tools with templating + plugin tools)
- Output schema validation and structured content rendering
- Plugin registries (tool, auth, prompt, resource, completion, HTTP router)
- Config-driven prompts, resources, and completion providers
- Auth middleware (bearer, JWT/JWKS, introspection, scope enforcement)
- Task store with peer isolation, TTL, cooperative cancellation, and status notifications
The complementary relationship is clearest with auth. The SDK provides client-side OAuth (PKCE flows, token acquisition, credential storage, automatic refresh). rust-mcp-core provides server-side auth (token validation, scope enforcement, WWW-Authenticate challenges, and the protected resource metadata endpoint). An rmcp client obtains a token and sends it; a rust-mcp-core server receives and validates it.
MCP specification compliance
This library implements the following capabilities from the MCP 2025-11-25 specification:
Server capabilities
| Capability | Description |
|------------|-------------|
| Tools | Config-driven and plugin-driven tool definitions. Supports input/output schema validation, list-changed notifications, and pagination. |
| Prompts | Inline (config-driven) and plugin-driven prompt providers with argument validation, template rendering, and list-changed notifications. |
| Resources | Inline and plugin-driven resource providers with subscribe/unsubscribe support and list-changed notifications. |
| Completion | Autocompletion for prompt and resource template arguments from inline value lists or plugin sources. |
| Logging | Structured log messages via notifications/message with syslog severity levels. Clients control notification threshold via logging/setLevel. |
| Progress | Long-running operation tracking via notifications/progress with rate limiting and monotonic progress enforcement. |
| Cancellation | In-progress request termination. Cancellable tools are aborted automatically; non-cancellable tools receive a fresh token and run to completion. |
| Tasks | Experimental task utility for long-running operations. Supports task-augmented tool calls, polling, deferred result retrieval, cooperative cancellation, TTL, peer isolation, and status notifications. |
| Pagination | Cursor-based pagination for tools/list and other list operations. |
Server-initiated client features
These require a registered plugin to invoke. The framework handles config validation and client capability negotiation; plugin code calls helpers via params.ctx (params: PluginCallParams).
| Feature | Description | |---------|-------------| | Sampling | Request LLM text/image/audio generation from the client, optionally with tool use. | | Roots | Query the client for filesystem root boundaries. | | Elicitation | Request structured user input (form mode) or trigger out-of-band interactions like OAuth flows (URL mode). |
Protocol fundamentals
- Capability negotiation during
initializehandshake - Ping/pong for connection health
- Feature-gate enforcement: disabled features return
method-not-foundand are omitted from capability advertisement
Compile-time features
All features are enabled by default. Disable with default-features = false and enable selectively.
| Feature | Description | Implies |
|---------|-------------|---------|
| streamable_http | HTTP transport (server.transport.mode=streamable_http) and HTTP router plugin surface | -- |
| http_hardening | Streamable HTTP hardening middleware (max_request_bytes, inbound rate limits, session abuse controls, panic/sensitive-header guards) | streamable_http |
| auth | Auth middleware: bearer, JWT/JWKS, OAuth introspection, scope enforcement | streamable_http |
| http_tools | Built-in outbound HTTP tool execution (tools.items[].execute.type=http) plus upstream auth (none, bearer, basic, oauth2) | -- |
| prompts | prompts/list + prompts/get capability | -- |
| resources | resources/list, resources/read, resources/templates/list, subscribe/unsubscribe | -- |
| completion | completion/complete for prompt/resource argument autocompletion | -- |
| client_logging | logging/setLevel + notifications/message | -- |
| progress_utility | notifications/progress via params.ctx.notify_progress(...) | -- |
| tasks_utility | Experimental: task-augmented tools/call, tasks/get, tasks/list, tasks/cancel | -- |
| client_features | Server-initiated client helpers via params.ctx: request_roots(), request_sampling(), request_elicitation() | -- |
Minimal build (stdio + plugin tools only):
cargo build --no-default-features
If config references a disabled feature, startup fails with a clear error message.
Installation
From crates.io:
[dependencies]
rust-mcp-core = "0.1"
From GitHub:
[dependencies]
rust-mcp-core = { git = "https://github.com/nullablevariant/rust-mcp-core" }
Quick start
Configuration
Create a YAML config file. This example defines one HTTP tool and one inline prompt over streamable HTTP transport. Stdio transport is also supported by setting transport.mode: stdio.
If you want a full copy/paste starter with every supported field, use mcp_config.template.yml.
version: 1
server:
host: 0.0.0.0
port: 3000
endpoint_path: /mcp
logging:
level: info
transport:
mode: streamable_http # also supports: stdio
auth:
enabled: false
client_logging:
level: info
upstreams:
api:
base_url: ${env:API_BASE_URL}
tools:
items:
- name: api.list_items
description: List items from the API
input_schema:
type: object
properties:
query:
type: string
execute:
type: http
upstream: api
method: GET
path: /items
query:
q: "${query}"
response:
type: structured
template:
items: "${$.items}"
fallback: text
Usage
use std::path::PathBuf;
use rust_mcp_core::{load_mcp_config_from_path, runtime, PluginRegistry};
use rust_mcp_core::McpError;
#[tokio::main]
async fn main() -> Result<(), McpError> {
let config = load_mcp_config_from_path(PathBuf::from("config/mcp_config.yml"))?;
let plugins = PluginRegistry::new();
runtime::run_from_config(config, plugins).await
}
With a custom tool plugin:
use rust_mcp_core::{load_mcp_config_from_path, runtime, McpError, PluginRegistry};
#[tokio::main]
async fn main() -> Result<(), McpError> {
let config = load_mcp_config_from_path("config/mcp_config.yml".into())?;
let plugins = PluginRegistry::new()
.register_tool(MyToolPlugin)?;
runtime::run_from_config(config, plugins).await
}
Any plugin referenced by config (for example via tools.items[].execute.plugin or provider plugin fields) must be both declared in config plugins[] and registered in PluginRegistry. Extra registered plugins that are not declared are ignored with a warning. See Plugin Guide for the full plugin contract.
Config reload (consumer-managed)
runtime::run_from_config(...) is a convenience entrypoint and does not expose reload control.
If you need config reload:
- use
runtime::build_runtime(...), - keep the returned
runtimehandle, - load updated config input yourself,
- call
runtime.reload_config(new_config).await.
rust-mcp-core does not automatically watch config files or trigger reloads.
use std::path::PathBuf;
use rust_mcp_core::{load_mcp_config_from_path, runtime, McpError, PluginRegistry};
#[tokio::main]
async fn main() -> Result<(), McpError> {
let initial = load_mcp_config_from_path(PathBuf::from("config/mcp_config.yml"))?;
let runtime = runtime::build_runtime(initial, PluginRegistry::new()).await?;
// Consumer-owned trigger (file watcher, signal, admin endpoint, etc.)
let updated = load_mcp_config_from_path(PathBuf::from("config/mcp_config.reload.yml"))?;
runtime.reload_config(updated).await?;
runtime.run().await
}
Upstream auth for HTTP tools
upstreams.<name>.auth controls outbound auth for tools.items[].execute.type=http:
type: none-> no auth header injected.type: bearer-> injectsAuthorization: Bearer <token>.type: basic-> injects HTTP Basic auth.type: oauth2-> acquires/caches access tokens viaclient_credentialsorrefresh_tokengrant, injects bearer token, and can retry once on401after forced refresh.
Token-endpoint secrets support inline, env, and path sources. Optio
Truncated for display — read the full file on GitHub.
Related Skills
Agent-Reach
84.5kGive your AI agent eyes to see the entire internet. Read & search Twitter, Reddit, YouTube, GitHub, Bilibili, XiaoHongShu — one CLI, zero API fees.
headroom
73.4kCompress tool outputs, logs, files, and RAG chunks before they reach the LLM. 20% fewer tokens for coding agents, 60-95% fewer tokens for JSON, same answers. Library, proxy, MCP server.
ruflo
73.0k🌊 The original agent harness. Deploy intelligent multi-player swarms, coordinate autonomous workflows, and build conversational AI systems. Features adaptive memory, self-learning intelligence, federation, vector RAG integration, and native Claude Code / Codex / Hermes and many more Integrated
CowAgent
47.1kOpen-source super AI assistant & Agent Harness. Plans tasks, runs tools and skills, self-evolves with memory and knowledge. Multi-agent, multi-model, multi-channel. Lightweight, extensible, one-line install.
