Skip to main content

MCP Server Fuzzer

Black-box security assessment for live Model Context Protocol servers. It drives an authorized target over its real transport, sends realistic and malformed input, classifies the responses, and writes findings and reproduction data to disk.

CI Lint Codecov PyPI version PyPI downloads MCP versions Docker pulls License: MIT Python 3.10+

Documentation | Assessment workflow | CLI reference | Releases

Authorization

Use this tool only against MCP servers you own or are explicitly authorized to test. It sends attack-pattern input, can start local processes, and with --auth-audit-intrusive will register OAuth clients on the target's authorization server. The built-in safety controls reduce accidental impact; they are not a substitute for a container, a VM, or an engagement-specific network boundary. --security-audit-intrusive sends a foreign-Origin probe to test DNS-rebinding defenses and requires the same explicit authorization.

What it does

The fuzzer connects over stdio, HTTP, SSE, or Streamable HTTP and answers a fixed set of assessment questions:

  • What tools, resources, prompts, and protocol methods does the server expose?
  • Does it reject malformed and out-of-contract input, or accept it?
  • Do tool descriptions or schemas carry poisoning markers, hidden instructions, duplicate definitions, typosquatted names, or dangerous capability combinations?
  • Does an advertised OAuth boundary publish unsafe metadata or serve tools without the expected authentication?
  • What does a local stdio server execute, read, write, or connect to while the test runs?

Install

Requires Python 3.10 or newer.

python -m pip install mcp-fuzzer
mcp-fuzzer --version

Optional runtime observation of local stdio processes:

python -m pip install "mcp-fuzzer[mcpfz-probe]"

Docker image (princekrroshan01/mcp-fuzzer):

docker pull princekrroshan01/mcp-fuzzer:latest
docker run --rm princekrroshan01/mcp-fuzzer:latest --help

Run an assessment

Against a remote HTTP or Streamable HTTP target:

mcp-fuzzer \
  --mode tools \
  --protocol streamablehttp \
  --endpoint https://target.example.com/mcp \
  --phase realistic \
  --runs 10 \
  --security-audit \
  --seed 42 \
  --output-dir reports/baseline

Against a local stdio target, confine file operations and deny non-local network access:

mcp-fuzzer \
  --mode all \
  --protocol stdio \
  --endpoint "python my_server.py" \
  --enable-safety-system \
  --fs-root "$PWD/fuzz-sandbox" \
  --no-network \
  --runs 5 \
  --seed 42 \
  --output-dir reports/baseline

To try the tool without a target, use the bundled fixtures in examples/.

Start with low run counts, bounded timeouts, dedicated credentials, and an isolated target. The assessment workflow describes what to record at each stage.

What it produces

Every session writes to --output-dir (default reports/):

Artifact Contents
findings.json Every finding, with category, severity, kind, target, run, detail, and an evidence object
run_summary.json Mode, status, tool discovery result, per-tool run counts and outcome buckets, finding totals by category
sessions/<session-id>/<timestamp>_fuzzing_results.json Per-run request and response records for the session
crashes/ One JSON repro per run that terminated the server process, containing the input and crash context. Written only when a run crashes the target

Severities are critical, high, medium, low, and info. Fuzz classifications include accepted_malformed, injection_reflection, crash, hang, error_leakage, internal_error, non_determinism, memory_growth, oversized_response, and performance_outlier.

A finding from --security-audit carries a stable check ID and maps to published sources:

{
  "category": "tool_poisoning",
  "severity": "high",
  "kind": "tool",
  "target": "read_notes",
  "detail": "Tool name or description contains injection/poisoning markers (hidden instructions or secret-path references).",
  "evidence": {
    "check_id": "TP1",
    "paper_arxiv_id": "2503.23278",
    "owasp_mcp_top_10": "MCP03:2025",
    "markers": ["ignore\\s+(all\\s+)?previous\\s+instructions?", "id_rsa"],
    "tool_definition_hash": "18cd91e6…"
  }
}

--export-csv, --export-xml, --export-html, and --export-markdown write additional per-run tables into the same directory. These exports carry a metadata block (session ID, mode, protocol, endpoint, timestamps) and per-run pass/fail rows. They do not carry severities or findings, and only the CSV export includes the arguments that produced each run. Treat findings.json as the authoritative output.

Exit codes: 0 success, 1 validation or execution failure, 2 no tools discovered with --fail-if-no-tools, 130 interrupted.

