Methodology

mcp-schema — Methodology v1

Version 1 · 19 Aug 2026 · the source and population are fixed at first collection. A change to any rule below is a new methodology version (v2), never an edit to this file, and the affected series is republished in full with a restatement note.

What is measured

The set of tools each remote MCP server publishes via tools/list, as observed by a real streamable-HTTP handshake. This is ephemeral and unarchived: a server can add, rename, remove, or re-schema its tools at any moment, and neither the Wayback Machine nor any index records what the schema was. Only a dated history of handshakes can.

Source and roster

The population is the official MCP registry — https://registry.modelcontextprotocol.io/v0.1/servers — paginated with its cursor to a full listing before any probe. This is the single source of truth for which servers exist; no directory or union of directories is merged in. Changing this source is a methodology change (v2), because it redefines the population and breaks comparability across the archive's history.

The raw registry response is the record, captured before any handshake: it is content-addressed (same rule as artifacts — hash, dedupe, write once) and referenced by a dated <slug>/roster/<day>.json. If pagination is cut short, complete: false marks the listing as truncated, so a short roster is never mistaken for a shrinking registry. A server that disappears from the registry is recorded as retired, never silently dropped — that would bake survivorship bias into the dataset.

Probe

Registry roster daily, paginated Handshake initialize → tools/list Raw response retained verbatim Canonicalise + hash sorted keys, no whitespace Drift event hash ≠ last observation
Every target, every run — the same five steps. A failed step still writes a row (see error classification below); nothing is silently skipped.

For each target, in order:

  1. initialize (protocolVersion 2024-11-05, no capabilities).
  2. notifications/initialized (best-effort; a failure here is not an error).
  3. tools/list, with the session id returned in the Mcp-Session-Id header.

The raw tools/list HTTP response body is the artifact, retained verbatim. Timeout is 20 seconds per request.

Error classification (error_class)

class meaning
timeout request exceeded 20s
tls connection/DNS/TLS failure
http_4xx HTTP 400–499 (except 401/403/429)
http_5xx HTTP 500–599
auth HTTP 401/403
rate_limited HTTP 429
no_endpoint server declared no streamable-http remote
parse response was not valid JSON-RPC

A failed poll writes a row with its class; it never writes nothing. The last known-good head is advanced only on success.

Partial runs are not a population sample

A collection run limited to the first N targets in roster order is not a random sample: the registry is not homogeneous in that order, running noticeably auth-heavy at the head and no_endpoint-heavy at the tail. A 250-target partial run measured auth 38% and no_endpoint 26%, while the full 23,231-target population measured auth 13% and no_endpoint 51%. Published error-class figures are always drawn from full collection runs, never partial ones.

Canonicalisation (frozen)

Identity hashes are computed over canonical bytes: JSON payloads are re-serialised with sorted object keys, no insignificant whitespace, and arrays of objects are sorted by their canonical serialisation. This collapses field ordering and array reordering so a publisher reordering its response is not recorded as drift. Raw bytes are retained separately; only the hash uses the canonical form.

Drift

A target has drifted iff its canonical hash changed since the last successful observation. The human-readable description (summarise_diff) reports added, removed, and changed tool names with their before/after inputSchema.

Schema half-life

The published "schema half-life" is the median survival time of a contract, estimated with the Kaplan-Meier estimator. A contract's lifetime is the interval between observed changes; the interval still in force at the end of the window is right-censored (it is a lower bound on that contract's survival). Censoring matters: a naive median over the observation window would just report the window length forever, because most contracts have not changed yet.

1.0 0 0.5 median half-life still-open intervals → censored time since last change →
Each step down is an observed change (an event). The line after the last event is dashed — those contracts have not changed yet, so their true survival is at least this long, not exactly this long. The half-life is only reported once the curve actually crosses 0.5.

Versioning

Cadence

Daily, at 03:15 UTC with a randomised delay. A coverage drop below 90% of active targets marks the run degraded; a run with zero attempts fails loudly.