内容
# mcp-guardrail-gateway
**A policy-enforcing proxy that sits in front of any MCP server and blocks the security gaps the MCP specification tells you not to trust.**
Model Context Protocol servers are getting connected to production hosts at scale, and the specification itself warns that tool descriptions and annotations must be treated as untrusted unless they come from a trusted server. In practice, most hosts feed those descriptions straight into the model's context, which opens the door to **tool poisoning**, **rug pulls**, **confused-deputy attacks**, and **credential exfiltration**. This project is a small, tested, easy-to-drop-in gateway that closes those gaps at the JSON-RPC layer, without patching the MCP SDK on either side.
It is designed to be language-agnostic on the server side (works with any MCP stdio server, regardless of SDK) and configuration-driven on the policy side (a single YAML file that a security reviewer can read and version-control).
This repository is the security-focused companion to the AAIF Ambassador blog post *"The Unknowns of MCP: What Most Developers Still Haven't Noticed"* (Unknown 4), and the second entry in an intended pair with [`mcp-beyond-tools`](https://github.com/shriramkv/mcp-beyond-tools). Together, the two repos cover the primitives (tools/resources/prompts) and the trust boundary.
## The four attack classes this gateway blocks
| # | Attack | How the gateway detects it |
|---|---|---|
| 1 | **Tool poisoning** (malicious instructions inside a tool description) | Regex scan of every tool description against configurable poison patterns; also rejects unusually long descriptions |
| 2 | **Rug pull** (server silently changes a tool's definition after approval) | SHA-256 hash of `(name + description + inputSchema)` compared against the previous snapshot; optionally pinned in the policy |
| 3 | **Confused deputy** (unexpected or over-permissioned tool calls) | Allow-list of tool names; anything not on the list is dropped from the exposed catalogue and refused at call time |
| 4 | **Credential exfiltration via arguments** (API keys, secrets smuggled into tool-call arguments) | Per-tool regex blocklists applied recursively to every string in the arguments |
Two policies ship with the repo: a permissive example for the [`mcp-beyond-tools/docvault`](https://github.com/shriramkv/mcp-beyond-tools) reference server, and a strict deny-all policy used to prove the gateway blocks the deliberately-malicious test server.
## Architecture in one picture
```
+------------+ stdio +----------------------+ stdio +------------------+
| MCP Host | <-------> | guardrail.proxy | <-------> | Upstream MCP |
| (Claude, | | | | server |
| VSCode, | | policy.yaml | | (any language, |
| custom) | | - allow-list | | any SDK) |
+------------+ | - poison patterns | +------------------+
| - forbidden args |
| - pinned hashes |
+----------------------+
```
The gateway operates purely at the JSON-RPC layer. It parses each line-delimited message, applies the enforcement rules, and forwards, rewrites, or refuses. No SDK patching. Works with servers written in any language.
## Quickstart
Requires Python 3.10+.
```bash
git clone https://github.com/shriramkv/mcp-guardrail-gateway.git
cd mcp-guardrail-gateway
pip install -r requirements.txt
# 1. Run all unit tests
python tests/test_policy.py # 13 tests, ~0.5 s
# 2. Run the end-to-end integration test
# (spawns the deliberately-malicious server behind the gateway and
# proves that zero tools reach the host)
python tests/test_integration.py
```
Expected final line of each:
```
13/13 passed
PASS: guardrail blocked every malicious tool and refused the direct call.
```
## Using it in front of a real MCP server
Put the gateway between your host and your upstream server. Any command that follows `--` on the command line is treated as the upstream server to spawn.
```bash
python -m guardrail.proxy \
--policy policies/example.yaml \
--log guardrail.log \
-- python -m docvault.server
```
For **Claude Desktop**, adjust your `claude_desktop_config.json` so the `command` is the guardrail rather than the raw server:
```json
{
"mcpServers": {
"docvault-guarded": {
"command": "python",
"args": [
"-m", "guardrail.proxy",
"--policy", "/absolute/path/to/policies/example.yaml",
"--", "python", "-m", "docvault.server"
],
"cwd": "/absolute/path/to/mcp-guardrail-gateway"
}
}
}
```
## Writing a policy
A policy is a single YAML file. Every field is optional; a missing field means "no restriction of that class". See `policies/example.yaml` for a working template and `policies/deny_all.yaml` for the strict variant used in the integration test.
Key semantics:
- `allowed_tools:` — **absent** means no allow-list; **empty list** means deny everything; **populated** means allow only those tools. Reviewers should be aware of this three-way distinction; it is enforced by explicit tests.
- `forbidden_arg_patterns:` — a map from tool name to a list of regex patterns. Every string value in the call arguments (including nested lists and dicts) is scanned against these.
- `poison_patterns:` — regexes checked against tool descriptions. A sensible default set is built in and covers "ignore previous instructions", "you are now DAN", zero-width characters used for hidden instruction smuggling, and similar.
- `require_pinned_hashes:` — if `true`, every tool must have a matching entry in `pinned_hashes`, computed as `SHA-256(name || description || inputSchema)`. This is the strongest defence against rug pulls.
## Repository structure
```
mcp-guardrail-gateway/
├── guardrail/
│ ├── __init__.py
│ ├── policy.py # Policy dataclass + Enforcer, pure logic, no I/O
│ └── proxy.py # stdio-to-stdio JSON-RPC proxy
├── policies/
│ ├── example.yaml # permissive policy for the DocVault reference server
│ └── deny_all.yaml # strict policy used in the integration test
├── examples/
│ └── malicious_server.py # deliberately-poisoned MCP server for demos
├── tests/
│ ├── test_policy.py # 13 unit tests covering every enforcement rule
│ └── test_integration.py # end-to-end: malicious server behind the proxy
├── requirements.txt
├── LICENSE # MIT
└── README.md
```
## Why this project exists
MCP is winning the standards race, and the AAIF donation in December 2025 turned it into durable infrastructure. But shipping infrastructure at scale is a security responsibility, not just an ergonomic one. The specification is refreshingly blunt that hosts should not trust tool descriptions from untrusted servers; hosts, in practice, treat every connected server as trusted because there is no easy tool to change that default. This gateway is one small step toward giving operators a knob they can actually turn.
The design is intentionally minimalist: one YAML file, one proxy binary, no databases, no daemons, no runtime dependency on cloud services. The goal is that a security-conscious developer can adopt it in an afternoon.
## Author
Shriram K Vasudevan ([@shriramkv](https://github.com/shriramkv))
YouTube: https://www.youtube.com/shriramvasudevan
Licensed under MIT.
连接信息
猜你喜欢
暂无推荐服务器