MCP Security Scanner
This is a Python-based penetration testing tool for Model Context Protocol (MCP) servers. It supports HTTP, stdio, and experimental SSE transports, runs a suite of checks mapped to scanner_specs.schema
(auth, transport, tools, prompts, resources), and includes a deliberately insecure MCP-like server for testing.
Note: SSE transport is discontinued in the latest version of MCP. Support for SSE in this tool is purely experimental and may not work!!!
# 1) Clone
git clone https://github.com/sidhpurwala-huzaifa/mcp-security-scanner
cd mcp-security-scanner
# 2) Create venv (Python >= 3.10)
python -m venv .venv
source .venv/bin/activate
# 3) Install dependencies
pip install -r requirements.txt
# 4) (Optional) Dev install for CLI entrypoints
pip install -e .
# Verify CLI is available
mcp-scan --help
# Reachability preflight example
mcp-scan scan --url http://127.0.0.1:65000
# -> Will fail fast with a clear error if nothing is listening
# Basic (HTTP JSON-RPC). Supports --test modes (Defaults to 0, otherwise choose a vulnerable model from below)
insecure-mcp-server --host 127.0.0.1 --port 9001
# Test modes currently supported
# --test 0 (default): basic insecure MCP-like server
# --test 1: prompt injection-style vulnerable server
# --test 2: tool poisoning-style vulnerable server
# --test 3: rug-pull tool mutation between listings
# --test 4: excessive permissions (admin tools exposed), private:// resource leakage
# --test 5: token theft (server leaks upstream access tokens to clients)
# --test 6: indirect prompt injection (external resource carries hidden instructions)
# --test 7: remote access control exposure (unauth tool enables remote access)
insecure-mcp-server --host 127.0.0.1 --port 9001 --test 0/1/2/3/4/5/6/7
# HTTP: Text report (no discovery; --url is the JSON-RPC endpoint)
mcp-scan scan --url http://127.0.0.1:9001/mcp --format text
# HTTP: JSON report
mcp-scan scan --url http://127.0.0.1:9001/mcp --format json --output report.json
# HTTP: Verbose tracing (real-time)
mcp-scan scan --url http://127.0.0.1:9001/mcp --verbose
# stdio: Scan local MCP servers via stdin/stdout
mcp-scan scan --transport stdio --command "npx -y @modelcontextprotocol/server-memory" --format json
# SSE: connect to explicit SSE endpoint, then scan via emitted /messages?sessionId=...
mcp-scan scan --url https://your-mcp.example.com --transport sse --sse-endpoint /sse --timeout 30 --verbose
Note: RPC commands only support HTTP and SSE transports, not stdio.
# List tools (HTTP)
mcp-scan rpc --url https://your-mcp.example.com/mcp --method tools/list --transport http
# Call a tool (HTTP)
mcp-scan rpc --url https://your-mcp.example.com/mcp \
--method tools/call \
--params '{"name":"weather","arguments":{"city":"Paris"}}' \
--transport http
# With SSE transport
mcp-scan rpc --url https://your-mcp.example.com --method tools/list --transport sse --sse-endpoint /sse
--explain <ID>
prints a focused explanation for a single finding (e.g.,--explain X-01
). It includes:- Test (ID and title)
- Expected outcome
- Got (scanner-observed details)
- Result (why PASS/FAIL)
- Remediation (from the spec)
Example:
mcp-scan scan --url https://your-mcp.example.com/mcp --explain X-01
--only-health
prints server details and enumerations without running the full scan.- Works for HTTP, stdio, and SSE transports.
- Supports
--format text
and--format json
.
Examples:
# HTTP
mcp-scan scan --url https://your-mcp.example.com/mcp --only-health --format text
# stdio
mcp-scan scan --transport stdio --command "npx -y @modelcontextprotocol/server-memory" --only-health --format json
# SSE
mcp-scan scan --url https://your-mcp.example.com --transport sse --sse-endpoint /sse --only-health --format json
# Bearer token
mcp-scan scan \
--url http://your-mcp.example.com/mcp \
--auth-type bearer \
--auth-token "$TOKEN"
# OAuth2 Client Credentials
mcp-scan scan \
--url http://your-mcp.example.com/mcp \
--auth-type oauth2-client-credentials \
--token-url https://issuer.example.com/oauth2/token \
--client-id "$CLIENT_ID" --client-secret "$CLIENT_SECRET" \
--scope "mcp.read mcp.tools"
- --transport auto|http|stdio|sse: Hint preferred transport; no dynamic discovery.
http
: Requires--url
for JSON-RPC endpointstdio
: Requires--command
for local MCP server processsse
: Requires--url
and--sse-endpoint
(experimental)
- --timeout : Per-request read timeout (default 12s). Increase for slow streams.
- --session-id : Pre-established session (
Mcp-Session-Id
header).
# Set up environment (if not already done)
python -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt
pip install -e .
# Run all tests
python -m pytest tests/ -v
# Run specific test module
python -m pytest tests/test_stdio_scanner.py -v
python -m pytest tests/test_security_checks.py -v
# Run specific test class
python -m pytest tests/test_stdio_scanner.py::TestStdioIntegration -v
# Build container
podman build -t mcp-scan .
# Run
podman run --rm mcp-scan scan --url ${MCP_SERVER} --format text
- Vulnerability ideas inspired by
Damn Vulnerable MCP Server
- https://github.com/harishsg993010/damn-vulnerable-MCP-server - Ye Wang from Red Hat for all his help in resolving
init
problems with certain MCP servers