Skip to main content

Security scanner for Python MCP server code

Project description

mcp-patch

Static security scanner for Python MCP server code.

43% of popular MCP servers have shell injection vulnerabilities. No existing tool does AST-level scanning with MCP context awareness. This one does.

Real CVEs this would have caught

  • CVE-2025-53967 (Framelink Figma MCP) — shell injection via unsanitized tool parameters
  • CVE-2025-6514 (mcp-remote, 437K downloads) — arbitrary command execution via unsanitized tool params

Install

pip install mcp-patch
mcp-patch scan my_server.py

Usage

# Scan a single file
mcp-patch scan server.py

# Scan a directory
mcp-patch scan ./servers/

Example output

Scanning server.py...

  CRITICAL  shell_injection  line 14
  subprocess.run(f"ls {path}", shell=True)
  subprocess.run(shell=True) — tool param 'path' flows to shell
  Fix: Use subprocess.run([cmd, shlex.quote(arg)]) without shell=True

  HIGH      path_traversal   line 28
  open(filename)
  open(filename) — tool param 'filename' used as file path without validation
  Fix: Use (base_dir / Path(filename).name).resolve() and verify result starts with base_dir

Found 2 issues (1 CRITICAL, 1 HIGH) in 1 file.

Checks

Check Severity What it detects
shell_injection CRITICAL subprocess.run/Popen/call(f"...{param}", shell=True), os.system(), os.popen() with tool params
path_traversal HIGH open(param), Path(param) with a tool param passed directly as a path
ssrf HIGH requests.get/post(url), httpx.get(url), urllib.request.urlopen(url) where url is a tool param

Only functions decorated with @tool or @mcp.tool() are scanned. Plain helper functions are ignored.

How it works

Pure stdlib. No network calls. No LLM. Parses your Python source with the ast module, finds @tool decorated functions, collects their parameter names, then walks each function body looking for dangerous call patterns where user-controlled params flow into dangerous sinks.

False positives

This is an MVP scanner — it prefers to over-report rather than miss real vulnerabilities. A path_traversal finding on open(filename) is real even if you have runtime validation elsewhere; the fix is to move validation into the same function so the scanner (and reviewers) can see it.

Development

python -m pytest tests/

No external dependencies. Python 3.9+.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

mcp_patch-0.1.0.tar.gz (10.0 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

mcp_patch-0.1.0-py3-none-any.whl (8.4 kB view details)

Uploaded Python 3

File details

Details for the file mcp_patch-0.1.0.tar.gz.

File metadata

  • Download URL: mcp_patch-0.1.0.tar.gz
  • Upload date:
  • Size: 10.0 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.13.12

File hashes

Hashes for mcp_patch-0.1.0.tar.gz
Algorithm Hash digest
SHA256 1a8b62020365f4c1396ac973ac1697e1f9ee1ad37acbc8589e04f08612410b25
MD5 46dc53015f18a4bfed9092c67c3faa36
BLAKE2b-256 d4cae3ca49760bb7e47ca1e4e43054335decf5b96da46103957709953e79ab0e

See more details on using hashes here.

File details

Details for the file mcp_patch-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: mcp_patch-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 8.4 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.13.12

File hashes

Hashes for mcp_patch-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 67d0fb560721e1d077eb881ba49d0d899042d85614fbf31d74dfb74975dc3396
MD5 e277fb3d71523b86328d2e54d84a4906
BLAKE2b-256 87f722449b6075345eeefe74ff608ad8ac0ca0f4b51f3d8815f20c1620a80998

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page