What it does not do

  • It does not read your source. This is a black-box client, not a SAST tool.
  • It does not prove exploitability. accepted_malformed means the server returned a non-error response to schema-invalid or attack-pattern input. That is a contract observation and a lead, not a demonstrated vulnerability.
  • It does not record the seed in any output file. --seed makes payload generation reproducible, but you must record the value yourself alongside the report for a run to be replayable.
  • It does not record the endpoint or protocol in run_summary.json. That metadata appears only in the CSV, XML, HTML, and Markdown exports.
  • It does not assign CVEs, CVSS scores, or remediation guidance, and it is not a certification.
  • It does not test authorization logic between users or tenants. The auth checks cover metadata, the authorization endpoint, and unauthenticated tool exposure.
  • It only reaches what the server advertises through tools/list, resources/list, and prompts/list. Undiscoverable surface is not tested.
  • Schema-driven fuzzing via --spec-schema-version reads MCP schemas from the schemas/mcp-spec submodule, which is not shipped in the PyPI package. From a released install, point MCP_SPEC_SCHEMA_ROOT at a schema directory or work from a git checkout.

Audit surfaces

--security-audit runs tool and schema checks plus active output oracles against the same run's results: poisoning markers, hidden or encoded instructions, tool shadowing, typosquatted names, dangerous capability combinations, cleartext transport, and command, path, SQL, and prompt-injection oracles. Add --security-audit-intrusive to probe whether an HTTP/SSE target rejects a foreign Origin. Every MCP revision requires servers to validate Origin; revisions from 2025-11-25 onward additionally mandate HTTP 403 for an invalid one, so the finding wording is scoped to the negotiated revision. The probe replays configured transport authentication, and a probe still refused with HTTP 401 is reported as inconclusive rather than clean.

--auth-audit runs read-only OAuth checks against an HTTP or SSE endpoint: metadata review, authorization-endpoint probes, and unauthenticated tool exposure where authentication is advertised. Add --auth-audit-intrusive only when your authorization explicitly covers dynamic client registration and redirect handling.

--runtime-probe observes process, filesystem, network, credential, privilege, and ptrace activity for a local stdio target. The mcpfz-probe sidecar is optional, disabled by default, and fails open if it cannot observe the target.

Handling evidence

Reports embed generated arguments, server responses, paths, and runtime observations. Values under credential-named keys (token, secret, authorization, api_key, and similar) are redacted in console output and in written artifacts, and credentials embedded in URLs are stripped. Redaction is key-driven, so a secret echoed inside a response body under an unrelated key is not caught. Review and redact artifacts before sharing them, and store them under the same restrictions as the engagement's other evidence. See understand run results.

Documentation

References

The checks in this project complement, and do not replace, the MCP Security Best Practices, the MCP authorization specification, and the OWASP MCP Top 10.

License

MIT. See LICENSE.

Download files

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

Source Distribution

mcp_fuzzer-0.7.0.tar.gz (378.5 kB view details)

Uploaded Source

Built Distribution

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

mcp_fuzzer-0.7.0-py3-none-any.whl (467.4 kB view details)

Uploaded Python 3

File details

Details for the file mcp_fuzzer-0.7.0.tar.gz.

File metadata

  • Download URL: mcp_fuzzer-0.7.0.tar.gz
  • Upload date:
  • Size: 378.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/7.0.0 CPython/3.10.20

File hashes

Hashes for mcp_fuzzer-0.7.0.tar.gz
Algorithm Hash digest
SHA256 bd132ffe78f2b5ad0a5f8736adc1de43d552d13fe721065c8553ddb2aba2c1ea
MD5 cc807cbc6dcfc6527a3748bafc0378ff
BLAKE2b-256 916330c68df9140e7754f35ce4f6e4f430f9a3dfd90f86b40cf4cf9eaf8dda04

See more details on using hashes here.

File details

Details for the file mcp_fuzzer-0.7.0-py3-none-any.whl.

File metadata

  • Download URL: mcp_fuzzer-0.7.0-py3-none-any.whl
  • Upload date:
  • Size: 467.4 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/7.0.0 CPython/3.10.20

File hashes

Hashes for mcp_fuzzer-0.7.0-py3-none-any.whl
Algorithm Hash digest
SHA256 3b2d53e4d16fe9facd82be69065d2f23661888ccbb10210b2138ddde3a2966ca
MD5 161ee13e070e1d0a265517ad7a04e80b
BLAKE2b-256 6521e2d1d3d932c095e4cce2c41ec490f7a55ae392528de3fc01a72705441115

See more details on using hashes here.

Release history Release notifications | RSS feed

This release

0.7.0 This release

2 files

0.6.0

2 files

0.5.0

2 files

0.4.3

2 files

0.4.2

2 files

0.4.0

2 files

0.3.6

2 files

0.3.5

2 files

0.3.4

2 files

0.3.3

2 files

0.3.2

2 files

0.3.1

2 files

0.3.0

2 files

0.2.9

2 files

0.2.8

2 files

0.2.7

2 files

0.2.6

2 files

0.2.5

2 files

0.2.4

2 files

0.2.3

2 files

0.2.2

2 files

0.2.1

2 files

0.2.0

2 files

0.1.9

2 files

0.1.7

2 files

0.1.6

2 files

0.1.5

2 files

0.1.4

2 files

0.1.3

2 files

0.1.2

2 files

0.1.1

2 files

0.1.0

2 files

Supported by

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