Skip to content

The Trust-Readiness Rubric

v0.6.2

The open standard behind every TrustScore. One scan of a property — a domain and any MCP server it runs — produces one signed scorecard, scored on three co-equal axes: Trust (can an agent believe who this is?), Access (can an agent find, read, and connect to it?), and MCP (if it runs an MCP server, is it a quality capability to build against?). The three are reported side by side and never blended into one number. A property with no MCP server simply scores the MCP-server checks as N/A — never as a failure.

Every check is labelled standard (a formal third-party spec exists) or convention (an emerging community/vendor convention — no standards body yet), independent of how widely adopted it is. 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.

Trust

Can an agent believe who this is? Trust is the headline axis. Each website Trust category also folds in the matching MCP-server checks (signing, provenance, honest tool behaviour, fail-closed auth) — those run only when the property has an MCP server, and are N/A otherwise.

How Trust scoring works

  • Each check scores pass = 1.0, partial = 0.5, or fail / not-served = 0.
  • A check is N/A — excluded from scoring, not failed — when the property honestly doesn't offer that capability (e.g. the MCP-server checks when there is no MCP server, or the OAuth-discovery checks when /auth.md declares no delegated authorization). We never reward faking a surface you don't have.
  • A category's score is the mean of its applicable checks, scaled to 0–100.
  • The overall score is the weighted mean of the category scores; a fully-N/A category is dropped and the remaining weights are renormalized.
  • Grades: A+ ≥ 90 (with a signed agent card), A ≥ 85, B ≥ 70, C ≥ 55, D ≥ 40, else F.
  • Caps: a 0 in the identity category caps the grade at F; an unsigned or missing agent card caps it at B.
CategoryWeight
Verifiable identity25%
Alignment & values20%
Attestation & provenance20%
Accountability20%
Delegation & auth15%

Verifiable identity

weight 25% · 5 checks

Can an agent prove who this is — and is that proof cryptographic?

  • Publishes an A2A agent card

    conventionemergingidentity.agent-card

    Inspects /.well-known/agent-card.json

    Scoring scored — counted equally; a partial/fail docks

    To satisfy: Create a file served at https://<your-domain>/.well-known/agent-card.json with Content-Type: application/json. Minimal valid A2A card: { "protocolVersion": "0.3.0", "name": "<Your service name>", "description": "<What this agent/service does>", "url": "https://<your-domain>", "capabilities": { "streaming": false }, "skills": [{ "id": "search", "name": "Search", "description": "<one concrete skill>" }], "securitySchemes": {} } Verify: `curl -sI https://<your-domain>/.well-known/agent-card.json` returns 200 + application/json. Spec: https://a2a-protocol.org/latest/specification/

    Reference standard
  • Agent card is cryptographically verifiable (signed / DID / VC)

    standardemergingidentity.agent-card-signed

    Inspects /.well-known/agent-card.json

    Scoring scored — counted equally; a partial/fail docks

    To satisfy: 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): "signatures": [{ "protected": "<base64url JWS header>", "signature": "<base64url sig>" }] Generate 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/

    Reference standard
  • Publishes an MCP server card (if it runs MCP)

    conventionemergingidentity.mcp-server-card

    Inspects /.well-known/mcp/server-card.json

    Scoring scored — counted equally; a partial/fail docks

    To satisfy: If you run an MCP server, advertise it at https://<your-domain>/.well-known/mcp/server-card.json (Content-Type: application/json). Minimal card: { "name": "<Your MCP server>", "version": "1.0.0", "transport": "streamable-http", "url": "https://<your-domain>/mcp", "tools": [{ "name": "<tool_name>", "description": "<what it does>" }] } Verify: `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/

    Reference standard
  • initialize advertises server identity

    standardestablishedMCP servermcp.identity.server-info

    Seeded from MCP spec; Gauntlet C20

    Scoring scored — counted equally; a partial/fail docks

    To satisfy: Make your MCP `initialize` response advertise a clear identity — a non-empty `serverInfo.name` and `serverInfo.version`, plus a top-level `instructions` string telling an arriving agent what the server is for. The result should look like: { "protocolVersion": "2025-06-18", "serverInfo": { "name": "<Your MCP server>", "version": "1.2.0" }, "instructions": "<what this server is for + how to start>", "capabilities": { "tools": {} } } Verify: `curl -s -X POST https://<your-domain>/mcp -H 'Content-Type: application/json' -H 'Accept: application/json, text/event-stream' -d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-06-18","capabilities":{},"clientInfo":{"name":"probe","version":"0"}}}' | jq '.result | {name:.serverInfo.name, version:.serverInfo.version, instructions}'` shows all three non-empty. Spec: https://modelcontextprotocol.io/specification

    Reference standard
  • Exposes cryptographically verifiable artifacts

    standardestablishedMCP servermcp.identity.signed-artifacts

    Seeded from Gauntlet C17/C29

    Scoring scored — counted equally; a partial/fail docks

    To satisfy: 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 (a `signature` or `jws` field) OR an embedded W3C Data Integrity proof (`eddsa-jcs-2022`, did:key), each verifiable against that JWKS. Envelope shape: { "payload": { /* your resource */ }, "jws": "<base64url JWS over the JCS-canonicalized payload>" } // JWKS advertised at e.g. https://<your-domain>/.well-known/jwks.json Verify: `curl -s https://<your-domain>/.well-known/jwks.json` returns your Ed25519 key; then fetch a signed resource, re-canonicalize (JCS) the stripped payload, and confirm the `jws`/`signature` verifies against that key — then flip one byte and confirm the tampered copy FAILS. Spec: https://www.w3.org/TR/vc-data-integrity/

    Reference standard

Alignment & values

weight 20% · 5 checks

