
A lightweight mcp to prevent poisoning CVE (CVE-2025-54136), researchers hijacking Claude Code/Copilot/Gemini via prompt injection, and hundreds of MCP servers exposed with zero auth, this mcp protects the individual developer's laptop, where most MCP servers actually run.
The security gateway for MCP servers — every tool call gets checked at the door.
CI npm License: Apache-2.0 PRs welcome
mcp-doorman is a drop-in proxy that sits between your AI agent (Claude Desktop, Claude Code, Cursor, VS Code, any MCP client) and the MCP servers it uses. One command, zero infrastructure, and every tools/list and tools/call passes through a guard pipeline:
Everyone is one npx some-random-mcp-server away from handing an unvetted process their API keys and a direct line into their model's context window. The documented attack classes are real, not hypothetical:
Enterprise MCP gateways exist for platform teams with Kubernetes clusters. Nothing lightweight guards the individual developer's laptop — the place where 99% of MCP servers actually run. That's the gap this project fills.
# 1. Create a config
npx -y mcp-doorman init
# 2. Edit doorman.config.json — put your real servers in it
# 3. Pin the current tool definitions (trust on first use)
npx -y mcp-doorman pin --config doorman.config.json
Then point your client at the gateway instead of your servers. Claude Desktop / Claude Code / Cursor:
// BEFORE — every server talks straight to the model
{
"mcpServers": {
"github": { "command": "npx", "args": ["-y", "@modelcontextprotocol/server-github"] },
"filesystem": { "command": "npx", "args": ["-y", "@modelcontextprotocol/server-filesystem", "/repos"] }
}
}
// AFTER — one doorman guards them all
{
"mcpServers": {
"doorman": {
"command": "npx",
"args": ["-y", "mcp-doorman", "run", "--config", "/absolute/path/to/doorman.config.json"]
}
}
}
Tools show up namespaced as github__create_issue, filesystem__read_file, etc., plus two built-ins: doorman__status and doorman__recent_events (ask your agent "what did doorman block recently?").
Windows note: if a server entry uses
npxdirectly, spawn it through cmd:"command": "cmd", "args": ["/c", "npx", "-y", "..."].
git clone https://github.com/Sushank05/mcp-doorman && cd mcp-doorman
npm install
npm run demo
The demo wires the gateway to a deliberately misbehaving server (examples/demo-server.mjs) that leaks fake credentials, serves a prompt-injection payload, and offers a destructive tool — and shows each guard catching it.
flowchart LR
A["MCP client\n(Claude Desktop, Cursor, ...)"] -- stdio --> D
subgraph D [mcp-doorman]
direction TB
P[policy] --> R[rate limit] --> AP[approval] --> RD[redaction] --> I[injection scan] --> AU[(audit log)]
end
D -- stdio --> S1[github server]
D -- stdio --> S2[filesystem server]
D -- streamable HTTP --> S3[remote server]
The gateway is an MCP server toward your client and an MCP client toward every upstream (stdio child processes or streamable-HTTP endpoints), aggregating them behind one connection. It is built on the official TypeScript SDK.
Everything lives in one JSON file. Full example with every option:
{
"servers": {
"github": {
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-github"],
"env": { "GITHUB_PERSONAL_ACCESS_TOKEN": "${GITHUB_TOKEN}" } // ${VAR} = read from gateway env
},
"remote": { "url": "https://mcp.example.com/mcp", "headers": { "Authorization": "Bearer ${MCP_TOKEN}" } }
},
"policy": {
"defaultAction": "allow", // "allow" | "deny" | "approve"
"rules": [ // first match wins, evaluated top-down
{ "match": "*__delete*", "action": "deny", "reason": "no destructive tools" },
{ "match": ["github__create_*", "*__send_*"], "action": "approve" },
{ "match": "filesystem__*", "action": "allow" }
]
},
"redaction": {
"enabled": true,
"disable": [], // built-in rule names to turn off
"enableOptIn": ["email"], // opt-ins: "email", "us-ssn", "ipv4"
"custom": [{ "name": "acme-id", "pattern": "ACME-[0-9]{6}" }],
"redactArguments": false // also scrub model-supplied arguments
},
"injection": {
"action": "flag", // "flag" (warn the model) | "block" | "off"
"scanToolDescriptions": true, // tool-poisoning check on tools/list
"custom": []
},
"pinning": {
"enabled": true,
"onNewTool": "pin", // "pin" (TOFU) | "block" (until `mcp-doorman pin`)
"onChangedTool": "block" // "block" | "warn"
},
"rateLimit": { "perMinute": 120, "perTool": { "*__send_*": 5 } },
"approval": { "fallback": "deny", "timeoutMs": 120000 }, // fallback when client lacks elicitation
"audit": { "enabled": true, "includeArguments": true, "includeResults": false },
"logLevel": "info"
}
Pin state and the audit log default to <config-name>.pins.json / <config-name>.audit.jsonl next to the config file.
| Command | What it does |
|---|---|
mcp-doorman run --config <path> | Start the gateway over stdio (default command) |
mcp-doorman pin --config <path> | Connect to all upstreams and pin (trust) their current tool definitions |
mcp-doorman init | Write a starter config with sensible defaults |
Security tooling that oversells is worse than none. Read this part.
deny/approve policies as the hard boundary; screening is defense-in-depth.approval.fallback (deny by default).resources/* and prompts/* proxying (currently tools-only)doorman-rules-finance, doorman-rules-healthcare…)mcp-doorman audit subcommand: pretty-print and query the JSONL logGrab anything above, or start with a [good first issue](https://github.com/YOUR_GITHUB_USERNAME/mcp-doorman/labels/good%20first%20issue). New detection rules are the easiest contribution: one regex + two tests. See CONTRIBUTING.md and docs/detection-rules.md.
npm install
npm test # 69 tests: unit + full stdio e2e
npm run build
npm run demo # watch the guards fire live
Apache-2.0 — free for any use, with an explicit patent grant.
| Attack | How it works |
|---|
| Tool poisoning | Malicious instructions hidden in a tool's description, invisible in most client UIs |
| Rug pull | Server presents innocent tools on day 1, swaps the definitions after you've approved them |
| Indirect prompt injection | A webpage/issue/email fetched by a legitimate tool carries instructions aimed at the model |
| Secret exfiltration | A leaked credential in one tool result + one injected instruction = your key on someone else's server |
| Runaway loops | A confused or hijacked agent mass-deletes, mass-mails, mass-scrapes |