Security scanner for Model Context Protocol servers.
6 checks. AST-level source analysis. Zero false criticals on clean servers.
pip install velox-mcp-scan No source access needed
Requires --source <path>
is_relative_to() containment. resolve() alone is not sufficient.shell=True with f-string commands. Catches CVE-2025-68144.urlparse alone doesn’t count.sk-, ghp_, AKIA, xoxb-) and high-entropy strings in secret-named variables.The repo ships with a deliberately broken MCP server containing 5 planted vulnerabilities. The scanner catches all 5 — 7 findings total. Zero false positives.
$ mcp-scan scan --stdio "python3 -m vulnerable_mcp.server" --source ./vulnerable_mcp
mcp-scan target: python3 -m vulnerable_mcp.server
checks run 6
findings 7
Summary by severity
━━━━━━━━━━━━━━━━━━━━━━━━
critical 4
high 3
medium 0
low 0
info 0
── CRITICAL MCPA-010 Path traversal risk in server.py:108
Path division with no is_relative_to() containment guard
── CRITICAL MCPA-010 Path traversal risk in server.py:110
read_text() with no is_relative_to() containment guard
── CRITICAL MCPA-012 Shell injection in server.py:118
subprocess.run(shell=True) with dynamic f-string command
── CRITICAL MCPA-001 Tool weather description contains injection markers
matched 'ignore all prior instructions'; matched 'exfiltrat'; matched '/etc/passwd'
── HIGH MCPA-070 Hardcoded secret in server.py:32
String matches known secret prefix (OpenAI API key)
── HIGH MCPA-060 SSRF sink in server.py:133
httpx.get() with variable URL and no host validation
── HIGH MCPA-002 Tool weather description contains hidden characters
2 ANSI escape(s), 2 hidden/control char(s) in description
✓ scan complete · 7 findings · 0 false positives · 1.8s weather description contains injection markersserver.py:108server.py:118weather description contains hidden charactersserver.py:133server.py:32$ pip install velox-mcp-scan$ mcp-scan scan --stdio "python3 -m my_server"$ mcp-scan scan --stdio "python3 -m my_server" --source ./src$ mcp-scan scan --stdio "..." -f json -o report.jsonIf introspection fails, the scanner says CRITICAL — not “clean.” A security tool that silently passes on errors is worse than no tool.
All checks are deterministic AST analysis and pattern matching. No API keys, no cloud calls, no probabilistic scoring. Runs fully offline.
SSRF detection traces URL variables through urlparse() to hostname comparisons against trusted collections. Parse-only is not validation.
Non-zero exit on findings. JSON output. Runs in 2 seconds. Drop it into any pipeline as a gate.