Are the operator's declared values, scope, and capabilities published and machine-readable?

  • Publishes an alignment / values card

    conventionemergingalignment.card

    Inspects /.well-known/alignment-card.json

    Scoring scored — counted equally; a partial/fail docks

    To satisfy: 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: { "values": ["honesty", "user-safety"], "autonomy_envelope": { "bounded_actions": ["read public data", "answer questions"], "forbidden_actions": ["make payments", "delete user data"] } } Verify: `curl -s https://<your-domain>/.well-known/alignment-card.json` shows values + scope + refusals. Spec: https://github.com/mnemom/aap

    Reference standard
  • Declared capabilities are present and coherent

    conventionemergingalignment.capabilities

    Inspects /.well-known/agent-card.json

    Scoring scored — counted equally; a partial/fail docks

    To satisfy: 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: "skills": [ { "id": "search", "name": "Search", "description": "Full-text search over docs" }, { "id": "summarize", "name": "Summarize", "description": "Summarize a URL" } ] Verify: `curl -s https://<your-domain>/.well-known/agent-card.json` shows ≥1 concrete skill/capability. Spec: https://a2a-protocol.org/latest/specification/

    Reference standard
  • Declares values / scope (alignment card or equivalent)

    conventionemergingMCP servermcp.alignment.card

    Seeded from Mnemom alignment-card convention (vendor-neutral; A2A card or equivalent also passes)

    Scoring scored — counted equally; a partial/fail docks

    To satisfy: Publish a machine-readable declaration of what this server is allowed to do — values/principles plus scope and/or refusals. Any ONE satisfies it: an A2A agent card with capabilities, an alignment/values card, or an equivalent documented resource (open-sourcing the implementation is NOT required). Example at https://<your-domain>/.well-known/alignment-card.json: { "values": ["honesty", "user-safety"], "scope": ["read public data"], "must_refuse": ["make payments", "delete user data"] } Verify: `curl -s https://<your-domain>/.well-known/alignment-card.json | jq '{values, scope, must_refuse}'` (or your A2A agent card) returns a structured values + scope/refusals declaration. Spec: https://a2a-protocol.org/latest/specification/

    Reference standard
  • Declares known limitations / non-goals

    conventionemergingMCP servermcp.alignment.known-limitations

    Seeded from Mnemom signed-known-limitations; IITR /non-goals.json

    Scoring scored — counted equally; a partial/fail docks

    To satisfy: Publish an honest, machine-readable statement of what this server does NOT do or guarantee — its known limitations / non-goals (ideally signed). This is on-brand transparency, not a demerit — declaring a limit SCORES; hiding it does not. Example at https://<your-domain>/non-goals.json (or /.well-known/non-goals.json): { "nonGoals": ["does not execute payments", "no real-time data (cached up to 24h)", "English-only responses"] } Verify: `curl -s https://<your-domain>/non-goals.json | jq '.nonGoals'` lists explicit known-limitations / non-goals. Spec: https://isittrustready.ai/non-goals.json

    Reference standard
  • Tools do what they say (output matches declared schema)

    standardestablishedMCP servermcp.honesty.descriptions-accurate

    Seeded from Gauntlet C11/C12

    Scoring scored — counted equally; a partial/fail docks

    To satisfy: Make each tool's behaviour match its declared `outputSchema`: every readable tool's live `structuredContent` must validate (strict) against the schema it declares, and descriptions must not overclaim what the tool returns. Fix by tightening the schema to the real output (or the output to the schema). Verify: call each public-read tool, e.g. `curl -s -X POST https://<your-domain>/mcp -H 'Content-Type: application/json' -H 'Accept: application/json, text/event-stream' -d '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"<tool>","arguments":{}}}'`, then run its `.result.structuredContent` through a JSON-Schema validator (AJV) against that tool's `outputSchema` — no drift. Spec: https://json-schema.org/

    Reference standard

Attestation & provenance

weight 20% · 3 checks

Are claims backed by signed attestations and verifiable provenance?

  • Publishes signed attestations / verifiable credentials

    standardemergingattestation.signed

    Inspects /.well-known/attestations.json

    Scoring scored — counted equally; a partial/fail docks

    To satisfy: 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: [{ "type": ["VerifiableCredential"], "issuer": "did:web:<your-domain>", "credentialSubject": { "id": "https://<your-domain>", "claim": "<what you attest>" }, "proof": { "type": "DataIntegrityProof", "proofValue": "<sig>" } }] Verify: `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/

    Reference standard
  • Build / behaviour provenance (Sigstore / SLSA)

    standardemergingattestation.provenance

    Inspects /.well-known/provenance.json

    Scoring scored — counted equally; a partial/fail docks

    To satisfy: 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: { "_type": "https://in-toto.io/Statement/v1", "predicateType": "https://slsa.dev/provenance/v1", "predicate": { "buildDefinition": { /* … */ } }, "dsseEnvelope": { "payload": "<base64>", "signatures": [{ "sig": "<sig>" }] } } Generate with `slsa-generator` or `cosign attest`. Verify: `curl -s …/provenance.json` shows the predicate + a signature/DSSE envelope. Spec: https://slsa.dev/

    Reference standard
  • Offers verifiable provenance / attestation

    standardemergingMCP servermcp.provenance.attestation

    Seeded from Gauntlet C19/C25

    Scoring scored — counted equally; a partial/fail docks

    To satisfy: Expose a verifiable provenance path an agent can check in-band: EITHER a signed scorecard/certificate whose Ed25519 signature verifies against a published key, OR an append-only attestation (hash-chain + merkle root) proving a claim derives from an unbroken checkpoint chain. Minimal shape: { "claim": "<what you attest>", "checkpoints": [{ "hash": "<h0>" }, { "prevHash": "<h0>", "hash": "<h1>" }], "merkleRoot": "<root>", "signature": "<Ed25519 sig over the root>" } Verify: `curl -s https://<your-domain>/.well-known/provenance.json` (or your attestation resource) returns the artifact; confirm it verifies (signature ok / hash_chain_valid=true), then submit a bogus/altered one and confirm it is REJECTED. Spec: https://modelcontextprotocol.io/specification

    Reference standard

Accountability

weight 20% · 7 checks

