In CI
Running the check on every pull request turns a twelve-month migration deadline into something you cannot drift past without noticing.
The action
Listed on GitHub Marketplace as MCP Stateless Check.
- uses: Khanthtutzin/mcp-stateless@v0.3.1 with: stdio: node dist/server.js fail-on: errorThe action ref pins the checker as well as the action. It runs the npm version
it was released with, not whatever npm currently calls latest, so a release
published tomorrow cannot change today’s result. Override with the version
input if you need a different one.
A moving v1 tag will exist from 1.0.0 onward. Until then, pin the exact
release as above.
A complete workflow
name: MCP conformance
on: [push, pull_request]
jobs: conformance: runs-on: ubuntu-latest steps: - uses: actions/checkout@v5 - uses: actions/setup-node@v5 with: node-version: '22' - run: npm ci && npm run build
- uses: Khanthtutzin/mcp-stateless@v0.3.1 with: stdio: node dist/server.js fail-on: errorThe server has to be built before it can be probed — the check spawns your server, it does not compile it.
Inputs
| Input | Default | Description |
|---|---|---|
stdio |
— | Command that starts the server on stdio. Mutually exclusive with http. |
http |
— | Streamable HTTP endpoint. Mutually exclusive with stdio. |
header |
— | Extra HTTP header as Name: value. One per line for several. |
format |
text |
text, json, sarif or markdown. |
output |
— | Write the report to this file instead of stdout. |
fail-on |
error |
Fail the step on error, warning, or never. |
only |
— | Comma-separated rule ids to run exclusively. |
skip |
— | Comma-separated rule ids to skip. |
timeout |
— | Per-request timeout in milliseconds. |
verbose |
false |
Include the JSON-RPC traffic behind each finding. |
summary |
true |
Append a markdown report to the GitHub step summary. |
version |
the release’s own | npm version of mcp-stateless to run. |
Outputs
| Output | Description |
|---|---|
ready |
"true" when no breaking issues were found |
errors |
Number of breaking findings |
warnings |
Number of advisory findings |
The three outputs and the printed report all come from one probe. That is
worth stating because it was once not true: the action used to invoke the
checker three times — once for the JSON behind its outputs, once for your
chosen format, once for the step summary — and three probes mean three verdicts.
Against a flaky server the errors output could contradict the report printed
directly above it. It now probes once and renders many times.
Use the outputs to react without re-running anything:
- uses: Khanthtutzin/mcp-stateless@v0.3.1 id: check with: stdio: node dist/server.js fail-on: never
- name: Comment when not ready if: steps.check.outputs.ready != 'true' run: echo "::warning::${{ steps.check.outputs.errors }} breaking findings"Note the fail-on: never: without it the step fails before the next one runs.
Findings in the Security tab
SARIF output puts each finding on the exact line of your workflow’s run in the GitHub code-scanning UI, and inline on pull requests.
- uses: Khanthtutzin/mcp-stateless@v0.3.1 with: stdio: node dist/server.js format: sarif output: mcp-stateless.sarif fail-on: never
- uses: github/codeql-action/upload-sarif@v3 with: sarif_file: mcp-stateless.sariffail-on: never is deliberate here too. If the check fails the job, the upload
step never runs and the findings never reach the Security tab — you lose the
report precisely when it has something to say.
Outside GitHub Actions
The action is a thin wrapper. Any CI system can run the same command, and the exit codes are the whole contract:
npx mcp-stateless --stdio "node dist/server.js" --emit sarif:report.sarif0 ready, 1 findings, 2 usage error, unreachable server, or a probe that
could not be completed. See Usage for the full set of flags.
Choosing a threshold
Start at fail-on: error. Breaking findings are the ones that stop a
2026-07-28 client from working with your server at all, and every one of them
names whether an SDK upgrade or your own code resolves it.
Move to fail-on: warning once you are clean, so the advisories cannot
accumulate quietly. Use never only where something downstream — a SARIF
upload, a comment, a report artefact — has to run regardless.