MCP Shield
Like Bandit for Python code, but for MCP servers.
Security scanner, runtime proxy, and audit logger for Model Context Protocol servers.
Install
pip install mcp-shield-cli
Requires Python 3.11+ and Node.js (for npx-based MCP servers).
Usage
mcp-shield test — scan a server
# Scan a local stdio server
mcp-shield test "npx -y @modelcontextprotocol/server-filesystem /tmp"
# Scan a remote HTTP server
mcp-shield test "http://localhost:8080/mcp"
# Run only specific suites (compliance, security, advisory, or all)
mcp-shield test "npx server" --suite security
mcp-shield test "npx server" --suite security --suite advisory
# Pass environment variables to the server process
mcp-shield test "npx server" --env API_KEY=sk-123 --env DB_URL=postgres://host/db
# Save JSON report to file
mcp-shield test "npx server" --output report.json
# JSON to stdout (for piping)
mcp-shield test "npx server" --format json
# SARIF output (for GitHub Code Scanning)
mcp-shield test "npx server" --format sarif
# SARIF to file (can combine with any --format)
mcp-shield test "npx server" --sarif-output report.sarif
# Both terminal and JSON output
mcp-shield test "npx server" --format both --output report.json
# CI mode: exit code 1 if any high+ severity check fails
mcp-shield test "npx server" --fail-on high
# Enable ML-based poisoning detection (DeBERTa, slower but more accurate)
mcp-shield test "npx server" --ml
# Set connection/check timeout (default 30s)
mcp-shield test "npx server" --timeout 10
Example output:
Check | Result | Severity | Message
COMP-001 | PASS | critical | Handshake OK
COMP-002 | PASS | error | Server identity: filesystem-server v0.2.0
SEC-002 | WARN | high | Found 11 potential injection vector(s) (CWE-78, CWE-89, CWE-22)
SEC-004 | FAIL | high | 2 dangerous tool(s): move_file, edit_file (CWE-78, CWE-250)
SEC-005 | WARN | medium | Write scope: local filesystem (CWE-434)
ADV-002 | WARN | info | External dependencies: filesystem access
Score: 57/100 Grade: D
─────────────── Recommendations ───────────────
[1] Block dangerous tools (SEC-004) (CWE-78, CWE-250)
Tools: move_file, edit_file
Action: Add --deny rules in proxy or require user confirmation
┌──── Ready-to-use proxy command ────┐
│ mcp-shield proxy "npx ..." \ │
│ --deny move_file --deny edit_file│
└────────────────────────────────────┘
mcp-shield proxy — runtime firewall
# Block specific tools by name (glob patterns)
mcp-shield proxy "npx server" --deny "delete_*" --deny "exec_*"
# Allow only safe tools (everything else is blocked)
mcp-shield proxy "npx server" --allow "read_*" --allow "list_*"
# Rate-limit to 30 requests/minute per client
mcp-shield proxy "npx server" --rate-limit 30
# Custom audit database path
mcp-shield proxy "npx server" --audit-db ./my-audit.db
# Require authentication
mcp-shield proxy "npx server" --auth bearer --token admin:secret123
mcp-shield proxy "npx server" --auth bearer --token alice:tok-a --token bob:tok-b
# Combine everything: deny + rate limit + auth + env
mcp-shield proxy "npx server" \
--deny "git_push" --deny "git_reset" \
--rate-limit 30 \
--auth bearer --token ci:token123 \
--env GITHUB_TOKEN=ghp_xxx
# Proxy a remote HTTP server
mcp-shield proxy "http://upstream:9090/mcp" --deny "drop_*"
The proxy sits between the LLM client and the MCP server:
LLM Client ──stdio──▶ mcp-shield proxy ──stdio──▶ MCP Server
│
┌─────┴─────┐
│ deny list │
│ rate limit│
│ auth check│
│ audit log │
└───────────┘
Blocked calls return an error to the client and are logged with the block reason.
mcp-shield audit — query logs
# Show last 50 events (default)
mcp-shield audit show
# Show last 100 events
mcp-shield audit show --last 100
# Filter by tool name
mcp-shield audit show --tool delete_file
# Show only blocked calls
mcp-shield audit show --blocked
# Filter by risk tier (read, write_reversible, write_external, write_sensitive)
mcp-shield audit show --risk write_sensitive
# Filter by client ID (when using --auth)
mcp-shield audit show --client admin
# Combine filters
mcp-shield audit show --blocked --risk write_sensitive --last 20
# Summary statistics (default: last 24 hours)
mcp-shield audit stats
# Stats for a time range (h=hours, d=days, w=weeks, m=months)
mcp-shield audit stats --since 1h
mcp-shield audit stats --since 7d
mcp-shield audit stats --since 4w
# Export to JSON
mcp-shield audit export -f json -o audit.json
# Export to CSV
mcp-shield audit export -f csv -o audit.csv
# Use a custom database path (applies to all subcommands)
mcp-shield audit --db /path/to/audit.db show --last 20
mcp-shield audit --db /path/to/audit.db stats --since 7d
What it checks
22 checks across 3 suites, ~2 seconds per scan.
Compliance (COMP-001..010)
| Check | What it verifies |
|---|---|
| COMP-001 | MCP handshake (JSON-RPC initialize) |
| COMP-002 | Server identity (name + version) |
| COMP-003 | Valid inputSchema on all tools |
| COMP-004 | Tool naming conventions |
| COMP-005 | Ping/pong support |
| COMP-006 | Tool descriptions present |
| COMP-007 | Server capabilities declared |
| COMP-008 | Schema field descriptions |
| COMP-009 | Schema constraints (maxLength, pattern) |
| COMP-010 | Resource/prompt validation |
Security (SEC-001..007)
| Check | What it detects | Severity | CWE |
|---|---|---|---|
| SEC-001 | Tool poisoning (hidden instructions in descriptions) | critical | CWE-94 |
| SEC-002 | Injection vectors (path, URL, SQL, code fields) | high | CWE-78, CWE-89, CWE-22 |
| SEC-003 | Aggregated security score (0-100) | -- | -- |
| SEC-004 | Dangerous operations (delete, exec, deploy) |
high | CWE-78, CWE-250 |
| SEC-005 | Write scope (local vs cloud vs user-facing) | medium | CWE-434 |
| SEC-006 | Idempotency risk (non-retryable operations) | medium | CWE-352 |
| SEC-007 | Cost risk (cloud provisioning, paid APIs) | low | CWE-770 |
Advisory (ADV-001..005)
Informational only — does not affect the score.
| Check | What it flags |
|---|---|
| ADV-001 | Auth requirement hints (API key, OAuth) |
| ADV-002 | External service dependencies (AWS, Stripe, GitHub) |
| ADV-003 | Bulk operation warnings (unbounded arrays) |
| ADV-004 | Sensitive data exposure (PII, credentials) |
| ADV-005 | External network access (URL + fetch patterns) |
Scoring
Composite score: 40% compliance + 60% security. Deductions per finding:
| Severity | Deduction |
|---|---|
| critical | -25 |
| high | -15 |
| medium | -5 |
| low | -2 |
Advisory checks are informational and do not affect the score.
Poisoning detection
Layer 1 — ~45 regex patterns across 11 categories:
| Category | Examples |
|---|---|
| Instruction override | "ignore previous instructions", "new instructions:" |
| Role hijacking | "act as", "pretend to be", "you are now" |
| Format injection | ChatML <|im_start|>, Llama [INST], Handlebars {{#system}} |
| Data exfiltration | Markdown image exfil, "send to URL", credential reading |
| Hidden content | HTML comments, CSS display:none, ANSI escapes, zero-width Unicode |
| Hardcoded secrets | API keys (sk-live-*), GitHub PATs, Slack tokens |
| Agent injection | ReAct format injection, tool call injection |
Layer 2 (opt-in, --ml) — DeBERTa-v3-base classifier for semantic detection.
ML dependencies (onnxruntime, tokenizers, huggingface-hub) are included in the default install. The --ml flag downloads the protectai/deberta-v3-base-prompt-injection-v2 ONNX model (~740 MB, cached in ~/.cache/mcp-shield/models/) on first use.
Why opt-in? The ML classifier can produce false positives on directive-like tool descriptions (e.g., "DEPRECATED: Use X instead" may be flagged as an injection). Use --ml when you want maximum detection sensitivity and can tolerate reviewing flagged results.
Risk classification
Every tool is classified into a risk tier:
| Tier | Examples |
|---|---|
read |
read_file, list_directory, search |
write_reversible |
write_file, create_directory |
write_external |
send_email, deploy, webhook |
write_sensitive |
delete, exec, eval, drop |
SARIF & GitHub Code Scanning
MCP Shield can output SARIF 2.1.0 reports — the standard format natively supported by GitHub's Security tab.
# Generate SARIF on stdout
mcp-shield test "npx server" --format sarif
# Save SARIF to file (works alongside any --format)
mcp-shield test "npx server" --sarif-output results.sarif
GitHub Actions integration
- name: Scan MCP server
run: |
pip install mcp-shield-cli
mcp-shield test "npx -y @modelcontextprotocol/server-filesystem /tmp" \
--sarif-output results.sarif \
--fail-on high
- name: Upload SARIF
if: always()
uses: github/codeql-action/upload-sarif@v3
with:
sarif_file: results.sarif
SARIF output includes CWE references, CVSS-like severity scores, and logical locations (MCP tool names) — all visible in the GitHub Security tab.
Contributing
Contributions are welcome. Open an issue or submit a pull request.
git clone https://github.com/thuggeelya/mcp-shield.git
cd mcp-shield
pip install -e ".[dev]"
pytest
Author
thuggeelya
- LinkedIn: thuggeelya
- Telegram: @thuggeelya
- Email: thuggeelya@gmail.com
License
Metadata
Release files for mcp-shield-cli 0.2.3
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 | |
|---|---|---|---|---|
| mcp_shield_cli-0.2.3.tar.gz | 127.2 kB | Without provenance | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| mcp_shield_cli-0.2.3-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 218.4 kB
Release files / mcp_shield_cli-0.2.3.tar.gz
| Download URL | mcp_shield_cli-0.2.3.tar.gz |
|---|---|
| Size | 127.2 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
ed4d60ab3b1a3d86bfdac81eea7118314a1f136ee0908ca7d6f40db6025f7560
|
|
BLAKE2b-256 checksum How to use checksums |
0dd80df536d6b3c22400e1a3b18f6b8095de408a73cb3251911f65680c39d5bd
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.10.7 {"installer":{"name":"uv","version":"0.10.7","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
|
Release files / mcp_shield_cli-0.2.3-py3-none-any.whl
| Download URL | mcp_shield_cli-0.2.3-py3-none-any.whl |
|---|---|
| Size | 91.2 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
ac0248b6753f4c891babb669a2fc4c7e4702c34c164159ac686bd13308095738
|
|
BLAKE2b-256 checksum How to use checksums |
6d2d35528516bfe01ba075ab46284edaa31e9f4a9f24b2204f64f05991882225
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.10.7 {"installer":{"name":"uv","version":"0.10.7","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
|
Security for mcp-shield-cli 0.2.3
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.