Is there a way to report, audit, and verify behaviour over time?

  • Serves security.txt

    standardestablishedaccountability.security-txt

    Inspects /.well-known/security.txt

    Scoring scored — counted equally; a partial/fail docks

    To satisfy: 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: Contact: mailto:security@<your-domain> Expires: 2027-01-01T00:00:00Z Canonical: https://<your-domain>/.well-known/security.txt Verify: `curl -s https://<your-domain>/.well-known/security.txt` shows the Contact: and Expires: lines. Spec: https://www.rfc-editor.org/rfc/rfc9116

    Reference standard
  • Publishes a dated, signed re-verification status

    conventionemergingaccountability.status

    Inspects /agent-readiness-status.json

    Scoring scored — counted equally; a partial/fail docks

    To satisfy: 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: { "status": "ready", "grade": "A", "lastVerified": "2026-06-11T00:00:00Z", "rubric": "https://www.isittrustready.ai/rubric" } Verify: `curl -s https://<your-domain>/agent-readiness-status.json` shows a recent date + a status/grade. Spec: https://www.mnemom.ai/for-agents/

    Reference standard
  • Publishes advisories / a STIX IoC feed

    standardemergingaccountability.advisories

    Inspects /.well-known/advisories.json

    Scoring scored — counted equally; a partial/fail docks

    To satisfy: 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): { "type": "bundle", "objects": [{ "type": "indicator", "name": "<advisory>", "pattern": "[…]", "valid_from": "2026-06-11T00:00:00Z" }] } An 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

    Reference standard
  • Verification discriminates real from tampered

    standardestablishedMCP servermcp.accountability.tamper-evidence

    Seeded from Gauntlet C19/C21/C25/C29

    Scoring scored — counted equally; a partial/fail docks

    To satisfy: 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 (`isError:false`, not an error). A verifier that 'confirms' a forgery is worthless. Verify: call the verify tool with a real artifact (→ verified:true), then with a one-byte-altered copy — `curl -s -X POST https://<your-domain>/mcp -H 'Content-Type: application/json' -H 'Accept: application/json, text/event-stream' -d '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"<verify_tool>","arguments":{"artifact":"<tampered>"}}}' | jq '{verified:.result.structuredContent.verified, isError:.result.isError}'` returns verified:false, isError:false. Spec: https://www.w3.org/TR/vc-data-integrity/

    Reference standard
  • Well-formed errors, no internal leakage

    standardestablishedMCP servermcp.accountability.error-hygiene

    Seeded from MCP / JSON-RPC spec; Gauntlet C13

    Scoring scored — counted equally; a partial/fail docks

    To satisfy: Return well-formed JSON-RPC 2.0 errors (unknown method/tool → a proper `error` object with code+message; tool failures → an `isError:true` result envelope) and never leak internal conformance signals (no `undocumented_status_code` / `spec_deviation` fields) to clients. Verify: `curl -s -X POST https://<your-domain>/mcp -H 'Content-Type: application/json' -H 'Accept: application/json, text/event-stream' -d '{"jsonrpc":"2.0","id":1,"method":"no_such_method"}' | jq '.error'` returns a JSON-RPC error object (code+message), and no response body contains spec-deviation fields. Spec: https://www.jsonrpc.org/specification

    Reference standard
  • Discloses caching / freshness honestly

    conventionemergingMCP servermcp.accountability.cache-transparency

    Seeded from Gauntlet C30

    Scoring scored — counted equally; a partial/fail docks

    To satisfy: If a tool can serve cached results, disclose it with a `cached` field and honour a freshness override (`fresh:true` ⇒ a live result, `cached:false`). Agents must be able to tell a cached answer from a live one. Verify: `curl -s -X POST https://<your-domain>/mcp -H 'Content-Type: application/json' -H 'Accept: application/json, text/event-stream' -d '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"<tool>","arguments":{"fresh":true}}}' | jq '.result.structuredContent.cached'` returns false (and a normal call may return true). Spec: https://modelcontextprotocol.io/specification

    Reference standard
  • Accountable maintainer contact

    conventionemergingMCP servermcp.accountability.maintainer-contact

    Seeded from Braille-discovered (Glama listing failure); Cloudflare public-MCP-repo practice

    Scoring scored — counted equally; a partial/fail docks

    To satisfy: Publish a real, reachable maintainer contact (e.g. a role email like `mcp@<your-domain>`) in your canonical home / server metadata, so an agent or user can report problems and reach an accountable owner. Add to your `server.json` / server card: { "maintainers": [{ "name": "<team>", "email": "mcp@<your-domain>" }] } Verify: `curl -s https://<your-domain>/.well-known/mcp/server-card.json | jq '.maintainers // .contact'` (or your server.json home) names a reachable contact. Spec: https://github.com/modelcontextprotocol/registry

    Reference standard

Delegation & auth

weight 15% · 7 checks

Can an agent discover how to authenticate and act on a user's behalf, correctly?

  • OAuth protected-resource metadata

    standardestablisheddelegation.protected-resource

    Inspects /.well-known/oauth-protected-resource

    Scoring scored — counted equally; a partial/fail docks

    To satisfy: Publish https://<your-domain>/.well-known/oauth-protected-resource (application/json) naming your authorization server(s) so agents discover how to authenticate. Example: { "resource": "https://<your-domain>", "authorization_servers": ["https://auth.<your-domain>"] } Verify: `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

    Reference standard
  • OAuth authorization-server metadata

    standardestablisheddelegation.auth-server

    Inspects /.well-known/oauth-authorization-server

    Scoring scored — counted equally; a partial/fail docks

    To satisfy: Publish https://<your-auth-server>/.well-known/oauth-authorization-server (application/json) with issuer, endpoints, and jwks_uri so token issuance is discoverable. Example: { "issuer": "https://auth.<your-domain>", "authorization_endpoint": "https://auth.<your-domain>/authorize", "token_endpoint": "https://auth.<your-domain>/token", "jwks_uri": "https://auth.<your-domain>/.well-known/jwks.json" } Verify: `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

    Reference standard
  • Documents agent authentication

    conventionemergingdelegation.auth-doc

    Inspects /auth.md

    Scoring scored — counted equally; a partial/fail docks

    To satisfy: 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: # Agent authentication This service uses <OAuth 2.1 / API keys / NO delegated auth>. - Register: <how an agent obtains credentials> - Token endpoint: <url or 'n/a'> - Scopes: <list or 'n/a'> Verify: `curl -s https://<your-domain>/auth.md | head` shows a substantive auth guide. Spec: https://github.com/workos/auth.md

    Reference standard
  • Serves coherent RFC 9728 protected-resource metadata

    standardestablishedMCP servermcp.auth.prm

    Seeded from RFC 9728; Gauntlet C5

    Scoring scored — counted equally; a partial/fail docks

    To satisfy: Serve protected-resource metadata at https://<your-domain>/.well-known/oauth-protected-resource/mcp (application/json) whose `resource` EQUALS your MCP endpoint and whose `authorization_servers` names the real issuer, and serve the AS metadata at that issuer. Template: { "resource": "https://<your-domain>/mcp", "authorization_servers": ["https://auth.<your-domain>"] } Verify: `curl -s https://<your-domain>/.well-known/oauth-protected-resource/mcp | jq '{resource, authorization_servers}'` shows resource=https://<your-domain>/mcp and a non-empty authorization_servers. Spec: https://www.rfc-editor.org/rfc/rfc9728

    Reference standard
  • Authed / write tools fail closed

    standardestablishedMCP servermcp.auth.fail-closed

    Seeded from RFC 9728 / OAuth; Gauntlet C6

    Scoring scored — counted equally; a partial/fail docks

    To satisfy: An anonymous call to any tool that mutates state or reads private data MUST return transport HTTP 401 with a `WWW-Authenticate` header pointing at your protected-resource metadata — never a 200 with an error body, never silent success. Header to emit: WWW-Authenticate: Bearer resource_metadata="https://<your-domain>/.well-known/oauth-protected-resource/mcp" Verify: `curl -s -o /dev/null -D - -X POST https://<your-domain>/mcp -H 'Content-Type: application/json' -H 'Accept: application/json, text/event-stream' -d '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"<authed_tool>","arguments":{}}}'` returns `401` and a `WWW-Authenticate: Bearer resource_metadata=...` line. Spec: https://www.rfc-editor.org/rfc/rfc9728

    Reference standard
  • Public reads leak no private/owner data

    conventionestablishedMCP servermcp.auth.least-privilege-reads

    Seeded from Gauntlet C8/C9

    Scoring scored — counted equally; a partial/fail docks

    To satisfy: Every tool reachable WITHOUT credentials must return only public, no-PII fields — an anonymous caller must never receive owner/account metadata (key prefixes, internal ids, emails). Scope private detail behind auth; return the minimal public projection to anon. Verify: call each anon-reachable read tool with NO credentials — `curl -s -X POST https://<your-domain>/mcp -H 'Content-Type: application/json' -H 'Accept: application/json, text/event-stream' -d '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"<read_tool>","arguments":{}}}'` — and confirm the response carries no owner/private fields. Spec: https://modelcontextprotocol.io/specification

    Reference standard
  • Dynamic Client Registration handles loopback safely

    standardemergingMCP servermcp.auth.dcr-loopback

    Seeded from RFC 7591/8252; Gauntlet C10

    Scoring scored — counted equally; a partial/fail docks

    To satisfy: If you support OAuth Dynamic Client Registration, accept loopback redirect URIs (`http://localhost`, `http://127.0.0.1`) as public clients (HTTP 201, no client_secret) and REJECT non-loopback/insecure redirects (HTTP 400 invalid_redirect_uri). Verify: `curl -s -o /dev/null -w '%{http_code}\n' -X POST https://auth.<your-domain>/register -H 'Content-Type: application/json' -d '{"redirect_uris":["http://127.0.0.1/cb"]}'` returns 201, and the same request with `"https://evil.example/cb"` returns 400. (N/A if you do not support DCR.) Spec: https://www.rfc-editor.org/rfc/rfc8252

    Reference standard

Access

Trust asks can an agent believe who this is? — Access asks can an agent find, read, and connect to it at all? The two are scored separately and never blended. Access spans five website discoverability categories plus three MCP-server categories (protocol hygiene, discoverability, breadth) that score only when a server is present.

How Access scoring works

  • Established checks dominate. Widely-adopted checks (robots.txt, sitemaps, structured data, OpenAPI) set each category's score.
  • Emerging checks are upside-only. Adopting a low-penetration draft (markdown negotiation, llms.txt, Content Signals, MCP cards, registry breadth) can raise a category — but not adopting one never lowers it.
  • Policy-neutral. 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.
  • Not applicable. A property with no APIs and no MCP server isn't penalized for lacking OAuth metadata or MCP protocol hygiene — those categories go N/A and the remaining weights renormalize.
  • Access grades use plain thresholds (A+ ≥ 90, A ≥ 85, B ≥ 70, C ≥ 55, D ≥ 40, else F) — no signing or identity caps.
CategoryWeight
Crawl discoverability25%
Agent content access20%
AI access policy15%
Capability discovery25%
Authorization discovery15%
Protocol hygiene35%
Discoverability40%
Breadth of publishing25%

Crawl discoverability

weight 25% · 3 checks

Can a crawler find the site's content and map (robots, sitemap, link relations)?

  • Serves a parseable robots.txt

    standardestablishedaccess.robots_present

    Inspects /robots.txt

    Scoring sets the category floor — a partial/fail docks

    To satisfy: Serve a valid RFC 9309 file at https://<your-domain>/robots.txt (Content-Type: text/plain). Minimal: User-agent: * Allow: / Sitemap: https://<your-domain>/sitemap.xml Verify: `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

    Reference standard
  • Publishes a sitemap

    standardestablishedaccess.sitemap

    Inspects /sitemap.xml

    Scoring sets the category floor — a partial/fail docks

    To satisfy: Publish https://<your-domain>/sitemap.xml (Content-Type: application/xml) and reference it from robots.txt (`Sitemap: https://<your-domain>/sitemap.xml`). Minimal: <?xml version="1.0" encoding="UTF-8"?> <urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9"> <url><loc>https://<your-domain>/</loc></url> </urlset> Verify: `curl -s https://<your-domain>/sitemap.xml | head` is XML with <urlset>. Spec: https://www.sitemaps.org/protocol.html

    Reference standard
  • Emits HTTP Link relations

    standardestablishedaccess.link_headers

    Inspects /

    Scoring sets the category floor — a partial/fail docks

    To satisfy: Emit an RFC 8288 `Link` response header on your homepage (https://<your-domain>/) pointing to typed relations. Add at your edge/server, e.g.: Link: </.well-known/api-catalog>; rel="api-catalog", </openapi.json>; rel="service-desc" Verify: `curl -sI https://<your-domain>/ | grep -i ^link` shows a Link header with rel values. Spec: https://www.rfc-editor.org/rfc/rfc8288.html

    Reference standard

Agent content access

weight 20% · 3 checks

Can an agent read the content efficiently and structured (markdown, llms.txt, JSON-LD)?

  • Serves markdown via content negotiation

    conventionemergingaccess.markdown_negotiation

    Inspects /

    Scoring upside-only — a pass raises the score, a partial/fail never docks

    To satisfy: 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/

    Reference standard
  • Publishes an llms.txt index

    conventionemergingaccess.llms_txt

    Inspects /llms.txt

    Scoring upside-only — a pass raises the score, a partial/fail never docks

    To satisfy: 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: # <Your site> > <One-line summary of what you offer agents> ## Docs - [Getting started](https://<your-domain>/docs): how to begin ## API - [OpenAPI](https://<your-domain>/openapi.json): machine-readable API Verify: `curl -s https://<your-domain>/llms.txt | head` starts with an H1 (not HTML). Spec: https://llmstxt.org/

    Reference standard
  • Embeds structured data (JSON-LD / OpenGraph)

    standardestablishedaccess.structured_data

    Inspects /

    Scoring sets the category floor — a partial/fail docks

    To satisfy: Embed schema.org JSON-LD in your homepage HTML <head> (a real @type) plus OpenGraph tags, so agents parse entities, not prose: <script type="application/ld+json"> { "@context": "https://schema.org", "@type": "Organization", "name": "<Your org>", "url": "https://<your-domain>" } </script> <meta property="og:title" content="<Your title>"> <meta property="og:type" content="website"> Verify: `curl -s https://<your-domain>/ | grep -i 'application/ld+json'` finds the block. Spec: https://schema.org/

    Reference standard

AI access policy

weight 15% · 2 checks

Has the operator published an explicit, parseable AI-access policy (any stance)?

  • Declares explicit AI-bot rules

    standardestablishedaccess.ai_bot_rules

    Inspects /robots.txt

    Scoring sets the category floor — a partial/fail docks

    To satisfy: 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): User-agent: GPTBot Disallow: / User-agent: ClaudeBot Allow: / User-agent: Google-Extended Disallow: / User-agent: PerplexityBot Allow: / User-agent: CCBot Disallow: / Verify: `curl -s https://<your-domain>/robots.txt` lists explicit AI user-agent groups. Spec: https://www.rfc-editor.org/rfc/rfc9309.html

    Reference standard
  • Publishes Content Signals

    conventionemergingaccess.content_signals

    Inspects /robots.txt

    Scoring upside-only — a pass raises the score, a partial/fail never docks

    To satisfy: 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): User-agent: * Content-Signal: search=yes, ai-input=yes, ai-train=no Allow: / Verify: `curl -s https://<your-domain>/robots.txt | grep -i content-signal` shows the directive. Spec: https://contentsignals.org/

    Reference standard

Capability discovery

weight 25% · 5 checks

Can an agent programmatically discover the site's APIs and tools (catalog, OpenAPI, MCP)?

  • Publishes an API catalog

    standardestablishedaccess.api_catalog

    Inspects /.well-known/api-catalog

    Scoring sets the category floor — a partial/fail docks

    To satisfy: Publish https://<your-domain>/.well-known/api-catalog (Content-Type: application/linkset+json) linking your API endpoints + their OpenAPI docs. Example: { "linkset": [{ "anchor": "https://<your-domain>", "service-desc": [{ "href": "https://api.<your-domain>/openapi.json", "type": "application/json" }] }] } Verify: `curl -s https://<your-domain>/.well-known/api-catalog` returns a linkset citing your OpenAPI. Spec: https://www.rfc-editor.org/rfc/rfc9727.html

    Reference standard
  • Publishes an OpenAPI document

    standardestablishedaccess.openapi

    Inspects /openapi.json

    Scoring sets the category floor — a partial/fail docks

    To satisfy: 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>: <link rel="service-desc" type="application/json" href="https://api.<your-domain>/openapi.json"> or 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

    Reference standard
  • Publishes an MCP server card

    conventionemergingaccess.mcp_server_card

    Inspects /.well-known/mcp/server-card.json

    Scoring upside-only — a pass raises the score, a partial/fail never docks

    To satisfy: 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: { "name": "<Your MCP server>", "transport": "streamable-http", "url": "https://<your-domain>/mcp", "tools": [{ "name": "<tool>", "description": "<what it does>" }] } Verify: `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/

    Reference standard
  • Foregrounds the primary agent channel (agents.txt → MCP)

    conventionemergingaccess.agent_entrypoint

    Inspects /agents.txt

    Scoring upside-only — a pass raises the score, a partial/fail never docks

    To satisfy: 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): # agents.txt — <your-domain> ## Use this service MCP (preferred): https://<your-domain>/mcp (streamable-http) first call: <your_first_tool>({ ... }) server card: https://<your-domain>/.well-known/mcp/server-card.json Verify: `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/

    Reference standard
  • DNS-AID agent discovery (DNSSEC-validated)

    conventionemergingaccess.dns_aid

    Inspects _index._agents

    Scoring upside-only — a pass raises the score, a partial/fail never docks

    To satisfy: 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: _index._agents.<your-domain>. 3600 IN SVCB 1 <your-domain>. ( alpn="h2" port=443 ) Enable 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/

    Reference standard

Authorization discovery

weight 15% · 2 checks

If the site exposes APIs, can an agent discover how to authenticate (OAuth metadata)?

  • OAuth protected-resource metadata

    standardestablishedaccess.oauth_protected_resource

    Inspects /.well-known/oauth-protected-resource

    Scoring sets the category floor — a partial/fail docks

    To satisfy: Publish https://<your-domain>/.well-known/oauth-protected-resource (application/json) naming your authorization server(s): { "resource": "https://<your-domain>", "authorization_servers": ["https://auth.<your-domain>"] } Verify: `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

    Reference standard
  • OAuth authorization-server metadata

    standardestablishedaccess.oauth_as_metadata

    Inspects /.well-known/oauth-authorization-server

    Scoring sets the category floor — a partial/fail docks

    To satisfy: Publish https://<your-auth-server>/.well-known/oauth-authorization-server (application/json) with issuer, endpoints, and jwks_uri: { "issuer": "https://auth.<your-domain>", "authorization_endpoint": "https://auth.<your-domain>/authorize", "token_endpoint": "https://auth.<your-domain>/token", "jwks_uri": "https://auth.<your-domain>/.well-known/jwks.json" } Verify: `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

    Reference standard

Protocol hygiene

weight 35% · 3 checks

Does the server speak MCP correctly — initialize, advertised capabilities, well-formed lists?

  • initialize returns protocolVersion + capabilities

    standardestablishedMCP servermcp.proto.initialize

    Seeded from MCP spec; Gauntlet C20

    Scoring sets the category floor — a partial/fail docks

    To satisfy: Your `initialize` response must return a `protocolVersion` and a `capabilities` object declaring what you support (`tools`, plus `resources`/`prompts` if offered). Result shape: { "protocolVersion": "2025-06-18", "capabilities": { "tools": {}, "resources": {} }, "serverInfo": { "name": "<server>", "version": "1.0.0" } } Verify: `curl -s -X POST https://<your-domain>/mcp -H 'Content-Type: application/json' -H 'Accept: application/json, text/event-stream' -d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-06-18","capabilities":{},"clientInfo":{"name":"probe","version":"0"}}}' | jq '.result | {protocolVersion, capabilities}'` shows both present. Spec: https://modelcontextprotocol.io/specification

    Reference standard
  • Advertised capabilities are actually served

    standardestablishedMCP servermcp.proto.capabilities-honest

    Seeded from MCP spec

    Scoring sets the category floor — a partial/fail docks

    To satisfy: 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: for each capability in `initialize`, confirm its list works — e.g. `curl -s -X POST https://<your-domain>/mcp -H 'Content-Type: application/json' -H 'Accept: application/json, text/event-stream' -d '{"jsonrpc":"2.0","id":1,"method":"resources/list"}' | jq '.result.resources'` returns an array (not an error). Spec: https://modelcontextprotocol.io/specification

    Reference standard
  • tools/resources/prompts lists are well-formed

    standardestablishedMCP servermcp.proto.lists-well-formed

    Seeded from MCP spec

    Scoring sets the category floor — a partial/fail docks

    To satisfy: 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 an `inputSchema`. Verify: `curl -s -X POST https://<your-domain>/mcp -H 'Content-Type: application/json' -H 'Accept: application/json, text/event-stream' -d '{"jsonrpc":"2.0","id":1,"method":"tools/list"}' | jq '.result.tools[] | {name, hasSchema: (.inputSchema|type=="object")}'` lists named tools each with an inputSchema. Spec: https://modelcontextprotocol.io/specification

    Reference standard

Discoverability

weight 40% · 4 checks

Can an arriving agent self-onboard with zero context, and is there one canonical public home?

  • Zero-auth orientation for arriving agents

    conventionemergingMCP servermcp.disco.orientation

    Seeded from Gauntlet C16/C22

    Scoring upside-only — a pass raises the score, a partial/fail never docks

    To satisfy: 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. Declare it in `tools/list` and make it callable anonymously. Verify: `curl -s -X POST https://<your-domain>/mcp -H 'Content-Type: application/json' -H 'Accept: application/json, text/event-stream' -d '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"get_started","arguments":{}}}' | jq '.result'` returns a usable surface map / value-prop with no auth. Spec: https://modelcontextprotocol.io/specification

    Reference standard
  • agents.txt / llms.txt surface the server door

    conventionemergingMCP servermcp.disco.agent-native-docs

    Seeded from Gauntlet C22/C23

    Scoring upside-only — a pass raises the score, a partial/fail never docks

    To satisfy: Publish https://<your-domain>/agents.txt and/or /llms.txt (text/plain or text/markdown) that name your MCP endpoint URL and orientation entrypoint in the first screenful, so an arriving agent finds the door without guessing. Template (agents.txt): # agents.txt — <your-domain> ## Use this service MCP (preferred): https://<your-domain>/mcp (streamable-http) first call: get_started({}) server card: https://<your-domain>/.well-known/mcp/server-card.json Verify: `curl -s https://<your-domain>/agents.txt` (or /llms.txt) references your /mcp endpoint near the top. Spec: https://llmstxt.org/

    Reference standard
  • Example calls execute verbatim, anonymously

    conventionemergingMCP servermcp.disco.executable-examples

    Seeded from Gauntlet C24

    Scoring upside-only — a pass raises the score, a partial/fail never docks

    To satisfy: Provide runnable examples (e.g. a `try_now` array of {tool, args}, or examples in your `instructions`) that an agent can execute EXACTLY as written, anonymously, with NO placeholders (`<...>`, `YOUR_`, `example.com`) and no errors. Verify: take each advertised example verbatim and run it — `curl -s -X POST https://<your-domain>/mcp -H 'Content-Type: application/json' -H 'Accept: application/json, text/event-stream' -d '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"<example_tool>","arguments":<example_args>}}' | jq '.result.isError'` returns false. Spec: https://modelcontextprotocol.io/specification

    Reference standard
  • One canonical public home, resolvable from the registry

    conventionestablishedMCP servermcp.disco.canonical-home

    Seeded from Braille-discovered (Glama); Cloudflare public-MCP-repo practice

    Scoring sets the category floor — a partial/fail docks

    To satisfy: Publish ONE canonical, public, documented home — 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 canonical MCP-registry id resolves to a public home containing server.json + connect + auth docs — e.g. `curl -s https://<your-domain>/.well-known/mcp/server-card.json | jq '{url, transport}'` resolves and links back to that home. Spec: https://github.com/modelcontextprotocol/registry

    Reference standard

Breadth of publishing

weight 25% · 1 checks

Meaningful presence in the canonical registry + reachable in-product. Upside-only; never a trust signal.

  • Meaningful presence in the canonical MCP registry

    conventionemergingMCP servermcp.breadth.canonical-registry

    Seeded from Canonical MCP registry (registry.modelcontextprotocol.io)

    Scoring upside-only — a pass raises the score, a partial/fail never docks

    To satisfy: 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. Publish a `server.json` and submit it per the registry's publish flow. Verify: `curl -s 'https://registry.modelcontextprotocol.io/v0/servers?search=<your-server>' | jq '.servers[].remotes[].url'` includes https://<your-domain>/mcp. Spec: https://registry.modelcontextprotocol.io/

    Reference standard

MCP

If the property runs an MCP server, is it a quality capability to build against? The MCP axis measures capability quality — described and typed tools, parameters, and output schemas, accurate behaviour annotations, and complete, consistent server metadata. The whole axis is N/A (not a failure) for a property with no MCP server.

How MCP scoring works

  • Each check scores pass = 1.0, partial = 0.5, or fail = 0; an inapplicable check is excluded, never counted as a failure.
  • A category's score is the mean of its applicable checks; the axis score is the weight-renormalized mean of its categories.
  • The axis grades on plain thresholds (A+ ≥ 90, A ≥ 85, B ≥ 70, C ≥ 55, D ≥ 40, else F) — there are no website-specific identity or signing caps.
  • Vendor naming preferences are flagged, never penalized; nothing on this axis rewards being listed on Mnemom.
CategoryWeight
Tool & schema quality40%
Annotations30%
Server metadata30%

Tool & schema quality

weight 40% · 5 checks

Are tools, parameters, and output schemas described and typed (no opaque bodies)?

  • Every tool has a meaningful description

    conventionemergingMCP servermcp.cap.tool-descriptions

    Seeded from Smithery: Capability Quality

    Scoring scored — counted equally; a partial/fail docks

    To satisfy: Give every tool a clear, non-empty `description` that says what it does AND when to use it (not just a restated name). Verify: `curl -s -X POST https://<your-domain>/mcp -H 'Content-Type: application/json' -H 'Accept: application/json, text/event-stream' -d '{"jsonrpc":"2.0","id":1,"method":"tools/list"}' | jq '[.result.tools[] | select((.description // "") | length < 15)]'` returns an empty array (no thin/missing descriptions). Spec: https://modelcontextprotocol.io/specification

    Reference standard
  • Every input parameter is described

    conventionemergingMCP servermcp.cap.param-descriptions

    Seeded from Smithery: Capability Quality

    Scoring scored — counted equally; a partial/fail docks

    To satisfy: Describe every input parameter in each tool's `inputSchema` (a `description` per property) so an agent knows what to pass. Shape: "inputSchema": { "type": "object", "properties": { "query": { "type": "string", "description": "<what to pass>" } }, "required": ["query"] } Verify: `curl -s -X POST https://<your-domain>/mcp -H 'Content-Type: application/json' -H 'Accept: application/json, text/event-stream' -d '{"jsonrpc":"2.0","id":1,"method":"tools/list"}' | jq '[.result.tools[].inputSchema.properties // {} | to_entries[] | select((.value.description // "")=="")]'` returns an empty array. Spec: https://json-schema.org/

    Reference standard
  • Every tool declares a real outputSchema

    standardestablishedMCP servermcp.cap.output-schemas

    Seeded from Smithery; Gauntlet C11/C12

    Scoring scored — counted equally; a partial/fail docks

    To satisfy: Declare a real, non-empty `outputSchema` on every tool that returns structured content, matching the live `structuredContent` shape. Shape: "outputSchema": { "type": "object", "properties": { "results": { "type": "array" } }, "required": ["results"] } Verify: `curl -s -X POST https://<your-domain>/mcp -H 'Content-Type: application/json' -H 'Accept: application/json, text/event-stream' -d '{"jsonrpc":"2.0","id":1,"method":"tools/list"}' | jq '[.result.tools[] | select(.outputSchema|not)]'` is empty, and live output validates against it. Spec: https://modelcontextprotocol.io/specification

    Reference standard
  • Typed request bodies (no opaque blobs)

    standardestablishedMCP servermcp.cap.typed-bodies

    Seeded from OpenAI ChatGPT-Apps preflight; Gauntlet C15

    Scoring scored — counted equally; a partial/fail docks

    To satisfy: 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: `curl -s -X POST https://<your-domain>/mcp -H 'Content-Type: application/json' -H 'Accept: application/json, text/event-stream' -d '{"jsonrpc":"2.0","id":1,"method":"tools/list"}' | jq '[.result.tools[] | select((.inputSchema.properties|length)==0 or .inputSchema.additionalProperties==true)]'` is empty (no untyped blobs). Spec: https://json-schema.org/

    Reference standard
  • Tools carry human-readable titles

    conventionemergingMCP servermcp.cap.titles

    Seeded from OpenAI ChatGPT-Apps preflight

    Scoring scored — counted equally; a partial/fail docks

    To satisfy: Give each tool a human-readable `title` (or `annotations.title`) so client UIs can present it cleanly to users. Shape: `{ "name": "search_docs", "title": "Search documentation", ... }`. Verify: `curl -s -X POST https://<your-domain>/mcp -H 'Content-Type: application/json' -H 'Accept: application/json, text/event-stream' -d '{"jsonrpc":"2.0","id":1,"method":"tools/list"}' | jq '[.result.tools[] | select((.title // .annotations.title // "")=="")]'` is empty. Spec: https://modelcontextprotocol.io/specification

    Reference standard

Annotations

weight 30% · 2 checks

Do tools carry accurate behaviour annotations (read-only / destructive / idempotent / open-world)?

  • Tools carry behaviour annotations

    standardestablishedMCP servermcp.cap.annotations-present

    Seeded from MCP spec; Smithery; Gauntlet C1/C2

    Scoring scored — counted equally; a partial/fail docks

    To satisfy: Annotate every tool with the four behaviour hints — `readOnlyHint`, `destructiveHint`, `idempotentHint`, `openWorldHint` — so clients can reason about side effects. Shape: "annotations": { "readOnlyHint": true, "destructiveHint": false, "idempotentHint": true, "openWorldHint": false } Verify: `curl -s -X POST https://<your-domain>/mcp -H 'Content-Type: application/json' -H 'Accept: application/json, text/event-stream' -d '{"jsonrpc":"2.0","id":1,"method":"tools/list"}' | jq '[.result.tools[] | select(.annotations.readOnlyHint==null or .annotations.destructiveHint==null or .annotations.idempotentHint==null or .annotations.openWorldHint==null)]'` is empty. Spec: https://modelcontextprotocol.io/specification

    Reference standard
  • Annotations are accurate

    conventionemergingMCP servermcp.cap.annotations-justified

    Seeded from OpenAI per-annotation justification

    Scoring scored — counted equally; a partial/fail docks

    To satisfy: Make annotations TRUE, not just present: 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 its method — a GET-style read ⇒ readOnlyHint:true). Verify: spot-check — call each `readOnlyHint:true` tool and confirm no state changed, e.g. `curl -s -X POST https://<your-domain>/mcp -H 'Content-Type: application/json' -H 'Accept: application/json, text/event-stream' -d '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"<read_tool>","arguments":{}}}'` leaves state unchanged, and confirm the tools that actually mutate are the ones marked destructive. Spec: https://modelcontextprotocol.io/specification

    Reference standard

Server metadata

weight 30% · 3 checks

Display name, description, homepage, icon, sensible config, and consistent naming.

  • Complete server metadata

    conventionemergingMCP servermcp.cap.server-metadata

    Seeded from Smithery: Server Metadata

    Scoring scored — counted equally; a partial/fail docks

    To satisfy: Publish complete server metadata — a display `name`, a `description`, a `homepage`, and an `icon` — in your `server.json` / registry listing. Shape: { "name": "<Your MCP server>", "description": "<what it does>", "homepage": "https://<your-domain>", "icons": [{ "src": "https://<your-domain>/icon.png", "sizes": "512x512" }] } Verify: `curl -s https://<your-domain>/.well-known/mcp/server-card.json | jq '{name, description, homepage, icons}'` (or your server.json) shows all four present. Spec: https://github.com/modelcontextprotocol/registry

    Reference standard
  • Consistent tool naming (preferences flagged, not penalized)

    conventionemergingMCP servermcp.cap.naming

    Seeded from Smithery naming PREFERENCE (flagged as preference, not a spec requirement)

    Scoring scored — counted equally; a partial/fail docks

    To satisfy: Use a consistent naming scheme across your tools (all snake_case, OR all dot.notation — pick one). 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: `curl -s -X POST https://<your-domain>/mcp -H 'Content-Type: application/json' -H 'Accept: application/json, text/event-stream' -d '{"jsonrpc":"2.0","id":1,"method":"tools/list"}' | jq '[.result.tools[].name]'` shows one consistent convention. Spec: https://modelcontextprotocol.io/specification

    Reference standard
  • Clear configuration UX

    conventionemergingMCP servermcp.cap.config-ux

    Seeded from Smithery: Configuration UX

    Scoring scored — counted equally; a partial/fail docks

    To satisfy: Declare required configuration explicitly with descriptions and sensible defaults in your `server.json` (env/inputs), so a user can connect without guessing. Shape: { "config": { "API_KEY": { "description": "<where to get it>", "required": true }, "REGION": { "description": "deployment region", "default": "us" } } } Verify: `curl -s https://<your-domain>/.well-known/mcp/server-card.json | jq '.config'` (or your server.json) lists each required input with a description/default. Spec: https://github.com/modelcontextprotocol/registry

    Reference standard

What we deliberately don’t measure

A check earns a place only when it’s evaluable from a static, unauthenticated fetch (or a DNS lookup, or a read-only MCP probe) of a neutral, third-party-specified surface, and rewards a real capability — not a vendor’s product, popularity, or licence. For transparency, here’s what we leave out on purpose:

  • WebMCP (navigator.modelContext) and other JS-runtime capabilitiesDetecting 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.
  • Performance / TTFB / Core Web VitalsSpeed 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.
  • Web Bot Auth (inbound bot verification)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.
  • Commerce protocols (x402 / UCP / ACP)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.
  • Whether a site ALLOWS vs BLOCKS AI (the stance)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.
  • Raw content quality, SEO, or backlinksThese are search-marketing signals, not agent-readiness. We measure machine-readability and discoverability of structure, not editorial merit.
  • Whether the server IMPLEMENTATION is open-sourceLeading 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.
  • Being listed on Mnemom (or any single vendor's directory)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.
  • Raw registry count / number of directories listedA malicious server can spam ten registries. We measure MEANINGFUL presence (canonical registry + reachable in-product), not count, so we don't incentivize registry-spam.
  • Tool count, popularity, or download numbersPopularity is not trust-readiness, and download counts are gameable and vendor-specific. We score verifiable properties of the server itself.
  • Latency / performanceSpeed is real but orthogonal to whether an agent can trust and safely use a server. Blending it would muddy the trust+access+DX signal.
  • In-product reachability (Claude Connectors / ChatGPT Apps listings)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.
  • A vendor naming PREFERENCE as a spec requirementNaming 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.