{
  "name": "isittrustready readiness rubric",
  "version": "0.6.1",
  "url": "https://www.isittrustready.ai/rubric",
  "description": "The open standard behind every TrustScore. The headline is a single COMPOSITE agent-readiness score — a weighted blend of three axes (Trust 50% · Access 30% · MCP 20%), renormalized when an axis is N/A. The three axes are SCORED SEPARATELY as the component breakdown and never cross-contaminate (MCP never feeds Trust): TRUST (verifiable identity, alignment, attestation, accountability, delegation), ACCESS / discoverability (can an agent find, read, and connect to the service), and MCP (capability quality of an associated MCP server — N/A when none). Anchored on neutral third-party specifications.",
  "basis": {
    "standard": "A formal, third-party standards-body specification exists (an RFC, W3C Recommendation, OASIS, schema.org, the OpenAPI / sitemaps protocols). The artifact is judged against a neutral spec.",
    "convention": "An emerging community or vendor convention with no standards-body specification yet (e.g. the agent-card / MCP-card / llms.txt / agents.txt / alignment-card / readiness-status conventions, or an IETF draft). Honest labeling — not a demerit; scoring is unaffected."
  },
  "stability": "The rubric is versioned with semver (the `rubricVersion` on every result). Immutable result permalinks (/r/<domain>/<scanId>) freeze the rubric version they were graded under, so a published historical grade never silently re-grades when the rubric changes; a fresh scan always states its current version.",
  "axes": {
    "trust": {
      "primary": true,
      "title": "Trust",
      "description": "Can an agent trust who/what this is? The primary, headline axis. The 5 categories hold both the website checks and the MCP-server checks folded in (server identity/signed artifacts → identity, provenance → attestation, alignment + honesty → alignment, auth boundary → delegation, accountability → accountability); the MCP ones are N/A without an associated server.",
      "scoring": {
        "checkScores": {
          "pass": 1,
          "partial": 0.5,
          "fail": 0,
          "error": 0
        },
        "scoringContribution": {
          "byMaturity": {
            "established": "scored",
            "emerging": "scored"
          },
          "rules": {
            "scored": "Trust-axis check — counted equally in the category mean (pass=1, partial=0.5, fail=0). A partial or fail LOWERS the score; maturity is informational on the trust axis and does not change scoring."
          }
        },
        "notApplicable": "A check is N/A (excluded from scoring, not failed) when the service honestly declares it does not offer that capability — e.g. the OAuth-discovery checks when /auth.md declares no delegated/OAuth authorization. A fully-N/A category is dropped and the remaining category weights are renormalized.",
        "categoryScore": "mean(applicable check scores) * 100",
        "overall": "weighted mean over applicable categories (weights renormalized)",
        "grades": {
          "A+": "score >= 90 AND identity.agent-card-signed = pass",
          "A": "score >= 85",
          "B": "score >= 70",
          "C": "score >= 55",
          "D": "score >= 40",
          "F": "score < 40"
        },
        "caps": [
          "identity category scoring 0 caps the grade at F",
          "an unsigned or missing agent card caps the grade at B"
        ]
      },
      "categories": [
        {
          "id": "identity",
          "title": "Verifiable identity",
          "weight": 0.25,
          "blurb": "Can an agent prove who this is — and is that proof cryptographic?"
        },
        {
          "id": "alignment",
          "title": "Alignment & values",
          "weight": 0.2,
          "blurb": "Are the operator's declared values, scope, and capabilities published and machine-readable?"
        },
        {
          "id": "attestation",
          "title": "Attestation & provenance",
          "weight": 0.2,
          "blurb": "Are claims backed by signed attestations and verifiable provenance?"
        },
        {
          "id": "accountability",
          "title": "Accountability",
          "weight": 0.2,
          "blurb": "Is there a way to report, audit, and verify behaviour over time?"
        },
        {
          "id": "delegation",
          "title": "Delegation & auth",
          "weight": 0.15,
          "blurb": "Can an agent discover how to authenticate and act on a user's behalf, correctly?"
        }
      ],
      "checks": [
        {
          "id": "identity.agent-card",
          "category": "identity",
          "title": "Publishes an A2A agent card",
          "maturity": "emerging",
          "basis": "convention",
          "specUrl": "https://a2a-protocol.org/latest/specification/",
          "surfacePath": "/.well-known/agent-card.json",
          "fixPrompt": "Create a file served at https://<your-domain>/.well-known/agent-card.json with Content-Type: application/json. Minimal valid A2A card:\n{\n  \"protocolVersion\": \"0.3.0\",\n  \"name\": \"<Your service name>\",\n  \"description\": \"<What this agent/service does>\",\n  \"url\": \"https://<your-domain>\",\n  \"capabilities\": { \"streaming\": false },\n  \"skills\": [{ \"id\": \"search\", \"name\": \"Search\", \"description\": \"<one concrete skill>\" }],\n  \"securitySchemes\": {}\n}\nVerify: `curl -sI https://<your-domain>/.well-known/agent-card.json` returns 200 + application/json. Spec: https://a2a-protocol.org/latest/specification/"
        },
        {
          "id": "identity.agent-card-signed",
          "category": "identity",
          "title": "Agent card is cryptographically verifiable (signed / DID / VC)",
          "maturity": "emerging",
          "basis": "standard",
          "specUrl": "https://www.w3.org/TR/vc-data-model-2.0/",
          "surfacePath": "/.well-known/agent-card.json",
          "fixPrompt": "Make /.well-known/agent-card.json tamper-evident by adding a cryptographic binding the scanner recognizes — ANY of: (a) a JWS in a top-level `signatures` array (A2A AgentCardSignature[]), (b) a W3C VC `proof` object, (c) a top-level `jws` string, or (d) a `did:`-prefixed `id`/`issuer`/`controller`. Example (a):\n\"signatures\": [{ \"protected\": \"<base64url JWS header>\", \"signature\": \"<base64url sig>\" }]\nGenerate the JWS over the card with your signing key (e.g. an Ed25519/ES256 JWK). Verify: re-fetch the card and confirm the `signatures`/`proof`/`did:` field is present and validates. Spec: https://www.w3.org/TR/vc-data-model-2.0/",
          "productLink": "https://www.mnemom.ai/what-we-prove/"
        },
        {
          "id": "identity.mcp-server-card",
          "category": "identity",
          "title": "Publishes an MCP server card (if it runs MCP)",
          "maturity": "emerging",
          "basis": "convention",
          "specUrl": "https://modelcontextprotocol.io/",
          "surfacePath": "/.well-known/mcp/server-card.json",
          "fixPrompt": "If you run an MCP server, advertise it at https://<your-domain>/.well-known/mcp/server-card.json (Content-Type: application/json). Minimal card:\n{\n  \"name\": \"<Your MCP server>\",\n  \"version\": \"1.0.0\",\n  \"transport\": \"streamable-http\",\n  \"url\": \"https://<your-domain>/mcp\",\n  \"tools\": [{ \"name\": \"<tool_name>\", \"description\": \"<what it does>\" }]\n}\nVerify: `curl -s https://<your-domain>/.well-known/mcp/server-card.json` returns the card with a name + tools. (If you don't run MCP, skip — this check is upside-only.) Spec: https://modelcontextprotocol.io/"
        },
        {
          "id": "alignment.card",
          "category": "alignment",
          "title": "Publishes an alignment / values card",
          "maturity": "emerging",
          "basis": "convention",
          "specUrl": "https://github.com/mnemom/aap",
          "surfacePath": "/.well-known/alignment-card.json",
          "fixPrompt": "Publish https://<your-domain>/.well-known/alignment-card.json (application/json) declaring your values AND scope AND refusals. Recognized shapes: top-level `values`/`principles` plus EITHER `scope`/`permitted_scope`/`boundaries` and `must_refuse`/`prohibited`, OR an AAP `autonomy_envelope` with `bounded_actions`+`forbidden_actions`. Example:\n{\n  \"values\": [\"honesty\", \"user-safety\"],\n  \"autonomy_envelope\": {\n    \"bounded_actions\": [\"read public data\", \"answer questions\"],\n    \"forbidden_actions\": [\"make payments\", \"delete user data\"]\n  }\n}\nVerify: `curl -s https://<your-domain>/.well-known/alignment-card.json` shows values + scope + refusals. Spec: https://github.com/mnemom/aap",
          "productLink": "https://www.mnemom.ai/governance/"
        },
        {
          "id": "alignment.capabilities",
          "category": "alignment",
          "title": "Declared capabilities are present and coherent",
          "maturity": "emerging",
          "basis": "convention",
          "specUrl": "https://a2a-protocol.org/latest/specification/",
          "surfacePath": "/.well-known/agent-card.json",
          "fixPrompt": "In /.well-known/agent-card.json, populate either a non-empty `capabilities` object or a non-empty `skills` array so a calling agent knows what this one can do. Example:\n\"skills\": [\n  { \"id\": \"search\", \"name\": \"Search\", \"description\": \"Full-text search over docs\" },\n  { \"id\": \"summarize\", \"name\": \"Summarize\", \"description\": \"Summarize a URL\" }\n]\nVerify: `curl -s https://<your-domain>/.well-known/agent-card.json` shows ≥1 concrete skill/capability. Spec: https://a2a-protocol.org/latest/specification/"
        },
        {
          "id": "attestation.signed",
          "category": "attestation",
          "title": "Publishes signed attestations / verifiable credentials",
          "maturity": "emerging",
          "basis": "standard",
          "specUrl": "https://www.w3.org/TR/vc-data-model-2.0/",
          "surfacePath": "/.well-known/attestations.json",
          "fixPrompt": "Publish https://<your-domain>/.well-known/attestations.json (application/json) — an array (or {credentials:[…]}/{attestations:[…]}) of W3C Verifiable Credentials, each carrying a `proof` object (or `jws`/`signatures`). Example:\n[{\n  \"type\": [\"VerifiableCredential\"],\n  \"issuer\": \"did:web:<your-domain>\",\n  \"credentialSubject\": { \"id\": \"https://<your-domain>\", \"claim\": \"<what you attest>\" },\n  \"proof\": { \"type\": \"DataIntegrityProof\", \"proofValue\": \"<sig>\" }\n}]\nVerify: `curl -s https://<your-domain>/.well-known/attestations.json` returns ≥1 credential WITH a proof/jws. Spec: https://www.w3.org/TR/vc-data-model-2.0/",
          "productLink": "https://www.mnemom.ai/what-we-prove/"
        },
        {
          "id": "attestation.provenance",
          "category": "attestation",
          "title": "Build / behaviour provenance (Sigstore / SLSA)",
          "maturity": "emerging",
          "basis": "standard",
          "specUrl": "https://slsa.dev/",
          "surfacePath": "/.well-known/provenance.json",
          "fixPrompt": "Publish https://<your-domain>/.well-known/provenance.json (application/json) — a SLSA/in-toto statement, ideally Sigstore/DSSE-signed. Recognized: a `predicateType`+`predicate` (in-toto) or a `dsseEnvelope`, plus `dsseEnvelope`/`signatures` to be a PASS (unsigned = partial). Example:\n{\n  \"_type\": \"https://in-toto.io/Statement/v1\",\n  \"predicateType\": \"https://slsa.dev/provenance/v1\",\n  \"predicate\": { \"buildDefinition\": { /* … */ } },\n  \"dsseEnvelope\": { \"payload\": \"<base64>\", \"signatures\": [{ \"sig\": \"<sig>\" }] }\n}\nGenerate with `slsa-generator` or `cosign attest`. Verify: `curl -s …/provenance.json` shows the predicate + a signature/DSSE envelope. Spec: https://slsa.dev/"
        },
        {
          "id": "accountability.security-txt",
          "category": "accountability",
          "title": "Serves security.txt",
          "maturity": "established",
          "basis": "standard",
          "specUrl": "https://www.rfc-editor.org/rfc/rfc9116",
          "surfacePath": "/.well-known/security.txt",
          "fixPrompt": "Create https://<your-domain>/.well-known/security.txt (Content-Type: text/plain). Set a real Contact and an Expires < 1 year out (ISO 8601). Template:\nContact: mailto:security@<your-domain>\nExpires: 2027-01-01T00:00:00Z\nCanonical: https://<your-domain>/.well-known/security.txt\nVerify: `curl -s https://<your-domain>/.well-known/security.txt` shows the Contact: and Expires: lines. Spec: https://www.rfc-editor.org/rfc/rfc9116"
        },
        {
          "id": "accountability.status",
          "category": "accountability",
          "title": "Publishes a dated, signed re-verification status",
          "maturity": "emerging",
          "basis": "convention",
          "specUrl": "https://www.mnemom.ai/for-agents/",
          "surfacePath": "/agent-readiness-status.json",
          "fixPrompt": "Publish https://<your-domain>/agent-readiness-status.json (application/json) carrying BOTH a date field (lastVerified/verifiedAt/updatedAt/generatedAt) and a verdict field (status/grade/verdict/ready/score), refreshed on a schedule (e.g. a daily CI job). Example:\n{\n  \"status\": \"ready\",\n  \"grade\": \"A\",\n  \"lastVerified\": \"2026-06-11T00:00:00Z\",\n  \"rubric\": \"https://www.isittrustready.ai/rubric\"\n}\nVerify: `curl -s https://<your-domain>/agent-readiness-status.json` shows a recent date + a status/grade. Spec: https://www.mnemom.ai/for-agents/",
          "productLink": "https://www.mnemom.ai/for-agents/"
        },
        {
          "id": "accountability.advisories",
          "category": "accountability",
          "title": "Publishes advisories / a STIX IoC feed",
          "maturity": "emerging",
          "basis": "standard",
          "specUrl": "https://oasis-open.github.io/cti-documentation/stix/intro",
          "surfacePath": "/.well-known/advisories.json",
          "fixPrompt": "Publish https://<your-domain>/.well-known/advisories.json (application/json) — a JSON array of advisories, an `{advisories:[…]}` object, or a STIX 2.1 bundle. Example (STIX 2.1):\n{\n  \"type\": \"bundle\",\n  \"objects\": [{ \"type\": \"indicator\", \"name\": \"<advisory>\", \"pattern\": \"[…]\", \"valid_from\": \"2026-06-11T00:00:00Z\" }]\n}\nAn empty array is valid (no current advisories). Verify: `curl -s …/advisories.json` parses as a feed/STIX bundle. Spec: https://oasis-open.github.io/cti-documentation/stix/intro"
        },
        {
          "id": "delegation.protected-resource",
          "category": "delegation",
          "title": "OAuth protected-resource metadata",
          "maturity": "established",
          "basis": "standard",
          "specUrl": "https://www.rfc-editor.org/rfc/rfc9728",
          "surfacePath": "/.well-known/oauth-protected-resource",
          "fixPrompt": "Publish https://<your-domain>/.well-known/oauth-protected-resource (application/json) naming your authorization server(s) so agents discover how to authenticate. Example:\n{\n  \"resource\": \"https://<your-domain>\",\n  \"authorization_servers\": [\"https://auth.<your-domain>\"]\n}\nVerify: `curl -s https://<your-domain>/.well-known/oauth-protected-resource` lists a non-empty `authorization_servers`. (If your service has NO delegated/OAuth auth, declare that in /auth.md instead — this check then becomes N/A, not a fail.) Spec: https://www.rfc-editor.org/rfc/rfc9728"
        },
        {
          "id": "delegation.auth-server",
          "category": "delegation",
          "title": "OAuth authorization-server metadata",
          "maturity": "established",
          "basis": "standard",
          "specUrl": "https://www.rfc-editor.org/rfc/rfc8414",
          "surfacePath": "/.well-known/oauth-authorization-server",
          "fixPrompt": "Publish https://<your-auth-server>/.well-known/oauth-authorization-server (application/json) with issuer, endpoints, and jwks_uri so token issuance is discoverable. Example:\n{\n  \"issuer\": \"https://auth.<your-domain>\",\n  \"authorization_endpoint\": \"https://auth.<your-domain>/authorize\",\n  \"token_endpoint\": \"https://auth.<your-domain>/token\",\n  \"jwks_uri\": \"https://auth.<your-domain>/.well-known/jwks.json\"\n}\nVerify: `curl -s …/.well-known/oauth-authorization-server` has issuer + an endpoint + jwks_uri. (N/A if you declare no delegated/OAuth auth in /auth.md.) Spec: https://www.rfc-editor.org/rfc/rfc8414"
        },
        {
          "id": "delegation.auth-doc",
          "category": "delegation",
          "title": "Documents agent authentication",
          "maturity": "emerging",
          "basis": "convention",
          "specUrl": "https://github.com/workos/auth.md",
          "surfacePath": "/auth.md",
          "fixPrompt": "Publish https://<your-domain>/auth.md (Markdown, ≥200 chars) documenting your real auth schemes (OAuth/token/bearer) and the agent registration flow — OR, if you have none, state that explicitly (the phrase \"no delegated\" or \"no OAuth\" makes the OAuth-discovery checks N/A instead of failures). Template:\n# Agent authentication\n\nThis service uses <OAuth 2.1 / API keys / NO delegated auth>.\n- Register: <how an agent obtains credentials>\n- Token endpoint: <url or 'n/a'>\n- Scopes: <list or 'n/a'>\nVerify: `curl -s https://<your-domain>/auth.md | head` shows a substantive auth guide. Spec: https://github.com/workos/auth.md"
        },
        {
          "id": "mcp.identity.server-info",
          "axis": "trust",
          "category": "identity",
          "subjectScope": "mcp-server",
          "title": "initialize advertises server identity",
          "maturity": "established",
          "basis": "standard",
          "specUrl": "https://modelcontextprotocol.io/specification",
          "source": "MCP spec; Gauntlet C20",
          "fixPrompt": "Make your MCP `initialize` response advertise a clear identity: a non-empty `serverInfo.name` and `serverInfo.version`, plus a non-empty top-level `instructions` string telling an arriving agent what the server is for. Verify: a JSON-RPC `initialize` call returns `result.serverInfo.name`, `result.serverInfo.version`, and `result.instructions`. Spec: https://modelcontextprotocol.io/specification"
        },
        {
          "id": "mcp.identity.signed-artifacts",
          "axis": "trust",
          "category": "identity",
          "subjectScope": "mcp-server",
          "title": "Exposes cryptographically verifiable artifacts",
          "maturity": "established",
          "basis": "standard",
          "specUrl": "https://www.w3.org/TR/vc-data-integrity/",
          "source": "Gauntlet C17/C29",
          "fixPrompt": "Publish at least one signed resource an agent can verify in-band. Advertise a JWKS resource (Ed25519, kty=OKP, crv=Ed25519) and serve resources whose body carries a detached Ed25519/JCS signature (`signature`/`jws`) OR an embedded W3C Data Integrity proof (`eddsa-jcs-2022`, did:key), each verifiable against that JWKS. Verify: fetch the resource, strip envelope fields, and the signature verifies against the published key; a tampered copy MUST fail. Spec: https://www.w3.org/TR/vc-data-integrity/"
        },
        {
          "id": "mcp.provenance.attestation",
          "axis": "trust",
          "category": "attestation",
          "subjectScope": "mcp-server",
          "title": "Offers verifiable provenance / attestation",
          "maturity": "emerging",
          "basis": "standard",
          "specUrl": "https://modelcontextprotocol.io/specification",
          "source": "Gauntlet C19/C25",
          "fixPrompt": "Expose a verifiable provenance path: either a signed scorecard/certificate whose Ed25519 signature verifies in-band, or an append-only attestation (hash-chain + merkle root) that proves a claim derives from an unbroken checkpoint chain. Verify: a real artifact verifies (hash_chain_valid / signature ok) and a bogus/altered one is rejected. Spec: https://modelcontextprotocol.io/specification"
        },
        {
          "id": "mcp.alignment.card",
          "axis": "trust",
          "category": "alignment",
          "subjectScope": "mcp-server",
          "title": "Declares values / scope (alignment card or equivalent)",
          "maturity": "emerging",
          "basis": "convention",
          "specUrl": "https://a2a-protocol.org/latest/specification/",
          "source": "Mnemom alignment-card convention (vendor-neutral; A2A card or equivalent also passes)",
          "fixPrompt": "Publish a machine-readable declaration of what this server is allowed to do — values/principles plus scope and/or refusals. Any of these satisfies it: an A2A agent card with capabilities, an alignment/values card, or an equivalent published document. Open-sourcing the implementation is NOT required. Verify: a documented URL returns a structured values/scope declaration. Spec: https://a2a-protocol.org/latest/specification/"
        },
        {
          "id": "mcp.alignment.known-limitations",
          "axis": "trust",
          "category": "alignment",
          "subjectScope": "mcp-server",
          "title": "Declares known limitations / non-goals",
          "maturity": "emerging",
          "basis": "convention",
          "specUrl": "https://isittrustready.ai/non-goals.json",
          "source": "Mnemom signed-known-limitations; IITR /non-goals.json",
          "fixPrompt": "Publish an honest, machine-readable statement of what this server does NOT do or guarantee (its known limitations / non-goals). Ideally sign it. This is on-brand transparency, not a demerit — declaring a limit scores; hiding it does not. Verify: a documented URL/resource lists known limitations or non-goals. Spec: https://isittrustready.ai/non-goals.json"
        },
        {
          "id": "mcp.honesty.descriptions-accurate",
          "axis": "trust",
          "category": "alignment",
          "subjectScope": "mcp-server",
          "title": "Tools do what they say (output matches declared schema)",
          "maturity": "established",
          "basis": "standard",
          "specUrl": "https://json-schema.org/",
          "source": "Gauntlet C11/C12",
          "fixPrompt": "Make tool behaviour match its description and declared `outputSchema`: every readable tool's live `structuredContent` must validate (strict) against the schema it declares, and descriptions must not overclaim. Verify: call each public-read tool and validate its `structuredContent` against its own `outputSchema` with a JSON-Schema validator (AJV) — no drift. Spec: https://json-schema.org/"
        },
        {
          "id": "mcp.auth.prm",
          "axis": "trust",
          "category": "delegation",
          "subjectScope": "mcp-server",
          "title": "Serves coherent RFC 9728 protected-resource metadata",
          "maturity": "established",
          "basis": "standard",
          "specUrl": "https://www.rfc-editor.org/rfc/rfc9728",
          "source": "RFC 9728; Gauntlet C5",
          "fixPrompt": "Serve `/.well-known/oauth-protected-resource/mcp` returning `{ \"resource\": \"<base>/mcp\", \"authorization_servers\": [\"<issuer>\"] }`, and serve the authorization-server metadata at the named issuer. The PRM `resource` MUST equal your MCP endpoint, and `authorization_servers` MUST include the real issuer. Verify: `curl -s <base>/.well-known/oauth-protected-resource/mcp` shows resource=<base>/mcp and a non-empty authorization_servers. Spec: https://www.rfc-editor.org/rfc/rfc9728"
        },
        {
          "id": "mcp.auth.fail-closed",
          "axis": "trust",
          "category": "delegation",
          "subjectScope": "mcp-server",
          "title": "Authed / write tools fail closed",
          "maturity": "established",
          "basis": "standard",
          "specUrl": "https://www.rfc-editor.org/rfc/rfc9728",
          "source": "RFC 9728 / OAuth; Gauntlet C6",
          "fixPrompt": "An anonymous call to a tool that mutates state or reads private data MUST return transport HTTP 401 with a `WWW-Authenticate` header pointing at your protected-resource metadata — not a 200 with an error body, and never silent success. Verify: an unauthenticated `tools/call` of an authed tool returns 401 + `WWW-Authenticate: Bearer resource_metadata=\"<base>/.well-known/oauth-protected-resource/mcp\"`. Spec: https://www.rfc-editor.org/rfc/rfc9728"
        },
        {
          "id": "mcp.auth.least-privilege-reads",
          "axis": "trust",
          "category": "delegation",
          "subjectScope": "mcp-server",
          "title": "Public reads leak no private/owner data",
          "maturity": "established",
          "basis": "convention",
          "specUrl": "https://modelcontextprotocol.io/specification",
          "source": "Gauntlet C8/C9",
          "fixPrompt": "Every tool reachable without credentials must return only public, no-PII fields — an anonymous caller must never receive owner/account metadata (e.g. key prefixes, internal ids). Scope private detail behind auth; return the minimal public projection to anon. Verify: call each anon-reachable read tool with no credentials and confirm the response carries no owner/private fields. Spec: https://modelcontextprotocol.io/specification"
        },
        {
          "id": "mcp.auth.dcr-loopback",
          "axis": "trust",
          "category": "delegation",
          "subjectScope": "mcp-server",
          "title": "Dynamic Client Registration handles loopback safely",
          "maturity": "emerging",
          "basis": "standard",
          "specUrl": "https://www.rfc-editor.org/rfc/rfc8252",
          "source": "RFC 7591/8252; Gauntlet C10",
          "fixPrompt": "If you support OAuth Dynamic Client Registration, accept loopback redirect URIs (`http://localhost`, `http://127.0.0.1`) as public clients (201, no client_secret) and REJECT non-loopback/insecure redirects (400 invalid_redirect_uri). Verify: POST /register with a localhost redirect → 201 public client; with a non-loopback host → 400. (N/A if you do not support DCR.) Spec: https://www.rfc-editor.org/rfc/rfc8252"
        },
        {
          "id": "mcp.accountability.tamper-evidence",
          "axis": "trust",
          "category": "accountability",
          "subjectScope": "mcp-server",
          "title": "Verification discriminates real from tampered",
          "maturity": "established",
          "basis": "standard",
          "specUrl": "https://www.w3.org/TR/vc-data-integrity/",
          "source": "Gauntlet C19/C21/C25/C29",
          "fixPrompt": "If your server offers any verify/attestation tool, it must DISCRIMINATE: a valid artifact returns verified:true, a tampered one returns verified:false as a SUCCESSFUL answer (not an error). A verifier that 'confirms' a forgery is worthless. Verify: verify a real artifact (true) and a tampered copy (false, isError:false). Spec: https://www.w3.org/TR/vc-data-integrity/"
        },
        {
          "id": "mcp.accountability.error-hygiene",
          "axis": "trust",
          "category": "accountability",
          "subjectScope": "mcp-server",
          "title": "Well-formed errors, no internal leakage",
          "maturity": "established",
          "basis": "standard",
          "specUrl": "https://www.jsonrpc.org/specification",
          "source": "MCP / JSON-RPC spec; Gauntlet C13",
          "fixPrompt": "Return well-formed JSON-RPC 2.0 errors (unknown method/tool → proper error object; tool failures → isError envelope) and never leak internal conformance signals (no `undocumented_status_code` / `spec_deviation` fields) to clients. Verify: an unknown tool returns a JSON-RPC error; no response carries internal spec-deviation fields. Spec: https://www.jsonrpc.org/specification"
        },
        {
          "id": "mcp.accountability.cache-transparency",
          "axis": "trust",
          "category": "accountability",
          "subjectScope": "mcp-server",
          "title": "Discloses caching / freshness honestly",
          "maturity": "emerging",
          "basis": "convention",
          "specUrl": "https://modelcontextprotocol.io/specification",
          "source": "Gauntlet C30",
          "fixPrompt": "If a tool can serve cached results, disclose it (a `cached` field) and honour a freshness override (e.g. `fresh:true` ⇒ a live result, `cached:false`). Agents must be able to tell a cached answer from a live one. Verify: a result discloses `cached`; calling with fresh:true returns cached:false (or no cache marker). Spec: https://modelcontextprotocol.io/specification"
        },
        {
          "id": "mcp.accountability.maintainer-contact",
          "axis": "trust",
          "category": "accountability",
          "subjectScope": "mcp-server",
          "title": "Accountable maintainer contact",
          "maturity": "emerging",
          "basis": "convention",
          "specUrl": "https://github.com/modelcontextprotocol/registry",
          "source": "Braille-discovered (Glama listing failure); Cloudflare public-MCP-repo practice",
          "fixPrompt": "Publish a real, reachable maintainer contact for the server (e.g. a role email like `mcp@<org>`) in your canonical home / server metadata, so an agent or user can report problems and reach an accountable owner. Verify: the server's documented home / `server.json` names a reachable maintainer contact. Spec: https://github.com/modelcontextprotocol/registry"
        }
      ]
    },
    "access": {
      "primary": false,
      "title": "Access / Discoverability",
      "description": "Can an agent find, read, understand the AI policy of, discover the capabilities of, and learn to authorize against this service? Scored separately from Trust. The 5 website categories are followed by 3 appended MCP-server categories (protocol hygiene, discoverability, breadth) that are N/A without an associated server.",
      "scoring": {
        "checkScores": {
          "pass": 1,
          "partial": 0.5,
          "fail": 0,
          "error": 0
        },
        "maturityWeighting": "Established checks dominate; emerging checks are upside-only. Per category: base = mean(established applicable checks) * 100; bonus = (100 - base) * mean(emerging applicable checks) * 0.5; categoryScore = base + bonus. A passing emerging check can RAISE a category; a failed, absent, or partial one can NEVER lower it.",
        "scoringContribution": {
          "byMaturity": {
            "established": "floor",
            "emerging": "upside-only"
          },
          "rules": {
            "floor": "Established check — included in the category floor (the mean of established checks, scaled to 0–100). A partial or fail LOWERS the category score.",
            "upside-only": "Emerging check — upside-only. A pass RAISES the category score (it closes part of the gap to 100), but a partial, fail, or absence can NEVER lower it. Adopting a low-penetration draft can only help."
          }
        },
        "policyNeutral": "The AI-access-policy checks reward declaring an explicit, parseable policy — they never reward openness nor penalize a site for choosing to disallow AI. We score the declaration, not the stance.",
        "notApplicable": "The authorization-discovery category goes N/A (excluded, not failed) when the service declares no delegated/OAuth authorization; remaining category weights are renormalized.",
        "overall": "weighted mean over applicable categories (weights renormalized)",
        "grades": {
          "A+": "score >= 90",
          "A": "score >= 85",
          "B": "score >= 70",
          "C": "score >= 55",
          "D": "score >= 40",
          "F": "score < 40"
        }
      },
      "categories": [
        {
          "id": "crawl-discoverability",
          "title": "Crawl discoverability",
          "weight": 0.25,
          "blurb": "Can a crawler find the site's content and map (robots, sitemap, link relations)?"
        },
        {
          "id": "content-access",
          "title": "Agent content access",
          "weight": 0.2,
          "blurb": "Can an agent read the content efficiently and structured (markdown, llms.txt, JSON-LD)?"
        },
        {
          "id": "ai-access-policy",
          "title": "AI access policy",
          "weight": 0.15,
          "blurb": "Has the operator published an explicit, parseable AI-access policy (any stance)?"
        },
        {
          "id": "capability-discovery",
          "title": "Capability discovery",
          "weight": 0.25,
          "blurb": "Can an agent programmatically discover the site's APIs and tools (catalog, OpenAPI, MCP)?"
        },
        {
          "id": "authorization-discovery",
          "title": "Authorization discovery",
          "weight": 0.15,
          "blurb": "If the site exposes APIs, can an agent discover how to authenticate (OAuth metadata)?"
        },
        {
          "id": "mcp-protocol-hygiene",
          "axis": "access",
          "subjectScope": "mcp-server",
          "title": "Protocol hygiene",
          "weight": 0.35,
          "blurb": "Does the server speak MCP correctly — initialize, advertised capabilities, well-formed lists?"
        },
        {
          "id": "mcp-discoverability",
          "axis": "access",
          "subjectScope": "mcp-server",
          "title": "Discoverability",
          "weight": 0.4,
          "blurb": "Can an arriving agent self-onboard with zero context, and is there one canonical public home?"
        },
        {
          "id": "mcp-breadth",
          "axis": "access",
          "subjectScope": "mcp-server",
          "title": "Breadth of publishing",
          "weight": 0.25,
          "blurb": "Meaningful presence in the canonical registry + reachable in-product. Upside-only; never a trust signal."
        }
      ],
      "checks": [
        {
          "id": "access.robots_present",
          "category": "crawl-discoverability",
          "title": "Serves a parseable robots.txt",
          "maturity": "established",
          "basis": "standard",
          "specUrl": "https://www.rfc-editor.org/rfc/rfc9309.html",
          "surfacePath": "/robots.txt",
          "fixPrompt": "Serve a valid RFC 9309 file at https://<your-domain>/robots.txt (Content-Type: text/plain). Minimal:\nUser-agent: *\nAllow: /\nSitemap: https://<your-domain>/sitemap.xml\nVerify: `curl -s https://<your-domain>/robots.txt` returns text/plain robots rules (not an HTML page). Spec: https://www.rfc-editor.org/rfc/rfc9309.html"
        },
        {
          "id": "access.sitemap",
          "category": "crawl-discoverability",
          "title": "Publishes a sitemap",
          "maturity": "established",
          "basis": "standard",
          "specUrl": "https://www.sitemaps.org/protocol.html",
          "surfacePath": "/sitemap.xml",
          "fixPrompt": "Publish https://<your-domain>/sitemap.xml (Content-Type: application/xml) and reference it from robots.txt (`Sitemap: https://<your-domain>/sitemap.xml`). Minimal:\n<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<urlset xmlns=\"http://www.sitemaps.org/schemas/sitemap/0.9\">\n  <url><loc>https://<your-domain>/</loc></url>\n</urlset>\nVerify: `curl -s https://<your-domain>/sitemap.xml | head` is XML with <urlset>. Spec: https://www.sitemaps.org/protocol.html"
        },
        {
          "id": "access.link_headers",
          "category": "crawl-discoverability",
          "title": "Emits HTTP Link relations",
          "maturity": "established",
          "basis": "standard",
          "specUrl": "https://www.rfc-editor.org/rfc/rfc8288.html",
          "surfacePath": "/",
          "fixPrompt": "Emit an RFC 8288 `Link` response header on your homepage (https://<your-domain>/) pointing to typed relations. Add at your edge/server, e.g.:\nLink: </.well-known/api-catalog>; rel=\"api-catalog\", </openapi.json>; rel=\"service-desc\"\nVerify: `curl -sI https://<your-domain>/ | grep -i ^link` shows a Link header with rel values. Spec: https://www.rfc-editor.org/rfc/rfc8288.html"
        },
        {
          "id": "access.markdown_negotiation",
          "category": "content-access",
          "title": "Serves markdown via content negotiation",
          "maturity": "emerging",
          "basis": "convention",
          "specUrl": "https://blog.cloudflare.com/agent-readiness/",
          "surfacePath": "/",
          "accept": "text/markdown",
          "fixPrompt": "Make your homepage content-negotiate Markdown: when a request sends `Accept: text/markdown`, return the page AS Markdown with `Content-Type: text/markdown` (agents read it with ~80% fewer tokens than HTML). Implement at your edge/server (check the Accept header → serve a .md rendering). Verify: `curl -s -H 'Accept: text/markdown' https://<your-domain>/ -D - | grep -i content-type` shows text/markdown and the body is Markdown, not HTML. Spec: https://blog.cloudflare.com/agent-readiness/"
        },
        {
          "id": "access.llms_txt",
          "category": "content-access",
          "title": "Publishes an llms.txt index",
          "maturity": "emerging",
          "basis": "convention",
          "specUrl": "https://llmstxt.org/",
          "surfacePath": "/llms.txt",
          "fixPrompt": "Publish https://<your-domain>/llms.txt (Content-Type: text/plain or text/markdown) — an H1 site name, an optional summary blockquote, then curated link sections. Template:\n# <Your site>\n\n> <One-line summary of what you offer agents>\n\n## Docs\n- [Getting started](https://<your-domain>/docs): how to begin\n\n## API\n- [OpenAPI](https://<your-domain>/openapi.json): machine-readable API\nVerify: `curl -s https://<your-domain>/llms.txt | head` starts with an H1 (not HTML). Spec: https://llmstxt.org/"
        },
        {
          "id": "access.structured_data",
          "category": "content-access",
          "title": "Embeds structured data (JSON-LD / OpenGraph)",
          "maturity": "established",
          "basis": "standard",
          "specUrl": "https://schema.org/",
          "surfacePath": "/",
          "fixPrompt": "Embed schema.org JSON-LD in your homepage HTML <head> (a real @type) plus OpenGraph tags, so agents parse entities, not prose:\n<script type=\"application/ld+json\">\n{ \"@context\": \"https://schema.org\", \"@type\": \"Organization\", \"name\": \"<Your org>\", \"url\": \"https://<your-domain>\" }\n</script>\n<meta property=\"og:title\" content=\"<Your title>\">\n<meta property=\"og:type\" content=\"website\">\nVerify: `curl -s https://<your-domain>/ | grep -i 'application/ld+json'` finds the block. Spec: https://schema.org/"
        },
        {
          "id": "access.ai_bot_rules",
          "category": "ai-access-policy",
          "title": "Declares explicit AI-bot rules",
          "maturity": "established",
          "basis": "standard",
          "specUrl": "https://www.rfc-editor.org/rfc/rfc9309.html",
          "surfacePath": "/robots.txt",
          "fixPrompt": "In https://<your-domain>/robots.txt add explicit groups for the major AI user-agents. YOUR STANCE IS YOURS — the rubric only checks that you STATE it; Allow and Disallow score identically (we never reward openness nor penalize blocking). Example (substitute your own Allow/Disallow per agent):\nUser-agent: GPTBot\nDisallow: /\n\nUser-agent: ClaudeBot\nAllow: /\n\nUser-agent: Google-Extended\nDisallow: /\n\nUser-agent: PerplexityBot\nAllow: /\n\nUser-agent: CCBot\nDisallow: /\nVerify: `curl -s https://<your-domain>/robots.txt` lists explicit AI user-agent groups. Spec: https://www.rfc-editor.org/rfc/rfc9309.html"
        },
        {
          "id": "access.content_signals",
          "category": "ai-access-policy",
          "title": "Publishes Content Signals",
          "maturity": "emerging",
          "basis": "convention",
          "specUrl": "https://contentsignals.org/",
          "surfacePath": "/robots.txt",
          "fixPrompt": "Add a Content-Signal directive to https://<your-domain>/robots.txt with explicit search / ai-input / ai-train values (yes/no) so your AI-usage preferences are machine-readable. Example (set each value to your own policy):\nUser-agent: *\nContent-Signal: search=yes, ai-input=yes, ai-train=no\nAllow: /\nVerify: `curl -s https://<your-domain>/robots.txt | grep -i content-signal` shows the directive. Spec: https://contentsignals.org/"
        },
        {
          "id": "access.api_catalog",
          "category": "capability-discovery",
          "title": "Publishes an API catalog",
          "maturity": "established",
          "basis": "standard",
          "specUrl": "https://www.rfc-editor.org/rfc/rfc9727.html",
          "surfacePath": "/.well-known/api-catalog",
          "fixPrompt": "Publish https://<your-domain>/.well-known/api-catalog (Content-Type: application/linkset+json) linking your API endpoints + their OpenAPI docs. Example:\n{\n  \"linkset\": [{\n    \"anchor\": \"https://<your-domain>\",\n    \"service-desc\": [{ \"href\": \"https://api.<your-domain>/openapi.json\", \"type\": \"application/json\" }]\n  }]\n}\nVerify: `curl -s https://<your-domain>/.well-known/api-catalog` returns a linkset citing your OpenAPI. Spec: https://www.rfc-editor.org/rfc/rfc9727.html"
        },
        {
          "id": "access.openapi",
          "category": "capability-discovery",
          "title": "Publishes an OpenAPI document",
          "maturity": "established",
          "basis": "standard",
          "specUrl": "https://spec.openapis.org/oas/latest.html",
          "surfacePath": "/openapi.json",
          "fixPrompt": "Publish your OpenAPI document and make it discoverable. Easiest: serve it at https://<your-domain>/openapi.json (Content-Type: application/json, top-level \"openapi\": \"3.1.0\"). If it lives on an api. subdomain, advertise it so the RFC 9727 chain finds it — add to your homepage <head>:\n<link rel=\"service-desc\" type=\"application/json\" href=\"https://api.<your-domain>/openapi.json\">\nor list it in /.well-known/api-catalog. Verify: `curl -s https://<your-domain>/openapi.json | head -c 200` shows an openapi/swagger version field. Spec: https://spec.openapis.org/oas/latest.html"
        },
        {
          "id": "access.mcp_server_card",
          "category": "capability-discovery",
          "title": "Publishes an MCP server card",
          "maturity": "emerging",
          "basis": "convention",
          "specUrl": "https://modelcontextprotocol.io/",
          "surfacePath": "/.well-known/mcp/server-card.json",
          "fixPrompt": "If you run an MCP server, advertise it at https://<your-domain>/.well-known/mcp/server-card.json (application/json) with transport, url, and tools so agents can connect:\n{\n  \"name\": \"<Your MCP server>\",\n  \"transport\": \"streamable-http\",\n  \"url\": \"https://<your-domain>/mcp\",\n  \"tools\": [{ \"name\": \"<tool>\", \"description\": \"<what it does>\" }]\n}\nVerify: `curl -s https://<your-domain>/.well-known/mcp/server-card.json` returns the card. (Upside-only — skip if you don't run MCP.) Spec: https://modelcontextprotocol.io/"
        },
        {
          "id": "access.agent_entrypoint",
          "category": "capability-discovery",
          "title": "Foregrounds the primary agent channel (agents.txt → MCP)",
          "maturity": "emerging",
          "basis": "convention",
          "specUrl": "https://llmstxt.org/",
          "surfacePath": "/agents.txt",
          "fixPrompt": "Publish a real text/plain https://<your-domain>/agents.txt (an agent-facing companion to robots.txt) that points arriving agents at your primary programmatic channel — reference your MCP endpoint URL (or the /.well-known/mcp/ server card), or surface it from /llms.txt, so an agent hitting the convention path finds the channel without guessing. Example (agents.txt):\n# agents.txt — <your-domain>\n## Use this service\nMCP (preferred): https://<your-domain>/mcp   (streamable-http)\n  first call: <your_first_tool>({ ... })\n  server card: https://<your-domain>/.well-known/mcp/server-card.json\nVerify: `curl -s https://<your-domain>/agents.txt` (or /llms.txt) references your /mcp endpoint or MCP server card. (Upside-only — never lowers your score.) Spec: https://llmstxt.org/ + https://modelcontextprotocol.io/"
        },
        {
          "id": "access.dns_aid",
          "category": "capability-discovery",
          "title": "DNS-AID agent discovery (DNSSEC-validated)",
          "maturity": "emerging",
          "basis": "convention",
          "specUrl": "https://datatracker.ietf.org/doc/draft-mozleywilliams-dnsop-dnsaid/",
          "transport": "dns",
          "surfacePath": "_index._agents",
          "fixPrompt": "Publish a DNS-AID ServiceMode SVCB record (RFC 9460) at _index._agents.<your-domain> (and/or _a2a._agents, _mcp._agents) pointing agents at your endpoints, then sign the zone with DNSSEC (resolver AD=true) so it's tamper-evident. Example zone record:\n_index._agents.<your-domain>. 3600 IN SVCB 1 <your-domain>. (\n  alpn=\"h2\" port=443\n)\nEnable DNSSEC at your DNS provider. Verify: `dig +dnssec SVCB _index._agents.<your-domain>` returns the SVCB record with the AD flag set. Spec: https://datatracker.ietf.org/doc/draft-mozleywilliams-dnsop-dnsaid/"
        },
        {
          "id": "access.oauth_protected_resource",
          "category": "authorization-discovery",
          "title": "OAuth protected-resource metadata",
          "maturity": "established",
          "basis": "standard",
          "specUrl": "https://www.rfc-editor.org/rfc/rfc9728",
          "surfacePath": "/.well-known/oauth-protected-resource",
          "fixPrompt": "Publish https://<your-domain>/.well-known/oauth-protected-resource (application/json) naming your authorization server(s):\n{\n  \"resource\": \"https://<your-domain>\",\n  \"authorization_servers\": [\"https://auth.<your-domain>\"]\n}\nVerify: `curl -s https://<your-domain>/.well-known/oauth-protected-resource` lists a non-empty authorization_servers. (If your APIs need NO delegated/OAuth auth, declare that in /auth.md — this whole category then goes N/A, not fail.) Spec: https://www.rfc-editor.org/rfc/rfc9728"
        },
        {
          "id": "access.oauth_as_metadata",
          "category": "authorization-discovery",
          "title": "OAuth authorization-server metadata",
          "maturity": "established",
          "basis": "standard",
          "specUrl": "https://www.rfc-editor.org/rfc/rfc8414",
          "surfacePath": "/.well-known/oauth-authorization-server",
          "fixPrompt": "Publish https://<your-auth-server>/.well-known/oauth-authorization-server (application/json) with issuer, endpoints, and jwks_uri:\n{\n  \"issuer\": \"https://auth.<your-domain>\",\n  \"authorization_endpoint\": \"https://auth.<your-domain>/authorize\",\n  \"token_endpoint\": \"https://auth.<your-domain>/token\",\n  \"jwks_uri\": \"https://auth.<your-domain>/.well-known/jwks.json\"\n}\nVerify: `curl -s …/.well-known/oauth-authorization-server` has issuer + endpoints + jwks_uri. (N/A if /auth.md declares no delegated/OAuth auth.) Spec: https://www.rfc-editor.org/rfc/rfc8414"
        },
        {
          "id": "mcp.proto.initialize",
          "axis": "access",
          "subjectScope": "mcp-server",
          "category": "mcp-protocol-hygiene",
          "title": "initialize returns protocolVersion + capabilities",
          "maturity": "established",
          "basis": "standard",
          "specUrl": "https://modelcontextprotocol.io/specification",
          "source": "MCP spec; Gauntlet C20",
          "fixPrompt": "Your `initialize` response must return a `protocolVersion` and a `capabilities` object declaring what you support (`tools`, and `resources`/`prompts` if offered). Verify: a JSON-RPC `initialize` returns `result.protocolVersion` and `result.capabilities`. Spec: https://modelcontextprotocol.io/specification"
        },
        {
          "id": "mcp.proto.capabilities-honest",
          "axis": "access",
          "subjectScope": "mcp-server",
          "category": "mcp-protocol-hygiene",
          "title": "Advertised capabilities are actually served",
          "maturity": "established",
          "basis": "standard",
          "specUrl": "https://modelcontextprotocol.io/specification",
          "source": "MCP spec",
          "fixPrompt": "Only advertise capabilities you actually serve: if `initialize` declares `resources`, then `resources/list` must work; if it declares `prompts`, `prompts/list` must work. Don't advertise an empty/erroring capability. Verify: each capability declared in `initialize` has a working list endpoint. Spec: https://modelcontextprotocol.io/specification"
        },
        {
          "id": "mcp.proto.lists-well-formed",
          "axis": "access",
          "subjectScope": "mcp-server",
          "category": "mcp-protocol-hygiene",
          "title": "tools/resources/prompts lists are well-formed",
          "maturity": "established",
          "basis": "standard",
          "specUrl": "https://modelcontextprotocol.io/specification",
          "source": "MCP spec",
          "fixPrompt": "Return well-formed `tools/list` (and `resources/list` / `prompts/list` if advertised): a JSON-RPC result with the documented array shape, each tool carrying at least a `name` and `inputSchema`. Verify: `tools/list` returns a result array of named tools with input schemas. Spec: https://modelcontextprotocol.io/specification"
        },
        {
          "id": "mcp.disco.orientation",
          "axis": "access",
          "subjectScope": "mcp-server",
          "category": "mcp-discoverability",
          "title": "Zero-auth orientation for arriving agents",
          "maturity": "emerging",
          "basis": "convention",
          "specUrl": "https://modelcontextprotocol.io/specification",
          "source": "Gauntlet C16/C22",
          "fixPrompt": "Give a zero-context agent a way to self-onboard with NO credentials: a `get_started`-style tool (or a rich `instructions` string) that returns who you are, what you offer, and a surface map. Verify: an anonymous, no-args orientation call returns a usable surface map / value-prop. Spec: https://modelcontextprotocol.io/specification"
        },
        {
          "id": "mcp.disco.agent-native-docs",
          "axis": "access",
          "subjectScope": "mcp-server",
          "category": "mcp-discoverability",
          "title": "agents.txt / llms.txt surface the server door",
          "maturity": "emerging",
          "basis": "convention",
          "specUrl": "https://llmstxt.org/",
          "source": "Gauntlet C22/C23",
          "fixPrompt": "Publish `/agents.txt` and/or `/llms.txt` (and an agent-native markdown root) that name your MCP endpoint URL and orientation entrypoint in the first screenful, so an arriving agent finds the door without guessing. Verify: `curl -s <site>/agents.txt` (or /llms.txt) references your /mcp endpoint near the top. Spec: https://llmstxt.org/"
        },
        {
          "id": "mcp.disco.executable-examples",
          "axis": "access",
          "subjectScope": "mcp-server",
          "category": "mcp-discoverability",
          "title": "Example calls execute verbatim, anonymously",
          "maturity": "emerging",
          "basis": "convention",
          "specUrl": "https://modelcontextprotocol.io/specification",
          "source": "Gauntlet C24",
          "fixPrompt": "Provide runnable examples (e.g. a `try_now` array of {tool, args}) that an agent can execute exactly as written, anonymously, with NO placeholders (<...>, YOUR_, example.com) and no errors. Verify: each example runs verbatim anon with isError:false. Spec: https://modelcontextprotocol.io/specification"
        },
        {
          "id": "mcp.disco.canonical-home",
          "axis": "access",
          "subjectScope": "mcp-server",
          "category": "mcp-discoverability",
          "title": "One canonical public home, resolvable from the registry",
          "maturity": "established",
          "basis": "convention",
          "specUrl": "https://github.com/modelcontextprotocol/registry",
          "source": "Braille-discovered (Glama); Cloudflare public-MCP-repo practice",
          "fixPrompt": "Publish ONE canonical, public, documented home for the server — a public repo (e.g. github.com/<org>/mcp) and/or docs page — carrying your `server.json`/manifest, connect instructions (URL + transport), and the auth model, and point your registry listings at it so they resolve to one source of truth. Open-sourcing the IMPLEMENTATION is NOT required — only this public metadata home. Verify: your official MCP-registry id resolves to a public home containing server.json + connect + auth docs. Spec: https://github.com/modelcontextprotocol/registry"
        },
        {
          "id": "mcp.breadth.canonical-registry",
          "axis": "access",
          "subjectScope": "mcp-server",
          "category": "mcp-breadth",
          "title": "Meaningful presence in the canonical MCP registry",
          "maturity": "emerging",
          "basis": "convention",
          "specUrl": "https://registry.modelcontextprotocol.io/",
          "source": "Canonical MCP registry (registry.modelcontextprotocol.io)",
          "fixPrompt": "List your server in the canonical MCP registry (registry.modelcontextprotocol.io) with a resolvable id whose remote URL points at this endpoint. This measures MEANINGFUL presence, not raw count — being in many registries adds nothing here, and it never affects your Trust score. Verify: your server resolves in the canonical MCP registry with a remote URL matching this endpoint. Spec: https://registry.modelcontextprotocol.io/"
        }
      ]
    },
    "mcp": {
      "primary": false,
      "title": "MCP",
      "description": "Capability quality of an associated MCP server (the former DX axis): tool / param / output-schema quality, accurate behaviour annotations, and server metadata. The whole axis is N/A when no MCP server is associated with the subject.",
      "scoring": {
        "checkScores": {
          "pass": 1,
          "partial": 0.5,
          "fail": 0,
          "error": 0
        },
        "scoringContribution": {
          "byMaturity": {
            "established": "scored",
            "emerging": "scored"
          },
          "rules": {
            "scored": "Trust-axis check — counted equally in the category mean (pass=1, partial=0.5, fail=0). A partial or fail LOWERS the score; maturity is informational on the trust axis and does not change scoring."
          }
        },
        "notApplicable": "The whole MCP axis (and every `subjectScope:\"mcp-server\"` check folded into Trust/Access) is N/A — excluded and renormalized out — for a subject with no associated MCP server. A website-only subject therefore scores Trust/Access exactly as it did under 0.5.1.",
        "categoryScore": "mean(applicable check scores) * 100",
        "overall": "weighted mean over applicable categories (weights renormalized)",
        "grades": {
          "A+": "score >= 90",
          "A": "score >= 85",
          "B": "score >= 70",
          "C": "score >= 55",
          "D": "score >= 40",
          "F": "score < 40"
        }
      },
      "categories": [
        {
          "id": "mcp-tool-schema-quality",
          "axis": "mcp",
          "subjectScope": "mcp-server",
          "title": "Tool & schema quality",
          "weight": 0.4,
          "blurb": "Are tools, parameters, and output schemas described and typed (no opaque bodies)?"
        },
        {
          "id": "mcp-annotations",
          "axis": "mcp",
          "subjectScope": "mcp-server",
          "title": "Annotations",
          "weight": 0.3,
          "blurb": "Do tools carry accurate behaviour annotations (read-only / destructive / idempotent / open-world)?"
        },
        {
          "id": "mcp-metadata",
          "axis": "mcp",
          "subjectScope": "mcp-server",
          "title": "Server metadata",
          "weight": 0.3,
          "blurb": "Display name, description, homepage, icon, sensible config, and consistent naming."
        }
      ],
      "checks": [
        {
          "id": "mcp.cap.tool-descriptions",
          "axis": "mcp",
          "subjectScope": "mcp-server",
          "category": "mcp-tool-schema-quality",
          "title": "Every tool has a meaningful description",
          "maturity": "emerging",
          "basis": "convention",
          "specUrl": "https://modelcontextprotocol.io/specification",
          "source": "Smithery: Capability Quality",
          "fixPrompt": "Give every tool a clear, non-empty `description` that says what it does and when to use it (not just a restated name). Verify: every tool in `tools/list` has a substantive description. Spec: https://modelcontextprotocol.io/specification"
        },
        {
          "id": "mcp.cap.param-descriptions",
          "axis": "mcp",
          "subjectScope": "mcp-server",
          "category": "mcp-tool-schema-quality",
          "title": "Every input parameter is described",
          "maturity": "emerging",
          "basis": "convention",
          "specUrl": "https://json-schema.org/",
          "source": "Smithery: Capability Quality",
          "fixPrompt": "Describe every input parameter in each tool's `inputSchema` (a `description` per property) so an agent knows what to pass. Verify: each `inputSchema` property carries a description. Spec: https://json-schema.org/"
        },
        {
          "id": "mcp.cap.output-schemas",
          "axis": "mcp",
          "subjectScope": "mcp-server",
          "category": "mcp-tool-schema-quality",
          "title": "Every tool declares a real outputSchema",
          "maturity": "established",
          "basis": "standard",
          "specUrl": "https://modelcontextprotocol.io/specification",
          "source": "Smithery; Gauntlet C11/C12",
          "fixPrompt": "Declare a real, non-empty `outputSchema` on every tool that returns structured content, matching the live `structuredContent` shape. Verify: every tool declares an outputSchema and live output validates against it. Spec: https://modelcontextprotocol.io/specification"
        },
        {
          "id": "mcp.cap.typed-bodies",
          "axis": "mcp",
          "subjectScope": "mcp-server",
          "category": "mcp-tool-schema-quality",
          "title": "Typed request bodies (no opaque blobs)",
          "maturity": "established",
          "basis": "standard",
          "specUrl": "https://json-schema.org/",
          "source": "OpenAI ChatGPT-Apps preflight; Gauntlet C15",
          "fixPrompt": "Type your request arguments: declare the real properties in each `inputSchema` instead of an opaque `additionalProperties: true` / free-form object blob, and ensure a payload built strictly from the published schema is accepted. Verify: no tool accepts only an untyped object; a strict-from-schema payload is accepted. Spec: https://json-schema.org/"
        },
        {
          "id": "mcp.cap.titles",
          "axis": "mcp",
          "subjectScope": "mcp-server",
          "category": "mcp-tool-schema-quality",
          "title": "Tools carry human-readable titles",
          "maturity": "emerging",
          "basis": "convention",
          "specUrl": "https://modelcontextprotocol.io/specification",
          "source": "OpenAI ChatGPT-Apps preflight",
          "fixPrompt": "Give each tool a human-readable `title` (or `annotations.title`) so client UIs can present it cleanly to users. Verify: every tool exposes a title. Spec: https://modelcontextprotocol.io/specification"
        },
        {
          "id": "mcp.cap.annotations-present",
          "axis": "mcp",
          "subjectScope": "mcp-server",
          "category": "mcp-annotations",
          "title": "Tools carry behaviour annotations",
          "maturity": "established",
          "basis": "standard",
          "specUrl": "https://modelcontextprotocol.io/specification",
          "source": "MCP spec; Smithery; Gauntlet C1/C2",
          "fixPrompt": "Annotate every tool with the four behaviour hints — `readOnlyHint`, `destructiveHint`, `idempotentHint`, `openWorldHint` — so clients can reason about side effects. Verify: each tool declares all four annotation hints. Spec: https://modelcontextprotocol.io/specification"
        },
        {
          "id": "mcp.cap.annotations-justified",
          "axis": "mcp",
          "subjectScope": "mcp-server",
          "category": "mcp-annotations",
          "title": "Annotations are accurate",
          "maturity": "emerging",
          "basis": "convention",
          "specUrl": "https://modelcontextprotocol.io/specification",
          "source": "OpenAI per-annotation justification",
          "fixPrompt": "Make annotations TRUE: a tool marked `readOnlyHint:true` must not mutate state; a `destructiveHint:false` tool must not delete. Align each hint with the tool's real behaviour (and method, e.g. GET ⇒ read-only). Verify: spot-check tools — read-only-marked tools cause no mutation; destructive-marked tools are the mutating ones. Spec: https://modelcontextprotocol.io/specification"
        },
        {
          "id": "mcp.cap.server-metadata",
          "axis": "mcp",
          "subjectScope": "mcp-server",
          "category": "mcp-metadata",
          "title": "Complete server metadata",
          "maturity": "emerging",
          "basis": "convention",
          "specUrl": "https://github.com/modelcontextprotocol/registry",
          "source": "Smithery: Server Metadata",
          "fixPrompt": "Publish complete server metadata: a display name, a description, a homepage URL, and an icon, in your `server.json` / registry listing. Verify: server metadata includes name, description, homepage, and icon. Spec: https://github.com/modelcontextprotocol/registry"
        },
        {
          "id": "mcp.cap.naming",
          "axis": "mcp",
          "subjectScope": "mcp-server",
          "category": "mcp-metadata",
          "title": "Consistent tool naming (preferences flagged, not penalized)",
          "maturity": "emerging",
          "basis": "convention",
          "specUrl": "https://modelcontextprotocol.io/specification",
          "source": "Smithery naming PREFERENCE (flagged as preference, not a spec requirement)",
          "fixPrompt": "Use a consistent naming scheme across your tools. NOTE: a vendor preference (e.g. Smithery's dot-notation) is a PREFERENCE, not an MCP spec requirement — we flag it, we never penalize you for choosing your own consistent scheme. Verify: tool names follow one consistent convention. Spec: https://modelcontextprotocol.io/specification"
        },
        {
          "id": "mcp.cap.config-ux",
          "axis": "mcp",
          "subjectScope": "mcp-server",
          "category": "mcp-metadata",
          "title": "Clear configuration UX",
          "maturity": "emerging",
          "basis": "convention",
          "specUrl": "https://github.com/modelcontextprotocol/registry",
          "source": "Smithery: Configuration UX",
          "fixPrompt": "Declare required configuration explicitly with sensible defaults and descriptions in your `server.json` (env/inputs), so a user can connect without guessing. Verify: required config is declared with descriptions/defaults. Spec: https://github.com/modelcontextprotocol/registry"
        }
      ]
    }
  },
  "doesNotMeasure": [
    {
      "item": "WebMCP (navigator.modelContext) and other JS-runtime capabilities",
      "why": "Detecting them requires executing the page in a headless browser. We scan with static fetches only — no code execution — so the scan stays cheap, safe, and reproducible. Absence here is not evidence of absence."
    },
    {
      "item": "Performance / TTFB / Core Web Vitals",
      "why": "Speed is real but orthogonal to whether an agent can find, read, and trust a service. Blending it in would muddy a trust+access signal with an unrelated one."
    },
    {
      "item": "Web Bot Auth (inbound bot verification)",
      "why": "It governs whether a site can verify bots calling IT — the opposite direction from whether the site is discoverable/usable BY an agent. It belongs to a future identity axis, not access."
    },
    {
      "item": "Commerce protocols (x402 / UCP / ACP)",
      "why": "Payment rails apply to a small slice of sites; scoring them would penalize the majority for not being storefronts. We may add an opt-in commerce axis later."
    },
    {
      "item": "Whether a site ALLOWS vs BLOCKS AI (the stance)",
      "why": "We score publishing an explicit, parseable AI policy — never the choice itself. Rewarding openness (or blocking) would impose our preference instead of measuring readiness. See the policy-neutrality note."
    },
    {
      "item": "Raw content quality, SEO, or backlinks",
      "why": "These are search-marketing signals, not agent-readiness. We measure machine-readability and discoverability of structure, not editorial merit."
    },
    {
      "item": "Whether the server IMPLEMENTATION is open-source",
      "why": "Leading teams keep the implementation private while publishing a public metadata home + contact (canonical-home / maintainer-contact score the metadata, never the source). Requiring open source would punish legitimate private servers and has nothing to do with trust-readiness."
    },
    {
      "item": "Being listed on Mnemom (or any single vendor's directory)",
      "why": "Neutrality is the whole asset. Breadth-of-publishing measures meaningful presence in the canonical MCP registry + in-product reachability; it is upside-only, never a trust signal, and explicitly excludes Mnemom's own directory. We never reward 'listed on us' nor punish a competitor."
    },
    {
      "item": "Raw registry count / number of directories listed",
      "why": "A malicious server can spam ten registries. We measure MEANINGFUL presence (canonical registry + reachable in-product), not count, so we don't incentivize registry-spam."
    },
    {
      "item": "Tool count, popularity, or download numbers",
      "why": "Popularity is not trust-readiness, and download counts are gameable and vendor-specific. We score verifiable properties of the server itself."
    },
    {
      "item": "Latency / performance",
      "why": "Speed is real but orthogonal to whether an agent can trust and safely use a server. Blending it would muddy the trust+access+DX signal."
    },
    {
      "item": "In-product reachability (Claude Connectors / ChatGPT Apps listings)",
      "why": "There is no neutral, automatable way to verify a first-party in-product listing without each vendor's private surface — and we won't let one vendor's directory be decisive. Deferred from v0.1; may return post-v1 as an owner-attested signal with right-of-response."
    },
    {
      "item": "A vendor naming PREFERENCE as a spec requirement",
      "why": "Naming conventions like dot-notation are vendor preferences, not MCP spec. We flag them as preferences and never penalize a server for a different, internally-consistent scheme."
    }
  ],
  "scoring": {
    "checkScores": {
      "pass": 1,
      "partial": 0.5,
      "fail": 0,
      "error": 0
    },
    "scoringContribution": {
      "byMaturity": {
        "established": "scored",
        "emerging": "scored"
      },
      "rules": {
        "scored": "Trust-axis check — counted equally in the category mean (pass=1, partial=0.5, fail=0). A partial or fail LOWERS the score; maturity is informational on the trust axis and does not change scoring."
      }
    },
    "notApplicable": "A check is N/A (excluded from scoring, not failed) when the service honestly declares it does not offer that capability — e.g. the OAuth-discovery checks when /auth.md declares no delegated/OAuth authorization. A fully-N/A category is dropped and the remaining category weights are renormalized.",
    "categoryScore": "mean(applicable check scores) * 100",
    "overall": "weighted mean over applicable categories (weights renormalized)",
    "grades": {
      "A+": "score >= 90 AND identity.agent-card-signed = pass",
      "A": "score >= 85",
      "B": "score >= 70",
      "C": "score >= 55",
      "D": "score >= 40",
      "F": "score < 40"
    },
    "caps": [
      "identity category scoring 0 caps the grade at F",
      "an unsigned or missing agent card caps the grade at B"
    ]
  },
  "categories": [
    {
      "id": "identity",
      "title": "Verifiable identity",
      "weight": 0.25,
      "blurb": "Can an agent prove who this is — and is that proof cryptographic?"
    },
    {
      "id": "alignment",
      "title": "Alignment & values",
      "weight": 0.2,
      "blurb": "Are the operator's declared values, scope, and capabilities published and machine-readable?"
    },
    {
      "id": "attestation",
      "title": "Attestation & provenance",
      "weight": 0.2,
      "blurb": "Are claims backed by signed attestations and verifiable provenance?"
    },
    {
      "id": "accountability",
      "title": "Accountability",
      "weight": 0.2,
      "blurb": "Is there a way to report, audit, and verify behaviour over time?"
    },
    {
      "id": "delegation",
      "title": "Delegation & auth",
      "weight": 0.15,
      "blurb": "Can an agent discover how to authenticate and act on a user's behalf, correctly?"
    }
  ],
  "checks": [
    {
      "id": "identity.agent-card",
      "category": "identity",
      "title": "Publishes an A2A agent card",
      "maturity": "emerging",
      "basis": "convention",
      "specUrl": "https://a2a-protocol.org/latest/specification/",
      "surfacePath": "/.well-known/agent-card.json",
      "fixPrompt": "Create a file served at https://<your-domain>/.well-known/agent-card.json with Content-Type: application/json. Minimal valid A2A card:\n{\n  \"protocolVersion\": \"0.3.0\",\n  \"name\": \"<Your service name>\",\n  \"description\": \"<What this agent/service does>\",\n  \"url\": \"https://<your-domain>\",\n  \"capabilities\": { \"streaming\": false },\n  \"skills\": [{ \"id\": \"search\", \"name\": \"Search\", \"description\": \"<one concrete skill>\" }],\n  \"securitySchemes\": {}\n}\nVerify: `curl -sI https://<your-domain>/.well-known/agent-card.json` returns 200 + application/json. Spec: https://a2a-protocol.org/latest/specification/"
    },
    {
      "id": "identity.agent-card-signed",
      "category": "identity",
      "title": "Agent card is cryptographically verifiable (signed / DID / VC)",
      "maturity": "emerging",
      "basis": "standard",
      "specUrl": "https://www.w3.org/TR/vc-data-model-2.0/",
      "surfacePath": "/.well-known/agent-card.json",
      "fixPrompt": "Make /.well-known/agent-card.json tamper-evident by adding a cryptographic binding the scanner recognizes — ANY of: (a) a JWS in a top-level `signatures` array (A2A AgentCardSignature[]), (b) a W3C VC `proof` object, (c) a top-level `jws` string, or (d) a `did:`-prefixed `id`/`issuer`/`controller`. Example (a):\n\"signatures\": [{ \"protected\": \"<base64url JWS header>\", \"signature\": \"<base64url sig>\" }]\nGenerate the JWS over the card with your signing key (e.g. an Ed25519/ES256 JWK). Verify: re-fetch the card and confirm the `signatures`/`proof`/`did:` field is present and validates. Spec: https://www.w3.org/TR/vc-data-model-2.0/",
      "productLink": "https://www.mnemom.ai/what-we-prove/"
    },
    {
      "id": "identity.mcp-server-card",
      "category": "identity",
      "title": "Publishes an MCP server card (if it runs MCP)",
      "maturity": "emerging",
      "basis": "convention",
      "specUrl": "https://modelcontextprotocol.io/",
      "surfacePath": "/.well-known/mcp/server-card.json",
      "fixPrompt": "If you run an MCP server, advertise it at https://<your-domain>/.well-known/mcp/server-card.json (Content-Type: application/json). Minimal card:\n{\n  \"name\": \"<Your MCP server>\",\n  \"version\": \"1.0.0\",\n  \"transport\": \"streamable-http\",\n  \"url\": \"https://<your-domain>/mcp\",\n  \"tools\": [{ \"name\": \"<tool_name>\", \"description\": \"<what it does>\" }]\n}\nVerify: `curl -s https://<your-domain>/.well-known/mcp/server-card.json` returns the card with a name + tools. (If you don't run MCP, skip — this check is upside-only.) Spec: https://modelcontextprotocol.io/"
    },
    {
      "id": "alignment.card",
      "category": "alignment",
      "title": "Publishes an alignment / values card",
      "maturity": "emerging",
      "basis": "convention",
      "specUrl": "https://github.com/mnemom/aap",
      "surfacePath": "/.well-known/alignment-card.json",
      "fixPrompt": "Publish https://<your-domain>/.well-known/alignment-card.json (application/json) declaring your values AND scope AND refusals. Recognized shapes: top-level `values`/`principles` plus EITHER `scope`/`permitted_scope`/`boundaries` and `must_refuse`/`prohibited`, OR an AAP `autonomy_envelope` with `bounded_actions`+`forbidden_actions`. Example:\n{\n  \"values\": [\"honesty\", \"user-safety\"],\n  \"autonomy_envelope\": {\n    \"bounded_actions\": [\"read public data\", \"answer questions\"],\n    \"forbidden_actions\": [\"make payments\", \"delete user data\"]\n  }\n}\nVerify: `curl -s https://<your-domain>/.well-known/alignment-card.json` shows values + scope + refusals. Spec: https://github.com/mnemom/aap",
      "productLink": "https://www.mnemom.ai/governance/"
    },
    {
      "id": "alignment.capabilities",
      "category": "alignment",
      "title": "Declared capabilities are present and coherent",
      "maturity": "emerging",
      "basis": "convention",
      "specUrl": "https://a2a-protocol.org/latest/specification/",
      "surfacePath": "/.well-known/agent-card.json",
      "fixPrompt": "In /.well-known/agent-card.json, populate either a non-empty `capabilities` object or a non-empty `skills` array so a calling agent knows what this one can do. Example:\n\"skills\": [\n  { \"id\": \"search\", \"name\": \"Search\", \"description\": \"Full-text search over docs\" },\n  { \"id\": \"summarize\", \"name\": \"Summarize\", \"description\": \"Summarize a URL\" }\n]\nVerify: `curl -s https://<your-domain>/.well-known/agent-card.json` shows ≥1 concrete skill/capability. Spec: https://a2a-protocol.org/latest/specification/"
    },
    {
      "id": "attestation.signed",
      "category": "attestation",
      "title": "Publishes signed attestations / verifiable credentials",
      "maturity": "emerging",
      "basis": "standard",
      "specUrl": "https://www.w3.org/TR/vc-data-model-2.0/",
      "surfacePath": "/.well-known/attestations.json",
      "fixPrompt": "Publish https://<your-domain>/.well-known/attestations.json (application/json) — an array (or {credentials:[…]}/{attestations:[…]}) of W3C Verifiable Credentials, each carrying a `proof` object (or `jws`/`signatures`). Example:\n[{\n  \"type\": [\"VerifiableCredential\"],\n  \"issuer\": \"did:web:<your-domain>\",\n  \"credentialSubject\": { \"id\": \"https://<your-domain>\", \"claim\": \"<what you attest>\" },\n  \"proof\": { \"type\": \"DataIntegrityProof\", \"proofValue\": \"<sig>\" }\n}]\nVerify: `curl -s https://<your-domain>/.well-known/attestations.json` returns ≥1 credential WITH a proof/jws. Spec: https://www.w3.org/TR/vc-data-model-2.0/",
      "productLink": "https://www.mnemom.ai/what-we-prove/"
    },
    {
      "id": "attestation.provenance",
      "category": "attestation",
      "title": "Build / behaviour provenance (Sigstore / SLSA)",
      "maturity": "emerging",
      "basis": "standard",
      "specUrl": "https://slsa.dev/",
      "surfacePath": "/.well-known/provenance.json",
      "fixPrompt": "Publish https://<your-domain>/.well-known/provenance.json (application/json) — a SLSA/in-toto statement, ideally Sigstore/DSSE-signed. Recognized: a `predicateType`+`predicate` (in-toto) or a `dsseEnvelope`, plus `dsseEnvelope`/`signatures` to be a PASS (unsigned = partial). Example:\n{\n  \"_type\": \"https://in-toto.io/Statement/v1\",\n  \"predicateType\": \"https://slsa.dev/provenance/v1\",\n  \"predicate\": { \"buildDefinition\": { /* … */ } },\n  \"dsseEnvelope\": { \"payload\": \"<base64>\", \"signatures\": [{ \"sig\": \"<sig>\" }] }\n}\nGenerate with `slsa-generator` or `cosign attest`. Verify: `curl -s …/provenance.json` shows the predicate + a signature/DSSE envelope. Spec: https://slsa.dev/"
    },
    {
      "id": "accountability.security-txt",
      "category": "accountability",
      "title": "Serves security.txt",
      "maturity": "established",
      "basis": "standard",
      "specUrl": "https://www.rfc-editor.org/rfc/rfc9116",
      "surfacePath": "/.well-known/security.txt",
      "fixPrompt": "Create https://<your-domain>/.well-known/security.txt (Content-Type: text/plain). Set a real Contact and an Expires < 1 year out (ISO 8601). Template:\nContact: mailto:security@<your-domain>\nExpires: 2027-01-01T00:00:00Z\nCanonical: https://<your-domain>/.well-known/security.txt\nVerify: `curl -s https://<your-domain>/.well-known/security.txt` shows the Contact: and Expires: lines. Spec: https://www.rfc-editor.org/rfc/rfc9116"
    },
    {
      "id": "accountability.status",
      "category": "accountability",
      "title": "Publishes a dated, signed re-verification status",
      "maturity": "emerging",
      "basis": "convention",
      "specUrl": "https://www.mnemom.ai/for-agents/",
      "surfacePath": "/agent-readiness-status.json",
      "fixPrompt": "Publish https://<your-domain>/agent-readiness-status.json (application/json) carrying BOTH a date field (lastVerified/verifiedAt/updatedAt/generatedAt) and a verdict field (status/grade/verdict/ready/score), refreshed on a schedule (e.g. a daily CI job). Example:\n{\n  \"status\": \"ready\",\n  \"grade\": \"A\",\n  \"lastVerified\": \"2026-06-11T00:00:00Z\",\n  \"rubric\": \"https://www.isittrustready.ai/rubric\"\n}\nVerify: `curl -s https://<your-domain>/agent-readiness-status.json` shows a recent date + a status/grade. Spec: https://www.mnemom.ai/for-agents/",
      "productLink": "https://www.mnemom.ai/for-agents/"
    },
    {
      "id": "accountability.advisories",
      "category": "accountability",
      "title": "Publishes advisories / a STIX IoC feed",
      "maturity": "emerging",
      "basis": "standard",
      "specUrl": "https://oasis-open.github.io/cti-documentation/stix/intro",
      "surfacePath": "/.well-known/advisories.json",
      "fixPrompt": "Publish https://<your-domain>/.well-known/advisories.json (application/json) — a JSON array of advisories, an `{advisories:[…]}` object, or a STIX 2.1 bundle. Example (STIX 2.1):\n{\n  \"type\": \"bundle\",\n  \"objects\": [{ \"type\": \"indicator\", \"name\": \"<advisory>\", \"pattern\": \"[…]\", \"valid_from\": \"2026-06-11T00:00:00Z\" }]\n}\nAn empty array is valid (no current advisories). Verify: `curl -s …/advisories.json` parses as a feed/STIX bundle. Spec: https://oasis-open.github.io/cti-documentation/stix/intro"
    },
    {
      "id": "delegation.protected-resource",
      "category": "delegation",
      "title": "OAuth protected-resource metadata",
      "maturity": "established",
      "basis": "standard",
      "specUrl": "https://www.rfc-editor.org/rfc/rfc9728",
      "surfacePath": "/.well-known/oauth-protected-resource",
      "fixPrompt": "Publish https://<your-domain>/.well-known/oauth-protected-resource (application/json) naming your authorization server(s) so agents discover how to authenticate. Example:\n{\n  \"resource\": \"https://<your-domain>\",\n  \"authorization_servers\": [\"https://auth.<your-domain>\"]\n}\nVerify: `curl -s https://<your-domain>/.well-known/oauth-protected-resource` lists a non-empty `authorization_servers`. (If your service has NO delegated/OAuth auth, declare that in /auth.md instead — this check then becomes N/A, not a fail.) Spec: https://www.rfc-editor.org/rfc/rfc9728"
    },
    {
      "id": "delegation.auth-server",
      "category": "delegation",
      "title": "OAuth authorization-server metadata",
      "maturity": "established",
      "basis": "standard",
      "specUrl": "https://www.rfc-editor.org/rfc/rfc8414",
      "surfacePath": "/.well-known/oauth-authorization-server",
      "fixPrompt": "Publish https://<your-auth-server>/.well-known/oauth-authorization-server (application/json) with issuer, endpoints, and jwks_uri so token issuance is discoverable. Example:\n{\n  \"issuer\": \"https://auth.<your-domain>\",\n  \"authorization_endpoint\": \"https://auth.<your-domain>/authorize\",\n  \"token_endpoint\": \"https://auth.<your-domain>/token\",\n  \"jwks_uri\": \"https://auth.<your-domain>/.well-known/jwks.json\"\n}\nVerify: `curl -s …/.well-known/oauth-authorization-server` has issuer + an endpoint + jwks_uri. (N/A if you declare no delegated/OAuth auth in /auth.md.) Spec: https://www.rfc-editor.org/rfc/rfc8414"
    },
    {
      "id": "delegation.auth-doc",
      "category": "delegation",
      "title": "Documents agent authentication",
      "maturity": "emerging",
      "basis": "convention",
      "specUrl": "https://github.com/workos/auth.md",
      "surfacePath": "/auth.md",
      "fixPrompt": "Publish https://<your-domain>/auth.md (Markdown, ≥200 chars) documenting your real auth schemes (OAuth/token/bearer) and the agent registration flow — OR, if you have none, state that explicitly (the phrase \"no delegated\" or \"no OAuth\" makes the OAuth-discovery checks N/A instead of failures). Template:\n# Agent authentication\n\nThis service uses <OAuth 2.1 / API keys / NO delegated auth>.\n- Register: <how an agent obtains credentials>\n- Token endpoint: <url or 'n/a'>\n- Scopes: <list or 'n/a'>\nVerify: `curl -s https://<your-domain>/auth.md | head` shows a substantive auth guide. Spec: https://github.com/workos/auth.md"
    }
  ]
}