mcp-quality
The CI quality suite for MCP servers
Lint, contract-test, benchmark, and load-test your MCP server before you ship it —
the pytest + lighthouse for the tools your agents depend on.
Security scanners tell you if your MCP server is dangerous. mcp-quality tells you if it's good — and blocks the merge when it gets worse. It grades any server across five dimensions into a single MCP Quality Score, runs deterministically in CI with no LLM and no key, and prints a badge.
$ mcp-quality run "python my_server.py" --legibility
MCP Quality Score 67 Grade D ⚠ hard-gate: 'legibility' capped the grade at C
Cost A 100 122 toolset tokens; $0.0004/task
Legibility F 0 50% right-tool selection; archive_record⇄delete_record 100%
Contract A 100 2 tools conform
Disambiguation matrix (row = correct tool · cell = % of times chosen)
┏━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━┳━━━━━━━━┓
┃ correct ↓ / chose → ┃ delete ┃ archiv ┃
┡━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━╇━━━━━━━━┩
│ delete_record │ 100% │ · │
│ archive_record │ 100% │ 0% │ ← agents pick delete when archive was right
└─────────────────────┴────────┴────────┘
↳ proposed rewrite: "Move a record to the archive (reversible); use delete_record to remove permanently."
Two tools described "Remove a record by id." — a data-loss bug living in your tool descriptions, invisible to every test you have. mcp-quality catches it and writes the fix.
Quickstart
pip install mcp-quality
mcp-quality run "python my_server.py" # graded A–F report
mcp-quality run "python my_server.py" --json --fail-under B # CI gate (exit 1 if < B)
mcp-quality static ./server.mcp.json # offline / air-gapped
The zero-LLM fast path (Contract + Cost) is deterministic and needs no model, key, or
network beyond your server. Add --legibility --model ollama:qwen2.5-3b for the
disambiguation matrix, --all for every family, or --deep-security to fold in
mcp-scan / Cisco findings.
Use it in CI
# .github/workflows/mcp-quality.yml
name: MCP Quality
on: [push, pull_request]
jobs:
mcp-quality:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with: { python-version: "3.12" }
- run: pip install mcp-quality
- run: mcp-quality run "python my_server.py" --fail-under B --no-regressions
Commit a baseline with mcp-quality snapshot "…" and --no-regressions fails the PR when
a commit silently breaks a tool or drops a score. mcp-quality badge emits an
mcp-quality: A SVG + shields.io endpoint for your README.
The check families
| Family | What it measures | Path |
|---|---|---|
| Contract | JSON-RPC/handshake conformance, schema validity, output conformance, determinism & error-path/recovery probes, 2026-07-28 stateless-conformance, snapshot & version-drift regression | zero-LLM |
| Cost | token weight of your whole toolset, per-tool bloat (leave-one-out), runtime response bloat, Context Efficiency, $-per-task | zero-LLM |
| Legibility (the differentiator) | agent-comprehension score, the disambiguation matrix, selection accuracy + over-triggering, description lints — with proposed rewrites you can auto-PR | small model |
| Performance | concurrent-agent load with real MCP semantics (not naive HTTP), p50/p95/p99, max concurrency, connection-leak detection | live |
| Security-lite | injection / secrets / dangerous-capability lints mapped to the OWASP MCP Top 10; --deep-security integrates the specialists |
zero-LLM + opt-in |
| Safety-Contract | are the tool annotations true? — a delete_* tool marked readOnlyHint (bypasses host confirmation), missing hints, retry-unsafe writes |
zero-LLM |
Overall score = a weighted, versioned rubric; measured families are renormalized, and an F in any family hard-gates the grade to C.
Reliability overlay — --reliability K
Accuracy asks "can it work?"; reliability asks "will it work every time?" — the
number a deploy gate actually cares about. --reliability K reruns the nondeterministic
families K times and reports pass^k: the projected probability all K runs pass. A
server that works 9 times in 10 is a 10% incident rate — pass^k over 5 runs is 59%, not an
A. Deterministic families (Contract, Cost, Safety) short-circuit to 100% with no reruns, so
the fast path stays free.
Experimental — --experimental (spec-surface)
Beyond tools, MCP servers can talk back: sampling/createMessage, elicitation/create,
and advertised resources — the surfaces where a server can smuggle instructions into your
model, phish your user, or dangle links that don't resolve. --experimental adds a
spec-surface family that drives the read-only tools, captures those server-originated
messages, and grades them (sampling-injection, over-broad context, sensitive-form
elicitation, unresolvable resources). It's opt-in and carries zero rubric weight — it's
reported but never moves your grade while these spec surfaces are still stabilizing.
Where it fits
mcp-quality doesn't compete with the security scanners or the point tools — it unifies the quality question into a CI gate. Credit to mcp-xray, which pioneered token-tax + tool-confusion scoring (we borrow its leave-one-out method).
| The question you're asking | Reach for |
|---|---|
| "Is this server dangerous?" | mcp-scan, Cisco mcp-scanner |
| "What's its token tax / tool confusion?" (run by hand) | mcp-xray |
| "Is this server good — gated in CI, every commit, with a badge?" | mcp-quality |
Commands
| Command | |
|---|---|
mcp-quality run <cmd|url> |
probe a live server (stdio / Streamable-HTTP / SSE) and grade it |
mcp-quality static <dump.json> |
score an offline tools/list dump (air-gapped CI) |
mcp-quality snapshot <target> |
write the regression baseline |
mcp-quality badge |
emit the grade badge (SVG + shields endpoint) |
mcp-quality fix --legibility |
apply proposed description rewrites (--apply / --pr) |
mcp-quality compare a.json b.json |
score-delta between two runs (sticky PR comment) |
mcp-quality serve |
hosted scoring API for registries ([registry] extra) |
Leaderboard
mcp-quality run against real public MCP servers (full table):
| Server | Grade | Toolset tokens |
|---|---|---|
server-memory, mcp-server-time, mcp-server-fetch, mcp-server-git |
A | 275–1,407 |
server-filesystem |
A (99) | 1,901 |
server-everything |
A (95) | 1,292 |
server-sequential-thinking |
D (67) | 918 — contract hard-gate¹ |
¹ Its one tool is stateful, so the determinism probe (identical args → different results) flags undeclared nondeterminism. Fix = declare the output volatile. A lower grade is an invitation to a PR, not a verdict.
Part of the Swarm Proof toolkit
Trust infrastructure for the agent economy — seven projects, one thesis.
| Project | What it does |
|---|---|
| stampede | Point a herd of realistic agents at your system before real ones arrive |
| mockworld | A synthetic internet for agents — fake Stripe, Gmail, exchange, instantly |
| mcp-quality ← you are here | The CI quality suite for MCP servers |
| costbomb | Denial-of-wallet fuzzing — find the inputs that make your agent spend $500 |
| exactly-once | Idempotency middleware so agent side-effects fire once |
| agent-postmortems | A structured incident database + post-mortem standard for agent failures |
| awesome-agent-reliability | The curated map of the field |
Docs
Demo · Leaderboard · Architecture · Requirements (PRD) · Design decisions · Roadmap · Changelog · Contributing
License
Apache-2.0. Provider-agnostic and Ollama-friendly; the CI-critical path needs
no LLM. Citable via CITATION.cff.
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file mcp_quality-0.3.0.tar.gz.
File metadata
- Download URL: mcp_quality-0.3.0.tar.gz
- Upload date:
- Size: 177.5 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
c7dcccbf1f8c6816269822f13f745c20a6b436fd005628437c5e81557214203e
|
|
| MD5 |
706b760a7a57aa12e42adbeeb639d860
|
|
| BLAKE2b-256 |
094b0516300e033c6c043a277d6757d9becafb4ca9648b49be466a7b31914715
|
Provenance
The following attestation bundles were made for mcp_quality-0.3.0.tar.gz:
Publisher:
release.yml on swarmproof/mcp-probe
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
mcp_quality-0.3.0.tar.gz -
Subject digest:
c7dcccbf1f8c6816269822f13f745c20a6b436fd005628437c5e81557214203e - Sigstore transparency entry: 2663852449
- Sigstore integration time:
-
Permalink:
swarmproof/mcp-probe@a67c530a73fb1c64fcce24196376938e81ed5480 -
Branch / Tag:
refs/tags/v0.3.0 - Owner: https://github.com/swarmproof
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@a67c530a73fb1c64fcce24196376938e81ed5480 -
Trigger Event:
release
-
Statement type:
File details
Details for the file mcp_quality-0.3.0-py3-none-any.whl.
File metadata
- Download URL: mcp_quality-0.3.0-py3-none-any.whl
- Upload date:
- Size: 111.5 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
12bf5279ba46a57caef7e93572dcad107017e43bad95c8a2ea2020f75d186621
|
|
| MD5 |
900a994868cffae2519aa308f008d143
|
|
| BLAKE2b-256 |
86b344a3eaf87b9415f6ab3fd3d439244c8478e3cb8f85d5f47e4ed6204261ab
|
Provenance
The following attestation bundles were made for mcp_quality-0.3.0-py3-none-any.whl:
Publisher:
release.yml on swarmproof/mcp-probe
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
mcp_quality-0.3.0-py3-none-any.whl -
Subject digest:
12bf5279ba46a57caef7e93572dcad107017e43bad95c8a2ea2020f75d186621 - Sigstore transparency entry: 2663852470
- Sigstore integration time:
-
Permalink:
swarmproof/mcp-probe@a67c530a73fb1c64fcce24196376938e81ed5480 -
Branch / Tag:
refs/tags/v0.3.0 - Owner: https://github.com/swarmproof
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@a67c530a73fb1c64fcce24196376938e81ed5480 -
Trigger Event:
release
-
Statement type: