Documentation
Everything the scanner checks, and how to run it yourself.
API
One endpoint. POST a target, get a full JSON report back.
POST /api/scan
Content-Type: application/json
{
"kind": "endpoint",
"url": "https://your-server.com/mcp",
"headers": { "Authorization": "Bearer <token>" } // optional
}
// or static GitHub analysis:
{ "kind": "github", "repo": "owner/repo" }
// or Docker / OCI image metadata:
{ "kind": "docker", "image": "ghcr.io/org/mcp-server:latest" }Example with curl:
curl -s https://your-instance.vercel.app/api/scan \
-H 'content-type: application/json' \
-d '{"kind":"endpoint","url":"https://mcp.deepwiki.com/mcp"}' | jq .overallConformance badge
Embed a live SVG badge in your README. Caches for 5 minutes.
  
GitHub Action
Gate PRs on a minimum conformance grade. Works with endpoint, GitHub, or Docker targets.
- uses: aking-beep/mcp-conformance-scanner@main
with:
target: https://your-server.com/mcp
min-grade: BCLI flags for the same gate: --min-grade, --report, --github-output.
Local CLI
npm install npm run scan -- https://your-server.com/mcp
Exits non-zero when the overall grade is D or F — handy in CI.
What we score
- Protocol compliance (22%) — reachability, version, serverInfo, capabilities.
- Tools (18%) — naming, JSON-Schema inputs, descriptions.
- Error handling (12%) — unknown-method (-32601) and malformed-input behavior.
- Authentication (12%) — enforcement, WWW-Authenticate, RFC 9728 PRM, AS metadata, PKCE S256, refresh_token, DCR.
- Security (14%) — TLS, CORS, injection surface, destructive-tool guardrails.
- Resources / Prompts (6% each) — URI hygiene and prompt validity when advertised.
- Streaming (6%) — Streamable HTTP / SSE support.
- Documentation (4%) — inline tool docs and server self-identification.
Skipped categories (e.g. a server with no prompts) are excluded from the weighted average, so you're never penalized for a capability you don't offer.
Saved reports
Reports are never stored unless you click Save & copy link or submit the optional email form. Permalinks live at /r/<id> and expire after 30 days.
POST /api/reports
{ "report": { /* full ScanReport */ }, "email": "optional@company.com" }
GET /api/reports/:id
→ { id, createdAt, expiresAt, report }Storage backends: Upstash Redis (UPSTASH_REDIS_REST_*) or a filesystem dir (REPORT_STORE_DIR). Dev defaults to .data/reports.
Privacy
Scans run server-side from your deployment. Results are not persisted unless you explicitly save a report. Email capture is optional and only sends when EMAIL_CAPTURE_WEBHOOK_URL is set. Basic scanning is always free.