Skip to main content
Every point in an mcpscore report traces back to one rule, and every rule cites its source in 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.
That run gives you three numbers: the main score (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 as security_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’s skipped_rules[] with one reason:
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:
  • 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 initialize handshake. The truncated-JSON probe runs only over HTTP, because the SDK path cannot inject malformed wire input safely, so stdio reports insufficient-data for that rule. HTTP-only questions such as Origin, headers, status codes, sessions, and auth metadata are not-applicable for 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 cacheScope across 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, from 2024-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 negotiates 2025-11-25, so the five tools_mcp_headers_* rules for 2026-07-28 skipped.
  • The report’s spec.era states which lifecycle was observed, following the spec’s own detection guidance. spec.negotiated_version and spec.latest_version give 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, as readiness.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.
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.
  • requestState integrity enforcement. Only tamper rejection is observable, and active tampering probes are deferred.
  • subscriptions/listen behavior 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:
  1. A different mcpscore version ran. Most releases add rules, which changes both numbers. The report’s mcpscore_version names the engine. Scores compare only within one version, per the stability contract.
  2. 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.
  3. 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-data skips, which changes the maximum.
To find the cause, diff the two --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 the rule_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