SkillAgentSearch skills...

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-core

If the server publishes to npm under a different name, use that package instead — check the repo README.

About this skill
🔌

MCP Server

Model Context Protocol server

Quality Score

80/100

Category

Legal

Supported Platforms

Claude Code
Claude Desktop
Gemini CLI
OpenAI Codex

rust-mcp-core

License: MIT Tests Coverage cargo-deny cargo-audit

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-Authenticate challenges. 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, ServerHandler trait, 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)
  • ServerHandler trait 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 initialize handshake
  • Ping/pong for connection health
  • Feature-gate enforcement: disabled features return method-not-found and 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 runtime handle,
  • 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 -> injects Authorization: Bearer <token>.
  • type: basic -> injects HTTP Basic auth.
  • type: oauth2 -> acquires/caches access tokens via client_credentials or refresh_token grant, injects bearer token, and can retry once on 401 after forced refresh.

Token-endpoint secrets support inline, env, and path sources. Optio

Truncated for display — read the full file on GitHub.

Related Skills

View on GitHub
GitHub Stars9
CategoryLegal
Updated6mo ago
Forks1

Languages

Rust

Security Score

86/100

Audited on Mar 11, 2026

2 low