Skip to main content

MCPProbe

Tells an MCP server author, in one run, whether their server is spec-compliant, robust to bad input, and usable by a real model.

Status: v1.0.0. Conformance (CONF), schema fuzzing (FUZZ), robustness (ROB) and security (SEC) suites over stdio and Streamable HTTP, for the stateless 2026-07-28 revision and the legacy initialize era (2025-11-25, 2025-06-18). Each server is classified as modern, legacy, dual-era or unknown, and only the checks for the era(s) it speaks run.

Every check cites the spec section it enforces, every failure is saved as a byte-for-byte replayable case, and the same seed always gives the same report.

Install

Requires Python 3.11+. No compiler needed on any platform.

pipx install mcpprobe-kit        # or: uv tool install mcpprobe-kit

The package is mcpprobe-kit; the command is mcpprobe. (PyPI refuses "mcpprobe" and "mcpprobe-cli" as too similar to unrelated existing projects.)

Full documentation: https://boyndasouth.github.io/MCPProbe/ (quickstart, CI recipes, configuration, the check catalog).

GitHub Action

- uses: boyndasouth/MCPProbe@v1
  with:
    stdio: node dist/index.js
    seed: "42"

Runs every suite, uploads SARIF to code scanning, attaches JSON, JUnit and HTML reports as an artifact, writes a job summary, and fails the job on error findings. Add baseline: mcpprobe-baseline.json to fail only on new ones. See docs/ci.md for every input.

Configuration

Options can live in mcpprobe.toml next to your server (command-line options win). ${NAME} reads an environment variable, so secrets stay out of the file:

[server]
stdio = "python -m my_server"
env = { API_KEY = "${API_KEY}" }

[run]
seed = 42

[checks]
disable = ["CONF-012"]
severity_overrides = { "SEC-002" = "info" }

See docs/configuration.md.

Usage

# A stdio server: give the command that starts it. Pin @latest with npx:
# a bare `npx -y pkg` silently reuses whatever version it cached first.
mcpprobe run --stdio "npx -y @modelcontextprotocol/server-everything@latest"
mcpprobe run --stdio "python -m my_server" --env API_KEY=...

# A Streamable HTTP server
mcpprobe run --http http://127.0.0.1:8000/mcp --header "Authorization: Bearer $TOKEN"

# Reproducible run with a machine-readable report
mcpprobe run --stdio "node dist/index.js" --seed 42 --report json -o probe.json

# Reports for CI: JUnit for test tabs, SARIF for GitHub code scanning, HTML to share
mcpprobe run --stdio "node dist/index.js" --report sarif -o probe.sarif --report html -o probe.html

# See which tools a run would call, without calling any
mcpprobe run --stdio "node dist/index.js" --dry-run

# Adopt in CI without fixing everything first: fail only on new findings
mcpprobe run --stdio "node dist/index.js" --report json -o probe-baseline.json  # once, commit it
mcpprobe run --stdio "node dist/index.js" --baseline probe-baseline.json

# Re-run one failure byte for byte against a fresh server
mcpprobe replay .mcpprobe/cases/CONF-020.json

# Browse the checks
mcpprobe checks list
mcpprobe checks explain CONF-006

Useful options for run:

Option Default What it does
--seed N random, printed Controls case order and fuzzing; same seed, same report
--suites LIST conf,fuzz,rob,sec Which suites to run
--examples N 50 Generated argument sets per tool (FUZZ)
--concurrency N 8 Requests in flight at once (ROB-007)
--report FORMAT terminal terminal, json, junit, sarif or html; repeatable; all deterministic
-o FILE stdout One per non-terminal report, in order (the summary then prints on stderr)
--baseline FILE none A previous JSON report: its findings are shown as known and don't fail the run
--sarif-path PATH entry file Repository file SARIF alerts point at (code scanning needs one)
--timeout S 10 Seconds allowed per case
--startup-timeout S 30 Seconds for the server's first answer (cold npx/uvx)
--allow-destructive off Also call tools not marked read-only or non-destructive
--allow-open-world off Also call tools marked openWorldHint: true
--keep-going off Run later suites even if conformance fails
--cases-dir DIR .mcpprobe/cases Where failing cases are saved
--config PATH ./mcpprobe.toml Config file
--total-timeout S 1800 Seconds for the whole run; when it runs out the rest is skipped (exit 2)
--dry-run off List the tools and which would be called; call none
Exit code Meaning
0 No error findings (warnings and notes allowed)
1 At least one error finding, crash or hang
2 Probe could not run (server didn't start, unreachable)
3 Config or invocation invalid

Eras

Before any check runs, MCPProbe asks server/discover (the 2026-07-28 way) and, failing that, initialize (the legacy way), then probes a modern server with initialize on a fresh process or session to spot dual-era servers.

Era Meaning What runs
modern Speaks 2026-07-28 only Modern and both-era checks
legacy Speaks an initialize-era revision only Legacy and both-era checks, inside a legacy session
dual Speaks both Everything; both-era checks run twice, the legacy run suffixed @legacy
unknown Answered neither way Nothing

Checks

error checks enforce a MUST and fail the run; warn enforces a SHOULD or flags a deprecated feature; info is advice and shows as a note.

ID Severity Era Check
CONF-001 error modern server/discover exists and lists supported versions and capabilities
CONF-002 error modern Requests missing required _meta fields are rejected with -32602
CONF-003 error modern Unsupported protocol version returns -32022 with data.supported
CONF-004 error modern Every result carries resultType
CONF-005 error both Request ids: null is rejected and responses echo the id exactly
CONF-006 error modern, HTTP HTTP headers that disagree with the body are rejected with -32020
CONF-007 error both, HTTP Origin header is validated on Streamable HTTP
CONF-008 info both Unknown tools get a JSON-RPC error, not a tool result
CONF-009 error modern Undeclared client capabilities are never relied on
CONF-010 error modern input_required results are well formed and only used where allowed
CONF-011 error both structuredContent matches the tool's outputSchema
CONF-012 warn modern tools/list returns tools in a deterministic order
CONF-013 error legacy initialize handshake and version negotiation
CONF-014 warn modern Initialize-era versions listed in supportedVersions really work
CONF-015 error both, stdio stdout carries only newline-delimited JSON-RPC messages
CONF-016 warn modern Deprecated logging capability is declared
CONF-017 warn modern Results identify the server in _meta serverInfo
CONF-018 error modern Cacheable results carry ttlMs and cacheScope
CONF-020 error modern, stdio Protocol version is read from each request, not remembered
FUZZ-001 error both Fuzzed tool arguments never crash the server or go unanswered
FUZZ-002 error both Invalid tool arguments are rejected cleanly, not with an internal error
FUZZ-003 warn both Invalid tool arguments are not accepted as a success
FUZZ-004 warn both Schema-valid tool arguments are not rejected as invalid params
ROB-001 warn both Malformed JSON gets a -32700 Parse error
ROB-002 warn both Invalid JSON-RPC envelopes are rejected, not executed
ROB-003 error both Unknown methods get -32601 Method not found
ROB-004 warn both tools/call with non-object arguments is rejected without an internal error
ROB-005 error both 1 MB and 10 MB requests are answered or rejected, never dropped
ROB-006 error both Cancellation is handled gracefully
ROB-007 error both Concurrent requests each get their own response
ROB-008 error both Deeply nested or invalid-Unicode requests are answered or rejected, never dropped
SEC-001 warn both Tool schemas do not depend on a network $ref
SEC-002 warn both Errors carry no stack traces
SEC-003 warn both Responses carry no secrets (--env values, credential-shaped strings)
SEC-004 warn both, HTTP A local HTTP server listens on loopback only
SEC-005 error both, HTTP Authorization is discoverable (RFC 9728) and invalid tokens get 401
SEC-006 warn both Tool metadata holds no injection-style instructions or hidden characters
SEC-007 error modern The tool list does not change between connections or after a call

FUZZ, ROB and SEC run once per server, in the modern era when the server speaks it: they test how the server handles input, which does not depend on the era.

SEC-005 only applies to HTTP servers that require authorization. Give MCPProbe a valid token with --header "Authorization: Bearer ...": SEC-005 then checks what a client without one (or with a bad one) is told. Secrets found by SEC-003 are never printed in full and are masked in saved cases. The liveness probe after every case turns a crash or hang into a finding, whatever the check's severity. | CONF-021 | warn | legacy | initialize answers an unsupported version with a supported one | | CONF-022 | info | legacy | Server negotiates an outdated revision (2025-03-26 or older) |

mcpprobe checks explain <ID> prints what a check sends, what it expects, and a link to the spec section.

Fuzzing

The FUZZ suite calls each tool --examples times (default 50) with arguments generated from its inputSchema by Hypothesis: valid values, and near-misses with one thing wrong (a required field missing, a wrong type, a value just past a bound, an extra property, null, deep nesting, a 100,000-character string, odd Unicode). Each argument set is classified as valid or invalid by validating it against the tool's own schema, so a finding never rests on MCPProbe's guess. One case per tool, FUZZ-001/<tool>, judges all four FUZZ checks from the same calls.

Every finding is shrunk to a minimal input ({"message": ""} rather than a page of random Unicode) and saved as a recording of just that call on a fresh server, so mcpprobe replay reproduces it in one step. Crashes are shrunk too, restarting a stdio server between attempts; requests that are never answered are not, since each attempt would cost a full timeout. Calls carry a progressToken, and a tool that keeps reporting progress gets up to three times --timeout before MCPProbe moves on (without a finding: slow is not stuck).

Generation, shrinking and case order all derive from --seed, and shrinking is bounded by a call budget rather than a clock, so the same seed gives the same report on any machine.

Generation uses hypothesis-jsonschema, which speaks JSON Schema drafts 4 to 7; 2020-12 schemas (the MCP default) are translated for the generator, and keywords with no draft-7 form (unevaluatedProperties) only cost coverage, never a wrong verdict. Tools whose schemas the generator cannot handle (recursive $ref, or a remote $ref, which MCPProbe never fetches) are skipped with the reason.

Calling your tools safely

CONF-008 to 011 and the FUZZ suite call real tools. MCPProbe only calls tools marked readOnlyHint: true or destructiveHint: false (MCP treats unannotated tools as destructive), and never tools marked openWorldHint: true. Any URL, email or hostname it generates points at a reserved .invalid name, and IP addresses come from the documentation ranges. --allow-destructive and --allow-open-world lift those rules; don't use them against a server connected to real data or credentials. Fuzzing sends many unusual inputs, so test against a staging copy.

Developer tools

record sends a file of JSON-RPC messages (one per line, byte for byte) and saves everything that crossed the wire; replay re-sends it to a fresh server and reports any difference.

mcpprobe record --stdio "npx -y @modelcontextprotocol/server-everything" \
  --send examples/legacy-session.jsonl -o everything.json --timeout 60
mcpprobe replay everything.json --timeout 60

Secrets passed with --env or sensitive --header values are masked in every saved recording; pass them again to replay.

Roadmap

Milestone Scope
M0 (done) Raw wire client, recorder, replay, runner
M1 (done, v0.1.0) Conformance checks for 2026-07-28, JSON report
M2 (done, v0.2.0) Legacy and dual-era detection and checks
M3 (done, v0.3.0) Schema fuzzing (FUZZ) and robustness (ROB) suites
M4 (done, v1.0.0) Security suite, SARIF/JUnit/HTML reports, GitHub Action, --baseline, config file, docs site; checked on 12 public servers
M5 Model-in-the-loop usability evaluation (EVAL, opt-in)

Development

Requires uv.

uv sync
uv run pytest
uv run ruff format . && uv run ruff check . && uv run mypy

See CONTRIBUTING.md and checks/README.md.

src/mcpprobe/
  cli.py          Typer entry point
  transport/      raw stdio, HTTP and SSE wire client + byte recorder
  protocol/       request building, era detection, schema instances
  engine/         runner, seeds, check catalog, record and replay
  suites/         conf/, fuzz/, rob/, sec/ (eval/ in M5)
  report/         terminal, json
checks/           one YAML file per check
fixtures/servers/ reference server; --break <ID> violates one check

License

MIT

Metadata

Release files for mcpprobe-kit 1.0.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for mcpprobe-kit 1.0.0
File Size Uploaded Provenance Actions
mcpprobe_kit-1.0.0.tar.gz 183.6 kB With provenance Details for mcpprobe_kit-1.0.0.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for mcpprobe-kit 1.0.0
File Interpreter ABI Platform Actions
mcpprobe_kit-1.0.0-py3-none-any.whl Python 3 none any Details for mcpprobe_kit-1.0.0-py3-none-any.whl

Total release size: 328.9 kB

Release files / mcpprobe_kit-1.0.0.tar.gz

Download URL mcpprobe_kit-1.0.0.tar.gz
Size 183.6 kB
Tags Source
SHA-256 checksum
How to use checksums
97047c4236b8fb8f10657a702c2b29a0dbefb0619736091b72733d7b4effc0be
BLAKE2b-256 checksum
How to use checksums
301cf2a320f2f07e89329c78b50c39d225cbbc32d63db3892b8dccbd59f18554
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.16

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Nov 2, 2026.

Transparency log

Release files / mcpprobe_kit-1.0.0-py3-none-any.whl

Download URL mcpprobe_kit-1.0.0-py3-none-any.whl
Size 145.3 kB
Tags Python 3
SHA-256 checksum
How to use checksums
7d4a1ad96fd77281413754f7d7d3d39d5ad1d3a58483b66327b0f46addb81ca9
BLAKE2b-256 checksum
How to use checksums
5ad7cfc1bd0cdcdf622d9a89aee83385a44a7377809ef651e2d36560cf5777a1
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.16

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Nov 2, 2026.

Transparency log

Security for mcpprobe-kit 1.0.0

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

Full provenance

Both files in this release have been uploaded with provenance metadata.

Select from 2 files

Attestation for mcpprobe_kit-1.0.0.tar.gz

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Nov 2, 2026.

Transparency log

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Release history Release notifications | RSS feed

This release

1.0.0 This release

2 release files Full provenance

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page