Web scorecard schema
A web scorecard is the structured output of the website agent-readiness audit. It scores a website and its MCP server across six visible categories with a fairness-driven two-score model: a check that does not apply to a site is excluded rather than counted against it, a present-but-broken surface costs more than an absent one, and a surface that works while violating a spec detail earns partial credit rather than the full penalty. This page documents every field a web scorecard carries.
The web scorecard is site-owned. Its schema_version is 0.4, independent of the CLI scorecard schema (currently 0.7) and of the agentnative spec spec_version. The CLI scorecard schema is documented separately at /scorecard-schema.
Top-level fields
{
"schema_version": "0.4",
"spec_version": "...",
"target_url": "https://example.com/",
"mcp_endpoint": "https://example.com/mcp",
"mcp_discovery": [ ... ],
"tool": { "name": "example.com", "url": "https://example.com/" },
"audience": null,
"audit_profile": null,
"site_type": null,
"public_listing": false,
"summary": { ... },
"coverage_summary": { ... },
"score_pct": 81,
"score": { "relative": 81, "global": 63 },
"categories": [ ... ],
"results": [ ... ]
}| Field | Type | Source | Meaning |
|---|---|---|---|
schema_version | string | engine | Version of the web-scorecard envelope. Site-owned, independent of the CLI schema. |
spec_version | string | engine | Version of the agentnative spec the run scored against. Same value the CLI scorecard carries. |
target_url | string | engine | The normalized audited URL: scheme, host, and a trailing slash. Web-specific. |
mcp_endpoint | string | null | engine | The discovered MCP endpoint, or null when none was found. Web-specific. |
mcp_discovery | array | engine | The discovery trail: each well-known card or common-path probe attempted, and what it returned. |
tool | object | engine | Web identity: { name, url }. No binary, install, tier, or language. See tool. |
audience | null | engine | Always null for web targets; the audience classifier is a CLI concept. |
audit_profile | null | engine | Always null for web targets; audit profiles are a CLI concept. |
site_type | string | null | engine | The declared site type the run scoped to: content, api, or null (everything ran). |
public_listing | boolean | engine | The submitter's opt-in to the public board listing. false unless explicitly set. |
summary | object | derived | Tally of check outcomes by status. See summary. |
coverage_summary | object | derived | MUST / SHOULD / MAY totals and how many were verified. See coverage_summary. |
score_pct | integer | derived | The headline RELATIVE score, 0-100. Equals score.relative. See scoring. |
score | object | derived | The two-score pair { relative, global }. See scoring. |
categories | array | derived | Per-category passed/counted rollups in display order. See categories. |
results | array of result obj | engine | One entry per check. See results. |
tool
Web identity. The CLI-only header fields (tier, language, repo, install) are absent on a web tool object.
"tool": { "name": "example.com", "url": "https://example.com/" }| Field | Type | Meaning |
|---|---|---|
name | string | The audited domain (host), used as the display name. |
url | string | The normalized audited URL. Matches target_url. |
The two-score model
Both scores derive from the same per-check outcomes; the engine computes them and consumers read the values straight from the JSON.
score.relative(the headline, mirrored at top-levelscore_pct) is earned points over the maximum achievable for this site's applicable checks, so a site perfect for its type approaches 100.score.globalis earned points over the maximum of a maximally agent-ready site (every check in the registry), so exposing and nailing more surfaces ranks higher. The web leaderboard sorts by it.
Per applicable check, with per-tier difficulty weights (currently 5 for MUST, 3 for SHOULD, 1 for MAY):
passearns the full weight.noncompliant(works, but a spec detail is violated) earns 0.25 x weight at every tier, and occupies its full weight in the relative denominator. An agent that calls the surface gets the outcome it asked for, so showing an imperfect capability has to pay better than withdrawing it: a withheld surface and an absent one look identical on the wire, so the only lever against withdrawal is to stop rewarding it.broken(present but invalid) costs 0.75 x weight at every tier: a malformed surface misleads agents, so it is worse than absence.- An absent MUST is a full-weight zero; an absent SHOULD is a zero that occupies only half its weight in the relative denominator; an absent MAY is
n_a(truly optional, never counted). n_a,skip, anderrorrows are excluded from both scores. Both scores floor at 0.
categories
Per-category rollups in the fixed display order. counted excludes n_a / skip / error rows, so a category with nothing applicable reads 0/0.
categories[] and results[].category are re-derived from the current registry at read time, so every render of a cached scorecard (the audit_website and get_website_audit MCP tools, the /web/<domain> page, and its .md twin) reflects the current category shape regardless of when it was cached. The score and score_pct reflect the registry at audit time; re-grouping the categories earns no points and never changes the stored score.
"categories": [
{ "id": "discoverability", "name": "Discoverability", "passed": 4, "counted": 5 },
{ "id": "content-for-agents", "name": "Content for agents", "passed": 7, "counted": 8 },
{ "id": "bot-crawl-policy", "name": "Bot & crawl policy", "passed": 3, "counted": 3 },
{ "id": "api", "name": "API", "passed": 2, "counted": 3 },
{ "id": "mcp", "name": "MCP", "passed": 4, "counted": 6 },
{ "id": "agent-discovery-auth", "name": "Agent discovery & auth", "passed": 3, "counted": 3 }
]coverage_summary
How many checks applied at each keyword level and how many passed. n_a / skip / error checks are excluded from the totals.
"coverage_summary": {
"must": { "total": 2, "verified": 2 },
"should": { "total": 15, "verified": 9 },
"may": { "total": 10, "verified": 7 }
}summary
A tally of every check by its final status.
"summary": { "pass": 23, "noncompliant": 3, "broken": 2, "absent": 4, "n_a": 7, "skip": 0, "error": 0 }results
One object per check.
{
"id": "llms-txt",
"label": "/llms.txt present with a summary and link index",
"category": "content-for-agents",
"group": "P2",
"layer": "web",
"keyword": "should",
"tier": "recommended",
"principle": "P2",
"status": "pass",
"evidence": "https://example.com/llms.txt -> 200"
}| Field | Type | Meaning |
|---|---|---|
id | string | The check id from the registry (e.g. llms-txt, mcp-initialize, mcp-modern-tools-list). The remediation-catalog and fix-skill key. |
label | string | Human-readable check title. |
category | string | The visible category slug (one of the categories[].id values). Drives the display grouping. |
group | string | Mirrors principle for shared-renderer compatibility. |
layer | string | Always web for a web scorecard row. |
keyword | string | must, should, or may, derived from the check's tier. |
tier | string | required, recommended, or optional (the keyword's source). |
principle | string | Internal principle tag P1 through P8. Kept as data; web surfaces neither display nor link it. |
status | string | pass, noncompliant, broken, absent, n_a, skip, or error. noncompliant = works but violates a spec detail; broken = present but invalid; absent = not there. See statuses. |
na_reason | string | Present only on n_a rows: antecedent-unmet (the check does not apply to this site), optional-absent (an applicable MAY not implemented), or posture-consistent (a deliberate, consistent opt-out of the probed surface pair). Absent on handler-emitted n_a rows with nothing to probe. |
unprobed | boolean | Present only when true: the row settled from an antecedent the audit did observe rather than from its own request, so the run holds no observation of the surface itself. It still scores, and it carries no remediation object, because a fix prompt would name a defect nothing observed. |
evidence | string | null | A compact human-readable summary of what the probe observed. |
Statuses
pass— the surface is present and valid.noncompliant— the surface works and an agent calling it gets the outcome it asked for, but a spec detail is violated. On the MCP family this is a well-formed JSON-RPC refusal carrying the wrong error code, or a correct refusal missing a required payload field. Scores above absent and well below pass.broken— the surface exists but is invalid (malformed body, wrong content-type, an unexpected status where the surface clearly exists). Scores below absent.absent— the surface is not there (404/410, no DNS records, no CORS headers).n_a— excluded from both scores;na_reasonsays why:antecedent-unmet(does not apply to this site),optional-absent(an applicable MAY not implemented), orposture-consistent(the CORS pair's deliberate no-CORS posture, withAccess-Control-Allow-Originon neither the preflight nor the POST). A handler with nothing to probe (no discovered MCP endpoint) emitsn_awith nona_reason.skip— the per-audit deadline passed before the check ran.error— an operational failure (network error, timeout); never credited, never penalized.
Remediation on the MCP surface
Scorecard rows carry no remediation; the fix guidance is assembled at read time. Both the audit_website and get_website_audit MCP tools return each row with a derived result line, and non-passing (noncompliant / broken / absent) rows additionally carry an inline remediation object:
"remediation": {
"goal": "Publish an OpenAPI description so non-MCP agents can call your API",
"fix": "Publish an OpenAPI 3.1 description at /openapi.json ...",
"skill_url": "https://anc.dev/web-audit/skill/openapi",
"resources": [{ "label": "OpenAPI 3.1", "url": "https://spec.openapis.org/oas/latest.html" }],
"prompt": "Goal: ...\nIssue: <this run's evidence>\nFix: ...\nSkill: ...\nDocs: ..."
}The same object is available by check id from get_web_remediation(check_id, evidence?), and each skill_url resolves to a fix-skill page with a markdown twin.
Evidence by probe type
Each check runs one of the probe handlers. The compact results[].evidence string is derived from the handler's structured evidence, which differs by handler:
- http — the resolved URL, the HTTP status, whether the assertion passed, and the failing reason when it did not. The canonical-redirect rule (the MCP server card) additionally records a per-alias verdict.
- cors-preflight — both probes of the CORS posture pair: a row per probe (tagged
probe: preflight/probe: post) with the URL, status, and theAccess-Control-Allow-Originvalue, plus-Methods/-Headerson the preflight row. The classified surface's own row leads and carries the verdict'swhy. - mcp — the endpoint, status, and the op-specific facts:
serverInfoandprotocolVersionforinitialize, the tool names and input-schema count fortools-list(legacy and modern header-routed alike), the supported protocol versions andserverInfoidentity forserver/discover, or the error code for the unknown-method probe or an era-shaped refusal. - dns-doh — the queried name, the resolver, the DNS status code, and the answer count.
- auth-md / webmcp / scoped-llms — the probed URLs (or root-HTML markers) and per-candidate outcomes.
Relationship to the CLI scorecard and the spec
The web scorecard is intentionally site-owned and not part of the agentnative spec. Formalizing the web shape into the spec is deferred until a second consumer exists. Until then, this page is the one published contract for the web scorecard JSON. The parallel CLI contract is /scorecard-schema.