dravr-tronc
A lightweight Rust runtime for building MCP servers with optional REST API support. Provides everything you need to go from zero to a production-ready MCP server in minutes — JSON-RPC 2.0 protocol, stdio and HTTP transports, bearer auth, health checks, CLI parsing, and structured tracing.
Why dravr-tronc?
Building an MCP server in Rust means writing the same boilerplate every time: JSON-RPC 2.0 types, request dispatching, transport layers, auth middleware, CLI args. dravr-tronc extracts all of that into a single crate so you only write your domain logic.
- Generic over state —
McpServer<S>works with anySend + Syncstate type - Two transports — stdio (for editor/CLI integration) and HTTP with SSE (for web clients)
- Zero configuration — sensible defaults, env-var driven auth, plug and play
- Production ready — constant-time auth, structured tracing, health checks, 76 tests
- Minimal dependencies — axum, tokio, serde, clap, tracing (no framework lock-in)
Quick start
[]
= "0.2"
1. Define your state and tools
use Arc;
use async_trait;
use ;
use ;
use ;
use RwLock;
;
2. Wire it up
async
3. Or serve over HTTP
// Serve over HTTP with SSE support
serve.await?;
4. Merge into an existing Axum app
use mcp_router;
let app = new
.route
.route
.merge // adds POST /mcp
.layer;
Modules
| Module | Purpose |
|---|---|
mcp::protocol |
JSON-RPC 2.0 types — requests, responses, errors, MCP initialize/tools/call |
mcp::server |
Generic McpServer<S> — dispatches initialize, tools/list, tools/call, ping |
mcp::tool |
McpTool<S> trait + ToolRegistry<S> — define and register tools |
mcp::transport::stdio |
Newline-delimited JSON over stdin/stdout |
mcp::transport::http |
Axum POST /mcp handler with SSE (Streamable HTTP) |
server::auth |
Bearer token middleware — env-var driven, constant-time comparison |
server::health |
HealthResponse builder with HTTP status codes |
server::cli |
ServerArgs / McpArgs — clap structs for #[command(flatten)] |
server::tracing_init |
Tracing subscriber — stderr for stdio, stdout for HTTP |
error |
ErrorResponse for REST APIs + JSON-RPC error code constants |
Auth middleware
Reads the API key from the environment variable you specify. If the variable is unset, all requests pass through (development mode). Uses subtle::ConstantTimeEq to prevent timing attacks.
// Only enforced when MY_API_KEY env var is set
require_auth.await
Health checks
use HealthResponse;
let resp = ok
.with_detail
.with_detail;
// Returns 200 for "ok", 503 for "degraded"
CLI args
Flatten shared args into your project's CLI struct:
use Parser;
use McpArgs;
Recommended project layout
my-project/
├── src/ # Core domain library
├── crates/my-project-mcp/ # MCP server (library + binary)
│ ├── src/state.rs # Your ServerState
│ ├── src/tools/ # Your McpTool<ServerState> implementations
│ └── src/main.rs # Thin entry point using dravr-tronc
└── crates/my-project-server/ # REST API + MCP unified server (binary)
├── src/router.rs # Axum routes + mcp_router() merge
└── src/main.rs # CLI + transport dispatch
License
Licensed under either of Apache License, Version 2.0 or MIT License at your option.