mcp-reality-check
Checks whether an MCP server's successful tool responses actually reflect reality.
mcp-doctor reads a server's source and never runs it. mcp-fuzz runs it, but only judges the bad-input path — does a missing or wrong-typed field come back as a structured error, or does the server crash? It explicitly declines to judge a successful call's content, since a schema-only placeholder value ("test") usually isn't realistic enough to fairly judge whether the response is actually correct.
mcp-reality-check is the piece that was missing: it calls each tool once with a best-effort realistic input, then checks whether the response is a genuine answer — not a disguised refusal, not empty, not silently violating the tool's own declared output schema.
Why no LLM?
The obvious way to judge "is this response actually correct" is to have another LLM read it and decide. Deliberately didn't build it that way for v1: an LLM judge means an API key, a per-call cost, and non-deterministic results — a real cost and reliability tradeoff, not free. Every check here is instead a plain, deterministic rule, in the same spirit as mcp-doctor and mcp-fuzz: zero cost, zero API key, fully reproducible, run it as many times as you want. The real tradeoff is recall: a refusal phrased in a way the pattern list doesn't cover won't be caught. That's an honest limitation, not hidden — see Known limitations.
Install
pip install mcp-reality-check
Use
mcp-reality-check -- python server.py
mcp-reality-check -- npx -y some-mcp-server
For each tool (read-only by default — see Safety below), mcp-reality-check generates one best-effort realistic set of arguments from the tool's own inputSchema (a city property gets a real city name, an email property gets a real-shaped email, not a bare placeholder), calls it once, and checks the response for:
- Refusal in disguise — the call reports success (
isErrorfalse/absent), but the content is actually an apology or refusal ("I don't have access to...", "as an AI, I cannot..."). A real, common failure mode neithermcp-doctornormcp-fuzzcatches, since both only ever look at the structuralisErrorflag, never the text itself. - Empty content on success — reports success, returns nothing.
- Output schema violation — if the tool declares an
outputSchema, its actualstructuredContentis validated against it. The one fully hard, non-heuristic check here. - Echo/relevance mismatch (reported separately, not scored) — none of the realistic string inputs used in the call appear anywhere in the response. A weak signal on its own (a genuine, on-topic answer doesn't have to repeat the input verbatim), flagged as worth a manual look rather than folded into the score.
A tool that itself honestly reports isError: true is never flagged — it's already telling the truth about failing, which is the opposite of a disguised failure.
Safety
Same default as mcp-fuzz: only tools annotated readOnlyHint: true are called. Pass --include-destructive to test everything, but only against a server you're confident is safe to call blindly.
JSON output / CI
mcp-reality-check --json -- python server.py
mcp-reality-check --fail-under 90 -- python server.py # non-zero exit if sanity < 90%
Real-world spot check
| Repo | Lang | What mcp-reality-check found |
|---|---|---|
modelcontextprotocol/server-everything |
TS | Official reference server, run via npx. Clean pass — 9/9 checkable tools, 100%/A. Includes get-structured-content, which declares a real outputSchema — confirmed the schema-validation check is actually exercised, not silently a no-op: read both the tool's declared schema and its live structuredContent directly off the wire before trusting the clean result. |
haris-musa/excel-mcp-server |
Python | Clean pass — 4/4 checkable tools, 100%/A. 19 write tools correctly skipped as not read-only. |
modelcontextprotocol/server-fetch |
Python | Clean pass, tested with --include-destructive (its one tool is genuinely read-only but isn't annotated as such) — 1/1, 100%/A, a real HTTP GET against a real URL. |
upstash/context7-mcp |
TS | Clean pass — 2/2, 100%/A. |
czlonkowski/n8n-mcp |
TS | Clean pass — 4/4 checkable tools, 100%/A. 3 more tools correctly recognized as honest isError: true failures rather than checked/flagged. |
No disguised refusals or output-schema violations found yet in this first round — an honest "nothing yet" is itself worth stating plainly rather than papering over with the echo-mismatch notes (which are real, but explicitly not a confirmed bug — see above).
Known limitations
- The refusal-pattern list is a fixed set of common phrasings, not exhaustive — a model-specific or oddly-worded refusal can slip through uncaught. Patterns are deliberately conservative (full phrases, not single words like "sorry") to avoid false-flagging a genuine answer that happens to apologize for something unrelated.
- The echo/relevance check is a substring match, not semantic understanding — it can't tell a correct paraphrase from an actually-wrong answer. That's exactly why it's reported separately and never scored.
- Output schema validation only fires when a server actually declares one — most MCP servers today don't yet.
- No true semantic correctness judgment (an LLM reading the response and deciding if it's right) — a deliberate scope decision, not an oversight. If this ever becomes an opt-in mode, it'll need its own API key and will be documented as non-deterministic, unlike everything else here.
License
MIT
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_reality_check-0.1.0.tar.gz.
File metadata
- Download URL: mcp_reality_check-0.1.0.tar.gz
- Upload date:
- Size: 15.4 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
1013816fb157a22796b9c5f0c3e5e15ceeb1b1e0d211e1e3682b3ad15cb040cc
|
|
| MD5 |
a8c6be85ae445c31b75be5f6df83cd35
|
|
| BLAKE2b-256 |
f0d03c132ffd6d3a849ba4ced4e07623b7af9246af3a39cfa8c1cdc21962c078
|
Provenance
The following attestation bundles were made for mcp_reality_check-0.1.0.tar.gz:
Publisher:
publish.yml on vishalhabib99/mcp-reality-check
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
mcp_reality_check-0.1.0.tar.gz -
Subject digest:
1013816fb157a22796b9c5f0c3e5e15ceeb1b1e0d211e1e3682b3ad15cb040cc - Sigstore transparency entry: 2733250765
- Sigstore integration time:
-
Permalink:
vishalhabib99/mcp-reality-check@2a135f64dcccb1b9205bebb54c7e61b7df410ccb -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/vishalhabib99
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@2a135f64dcccb1b9205bebb54c7e61b7df410ccb -
Trigger Event:
release
-
Statement type:
File details
Details for the file mcp_reality_check-0.1.0-py3-none-any.whl.
File metadata
- Download URL: mcp_reality_check-0.1.0-py3-none-any.whl
- Upload date:
- Size: 15.2 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 |
3be6eb6cd7906168805e155396d4023d2ff15119dec7bcb0d21d3847b25df2b3
|
|
| MD5 |
ff4de7d45f4ccfb1555bb8265db5eea3
|
|
| BLAKE2b-256 |
4c2a5906d3a18b57545517d990ab4c05e95ca4246667aa4bfaeb0065bf544079
|
Provenance
The following attestation bundles were made for mcp_reality_check-0.1.0-py3-none-any.whl:
Publisher:
publish.yml on vishalhabib99/mcp-reality-check
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
mcp_reality_check-0.1.0-py3-none-any.whl -
Subject digest:
3be6eb6cd7906168805e155396d4023d2ff15119dec7bcb0d21d3847b25df2b3 - Sigstore transparency entry: 2733250785
- Sigstore integration time:
-
Permalink:
vishalhabib99/mcp-reality-check@2a135f64dcccb1b9205bebb54c7e61b7df410ccb -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/vishalhabib99
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@2a135f64dcccb1b9205bebb54c7e61b7df410ccb -
Trigger Event:
release
-
Statement type: