MCP Guard
Security layer for MCP (Model Context Protocol) tool calls. Validates inputs and detects response anomalies before they reach your systems.
The Problem
MCP servers are the primary tool-calling layer for AI agents (Claude, Cursor, etc). Known vulnerabilities include:
- Prompt injection → RCE: Malicious prompts can inject shell commands via MCP tool parameters
- Path traversal: Accessing sensitive files outside intended directories
- SSRF: Reaching internal services through URL parameters
- Data exfiltration: Anomalous responses leaking unexpected data
No open-source security layer exists for validating MCP calls before execution. MCP Guard fills that gap.
Architecture
MCP Guard supports three integration patterns:
Pattern 1: Pre-check API (validate before calling)
AI Agent → guard.check_request() → MCP Server
↓ (if unsafe)
Block / warn
Pattern 2: Wrap API (full lifecycle guard)
AI Agent → guard.wrap(tool, params, execute_fn)
├── check_request() → block if unsafe
├── execute_fn() → call MCP server
└── check_response() → anomaly detection
Pattern 3: Transparent Proxy (zero code changes)
AI Agent ←stdio→ mcp-guard proxy ←stdio→ MCP Server
├── intercepts tools/call
├── blocks unsafe requests
├── forwards safe requests
└── checks responses for anomalies
The proxy mode is the recommended approach for securing existing MCP servers without modifying any code. It works with any MCP server that uses stdio transport.
Install
pip install mcp-guard
Quick Start
Proxy Mode (recommended)
Wrap any MCP server with security checks — zero code changes required:
# Secure a git MCP server
mcp-guard proxy -- npx @modelcontextprotocol/server-git
# With custom config
mcp-guard proxy --config guard-config.json -- npx @modelcontextprotocol/server-git
# Log blocked/anomalous calls to file
mcp-guard proxy --log security.log -- python my_mcp_server.py
Use in your MCP client config (e.g. Claude Desktop):
{
"mcpServers": {
"git": {
"command": "mcp-guard",
"args": ["proxy", "--", "npx", "@modelcontextprotocol/server-git"]
}
}
}
The proxy intercepts tools/call requests and:
- Blocks unsafe calls with a JSON-RPC error (
-32600) before they reach the server - Forwards safe calls to the child server transparently
- Monitors responses for anomalies (size spikes, unexpected keys, error rate changes)
- Passes through all other methods (
initialize,tools/list, etc.) unmodified
Python API
from mcp_guard import MCPGuard
guard = MCPGuard()
# Validate before calling a tool
result = guard.check_request("git", {"command": "checkout main; cat /etc/passwd"})
print(result.safe) # False
print(result.violations) # ['shell_injection: shell metacharacter in "command"', ...]
# Safe call
result = guard.check_request("git", {"command": "checkout main"})
print(result.safe) # True
# Wrap an entire MCP call with security checks
def my_mcp_call(tool_name, params):
# ... your actual MCP execution logic
return {"status": "ok"}
result = guard.wrap("git", {"command": "status"}, my_mcp_call)
print(result.allowed) # True
print(result.response) # {"status": "ok"}
CLI
# Validate tool parameters
mcp-guard validate --tool git --params '{"command": "checkout main"}'
# → SAFE: no issues detected for tool 'git'
mcp-guard validate --tool git --params '{"command": "checkout main; cat /etc/passwd"}'
# → BLOCKED: 2 violation(s) detected for tool 'git'
# Analyze a response for anomalies
mcp-guard analyze --tool git --request '{"command": "status"}' --response '{"output": "clean"}'
# Scan a JSONL file of MCP calls
mcp-guard scan --file calls.jsonl
# View baseline statistics
mcp-guard stats
# JSON output
mcp-guard --json validate --tool git --params '{"command": "status"}'
What It Detects
Input Validation (pre-call)
| Category | Examples |
|---|---|
| Shell injection | ;, |, &&, ||, $(), backticks, >, < |
| Path traversal | ../, sensitive paths (/etc/passwd, /proc/) |
| SQL injection | UNION SELECT, DROP TABLE, '; -- |
| SSRF | 127.0.0.1, localhost, 169.254.169.254, private IPs |
Response Anomaly Detection (post-call)
| Check | Description |
|---|---|
| Response size | Z-score > 3 from baseline average |
| Duration | Response time outliers |
| Error rate | Spike detection vs baseline |
| Unexpected keys | New keys not seen in previous responses |
Configuration
guard = MCPGuard(config={
# Add custom detection rules
"custom_rules": [
(r"API_KEY", "API key in parameters"),
],
# Allowlist specific values per tool
"allowlist": {
"deploy": ["restart; reload"],
},
# Disable specific check categories
"disabled_checks": ["ssrf"],
# Don't block, just warn
"block_on_violation": False,
# Custom baselines storage path
"baselines_path": "/path/to/baselines.json",
})
Config file for proxy mode (guard-config.json):
{
"custom_rules": [["API_KEY", "API key in parameters"]],
"disabled_checks": ["ssrf"],
"block_on_violation": true
}
Project Structure
src/mcp_guard/
├── __init__.py # Public API exports
├── sanitizer.py # Input validation & sanitization
├── anomaly.py # Response anomaly detection
├── guard.py # Main orchestrator (MCPGuard)
├── proxy.py # Stdio MCP proxy (MCPProxy)
└── cli.py # CLI interface
Development
git clone https://github.com/your-org/mcp-guard.git
cd mcp-guard
pip install -e ".[dev]"
pytest tests/ -v
License
MIT
Metadata
Release files for safemcp 0.1.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | |
|---|---|---|---|---|
| safemcp-0.1.0.tar.gz | 21.6 kB | Without provenance | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| safemcp-0.1.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 36.9 kB
Release files / safemcp-0.1.0.tar.gz
| Download URL | safemcp-0.1.0.tar.gz |
|---|---|
| Size | 21.6 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
525fef936c34e69bfafc37959a15bedde1631e3d55e3b636d9b41cdadce3a6e3
|
|
BLAKE2b-256 checksum How to use checksums |
9e2a64d56147ef3cf7018dc8fb7ba8d7a5e6ac4e5e205e269b25e8d38dd42074
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.12.3
|
Release files / safemcp-0.1.0-py3-none-any.whl
| Download URL | safemcp-0.1.0-py3-none-any.whl |
|---|---|
| Size | 15.3 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
19f2d9bd1fcd645e43298a63f7c5c3f591cf71ac50b265b6c48c96f017f22311
|
|
BLAKE2b-256 checksum How to use checksums |
232f9f81fb810a81109d70e8dff0fd064a8921a7cb9d95727dbceaabd5eb55c2
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.12.3
|
Security for safemcp 0.1.0
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.