Security gateway for Model Context Protocol (MCP) traffic. Blocks prompt injection, cross-repo exfiltration, and destructive commands.
Project description
MCPGate
MCPGate blocks the prompt-injection attacks Anthropic decided not to fix at the MCP protocol level. Install in 60 seconds, defend against the Invariant Labs GitHub heist, the Supabase/Cursor SQL exfiltration, and destructive agent commands — with one line of config.
Why this exists
Between May 2025 and April 2026, at least six public incidents demonstrated that MCP servers are an unguarded attack surface:
- Invariant Labs (May 2025): A malicious public GitHub issue hijacked Claude via the official GitHub MCP server and exfiltrated private repository contents to public comments.
- Supabase/Cursor (July 2025): Prompt injection through a support ticket caused an agent to run
service_roleSQL queries and leak a full customer table. - Postmark MCP (August 2025): A compromised community MCP server silently BCC'd every outgoing email to an attacker.
Anthropic has stated these behaviors are "expected" and will not be patched at the protocol level. MCPGate is defense-in-depth that sits in front of any MCP server and blocks the three most-cited attack classes before they reach the model.
Installation
pip install mcpgate
The PyPI package has not yet been published. Until it is, clone this repo and install from source:
git clone https://github.com/mcpgatehq/mcpgate.git
cd mcpgate
pip install -e .
Python 3.11+ on Linux or macOS. Windows is not supported in v0.1.
Quick start
MCPGate wraps an existing MCP server command. Wherever your MCP client config invokes the server directly, change it to route through mcpgate run --.
For example, the stock Claude Code config for the official GitHub MCP server:
{
"mcpServers": {
"github": {
"command": "npx",
"args": ["@modelcontextprotocol/server-github"]
}
}
}
becomes:
{
"mcpServers": {
"github": {
"command": "mcpgate",
"args": ["run", "--", "npx", "@modelcontextprotocol/server-github"]
}
}
}
That is the only change required. MCPGate spawns the server as a subprocess, forwards MCP traffic byte-for-byte in both directions, and records every message to ~/.mcpgate/audit.db. The agent does not need to know MCPGate is there. Override the DB path with the MCPGATE_DB_PATH environment variable if you want it elsewhere.
What it blocks
MCPGate v0.1 enforces three hard-coded rules. Any blocked message is replaced with a JSON-RPC error response (code: -32000) so the agent sees a clean failure instead of a hang.
Cross-repository access. The first time the session calls a GitHub or GitLab MCP tool with a repo argument, MCPGate records that repository. Any subsequent tool call targeting a different repository is blocked. This contains blast radius if an agent is tricked — by a poisoned issue, ticket, or retrieved document — into touching a repo the user never intended to expose.
Prompt-injection phrases in tool responses. Tool responses are the attack surface: an adversary who controls the content of a GitHub issue, Jira ticket, web page, or file can seed text that hijacks the agent. MCPGate scans every tool response for a curated list of known injection phrases ("ignore previous instructions", "jailbreak", "reveal your instructions", and others) and blocks the response before it reaches the model. The matched phrase itself is never forwarded — only a generic error.
Destructive shell and database commands. Tool-call arguments are scanned for patterns that almost always indicate accidental or adversarial destruction — rm -rf, DROP TABLE, DROP DATABASE, unqualified DELETE FROM (no WHERE clause), TRUNCATE TABLE, git push --force, git reset --hard, mkfs, fork bombs, writes to /dev/sda, chmod -R 777 /, and similar. These are blocked at the proxy before they reach the server tool runner.
Tailing the audit log
mcpgate tail # print current log and exit
mcpgate tail --follow # stream new rows as they arrive
mcpgate tail --session <id> # filter to one session
Each row is color-coded by decision: green ALLOW, red BLOCK, yellow WARN (framing errors and similar). The full JSON of each message lives in the messages.message_json column of the SQLite DB if you need to dig deeper with sqlite3 ~/.mcpgate/audit.db.
Known limitations
- Stdio transport only. HTTP and SSE MCP transports are not proxied in v0.1.
- Rules are hard-coded. There is no config file, policy DSL, or rule-authoring API. The three rules described above are the only rules; customisation requires editing
patterns.pyandrules.py. - No configuration beyond
MCPGATE_DB_PATH. No YAML, no TOML, no env vars for tuning behavior. - No alerting. Blocks are visible via
mcpgate tail; there is no webhook, email, or Slack path. - No UI. CLI only. No web dashboard.
- Linux and macOS only. Windows is not supported.
- Single user, no authentication. The audit DB is a local file and has no access control beyond filesystem permissions.
Manual smoke test
-
pip install -e . -
In terminal A, start following the log:
mcpgate tail --follow -
In terminal B, drive the bundled fake server through the proxy:
echo '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{}}' | \ mcpgate run -- python tests/fake_mcp_server.pyYou should see one
initializerow appear in terminal A with decisionALLOW. -
To see a block in action, pipe a request that the fake server will answer with an injection phrase:
( echo '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{}}' echo '{"jsonrpc":"2.0","id":2,"method":"tools/call","params":{"name":"inject_test","arguments":{}}}' ) | mcpgate run -- python tests/fake_mcp_server.pyTerminal A will show one
ALLOW(the initialize response) followed by aBLOCKwithreason: injection_phrase_detected, and the client receives a JSON-RPC error instead of the poisoned tool result.
License
Apache 2.0. See LICENSE.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file gateward-0.1.0.tar.gz.
File metadata
- Download URL: gateward-0.1.0.tar.gz
- Upload date:
- Size: 17.0 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.11.15
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
774b353240980cbe932b2b9c1fa0d8280430e76ee95f86c7b66efcf828999be0
|
|
| MD5 |
780c4d851d47afae56c9605ab7b2a8be
|
|
| BLAKE2b-256 |
b34af6e7167c0edc51b49d8a5191cc355b6f81f88f4215f2d462627cabb1fed6
|
File details
Details for the file gateward-0.1.0-py3-none-any.whl.
File metadata
- Download URL: gateward-0.1.0-py3-none-any.whl
- Upload date:
- Size: 20.8 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.11.15
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
38d82b5cba84764377cefbae1c1aded5813f0faa2da895a6ba5b35454c530527
|
|
| MD5 |
8b82d3e5dd4d799ede24b59fb0bb2a2f
|
|
| BLAKE2b-256 |
9f983062e6a685c0b4da4874faf1cd167227c53b2b2092aaec19001ae8c26efa
|