Public API · schema 2026-08-11
One public computation. Four ways to read it.
Three CORS-open GET endpoints and one MCP server. Read-only, anonymous, and free—without a second data tier or a different score behind authentication.
GET /api/score?id=host:2s.io
{
"subject": { "id": "host:2s.io", … },
"rating": {
"status": "not_rated",
"grade": "NR",
"score": null,
"published": false,
"publication_floor": {
"met": false,
"unmet": [ …, … ],
"eligible_from_date": "…"
}
},
"observations": { … },
"components": [ … ],
"evidence": [ … ]
}
A withheld score is null, never a placeholder number. The floor names both thresholds — 7 archive days and 3 successful observations — and exactly which are unmet.
GET /api/score
The full public scorecard for one listing: rating, publication floor, measured components, cited evidence, constraints, financial evidence, history, accepted corrections, and coverage limits.
curl -s 'https://mcpscores.com/api/score?id=host:2s.io'
const r = await fetch('https://mcpscores.com/api/score?id=host:2s.io');
const card = await r.json();
if (card.rating.published) console.log(card.rating.grade, card.rating.score);
else console.log('NR —', card.rating.reason);
Returns 200 when a research record exists and 404 with a well-formed not-rated payload when it does not. A 404 here is data, not an error: it means the identifier is outside the archive.
What a withheld score looks like
When published is false, grade is NR and score is null. There is no provisional figure anywhere in the payload, and publication_floor states exactly which conditions are unmet and the earliest date the listing could become eligible.
| Field | Type | Meaning |
|---|---|---|
subject | object | Identifier, kind, name, title, publisher, endpoint, registry dates. |
rating | object | Grade, score, published flag, confidence, outlook, and the publication floor. When published is false, score is null — there is no provisional figure to read. |
rating.publication_floor | object | Thresholds, current archive days and observations, what is unmet, and the earliest eligible publication date. |
observations | object | As-of date, archive days, successful observations, archive coverage, timestamp precision. |
components | array | Five measured components with 0–100 value, weight percent, and applicability. |
evidence | array | Measured statements with source table, coverage confidence, and observation date. |
constraints | array | Material observations that capped or forced the grade. |
financial_evidence | object | Declared payee, balance snapshot, observed inflow with block range, payer count and concentration. |
history | object | Stored engine score records and daily observed wallet inflow. |
corrections_applied | array | Accepted operator corrections, dated. Empty array when none. |
coverage | object | What is included, the stated limitations, and pending model inputs. |
GET /api/top
Highest published ratings. Candidates are drawn from the stored rating sweep and then every figure is recomputed through the authoritative path before it is returned.
curl -s 'https://mcpscores.com/api/top?limit=10'
limit is 1–10, default 10.
An empty list is a real answer
When nothing clears the publication floor the response carries status: "no_published_ratings", an explanation, the floor itself, the real archive coverage, and a per-candidate reason in evaluation.blocking_reasons. Ratings are never invented to fill the list — parse status rather than assuming an empty array means failure.
Right now this endpoint has evaluated 4 candidate(s) and returns 0 published rating(s), while the archive holds 2 day(s) against a 7-day floor.
GET /api/field
The whole register as a point field: one row per researched listing with kind, observed state, tool count, USDC treasury, observed on-chain inflow, and domain year. This is the exact dataset the homepage network map plots — same computation, same cache.
curl -s 'https://mcpscores.com/api/field'
No parameters. Rows are ordered by observed state, then kind, then id — the array index is the register rank the map uses for placement. Attributes the observatory has not recorded are 0, never estimated.
Columns per row: id, kind (0 x402 host, 1 MCP server), state (0 answering, 1 silent, 2 unprobed), tool_count, usdc_balance, usdc_inflow_observed, distinct_payers, domain_created_year. The payload carries its own counts, max, and limitations fields.
POST /mcp
The same two reads as MCP tools, over Streamable HTTP and JSON-RPC 2.0. Free: there is no x402 gate on this server, so an unpaid tools/call simply returns the data.
curl -s -X POST 'https://mcpscores.com/mcp' \
-H 'content-type: application/json' \
-d '{"jsonrpc":"2.0","id":1,"method":"tools/list"}'
curl -s -X POST 'https://mcpscores.com/mcp' \
-H 'content-type: application/json' \
-d '{"jsonrpc":"2.0","id":2,"method":"tools/call",
"params":{"name":"score_lookup","arguments":{"id":"host:2s.io"}}}'
No account, no gate
There is no x402 challenge on this MCP server and no API key anywhere in the reference. An unpaid tools/call returns the same structured content the website renders.
Registry manifest: /server.json · AI-readable site guide: /llms.txt · readiness: /health
| Tool | Arguments | Returns |
|---|---|---|
score_lookup | id (string, required) | The full scorecard as structured content. |
top_rated | limit (integer 1–10) | Published ratings with the same empty-result semantics as /api/top. |
Listing identifiers.
Every listing has one canonical identifier.
host:<hostname> an x402 endpoint host mcp:<publisher>/<name> a registry-listed MCP server
Hostnames are lower-cased with a trailing dot stripped. If you only have a URL, GET /lookup?q=https://api.example.com/pay resolves it and redirects to the canonical scorecard.
Rate limits and caching.
60 requests per minute per client address on /api/* and /mcp; 120 per minute on site pages. Enforced by a per-address counter, not per PoP. Responses carry RateLimit-Limit, RateLimit-Policy, RateLimit-Remaining and, on a 429, a bounded Retry-After. If the limiter itself fails, requests are served rather than blocked.
Scorecards are cached 60s in the browser and 300s at the edge. X-MCP-Scores-Methodology carries the model version on every API response, so a client can detect a model change without diffing payloads.
Attribution and reuse.
The API is free for commercial and non-commercial use, including inside a paid product.
Cite a figure as: MCP Scores, MCP Authority, model 1.0, with the scorecard URL and the observation date shown on the card.
Two requests, both enforceable by reputation rather than by licence: carry the observation date with the number, and do not present a withheld figure as a low score. NR means the archive cannot support a grade yet.
Do not cache a rating forever
Ratings move when the endpoint's behaviour moves. A number scraped once and displayed for months stops being a measurement. Re-read at least daily, or embed the live badge and let it stay current on its own.