The problem
Every AI tool that talks to MCP servers (Claude, Cursor, etc.)
connects directly — no auth, no rate limiting, no observability.
You have no idea what's hitting your servers or how often.
What I built
MCP Gateway sits in front of all your MCP servers and handles:
- Routing — /mcp/server-name/* proxies to the right backend
- Auth — per-server API keys encrypted AES-256-GCM in memory
- Rate limiting — token bucket per client, 429 + Retry-After
- Logging — SQLite log of every request with latency + status
- Usage tracking — token counts from Anthropic/OpenAI responses
- CLI — mcpgw server add/list/remove, mcpgw logs show, mcpgw stats
Quickstart
MCPGW_MASTER_SECRET=your-secret docker compose up --build
Stack
Rust, Axum, SQLite (rusqlite), DashMap, AES-GCM
Top comments (6)
This is a great systems-level project—building a self-hosted reverse proxy for MCP servers in Rust immediately signals a strong focus on performance and control. I like the architectural direction here, especially the idea of centralizing routing, auth, and observability instead of pushing those concerns into individual services. Rust feels like a solid choice given the need for low-latency request handling and safety in concurrent workloads. One thing I’d be curious about is how you handle dynamic service discovery and hot reloads without downtime. Also interesting to see how this scales when multiple MCP servers have different protocol or latency characteristics.
Thanks! The dynamic service discovery question is a good one right now it's intentionally static (servers registered via CLI, stored in SQLite), which keeps the operational model simple. Hot reload without downtime is on the roadmap. the plan is to use a watch channel on the server registry so new registrations propagate to the router without restarting the process. For servers with different latency profiles, the token bucket rate limiter is per-server so you can tune them independently, but I haven't tackled adaptive backpressure yet. That's a real gap for mixed latency setups.
the policy-based controls idea is actually on the roadmap — per-client tool allowlists make a lot of sense once you have multiple agents hitting the same gateway with different trust levels. approval flows for high-risk actions are trickier but the SQLite audit log already gives you the foundation to build that on top of. will keep you posted as it develops
The 'no auth, no rate limiting, no observability' problem is real — and it compounds when you add a memory layer on top. If your agent can call MCP tools and those calls hit a raw server with no visibility, you lose the ability to audit what the agent actually did.
We're working on an MCP-compatible memory store in moteDB that would slot cleanly into a setup like this — the gateway handles routing/auth, and the memory layer handles 'what happened in this session.' Both problems need solving together.
Curious about the AES-256-GCM in-memory key storage — do you persist keys to disk at all, or is a restart a full key reset? The latter is safe but operationally painful for a long-running gateway.
The audit trail point is exactly right — that's actually what pushed me to add SQLite request logging instead of just stdout. Every proxied call gets a row with timestamp, server, latency, status, and token counts where available. Not perfect but it's a start for "what did the agent actually do."
On the AES-256-GCM question: keys are persisted to SQLite encrypted at rest using the master secret, so a restart doesn't wipe them. The master secret itself is env-var only (MCPGW_MASTER_SECRET) — never touches disk. So restart = re-derive the key from the same secret = keys survive. The operationally painful scenario is if you lose the master secret, which is on the operator. Interested in what the moteDB memory store looks like — does it expose an MCP-compatible tool interface or a separate API?
Some comments may only be visible to logged-in visitors. Sign in to view all comments.