details.basis: a section of the MCP specification for
most rules, RFC 9728 for authorization, the MCP Registry server.json
schema and the package registries for packaging, JSON-RPC 2.0 for malformed
requests, and a named mcpscore recommendation where the spec leaves a field
optional. This page follows one real audit from the
command to the final number. Then it covers what runs against your server
and what the score leaves out, so you can check any score yourself.
87/103), the spec revision
the server speaks (2025-11-25, legacy), and a separate readiness score for
the newest revision (3/13). The rest of this page explains each one.
How 87/103 adds up
A rule is one check against your server, such assecurity_origin_validation.
Each rule has a severity, and the severity sets its weight. A passing rule
earns its weight. A failing rule earns nothing. The score is points earned
over points available.
The same DeepWiki audit, grouped by category:
Fixing the one Security & Auth failure moves the score to 90/103. The
--json report carries the same arithmetic per rule in results[].severity_value
and results[].passed, so you can recompute any score from the report alone.
Skipped rules count for nothing
Only rules that ran count toward the maximum. A rule that has nothing to judge is skipped and left out of both numbers, never failed. That is why DeepWiki is scored out of 103 and a server with prompts and resources is scored out of more. DeepWiki serves no prompts or resources, so the 24 rules about them were skipped. Every skip appears in the report’sskipped_rules[] with one reason:
Technical details: empty and unreadable catalogs
Technical details: empty and unreadable catalogs
An empty tools catalog that was fetched successfully gives the per-tool rules
nothing to assess, so they skip as
not-applicable. A declared catalog that
could not be fetched skips as insufficient-data instead, because an item may
exist unobserved. A separate presence rule, tools_at_least_one, still judges
whether a complete tools catalog is empty.Four categories, readiness counted when it applies
The main score always includes three categories. Readiness is the fourth: it has its own score, and it also counts in the main score on a full audit of a modern or dual-era server. Legacy servers and partial audits leave it out. The server audit has 102 rules today. The rules reference lists each one with its weight and the spec revisions it applies to.
A separate set of six packaging rules scores a published npm or PyPI package
instead of a running server. See package audits.
Security & Auth: the server’s security posture
Security & Auth scores the security posture that is observable on a deployed server, from outside, without calling a tool. OWASP MCP Top 10 coverage maps these rules to the OWASP risks and lists the risks an audit from outside cannot see. The OWASP MCP Top 10 blog post walks through the three catalog-text rules with a working demo.
Three related checks live in other categories, because the spec files them
there. Tool behavior annotations are
tools_annotations_present and
sensitive tool header parameters are tools_mcp_headers_not_sensitive, both
in Primitives. Session-ID handling on the stateless lifecycle is
readiness_2026_no_session_id, in Readiness.
A server that serves anonymous requests has no authorization posture to
grade, so the eight auth_* rules skip as not-applicable. That is the case
for DeepWiki above. To score the authorization flow behind the gate, see
authenticated servers.
How an audit runs
1
Connect
Stdio for local servers, Streamable HTTP or SSE for URLs, detected
automatically. mcpscore tries the legacy
initialize handshake first. If
that lifecycle is absent, stateless probes establish whether the target is
a modern-only server rather than an unreachable one.2
Collect
Protocol version, server info, capabilities, and the complete paginated
listings of tools, prompts, resources, and resource templates, plus TLS
details for HTTPS targets.
3
Probe
Sessionless requests that observe behavior the spec defines outside the
negotiated session. Probes read state and change nothing. An audit never
invokes
tools/call. The one opt-in exception is the CLI’s
smoke mode, for your own server, reported outside the score.4
Evaluate
Every registered rule runs against the collected data and the probe
observations.
What the probes send
Several probes are malformed on purpose, because the spec says how a server must answer them. They can look like scanning in a WAF log. Each one checks documented behavior:Technical details: stdio probes, cursors, and pagination bounds
Technical details: stdio probes, cursors, and pagination bounds
- Stdio gets the same JSON-RPC probes. The modern lifecycle is stateless,
so behaviors expressible through the SDK are probed over stdio too, using
two short-lived sibling processes and no
initializehandshake. The truncated-JSON probe runs only over HTTP, because the SDK path cannot inject malformed wire input safely, so stdio reportsinsufficient-datafor that rule. HTTP-only questions such asOrigin, headers, status codes, sessions, and auth metadata arenot-applicablefor stdio. - Invalid-cursor probes use the initialized session when one exists. Legacy and dual-era servers can reject a sessionless request before the cursor is judged. Modern-only servers are assessed through the stateless path.
- Pagination traversal is bounded. For modern servers, mcpscore follows
declared paginated lists to compare
cacheScopeacross pages. It is read-only, capped at 100 pages per list and 30 seconds in total, and skips when no list returns more than one complete page.
Scoring across spec revisions
MCP publishes dated revisions, from2024-11-05 to 2026-07-28. The
2026-07-28 revision replaces the stateful initialize lifecycle with a
stateless one. The spec
calls stateful servers legacy, stateless servers
modern, and servers that speak both dual-era. mcpscore detects which one your
server is and scores it against the revision it negotiated:
- Rules declare the revisions they apply to. Outside that range they skip as
not-applicable, so a server is never failed on a revision it does not speak. DeepWiki negotiates2025-11-25, so the fivetools_mcp_headers_*rules for 2026-07-28 skipped. - The report’s
spec.erastates which lifecycle was observed, following the spec’s own detection guidance.spec.negotiated_versionandspec.latest_versiongive the revisions. - Modern-only servers are fully supported over HTTP and stdio. When the legacy handshake fails but stateless requests succeed, the audit runs through the probe layer instead of reporting a connection failure.
The readiness score: separate, informative
Readiness answers a second question: how ready is this server for the 2026-07-28 revision. It is always reported on its own axis, asreadiness.score over readiness.max_score. Whether its points also count
in the main score depends on the server:
DeepWiki is legacy, so its
3/13 is guidance only. Its CLI line says
4 of 20 checks assessed: the server has no stateless lifecycle, so the
two gateway rules (readiness_2026_server_discover and
readiness_2026_stateless_request) failed and 16 detail checks skipped as
requires-modern-support. The report carries readiness.assessed,
readiness.skipped, and readiness.total, so a perfect fraction never hides
checks that did not run.
Technical details: every readiness rule and its normative basis
Technical details: every readiness rule and its normative basis
Each readiness rule is anchored to normative language of the 2026-07-28
revision. The citations are re-checked against the dated spec URLs whenever
a revision goes final.
Origin validation is not on this axis. Every Streamable HTTP revision
requires it, so security_origin_validation scores it in Security & Auth
for legacy and modern servers alike. The session-ID and removed-method rules
check for legacy behavior leaking into the modern lifecycle, so they run only
when the server shows modern support. Missing-protocol-version rejection and
GET-stream removal skip dual-era endpoints, because the spec permits
compatibility with older Streamable HTTP revisions
there.What mcpscore does not test
These are out of scope today, either because they are not observable from outside or because they cannot yet be tested safely from outside:- What tools do. The audit never calls them, so the score judges how tools are described and typed, not how they behave. Smoke mode covers that for your own server, outside the score.
- Whether tool descriptions are honest. Catalog text is scanned for hidden characters, credentials and a fixed list of prompt-injection phrasings, not judged for meaning, so a description that misleads in plain words passes.
- The package behind the server. mcpscore does not scan code or dependencies for malware. Pair it with a package scanner for that.
- True statelessness, meaning no hidden state across requests. Requests from outside can sample it but never prove it.
requestStateintegrity enforcement. Only tamper rejection is observable, and active tampering probes are deferred.subscriptions/listenbehavior and SSE stream semantics.- The Tasks and MCP Apps extensions, which version separately from the core spec.
- Client-side OAuth obligations such as issuer validation and credential binding. A server audit cannot observe them.
When the score changes
The score is deterministic: the same server state and the same mcpscore version give the same score. When it moves, one of three things moved:- A different mcpscore version ran. Most releases add rules, which
changes both numbers. The report’s
mcpscore_versionnames the engine. Scores compare only within one version, per the stability contract. - The audit type differs. A partial audit covers far fewer checks. A
modern server’s main score includes readiness points
(
readiness.counted_in_main) and a legacy server’s does not. - The server answered differently. Rolling deploys and mixed replica
versions behind a load balancer give identical probes different answers.
A server that rate-limits the probes turns rules into
insufficient-dataskips, which changes the maximum.
--json reports by rule_id. The rule that
flipped is the finding. For fixes to the rules servers fail most, see
improve your score.
Disputing a rule
Open an issue with therule_id and the spec text you believe contradicts it. Every rule must be
defensible by citation, and a rule that is not is a bug. Most results carry
their citation in details.basis, and readiness results in details.sep.
To propose a new rule, see
CONTRIBUTING.
What’s next
Rules reference
Every rule, its weight, and the spec revisions it applies to
Stability contract
What you can build on, and what moves between releases