--smoke runs the normal audit,
then actually calls your server’s tools over the same connection and
verifies they behave:
What it verifies on every run
Every check verdict is pass, fail, or skip — skip meaning the check could not be exercised, never that the server failed it.
For the two rejection checks, any JSON-RPC error code your server sends
counts as a rejection except the three that are crashes wearing an
error’s clothes: a request timeout, a closed connection, and
-32603
internal error (the server tried to run the call and broke).
The safety model
- Only tools annotated
readOnlyHint: trueare called by default. An absent annotation defaults to false per the spec, so unannotated tools are skipped, never called — and each skip is reported, which makes missing annotations a visible cost. --call-allis the explicit second consent for everything else. It is never implied by another flag and has no environment-variable form.- The unknown-tool probe cannot hit a real tool. Its name is derived deterministically to be absent from your server’s own collected catalog; if the tool listing failed or is incomplete, the check skips rather than gamble on a name.
- Argument synthesis is deterministic and never an LLM — sample values
come from the input schema itself (
default→const→ first example → first enum entry → type zero-values), so the same server sees the same calls on every run. Malformed schema fragments are tolerated rather than aborting the run.
Outage semantics: skip, not fail
A tool that returns an error result when called with valid synthesized arguments reports as skip — it may be rejecting the synthesized sample, or its upstream dependency may be down, and someone else’s outage should not fail your build. Only behavior your server owns can fail a smoke check.Gating CI on it
A smoke failure exits with its own code, 4, distinct from the score gate’s 3 — so CI can tell “the server scored badly” apart from “the tools are broken”:readOnlyHint: true tools exits 0 (and tells you what it skipped
and why).
Results never touch the score
Determinism is the score’s contract — same server, same score — and tool calls depend on upstreams and environment. So smoke results live in their ownsmoke section of the JSON report and are
never counted in score/max_score:
--smoke is requested but no session exists to call tools on — a
partial audit of an auth-gated server, or a
modern-only probe audit — the section reports "executed": false with the
reason, instead of silently vanishing.
What smoke mode is not
- Not available on mcpscore.dev — invoking tools on arbitrary third-party URLs from our infrastructure is what the security posture forbids. Smoke mode is CLI-only (GitHub Action support is planned).
- Not a replacement for your test suite. It proves the MCP contract — honest schemas, proper rejections, tools that answer — not your business logic.
- Not part of the score, ever. A perfectly passing smoke run adds zero points; a failing one subtracts none.
See also
GitHub Action
Gate PRs on the score today; smoke input coming
Stability Contract
Exit codes and the
smoke report sectionScoring Methodology
Why the audit itself never calls tools
Authenticated Servers
Pass credentials so smoke can reach behind the gate