MCP middleware: gating any MCP server with policy
Every guardrail product on the market lives inside your agent code: import an SDK, wrap your tool handlers, write rules. That works — but it only works for tools you wrote. MCP changed the question. Most production agents now load tools from third-party MCP servers (Stripe, GitHub, Slack, a Linear server your colleague vibe-coded). You did not write those handlers. You cannot wrap them. mcpguard-guard is the meta-MCP-server that sits in front of them.
The claim
mcpguard-guard is an MCP server whose tools are someone else's tools. You point your agent at the guard; the guard advertises the upstream server's tool list verbatim; every tool invocation from the agent is intercepted, evaluated against your MCP Guard policy, and only then forwarded to the upstream. Allow → forward. Deny → return a structured rejection. Review → create a review row, return a structured pending error, the agent surfaces it through its normal channel.
Your agent code does not change. Your upstream MCP server does not change. The middleware is the only new moving part — and it is configured with a single YAML file.
Architecture
The agent thinks it's talking to stripe-mcp. The tool list it sees is identical. The arguments it sends are identical. The difference is that every call now also writes a hash-chained audit row and runs your policy before the upstream sees it.
Wrapping stripe-mcp in 30 seconds
Drop a config file. The guard reads the upstream server's tool list at startup and proxies it forward.
# 1. point the guard at your MCP Guard tenant key
api_key_env: MCPGUARD_API_KEY
# 2. declare the upstream MCP server to proxy.
upstream:
name: stripe-mcp
# stdio (spawned subprocess) or http transport — both supported.
transport: stdio
command: ['npx', '-y', '@stripe/mcp', '--api-key', '$STRIPE_API_KEY']
# 3. map upstream tool names to MCP Guard action_ids.
# omit a tool to pass it through ungated.
actions:
create_refund: billing.refund
create_charge: billing.charge
delete_customer: billing.delete_customerRun the guard as your MCP server entry point:
{
"mcpServers": {
"stripe-guarded": {
"command": "npx",
"args": ["-y", "mcpguard-guard", "--config", "./mcp-guard.yaml"],
"env": { "MCPGUARD_API_KEY": "mcg_live_…" }
}
}
}/dashboard/audit fills up immediately.Config reference
The full config schema (every key optional unless marked required):
api_key_env(required) — env var holding your MCP Guard live key.upstream.name(required) — display name; shown in the audit log.upstream.transport—stdioorhttp. Defaults tostdio.upstream.command— argv array for stdio transport.upstream.url— URL for http transport.actions— map of upstream tool name → MCP Guardaction_id. Unmapped tools pass through ungated (this is opt-in by design — gating an unknown tool blind is worse than ungating one explicitly).mode_hint—observeorenforce. The server is still the source of truth; this is forwarded for tenants that A/B by client.review.short_circuit— whentrue, the middleware long-pollswaitForReviewbefore returning to the agent (good for human-in-the-loop UX). Whenfalse, it returns apolicy_review_requirederror immediately and the agent retries with the resolved review.
Why this is novel
Every other guardrail product on the market — LangSmith, Guardrails AI, NeMo Guardrails, Lakera, Robust Intelligence, Protect AI — is shaped as a library you import into your agent code. That works fine for the framework they were designed around. It does not work when:
- You did not write the tools. They live in
stripe-mcp,github-mcp, an internal Linear server. - The MCP client is Claude Desktop, Cursor, or another IDE that you do not have source access to.
- You want a single policy across an MCP zoo — Stripe, GitHub, a custom warehouse server — without modifying any of them.
MCP middleware is a deployment shape, not just a code shape. The closest analogue is an HTTP proxy with a WAF — and just like a WAF, the value compounds because one config covers any MCP-speaking client.
License & distribution
mcpguard-guard is MIT-licensed. Use it standalone, fork it, ship it inside another product, vendor the code — the only thing the wrapper does that isn't free is talk to api.mcp-guard.ai for the policy evaluation and audit row. The hosted API is the commercial surface; the wrapper itself is the OSS distribution play.
base_url in its config, so self-hosted MCP Guard customers point it at their own backend and never touch the public API.