MCPGuard
Security scanner and runtime protection for MCP servers.
MCP is becoming the TCP/IP of AI agents. MCPGuard makes sure it doesn't become the next Log4j.
MCPGuard scans your MCP server configurations for the vulnerabilities in the OWASP MCP Top 10 and provides runtime middleware to enforce security policies on every tool call. It works without a running server — pure static analysis of your config files.
Install
pip install mcpguard
Quick Start
# Scan your Claude Desktop or Cursor MCP config (auto-detected)
mcpguard scan
# Scan a specific config
mcpguard scan --config ./claude_desktop_config.json
# Get a JSON report
mcpguard scan --format json --output report.json
Programmatic usage:
from mcpshield import scan
result = scan()
print(f"Score: {result.score}/100 ({result.rating})")
for finding in result.sorted_findings():
print(f"[{finding.severity.value}] {finding.rule_id}: {finding.title}")
What It Detects
MCPGuard covers all 10 categories of the OWASP MCP Top 10:
| Rule | Severity | OWASP | Description |
|---|---|---|---|
| MCPS-001 | CRITICAL | MCP01 | Hardcoded API keys and secrets in env vars |
| MCPS-002 | HIGH | MCP03 | Filesystem server with access to / or ~/.ssh |
| MCPS-003 | HIGH | MCP08 | npx -y with unverified or unpinned packages |
| MCPS-004 | CRITICAL | MCP04 | Shell invocation enabling command injection |
| MCPS-005 | HIGH | MCP05 | HTTP/SSE server without authentication or TLS |
| MCPS-006 | HIGH | MCP03 | Wildcard tool permissions (files:*, admin:*) |
| MCPS-007 | MEDIUM | MCP02 | Tool descriptions with injection keywords or hidden Unicode |
| MCPS-008 | MEDIUM | MCP10 | URL parameters without domain allowlisting (SSRF) |
| MCPS-009 | LOW | MCP09 | Missing audit logging configuration |
| MCPS-010 | HIGH | MCP06 | Shared session memory without user isolation |
| MCPS-011 | MEDIUM | MCP05 | stdio server running without sandboxing |
| MCPS-012 | CRITICAL | MCP08 | Known CVE — mcp-remote, MCP Inspector, filesystem |
CLI
# Scan auto-detected config
mcpguard scan
# Scan specific file
mcpguard scan --config ./mcp-config.json
# Output formats
mcpguard scan --format json --output report.json
mcpguard scan --format sarif --output report.sarif # GitHub Security tab
mcpguard scan --format html --output report.html # Shareable HTML
# Fail CI on critical/high findings
mcpguard scan --fail-on critical
mcpguard scan --fail-on high
# Skip specific rules
mcpguard scan --skip-rules MCPS-009,MCPS-011
# Check a package against the vulnerability database
mcpguard check-package mcp-remote
mcpguard check-package mcp-remote@0.1.7
# Generate a starter policy file
mcpguard init-policy --output policy.yaml
# Validate an existing policy
mcpguard validate-policy policy.yaml
Runtime Guard
Protect your MCP server's tool handlers at runtime with policy enforcement:
from mcpshield.runtime import MCPGuard, Policy
# Load security policy
policy = Policy.from_yaml("policy.yaml")
# Create guard
guard = MCPGuard(policy=policy)
# Protect tool handlers
@guard.protect
async def handle_tool_call(tool_name: str, arguments: dict) -> dict:
# Blocked tools raise PolicyViolationError before reaching here
# Path and domain restrictions are enforced automatically
# Rate limits are checked per-tool
...
Policy File
# policy.yaml
version: "1.0"
rules:
blocked_tools:
- "execute_command"
- "run_shell"
tool_restrictions:
filesystem_read:
allowed_paths:
- "/data/**"
- "/public/**"
blocked_paths:
- "~/.ssh/**"
- "~/.aws/**"
http_request:
allowed_domains:
- "api.github.com"
blocked_domains:
- "169.254.169.254" # AWS metadata
- "localhost"
rate_limits:
default: 100/minute
per_tool:
database_query: 20/minute
approval_required:
- "delete_file"
- "send_email"
audit:
enabled: true
log_file: "mcpguard_audit.jsonl"
log_level: "all"
CI/CD Integration
Add to .github/workflows/security.yml:
name: MCP Security Scan
on: [push, pull_request]
jobs:
mcpguard:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: "3.11"
- run: pip install mcpguard
- name: Scan MCP config
run: mcpguard scan --config ./claude_desktop_config.json --fail-on high
- name: Generate SARIF report
run: mcpguard scan --config ./claude_desktop_config.json --format sarif --output mcpguard.sarif
- name: Upload to GitHub Security tab
uses: github/codeql-action/upload-sarif@v3
with:
sarif_file: mcpguard.sarif
Writing Custom Rules
Extend BaseRule to add your own checks:
from mcpshield.scanner.rules.base import BaseRule
from mcpshield.scanner.finding import Finding, ServerConfig
from mcpshield.utils.severity import Severity
class MyCustomRule(BaseRule):
rule_id = "CUSTOM-001"
title = "My Security Check"
owasp_mapping = "MCP01"
def check(self, server: ServerConfig) -> list[Finding]:
findings = []
if "dangerous_pattern" in str(server.raw):
findings.append(Finding(
rule_id=self.rule_id,
title=self.title,
description="Dangerous pattern detected",
severity=Severity.HIGH,
owasp_mcp=self.owasp_mapping,
server_name=server.name,
location="config",
remediation="Remove the dangerous pattern.",
references=["https://owasp.org/www-project-mcp-top-10/"],
))
return findings
# Use with the engine
from mcpshield.scanner.engine import ScanEngine
from mcpshield.scanner.rules import DEFAULT_RULES
engine = ScanEngine(rules=DEFAULT_RULES + [MyCustomRule])
Security Score
MCPGuard computes a score from 0-100:
| Score | Rating |
|---|---|
| 90-100 | EXCELLENT |
| 70-89 | GOOD |
| 50-69 | FAIR |
| 25-49 | POOR |
| 0-24 | CRITICAL |
Each CRITICAL finding deducts 25 points, HIGH deducts 15, MEDIUM deducts 8, LOW deducts 3.
References
- OWASP MCP Top 10
- MCP Security Best Practices
- CVE-2025-6514 — mcp-remote command injection
- Model Context Protocol Specification
Contributing
Issues and pull requests welcome at github.com/aryanjp1/mcpguard.
To run the test suite:
pip install -e ".[dev]"
pytest --cov
To add a new rule, create a file in src/mcpshield/scanner/rules/, extend BaseRule, and add it to DEFAULT_RULES in src/mcpshield/scanner/rules/__init__.py.
License
MIT — see LICENSE.
Metadata
Release files for mcpguard 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 | |
|---|---|---|---|---|
| mcpguard-0.1.0.tar.gz | 62.7 kB | Without provenance | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| mcpguard-0.1.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 135.4 kB
Release files / mcpguard-0.1.0.tar.gz
| Download URL | mcpguard-0.1.0.tar.gz |
|---|---|
| Size | 62.7 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
03993decc764f392358f7e99b2851d64e6084cf6a151ae06a1a5904eb4dcb1ce
|
|
BLAKE2b-256 checksum How to use checksums |
bfbca52ca1668477496b9b350307f7d77605f2253a9a19c5d6a075fe1a2d1e50
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.10.16
|
Release files / mcpguard-0.1.0-py3-none-any.whl
| Download URL | mcpguard-0.1.0-py3-none-any.whl |
|---|---|
| Size | 72.6 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
2e920524a5b67641c64a501536d1ceb612228174e13179d143961ecff6781034
|
|
BLAKE2b-256 checksum How to use checksums |
0386a74334b82da6558d1c420ecbcca7a271a3c4b40003b6910f0734d81e93fa
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.10.16
|
Security for mcpguard 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.