mcpwatch — MCP server security scanner
Static analysis tool for MCP servers. Finds RCE paths, shell injection, and unauthenticated tool handlers before attackers do — fully local, no telemetry, no cloud.
pip install mcpwatch
mcpwatch scan ./your-mcp-server
What it finds
We scanned 3,199 public MCP servers and the top 20 Python repos by stars. Four attack classes came back across 2,627 findings, 205 of them CRITICAL.
AEGIS-001 — Tool Schema Injection → Code Execution (CRITICAL)
eval() or exec() called inside an @tool handler with LLM-controlled input. Any prompt injection reaching that tool — from a malicious document, API response, or injected debug symbol — becomes arbitrary code execution on the machine running the server.
Found in: mrexodia/ida-pro-mcp (★8k) — py_eval tool exposes full IDA Python API with no auth. Disclosure filed #392; closed without fix.
AEGIS-002 — Shell Injection via LLM-Controlled Input (HIGH)
subprocess.Popen(shell=True) or os.system() with a command string built from tool arguments. Shell metacharacters in the LLM's argument become shell syntax.
Found in: 0x4m4/hexstrike-ai (★8k) — nmap tool builds f"nmap {target}" and shells it. Same tool is a security scanner. 26 paths across 6 repos.
AEGIS-003 — Unauthenticated Tool Handler Exposure (MEDIUM)
@tool handlers with no authentication check — no token verification, no session guard, no raise HTTPException(401). Any LLM with transport access can call them.
Found in: 13 of 20 repos. 2,396 unguarded handlers (1,075 excluding the fastmcp framework itself). awslabs/mcp (★9k) — AWS official MCP collection — has 83.
AEGIS-004 — Destructive Unauthenticated Tool Handler (CRITICAL)
@tool handlers marked destructiveHint=True or containing keywords like delete, shell, execute, powershell, registry — with no authentication gate. Exploitable by any LLM in the session, including one prompt-injected by a second connected server.
Found in: CursorTouch/Windows-MCP (★5k) — Click, Type, Scroll, Shortcut tools: full Windows desktop control, no auth. awslabs/mcp — 24 CRITICAL findings across the AWS collection. 197 total (167 excluding fastmcp).
Usage
# Install
pip install mcpwatch
# Scan a local server directory
mcpwatch scan ./your-mcp-server
# Scan a single file
mcpwatch scan src/server.py
# JSON output for CI
mcpwatch scan ./server --format json > findings.json
Output shows rule ID, severity, file, line, and a plain-English description of the vulnerability. Exit code 1 if any CRITICAL or HIGH findings are present.
Rules
| Rule | Severity | What it detects |
|---|---|---|
| AEGIS-001 | CRITICAL | eval/exec inside @tool handlers |
| AEGIS-002 | HIGH | shell=True subprocess with non-literal command |
| AEGIS-003 | MEDIUM | @tool handler with no auth check |
| AEGIS-004 | CRITICAL | Destructive @tool handler with no auth check |
Rules in progress: AEGIS-005 (hardcoded credentials), AEGIS-006 (supply chain), TypeScript support.
Research findings
Full write-up of the four attack classes, real-world examples with code, attack chains, and remediation guidance:
Key numbers from the corpus scan (20 repos, top Python MCP servers by stars):
| Severity | Count |
|---|---|
| CRITICAL | 205 |
| HIGH | 26 |
| MEDIUM | 2,396 |
Responsible disclosure
We disclose findings to maintainers before publishing. If mcpwatch finds something in your server, please fix it. If you find a vulnerability in mcpwatch itself, open a GitHub issue marked [security].
| Date | Repo | Issue | Status |
|---|---|---|---|
| 2026-05-01 | mrexodia/ida-pro-mcp (★8k) | #392 | Closed without fix |
Privacy
mcpwatch makes no network calls during analysis. No code, file paths, or findings leave your machine. AGPL-3.0.
Contributing
git clone https://github.com/Fredbcx/mcpwatch
cd mcpwatch
pip install -e ".[dev]"
pytest tests/
New rules go in src/mcpwatch/rules/. Each rule is a class inheriting from Rule with a single check(ctx: ScanContext) -> list[Finding] method. Add fixtures in tests/fixtures/aegis00N/ and a test file in tests/test_aegis00N.py.
Metadata
Release files for mcpwatch 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 | |
|---|---|---|---|
| mcpwatch-0.1.0.tar.gz | 254.6 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| mcpwatch-0.1.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 271.0 kB
Release files / mcpwatch-0.1.0.tar.gz
| Download URL | mcpwatch-0.1.0.tar.gz |
|---|---|
| Size | 254.6 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
19b34ab14763bc53c72c0e186d2b65e2e56a237da231faf637f8dc5be845a61c
|
|
BLAKE2b-256 checksum How to use checksums |
def409954acad94d0c7a25007793374efddea07c8b930be6c38e6dd33314227b
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.14.0
|
Release files / mcpwatch-0.1.0-py3-none-any.whl
| Download URL | mcpwatch-0.1.0-py3-none-any.whl |
|---|---|
| Size | 16.4 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
04cdecd55e4a79f2958eeff0dd78502355aa256c7e62c475acd1ec5bf4f1c1e1
|
|
BLAKE2b-256 checksum How to use checksums |
ec0efda74310b68d2d7ddbc782085db0e47736656d5949e45bdb7f67809b8490
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.14.0
|