{"contractVersion":"1.25.0","layers":[{"id":"discovery","name":"Discovery","weight":20},{"id":"accessibility","name":"Access","weight":30},{"id":"usability","name":"Usability","weight":40},{"id":"payments","name":"Payments","weight":10}],"checks":[{"id":"ard-catalog","name":"ARD discovery","description":"One catalog that tells agents everything you offer them: MCP servers, APIs, agents, and skills. Without it, every agent has to hunt for your capabilities page by page. We look for an Agentic Resource Discovery catalog at /.well-known/ard.json (the ARD v0.91 canonical path), falling back to the predecessor /.well-known/ai-catalog.json, which the spec keeps as an equivalent source. Weighted at 1 point while ecosystem adoption is early (2026-08 audit; was 3).","layer":"discovery","maxScore":1,"bonus":false,"applicability":"all","appliesTo":["domain","mcp","mcp-app"],"tier":"required","maturity":"verified","draft":false,"beta":false,"specUrl":"https://agenticresourcediscovery.org/","recommendation":"Publish an Agentic Resource Discovery catalog at /.well-known/ard.json (the ARD v0.91 canonical path; the legacy /.well-known/ai-catalog.json remains a valid alias) listing your agentic resources (MCP servers, agents, skills, APIs), each entry with a urn:air identifier, a media type, and exactly one of url or data. See https://agenticresourcediscovery.org/"},{"id":"ai-catalog-published","name":"AI Catalog discovery","description":"The AI Catalog Standard (ai-catalog.io, Agent-Card WG) specifies its own discovery path, /.well-known/ai-catalog.json, separately from ARD's ard.json. Serving a valid catalog there keeps you discoverable by consumers that follow that spec. Bonus: earns credit when present, never costs points.","layer":"discovery","maxScore":1,"bonus":true,"applicability":"all","appliesTo":["domain","mcp","mcp-app"],"tier":"recommended","maturity":"verified","draft":false,"beta":false,"specUrl":"https://ai-catalog.io/","recommendation":"Serve a valid catalog at /.well-known/ai-catalog.json - the AI Catalog Standard's own discovery path - so consumers following that spec (see https://ai-catalog.io/) also find you. The same document you serve at /.well-known/ard.json works unchanged."},{"id":"ard-entries-valid","name":"ARD entry validity","description":"Each entry in your catalog is complete enough for an agent to actually use it: an identifier, a display name, a media type, and a working target. Validated against the AI Catalog Standard's entry model on whichever path serves your catalog (ard.json preferred, else the legacy ai-catalog.json). Only applies when the catalog exists; partial adoption earns credit and never costs points.","layer":"discovery","maxScore":2,"bonus":true,"applicability":"all","appliesTo":["domain","mcp","mcp-app"],"tier":"recommended","maturity":"verified","draft":false,"beta":false,"specUrl":"https://ai-catalog.io/","recommendation":"Make every catalog entry fully valid: a domain-anchored urn:air identifier, a displayName, a media type, and exactly one of url or data. Applies to the catalog at /.well-known/ard.json or the legacy /.well-known/ai-catalog.json."},{"id":"ard-trust-manifest","name":"ARD trust manifest","description":"Trust signals inside your catalog (verified identity, compliance attestations, signatures) that let cautious agents pick you over an unverified alternative. The trust model comes from the AI Catalog Standard and is validated on whichever path serves your catalog. Only applies when the catalog exists; never costs points.","layer":"discovery","maxScore":2,"bonus":true,"applicability":"all","appliesTo":["domain","mcp","mcp-app"],"tier":"recommended","maturity":"verified","draft":false,"beta":false,"specUrl":"https://ai-catalog.io/","recommendation":"Add a trustManifest (verifiable identity, compliance attestations, or signature) to your catalog entries (ard.json, or the legacy ai-catalog.json) so clients can verify your resources with progressive trust."},{"id":"agentic-search-usecase","name":"Category share of voice","description":"When someone asks an AI for a tool that does what you do, do you come up? This measures your share of voice for the problem you solve, not just your name.","layer":"discovery","maxScore":6,"bonus":false,"applicability":"domain-only","appliesTo":["domain"],"tier":"recommended","maturity":"verified","draft":false,"beta":true,"recommendation":"Build topical authority for your category. Publish comparison pages, 'best X for Y' content, tutorials, and integration guides that rank for generic use-case queries - not just your brand name - so agents surface you when users describe a need."},{"id":"agentic-search-specific","name":"Developer resource discoverability","description":"Can an agent that knows your name find your developer resources by searching: API docs, OpenAPI spec, MCP server, auth docs, developer portal, SDK documentation? Any one recognized resource type earns full marks. Missing resources refer to this search sample, not proof that pages are unindexed. Weighted at 3 points while search-result categorisation is noisy (2026-08 audit; was 6, requiring 2 types).","layer":"discovery","maxScore":3,"bonus":false,"applicability":"domain-only","appliesTo":["domain"],"tier":"recommended","maturity":"verified","draft":false,"beta":false,"recommendation":"Check whether your developer resources (API docs, OpenAPI spec, auth docs, developer portal, MCP server, SDK documentation) surface in name-based searches. If they do not, use predictable URLs, link them in llms.txt, and include your product name in page titles and headings. This result reflects one search sample."},{"id":"brand-search-accuracy","name":"Brand name discoverability","description":"A plain search for your brand name should put your domain in the top results. If it does not, agents cannot reliably tell you apart from lookalikes and resellers.","layer":"discovery","maxScore":3,"bonus":false,"applicability":"domain-only","appliesTo":["domain"],"tier":"required","maturity":"verified","draft":false,"beta":false,"recommendation":"Make sure a clean search for your brand name returns your own domain in the top results. If it does not, your brand may be too generic, conflict with a more established term, or not yet indexed. Strengthen brand-name search by claiming consistent NAP across listings, earning press mentions that link to the canonical domain, and avoiding redirect chains that mask the apex domain in search results."},{"id":"wikipedia-presence","name":"Wikipedia / Wikidata entity presence","description":"A Wikipedia article and Wikidata entry that link to your domain. Wikipedia is the largest single source of citations in AI answers (~48% of ChatGPT citations), so presence there decides whether AIs can verify who you are.","layer":"discovery","maxScore":4,"bonus":true,"applicability":"domain-only","appliesTo":["domain"],"tier":"recommended","maturity":"verified","draft":false,"beta":false,"recommendation":"Establish a Wikipedia article and a Wikidata entity for your brand, with the domain set as the official website (Wikidata property P856) and a corresponding external link on Wikipedia. Wikipedia is the largest single source of citations in ChatGPT and a primary input to Knowledge Graphs across Google, Bing, and LLM training data. Earn third-party press coverage first to satisfy notability, then draft the article with cited references rather than self-promotion."},{"id":"sitemap","name":"Sitemap exists","description":"A map of every page you want found. Agents use your XML sitemap to discover content without crawling blind, so gaps here mean pages that never get read.","layer":"accessibility","maxScore":2,"bonus":false,"applicability":"domain-only","appliesTo":["domain"],"tier":"required","maturity":"verified","draft":false,"beta":false,"recommendation":"Add a valid XML sitemap at /sitemap.xml listing all indexable URLs. Include lastmod dates and keep it under 50MB."},{"id":"content-no-js","name":"Content without JavaScript","description":"Most AI crawlers never run JavaScript. If your pages need it to show content, agents see a blank site. We fetch your pages with JavaScript off and check the content is still there.","layer":"accessibility","maxScore":3,"bonus":false,"applicability":"domain-only","appliesTo":["domain"],"tier":"required","maturity":"verified","draft":false,"beta":false,"recommendation":"Serve at least 500 characters of meaningful homepage content in raw HTML. Add a clear H1, keep deeper heading levels sequential, and remove excessive non-content markup."},{"id":"bot-detection","name":"Not blocked by bot detection","description":"Your bot protection may be turning away the visitors you want. We check whether AI agents can reach your site without being blocked.","layer":"accessibility","maxScore":2,"bonus":false,"applicability":"domain-only","appliesTo":["domain"],"tier":"required","maturity":"verified","draft":false,"beta":false,"recommendation":"Allowlist known AI agent User-Agents (ChatGPT-User, ClaudeBot, Google-Extended, DeepSeekBot) in your WAF or bot-detection rules."},{"id":"robots-ai-policy-quality","name":"robots.txt AI crawler policy","description":"Whether robots.txt permits training collection by GPTBot and ClaudeBot and search crawling by OAI-SearchBot, Claude-SearchBot, and PerplexityBot on the homepage and evaluated public pages. General permissions count. Applicable search=yes, ai-train=no retains full credit when evaluated crawling and search are permitted; other restrictions reduce credit.","layer":"discovery","maxScore":2,"bonus":false,"applicability":"domain-only","appliesTo":["domain"],"tier":"required","maturity":"verified","draft":false,"beta":false,"recommendation":"For broad training and search readiness, permit GPTBot and ClaudeBot to collect the affected public pages for training, and OAI-SearchBot, Claude-SearchBot, and PerplexityBot to crawl them for search. Review the reported URLs, rule lines, and applicable ai-train or search Content Signals. Keep private and account paths restricted. General permissions already count; named directives and Content Signals are optional. The paired search=yes, ai-train=no retains full credit when all evaluated crawling and search are permitted. Other training restrictions mean partial coverage under this benchmark. Usage permission never overrides Disallow. Use the existing agent-user policy and live access results to assess visits."},{"id":"agent-discovery-file","name":"Agent discovery file","description":"A dedicated endpoint that tells arriving agents what you are and where to start, like a front desk for automated visitors.","layer":"accessibility","maxScore":2,"bonus":false,"applicability":"domain-only","appliesTo":["domain"],"tier":"required","maturity":"verified","draft":false,"beta":false,"recommendation":"Publish an Agent Skills index at /.well-known/agent-skills/index.json that lists your capabilities, with each skill carrying a name and a description so agents can find and parse what you offer."},{"id":"agent-skills-index-v2","name":"Agent Skills index conformance (v0.2.0)","description":"Your published agent skills follow the current discovery spec, so tools can verify and install them safely. We check /.well-known/agent-skills/index.json for the v0.2.0 schema, typed entries, and artifact digests.","layer":"accessibility","maxScore":2,"bonus":true,"applicability":"domain-only","appliesTo":["domain"],"tier":"emerging","maturity":"emerging","draft":false,"beta":false,"recommendation":"Upgrade /.well-known/agent-skills/index.json to the v0.2.0 schema: add \"$schema\": \"https://schemas.agentskills.io/discovery/0.2.0/schema.json\", and give every entry a type (skill-md or archive), url, and digest. Use \"digest\": \"sha256:<64 lowercase hex chars>\" (e.g. \"digest\": \"sha256:a3f1...\") - a bare \"sha256\": \"<hex>\" field is also accepted. Compute the value from the artifact's raw bytes."},{"id":"a2a-agent-card","name":"A2A / agent-card","description":"A business card for agent-to-agent contact: who you are, what you can do, and how to reach you, published at /.well-known/agent-card.json (the A2A protocol).","layer":"accessibility","maxScore":2,"bonus":true,"applicability":"domain-only","appliesTo":["domain"],"tier":"recommended","maturity":"verified","draft":false,"beta":false,"recommendation":"Publish an Agent-to-Agent (A2A) agent card at /.well-known/agent-card.json describing your agent's capabilities, skills, and contact endpoint."},{"id":"mcp-registry-listed","name":"Listed in MCP registries","description":"Agents find MCP servers through registries the way people find apps through app stores. We check the major ones (Smithery, mcp.so) for an entry verified against your domain.","layer":"discovery","maxScore":1,"bonus":false,"applicability":"all","appliesTo":["domain","mcp","mcp-app"],"tier":"recommended","maturity":"verified","draft":false,"beta":false,"recommendation":"Register your MCP server on Smithery (smithery.ai) or mcp.so so agent platforms can discover your tools. Link the registry entry from your homepage or docs for bi-directional verification."},{"id":"npm-sdk-package","name":"NPM/PyPI SDK package","description":"An official SDK or CLI on NPM or PyPI gives agents and the developers steering them a ready-made way in, instead of hand-rolling every API call.","layer":"discovery","maxScore":1,"bonus":false,"applicability":"domain-only","appliesTo":["domain"],"tier":"recommended","maturity":"verified","draft":false,"beta":false,"recommendation":"Publish a JavaScript/TypeScript SDK package on npm so developers can integrate your API programmatically. In package.json set `repository` to your source repo and `homepage` to your product domain - these links are how agents confirm the package is your official SDK rather than a third-party tool with a similar name."},{"id":"agent-rules-repo","name":"Agent platform configs","description":"Published rules or config files for AI coding tools (Claude, Cursor, Windsurf). They teach coding agents to use your product correctly from the first prompt.","layer":"discovery","maxScore":1,"bonus":false,"applicability":"domain-only","appliesTo":["domain"],"tier":"emerging","maturity":"emerging","draft":false,"beta":false,"recommendation":"Add an AGENTS.md or .cursorrules file to your public GitHub repo with instructions for how AI coding agents should interact with your codebase. Then make sure the repo is documented in the entry-point pages agents read - homepage, docs, and llms.txt - so it can be discovered without guessing."},{"id":"agent-plugins-repo","name":"Agent Plugins manifest","description":"An Agent Plugins manifest (plugin.json) in your public GitHub repos, bundling skills and MCP servers into one installable package. An emerging format, so it never costs points.","layer":"discovery","maxScore":1,"bonus":true,"applicability":"domain-only","appliesTo":["domain"],"tier":"emerging","maturity":"emerging","draft":true,"beta":false,"specUrl":"https://agent-plugins.org/specification","recommendation":"Bundle your agent skills and MCP servers as an Agent Plugin: a plugin.json manifest with the agent-plugins.org $schema and a name in your public repo. See https://agent-plugins.org/specification"},{"id":"skills-sh-listed","name":"Listed on skills.sh","description":"Official skills published on skills.sh, the public directory where agents and developers browse for ready-made capabilities.","layer":"accessibility","maxScore":1,"bonus":false,"applicability":"all","appliesTo":["domain","mcp","mcp-app"],"tier":"emerging","maturity":"emerging","draft":false,"beta":false,"recommendation":"Publish agent skills on skills.sh so AI agents can discover your product's capabilities. Create a SKILL.md in your GitHub repo and register it with 'npx skills add'. See skills.sh/docs."},{"id":"pricing-md","name":"pricing.md exists","description":"An agent comparing options needs your prices in a form it can read. We check for a machine-readable pricing file at /pricing.md.","layer":"accessibility","maxScore":2,"bonus":false,"applicability":"domain-only","appliesTo":["domain"],"tier":"emerging","maturity":"emerging","draft":false,"beta":false,"recommendation":"Create a /pricing.md file with your pricing tiers, features, and limits in plain markdown. This lets AI agents compare costs and recommend plans without scraping HTML pricing pages."},{"id":"nlweb-schema-feeds","name":"NLWeb Schema Feeds","description":"A schemamap directive in robots.txt pointing at structured data feeds (NLWeb). It hands agents your catalog as data instead of making them scrape pages.","layer":"accessibility","maxScore":1,"bonus":false,"applicability":"domain-only","appliesTo":["domain"],"tier":"emerging","maturity":"emerging","draft":false,"beta":false,"recommendation":"Add a schemamap: directive to robots.txt pointing to a Schema Map XML file listing your structured data feeds (JSONL/RSS). See the NLWeb Schema Feeds spec."},{"id":"mcp-well-known-discovery","name":"MCP well-known discovery","description":"Publishing an MCP server is not enough; agents have to find it. We check the standard places: well-known paths, server-card.json, and your llms.txt.","layer":"accessibility","maxScore":2,"bonus":true,"applicability":"domain-only","appliesTo":["domain"],"tier":"recommended","maturity":"verified","draft":false,"beta":false,"recommendation":"Serve your MCP server at /.well-known/mcp, publish a server-card.json at /.well-known/mcp/server-card.json, or reference it in llms.txt so agents can discover it automatically without manual URL input."},{"id":"agent-mode-view","name":"Agent mode view","description":"A stripped-down, structured view of your site at ?mode=agent, built for machine readers: plain content and direct endpoint links.","layer":"accessibility","maxScore":2,"bonus":true,"applicability":"domain-only","appliesTo":["domain"],"tier":"emerging","maturity":"emerging","draft":false,"beta":false,"recommendation":"Add a ?mode=agent query parameter to your homepage that returns a structured, machine-readable view with API endpoints, authentication info, and key capabilities instead of marketing HTML."},{"id":"link-headers-discovery","name":"HTTP Link headers (RFC 8288)","description":"HTTP Link headers that point agents at your sitemap and service docs before they parse a single page, making every automated visit faster.","layer":"accessibility","maxScore":1,"bonus":true,"applicability":"domain-only","appliesTo":["domain"],"tier":"required","maturity":"verified","draft":false,"beta":false,"recommendation":"Add HTTP Link: response headers (RFC 8288) advertising your sitemap, markdown alternates, API service descriptions, and API catalog. Example: Link: </sitemap.xml>; rel=\"sitemap\", </index.md>; rel=\"alternate\"; type=\"text/markdown\"."},{"id":"markdown-url-fallback","name":"Markdown URL fallback","description":"Append .md to a page URL and get the markdown version: the cleanest possible read for an agent. Homepage /index.md is the baseline; .md twins on content pages earn full credit.","layer":"accessibility","maxScore":2,"bonus":true,"applicability":"domain-only","appliesTo":["domain"],"tier":"emerging","maturity":"emerging","draft":false,"beta":false,"recommendation":"Let agents fetch markdown by appending .md to page URLs. Required for any credit: serve a markdown homepage at /index.md. For full credit (2/2): also serve a .md twin for each content page (e.g. /docs/auth -> /docs/auth.md). Content-Type should be text/markdown and the body should start with a top-level heading (not HTML)."},{"id":"modular-llms-txt","name":"Modular llms.txt per product area","description":"Per-section llms.txt files (like /docs/llms.txt) so an agent working in one area gets a focused index instead of your whole site.","layer":"accessibility","maxScore":1,"bonus":true,"applicability":"domain-only","appliesTo":["domain"],"tier":"emerging","maturity":"emerging","draft":false,"beta":false,"recommendation":"Add per-section llms.txt files (e.g. /docs/llms.txt, /api/llms.txt, /developers/llms.txt) so agents can fetch scoped context for specific product areas instead of the whole manual."},{"id":"registry-branding","name":"Registry branding","description":"Your MCP registry entry has a display name, icon, and description. Agents choosing between servers see this first; a bare entry looks abandoned.","layer":"discovery","maxScore":2,"bonus":false,"applicability":"all","appliesTo":["domain","mcp","mcp-app"],"tier":"emerging","maturity":"emerging","draft":false,"beta":false,"recommendation":"Give your MCP server-card (at /.well-known/mcp/server-card.json) a display name, an icon or logo, and a description - all three together are what reads as a complete, branded listing agents can present."},{"id":"chatgpt-app-listed","name":"ChatGPT app listed","description":"Listed in the ChatGPT app directory, where hundreds of millions of users can pull your product into a conversation by name. Upside-only: the directory is curated and gated, so absence never costs points.","layer":"discovery","maxScore":2,"bonus":true,"applicability":"all","appliesTo":["domain","mcp","mcp-app"],"tier":"recommended","maturity":"verified","draft":false,"beta":false,"recommendation":"Submit your app to the ChatGPT apps / connectors directory (the apps-in-ChatGPT surface) so ChatGPT users can discover and use your product."},{"id":"sitemap-lastmod","name":"Sitemap freshness (lastmod)","description":"Dates in your sitemap tell agents what changed and when, so they reread fresh pages instead of guessing. We check lastmod dates parse and the newest is recent.","layer":"accessibility","maxScore":1,"bonus":true,"applicability":"domain-only","appliesTo":["domain"],"tier":"recommended","maturity":"verified","draft":false,"beta":false,"specUrl":"https://www.sitemaps.org/protocol.html","recommendation":"Add <lastmod> dates (W3C datetime, e.g. 2026-08-01) to your sitemap entries and update them when content actually changes. Aim for lastmod on at least half your entries with the newest within the last year. Verify with `curl https://yourdomain.com/sitemap.xml | grep lastmod`."},{"id":"robots-agent-user-policy","name":"robots.txt agent-user policy","description":"Declared homepage permission for ChatGPT-User, Claude-User, and Perplexity-User. General rules and permission by default count. Actual fetch behavior depends on the vendor; unverifiable policies are N/A.","layer":"accessibility","maxScore":2,"bonus":false,"applicability":"domain-only","appliesTo":["domain"],"tier":"required","maturity":"verified","draft":false,"beta":false,"recommendation":"Review the matched homepage rules for ChatGPT-User, Claude-User, and Perplexity-User. If you intend to permit these requests, remove or narrow the reported restriction while keeping private paths protected. Review applicable ai-input=no declarations if answer-time use is intended. This check reports declared permission; a robots.txt change alone does not establish live access."},{"id":"llms-txt-exists","name":"llms.txt exists","description":"llms.txt is your site's guide for AI readers: what you do and where the important pages are. We check for /llms.txt or /.well-known/llms.txt.","layer":"accessibility","maxScore":1,"bonus":false,"applicability":"domain-only","appliesTo":["domain"],"tier":"required","maturity":"verified","draft":false,"beta":false,"recommendation":"Create an llms.txt file at your domain root (/llms.txt) - the AI equivalent of robots.txt. Write at least 100 characters of real content: what your product is, what it does, and links to your key docs. Then verify it with `curl https://yourdomain.com/llms.txt` - you should see your text, not HTML. If your app returns its homepage for every URL (common with single-page apps), add a static file route so the raw text is served. A placeholder with just a heading earns no credit."},{"id":"llms-txt-formatting","name":"llms.txt formatting","description":"An llms.txt only helps if agents can parse it. We check the format: a heading up top, markdown links, and enough substance to navigate by.","layer":"accessibility","maxScore":2,"bonus":false,"applicability":"domain-only","appliesTo":["domain"],"tier":"recommended","maturity":"verified","draft":false,"beta":false,"recommendation":"Format your llms.txt as a navigation index: start with a markdown heading, include markdown links to deeper resources, and keep it under 30,000 characters. If you have more to say, move long-form content into /llms-full.txt or per-section files (e.g. /docs/llms.txt, /api/llms.txt) and link to them from the main index."},{"id":"json-ld","name":"JSON-LD structured data","description":"Structured data that states in machine terms what you are: a product, a company, a person. Without it, every AI describing you is guessing from prose. We grade the completeness of your homepage JSON-LD.","layer":"accessibility","maxScore":4,"bonus":false,"applicability":"domain-only","appliesTo":["domain"],"tier":"required","maturity":"verified","draft":false,"beta":false,"recommendation":"Add JSON-LD structured data to your homepage using the identity type that matches your site - SoftwareApplication for products, Organization or LocalBusiness for companies, Person for personal sites, Article for blogs - with name, description, url, and type-appropriate fields (offers, sameAs, author) so AI can parse your identity programmatically."},{"id":"pricing-info","name":"Pricing info accessible","description":"If an agent cannot find your prices, it cannot recommend you for a purchase. We check that pricing is discoverable and readable on your site.","layer":"accessibility","maxScore":3,"bonus":false,"applicability":"domain-only","appliesTo":["domain"],"tier":"required","maturity":"verified","draft":false,"beta":false,"recommendation":"Make pricing discoverable - add a /pricing page or include pricing as schema.org/Offer structured data, so agents can find it without scraping a marketing page."},{"id":"public-api-docs","name":"Public API/docs linked from homepage","description":"Your API docs, linked straight from your homepage. If an agent has to search for your documentation, most will not. Only docs you own count.","layer":"accessibility","maxScore":3,"bonus":false,"applicability":"domain-only","appliesTo":["domain"],"tier":"required","maturity":"verified","draft":false,"beta":false,"recommendation":"Publish API documentation at a discoverable URL (/docs, /api, /developers). Include authentication, endpoints, and example requests."},{"id":"agent-instruction","name":"Agent instruction / when-to-use","description":"Explicit guidance on when to use your product, written where agents will read it. An agent choosing between ten tools picks the one that says what it is for.","layer":"accessibility","maxScore":3,"bonus":false,"applicability":"domain-only","appliesTo":["domain"],"tier":"required","maturity":"verified","draft":false,"beta":false,"recommendation":"Tell agents when to reach for you: add a 'when to use this' section to your llms.txt (or a dedicated agent-instructions file) that names your best-fit use cases and how an agent should call you. Be specific about the jobs you are right for - generic marketing copy does not read as guidance."},{"id":"skills-sh-quality","name":"Skills.sh skill quality","description":"Not just listed on skills.sh, but worth installing: multiple skills, descriptive names, and real adoption.","layer":"accessibility","maxScore":2,"bonus":false,"applicability":"all","appliesTo":["domain","mcp","mcp-app"],"tier":"emerging","maturity":"emerging","draft":false,"beta":false,"recommendation":"Expand your skills.sh presence with multiple skill repos covering different use cases. Add descriptive skill names, clear SKILL.md files, and organize by capability area."},{"id":"json-ld-entity-linking","name":"JSON-LD entity linking (sameAs)","description":"sameAs links from your structured data to your official profiles (GitHub, LinkedIn, app stores). They let AIs confirm that every mention of you is actually you.","layer":"accessibility","maxScore":2,"bonus":false,"applicability":"domain-only","appliesTo":["domain"],"tier":"recommended","maturity":"verified","draft":false,"beta":false,"recommendation":"Add sameAs links in your JSON-LD structured data pointing to your Wikipedia page, Wikidata entry, GitHub org, and social profiles. This helps AI disambiguate your brand from similarly named entities."},{"id":"mcp-tool-descriptions","name":"MCP tool descriptions","description":"An agent picks tools by reading their descriptions: vague ones get skipped, clear ones get called. We grade every tool on your MCP server, with different bars for product and docs servers.","layer":"usability","maxScore":3,"bonus":true,"applicability":"mcp","appliesTo":["domain","mcp","mcp-app"],"tier":"recommended","maturity":"verified","draft":false,"beta":false,"recommendation":"Add detailed descriptions (>= 20 chars) to every MCP tool. Agents use these to decide which tool to call - vague descriptions lead to wrong tool selection."},{"id":"mcp-param-schemas","name":"MCP parameter schemas","description":"Typed parameter schemas on your MCP tools, so agents know what to send without trial and error. Product servers need required-field lists; docs servers need at least a query.","layer":"usability","maxScore":2,"bonus":true,"applicability":"mcp","appliesTo":["domain","mcp","mcp-app"],"tier":"recommended","maturity":"verified","draft":false,"beta":false,"recommendation":"Define inputSchema with typed properties and required arrays for each tool. Agents need schema info to construct valid tool calls without guessing."},{"id":"mcp-server-identity","name":"MCP server identity","description":"Your MCP server introduces itself in the handshake: name, version, and usage instructions. An anonymous server makes every agent guess what it connected to.","layer":"usability","maxScore":1,"bonus":true,"applicability":"mcp","appliesTo":["domain","mcp","mcp-app"],"tier":"recommended","maturity":"verified","draft":false,"beta":false,"recommendation":"Set server name, version, and instructions in your MCP server's initialize response. Instructions help agents understand your server's purpose and constraints."},{"id":"metadata-completeness","name":"Metadata completeness","description":"The basics AIs use to identify a page: canonical URL, language, and Open Graph image and type. Missing pieces mean mangled citations and wrong previews.","layer":"accessibility","maxScore":2,"bonus":false,"applicability":"domain-only","appliesTo":["domain"],"tier":"required","maturity":"verified","draft":false,"beta":false,"recommendation":"Add all four signals to your homepage: <link rel=\"canonical\">, <html lang=\"...\">, <meta property=\"og:image\">, and <meta property=\"og:type\">. Agents use these for entity resolution and attribution."},{"id":"org-schema-completeness","name":"Organization schema completeness","description":"Company details (contact, address) in your structured data. AIs use them to verify you are a real business before recommending you.","layer":"accessibility","maxScore":2,"bonus":false,"applicability":"domain-only","appliesTo":["domain"],"tier":"recommended","maturity":"verified","draft":false,"beta":false,"recommendation":"Add Organization JSON-LD that includes both contactPoint (with email/phone and contactType) and address (PostalAddress). This lets AI verify your business legitimacy and answer contact queries."},{"id":"schema-type-breadth","name":"Schema type breadth","description":"The more schema.org types you publish (FAQs, products, articles, events), the more kinds of questions an AI can answer about you with confidence.","layer":"accessibility","maxScore":2,"bonus":false,"applicability":"domain-only","appliesTo":["domain"],"tier":"recommended","maturity":"verified","draft":false,"beta":false,"recommendation":"Expand your JSON-LD beyond Organization/WebSite. Add FAQPage for common questions, Service or Product for offerings, AggregateRating or Review for social proof, and BreadcrumbList for navigation context."},{"id":"trust-anchors","name":"Trust anchor pages","description":"About, contact, and privacy pages with real content. Agents check these to verify you are legitimate before recommending you, the way a careful person would.","layer":"accessibility","maxScore":2,"bonus":false,"applicability":"domain-only","appliesTo":["domain"],"tier":"required","maturity":"verified","draft":false,"beta":false,"recommendation":"Publish real /about, /contact, and /privacy pages with at least 500 characters of content each. These are the pages AI agents check to verify your business is legitimate before recommending you."},{"id":"mcp-tool-listing","name":"MCP tool listing","description":"Your MCP server actually returns tools when asked. We call tools/list and grade the surface: product servers earn on breadth, docs servers on focus.","layer":"usability","maxScore":3,"bonus":true,"applicability":"mcp","appliesTo":["domain","mcp","mcp-app"],"tier":"recommended","maturity":"verified","draft":false,"beta":false,"recommendation":"Expose 3+ tools via your MCP server's tools/list endpoint. Cover your core API surface - agents need tools for read, write, and search operations."},{"id":"mcp-tool-naming","name":"MCP tool naming","description":"Predictable tool names (create_invoice, search_docs) that agents parse at a glance. Inconsistent naming makes every call a small research project.","layer":"usability","maxScore":2,"bonus":true,"applicability":"mcp","appliesTo":["domain","mcp","mcp-app"],"tier":"recommended","maturity":"verified","draft":false,"beta":false,"recommendation":"Use consistent naming conventions (snake_case or camelCase) for all MCP tools. Names should be descriptive (>= 4 chars) and not generic (avoid 'run', 'get', 'do')."},{"id":"llms-txt-links-resolve","name":"llms.txt links resolve","description":"The markdown links an llms.txt declares actually resolve - broken links strand agents that follow the index","layer":"accessibility","maxScore":2,"bonus":false,"applicability":"domain-only","appliesTo":["domain"],"tier":"recommended","maturity":"verified","draft":false,"beta":false,"specUrl":"https://llmstxt.org","recommendation":"Make every link your llms.txt declares resolve to real content. Verify each one with `curl -L <url>` - you should see the linked document, not your homepage. If your app returns the homepage shell for unknown paths (common with single-page apps), a 200 status is not proof: check the body. Fix or remove any dead link; agents that follow the index treat a broken link as a dead end."},{"id":"markdown-link-alternate","name":"Markdown alternate link","description":"Pages advertise their markdown twin via a rel=alternate link or HTTP Link header, and the advertised target really serves markdown.","layer":"accessibility","maxScore":1,"bonus":true,"applicability":"domain-only","appliesTo":["domain"],"tier":"emerging","maturity":"emerging","draft":false,"beta":false,"specUrl":"https://www.rfc-editor.org/rfc/rfc8288","recommendation":"Advertise a markdown twin of each page with <link rel=\"alternate\" type=\"text/markdown\" href=\"...\"> in the HTML head (or an equivalent Link response header), and make sure the advertised URL actually serves markdown - an advertisement pointing at HTML is worse than none. Verify the target with `curl -s <href>` and check the body starts with a heading, not <!doctype html>."},{"id":"markdown-frontmatter","name":"Markdown frontmatter metadata","description":"Served markdown docs open with a frontmatter block (title plus description / canonical / last-updated) so agents get document metadata without scraping","layer":"accessibility","maxScore":1,"bonus":false,"applicability":"domain-only","appliesTo":["domain"],"tier":"emerging","maturity":"emerging","draft":false,"beta":false,"recommendation":"Open your served markdown docs with a --- frontmatter block carrying title plus at least one of description, canonical, or last-updated. Agents read frontmatter as document metadata without scraping. A Link: rel=\"canonical\" response header also satisfies the canonical slot."},{"id":"redirect-hygiene","name":"Redirect hygiene","description":"Pages reach real content without meta-refresh stubs, JavaScript-only redirects, or cross-domain hops that strand non-JS agents","layer":"accessibility","maxScore":1,"bonus":false,"applicability":"domain-only","appliesTo":["domain"],"tier":"recommended","maturity":"verified","draft":false,"beta":false,"specUrl":"https://www.rfc-editor.org/rfc/rfc9110#name-redirection-3xx","recommendation":"Replace meta-refresh and JavaScript-only redirects with real HTTP 301/302 redirects. Non-JS agents never execute `location.href` or wait for a meta refresh - they see only the stub page. Verify with `curl -sI <url>` - you should see a Location header, not a 200 with a near-empty body."},{"id":"page-token-budget","name":"Page token budget","description":"Individual pages keep extracted text within an agent-readable budget (~25K tokens) so they fit a context window without truncation","layer":"accessibility","maxScore":1,"bonus":false,"applicability":"domain-only","appliesTo":["domain"],"tier":"recommended","maturity":"verified","draft":false,"beta":false,"recommendation":"Keep each page's extracted text under ~100K characters (~25K tokens) so it fits an agent's context window without truncation. Split oversized reference pages into focused per-topic documents and link them from an index. Check a page with `curl -s <url> | wc -c` and remember agents read the extracted text, not the raw HTML."},{"id":"code-fence-validity","name":"Code fence validity","description":"Fenced code blocks in served markdown are balanced - an unclosed fence swallows the rest of the document when an agent parses it","layer":"accessibility","maxScore":1,"bonus":false,"applicability":"domain-only","appliesTo":["domain"],"tier":"emerging","maturity":"emerging","draft":false,"beta":false,"specUrl":"https://spec.commonmark.org/0.31.2/#fenced-code-blocks","recommendation":"Close every fenced code block (``` or ~~~) in your served markdown. CommonMark treats everything after an unclosed fence as code, so an agent parsing the document silently loses the rest of it. Count fence lines per file - the total must be even."},{"id":"docs-auth-gate","name":"Content behind auth","description":"Sampled content pages are publicly readable - pages behind a login wall are invisible to agents","layer":"accessibility","maxScore":2,"bonus":false,"applicability":"domain-only","appliesTo":["domain"],"tier":"recommended","maturity":"verified","draft":false,"beta":false,"recommendation":"Serve your content pages without a login wall. Agents cannot complete auth flows while browsing - a 401/403 or a login-form page is invisible content. Keep public documentation public; if some content must stay gated, publish an ungated summary so agents can still represent it."},{"id":"public-api","name":"Public API with reachable endpoints","description":"The foundation of agent access: an API that agents can actually call. We check for documentation and at least one endpoint that responds.","layer":"usability","maxScore":7,"bonus":false,"applicability":"api","protocol":"either","appliesTo":["domain"],"tier":"required","maturity":"verified","draft":false,"beta":false,"recommendation":"Expose a public REST or GraphQL API. AI agents need programmatic access  - not just a web UI  - to integrate with your product."},{"id":"openapi-spec","name":"OpenAPI spec published","description":"An OpenAPI spec is your API in a form machines can read. Agents use it to integrate without a human studying the docs, so it is one of the highest-leverage files you can publish.","layer":"accessibility","maxScore":7,"bonus":false,"applicability":"domain-only","appliesTo":["domain"],"tier":"required","maturity":"verified","draft":false,"beta":false,"recommendation":"Publish an OpenAPI (Swagger) specification at /openapi.json or /api/openapi.yaml. This is how agents understand your API surface automatically."},{"id":"oauth-support","name":"OAuth 2.0 support","description":"Agents need a standard way to sign in. We check for OAuth 2.0, or an explicitly open API that needs no keys at all.","layer":"usability","maxScore":5,"bonus":false,"applicability":"domain-only","appliesTo":["domain"],"tier":"required","maturity":"verified","draft":false,"beta":false,"recommendation":"Implement OAuth 2.0 for API authentication. Publish your authorization server metadata at /.well-known/oauth-authorization-server."},{"id":"scoped-permissions","name":"Scoped permissions","description":"Granular permissions so an agent gets only the access it needs, nothing more. Businesses connect faster when the blast radius of a mistake is small. We look for declared OAuth scopes (OpenAPI security schemes, RFC 9728 metadata), not prose mentions.","layer":"usability","maxScore":5,"bonus":false,"applicability":"domain-only","appliesTo":["domain"],"tier":"recommended","maturity":"verified","draft":false,"beta":false,"recommendation":"Declare scoped API permissions where machines can read them: named OAuth scopes in your OpenAPI security schemes, or scopes_supported in RFC 9728 protected-resource metadata. Prose descriptions of roles help humans, but agents need the machine-readable declaration to request least-privilege access."},{"id":"developer-portal","name":"Developer portal","description":"A place to sign up, get keys, and manage an integration without emailing anyone. Self-serve is the difference between integrating today and never.","layer":"accessibility","maxScore":6,"bonus":false,"applicability":"domain-only","appliesTo":["domain"],"tier":"recommended","maturity":"verified","draft":false,"beta":false,"recommendation":"Create a developer portal at /developers with API keys, documentation, quickstart guides, and a sandbox environment."},{"id":"mcp-auth-mechanism","name":"MCP auth mechanism","description":"The right lock on the right door: docs servers should be public, product servers should require OAuth. We check your MCP auth matches what the server does.","layer":"usability","maxScore":2,"bonus":true,"applicability":"mcp","appliesTo":["domain","mcp","mcp-app"],"tier":"recommended","maturity":"verified","draft":false,"beta":false,"recommendation":"Protect your MCP server with OAuth 2.0 authentication. Publish authorization server metadata at /.well-known/oauth-authorization-server for automatic agent auth flows."},{"id":"mcp-oauth-metadata","name":"MCP OAuth metadata","description":"Standard OAuth metadata (RFC 8414) that lets agents discover your sign-in flow automatically, instead of a developer wiring it by hand.","layer":"usability","maxScore":2,"bonus":true,"applicability":"mcp","appliesTo":["domain","mcp","mcp-app"],"tier":"recommended","maturity":"verified","draft":false,"beta":false,"recommendation":"Publish RFC 8414 authorization server metadata with issuer, authorization_endpoint, and token_endpoint so agents can authenticate without hardcoded URLs. For client registration, advertise client_id_metadata_document_supported (CIMD) - Dynamic Client Registration is deprecated and worth keeping only as a compatibility path."},{"id":"mcp-pkce-s256","name":"MCP PKCE S256 support","description":"PKCE with S256, the OAuth hardening that stops intercepted codes from being replayed. Table stakes for agent auth done right.","layer":"usability","maxScore":2,"bonus":true,"applicability":"mcp","appliesTo":["domain","mcp","mcp-app"],"tier":"recommended","maturity":"verified","draft":false,"beta":false,"recommendation":"Support PKCE with S256 code challenge method in your OAuth server. Add 'S256' to code_challenge_methods_supported in your authorization server metadata."},{"id":"mpp-support","name":"MPP payment protocol","description":"Machine Payments Protocol lets an agent pay you over plain HTTP. Supporting any one payment protocol is enough, so this reads N/A when another is detected. Optional for non-commerce sites.","layer":"payments","maxScore":2,"bonus":true,"applicability":"domain-only","appliesTo":["domain"],"tier":"required","maturity":"verified","draft":false,"beta":false,"recommendation":"Implement the Machine Payments Protocol so agents can pay for premium resources over HTTP 402. Return a complete WWW-Authenticate: Payment challenge - the full set of standard MPP parameters, not just the bare scheme - and advertise x-payment-info in your OpenAPI spec so agents can discover it."},{"id":"x402-support","name":"x402 payment protocol","description":"x402 lets an agent pay per request over plain HTTP micropayments. Supporting any one payment protocol is enough, so this reads N/A when another is detected. Optional for non-commerce sites.","layer":"payments","maxScore":2,"bonus":true,"applicability":"domain-only","appliesTo":["domain"],"tier":"required","maturity":"verified","draft":false,"beta":false,"recommendation":"Implement x402 payment protocol so AI agents can pay for API access via HTTP 402. x402 uses PAYMENT-REQUIRED/PAYMENT-SIGNATURE/PAYMENT-RESPONSE headers with Base64-encoded JSON. Add a /discovery/resources endpoint for agent discovery."},{"id":"onboarding-friction","name":"Agent onboarding friction","description":"Can an agent go from discovering you to a first successful API call with no human in the loop? Every manual step is a place automated integrations quietly die.","layer":"usability","maxScore":2,"bonus":false,"applicability":"domain-only","appliesTo":["domain"],"tier":"recommended","maturity":"verified","draft":false,"beta":false,"recommendation":"Offer a free tier or trial, self-serve API key generation, and a sandbox environment. Agents can't fill out 'contact sales' forms."},{"id":"web-bot-auth-directory","name":"Web Bot Auth directory","description":"A public key directory (RFC 9421) that lets agents cryptographically sign their requests, so you know exactly who is calling and can let the good ones through.","layer":"usability","maxScore":2,"bonus":true,"applicability":"domain-only","appliesTo":["domain"],"tier":"emerging","maturity":"emerging","draft":false,"beta":false,"recommendation":"Publish a Web Bot Auth directory at /.well-known/http-message-signatures-directory. Serve a JSON document with a 'keys' array of Ed25519 JWKs (kty=OKP, crv=Ed25519, kid, nbf, exp). This lets agents sign their requests per RFC 9421 so you can distinguish legitimate bots from spoofers."},{"id":"api-catalog-rfc9727","name":"API catalog (RFC 9727)","description":"A machine-readable list of all your APIs at /.well-known/api-catalog (RFC 9727), so agents see your full surface in one request.","layer":"accessibility","maxScore":2,"bonus":true,"applicability":"domain-only","appliesTo":["domain"],"tier":"required","maturity":"verified","draft":false,"beta":false,"recommendation":"Publish an API catalog at /.well-known/api-catalog per RFC 9727. Serve it with Content-Type: application/linkset+json;profile=\"https://www.rfc-editor.org/info/rfc9727\" and include a 'linkset' array with item entries pointing to your OpenAPI specs and service descriptions."},{"id":"oauth-protected-resource","name":"OAuth Protected Resource metadata (RFC 9728)","description":"Metadata at /.well-known/oauth-protected-resource (RFC 9728) that tells agents your auth requirements up front, instead of leaving them to trial and error.","layer":"usability","maxScore":2,"bonus":true,"applicability":"domain-only","appliesTo":["domain"],"tier":"required","maturity":"verified","draft":false,"beta":false,"recommendation":"Publish RFC 9728 protected-resource metadata at /.well-known/oauth-protected-resource. Include the resource field plus enough supporting metadata - your authorization servers, supported scopes, accepted bearer methods - that an agent can work out how to authenticate without first triggering a 401."},{"id":"ucp-support","name":"UCP - Universal Commerce Protocol","description":"A Universal Commerce Protocol profile at /.well-known/ucp, telling shopping agents how to transact with you. Supporting any one payment protocol is enough, so this reads N/A when another is detected. Optional for non-commerce sites.","layer":"payments","maxScore":3,"bonus":true,"applicability":"domain-only","appliesTo":["domain"],"tier":"required","maturity":"verified","draft":false,"beta":false,"recommendation":"Publish a UCP discovery profile at /.well-known/ucp with a required `version` (YYYY-MM-DD) and advertised `services`/`capabilities` per ucp.dev. Also expose the REST checkout surface (`POST /checkout-sessions` with `UCP-Agent` and `Idempotency-Key` headers) so agents can transact without per-vendor integrations."},{"id":"acp-support","name":"ACP - Agentic Commerce Protocol","description":"A live Agentic Commerce Protocol checkout endpoint (/checkout_sessions), the flow behind agent-driven purchases in ChatGPT. Supporting any one payment protocol is enough, so this reads N/A when another is detected. Optional for non-commerce sites.","layer":"payments","maxScore":3,"bonus":true,"applicability":"domain-only","appliesTo":["domain"],"tier":"required","maturity":"verified","draft":false,"beta":false,"recommendation":"Implement the Agentic Commerce Protocol checkout REST API: `POST /checkout_sessions` (create), update/get/complete/cancel variants, with `API-Version: YYYY-MM-DD` and `Idempotency-Key` required headers. Preflight OPTIONS should allow POST or return an ACP-shaped error with `supported_versions` so agents can negotiate."},{"id":"acp-delegate-payment","name":"ACP delegate payment","description":"The ACP endpoint that lets a buyer's agent hand you a payment credential securely (/agentic_commerce/delegate_payment). Supporting any one payment protocol is enough, so this reads N/A when another is detected. Optional for non-commerce sites.","layer":"payments","maxScore":3,"bonus":true,"applicability":"domain-only","appliesTo":["domain"],"tier":"recommended","maturity":"verified","draft":false,"beta":false,"recommendation":"Expose the ACP Delegate Payment endpoint at `POST /agentic_commerce/delegate_payment`. The request takes `payment_method`, `allowance` (max amount, currency, expiry, merchant scope), and `risk_signals`; the response returns a vault token. This lets agents pay on behalf of users with scoped, revocable credentials."},{"id":"ap2-support","name":"AP2 - Agent Payments Protocol","description":"Google's Agent Payments Protocol: signed mandates that prove a human authorized the purchase, backed by Mastercard, Visa, PayPal and Amex. Supporting any one payment protocol is enough, so this reads N/A when another is detected. Optional for non-commerce sites.","layer":"payments","maxScore":3,"bonus":true,"applicability":"domain-only","appliesTo":["domain"],"tier":"recommended","maturity":"verified","draft":false,"beta":false,"specUrl":"https://ap2-protocol.org/","recommendation":"Adopt Google's AP2 (Agent Payments Protocol) authorization layer: advertise an AP2 mandate capability (e.g. `dev.ucp.shopping.ap2_mandate`) in your UCP discovery profile, and verify the three signed mandates (Intent, Cart, Payment - SD-JWT verifiable digital credentials) server-side before routing to a settlement rail. Note: one agentic payment protocol is sufficient - AP2 is only needed if you are not already covered by x402 / MPP / ACP / UCP."},{"id":"auth-md-exists","name":"auth.md exists","description":"auth.md is a walkthrough that teaches an agent how to get its own credentials, served at /auth.md. An emerging standard from WorkOS.","layer":"usability","maxScore":2,"bonus":true,"applicability":"domain-only","appliesTo":["domain"],"tier":"required","maturity":"verified","draft":true,"beta":false,"specUrl":"https://github.com/workos/auth.md/blob/main/AUTH.md","recommendation":"Publish /auth.md as a markdown prose walkthrough of how agents should obtain credentials. Serve it with Content-Type: text/markdown, lead with a top-level heading, and write at least ~200 chars of real content (not just a placeholder). See the WorkOS auth.md spec at https://github.com/workos/auth.md."},{"id":"auth-md-structure","name":"auth.md structure","description":"Your auth.md follows the standard walkthrough structure (discover, pick a method, register, claim, exchange, use, errors, revocation), so any agent can follow it step by step. We grade the content of each section, not just the headings.","layer":"usability","maxScore":2,"bonus":true,"applicability":"domain-only","appliesTo":["domain"],"tier":"recommended","maturity":"verified","draft":true,"beta":false,"specUrl":"https://github.com/workos/auth.md/blob/main/AUTH.md","recommendation":"Structure /auth.md as the WorkOS spec prescribes: sections for Discover, Pick a method, Register, Claim, Exchange, Use the access_token, Errors, and Revocation, with spec anchor keywords (agent_auth, identity_endpoint, identity_assertion, service_auth, id-jag, WWW-Authenticate). Reference https://github.com/workos/auth.md."},{"id":"auth-md-walkthrough-simulation","name":"auth.md walkthrough simulation","description":"We do not take your auth.md's word for it: we simulate the walkthrough end to end (read-only) and verify an agent that only knows a user's email could actually get through it.","layer":"usability","maxScore":2,"bonus":true,"applicability":"domain-only","appliesTo":["domain"],"tier":"recommended","maturity":"verified","draft":true,"beta":false,"specUrl":"https://github.com/workos/auth.md/blob/main/AUTH.md","recommendation":"Make your published auth-discovery chain traversable end to end: an agent starting at /auth.md (or your protected-resource metadata) should be able to follow the links to your authorization-server metadata and registration endpoint without hitting a dead link. Test the whole path, not just each file in isolation."},{"id":"agent-auth-discovery-metadata","name":"Agent auth discovery metadata","description":"The machine-readable half of agent auth: discovery documents (RFC 9728 and 8414) with an agent_auth block that round-trips to your auth.md, so agents can look up the exact request shape for each supported identity type.","layer":"usability","maxScore":3,"bonus":true,"applicability":"domain-only","appliesTo":["domain"],"tier":"recommended","maturity":"verified","draft":true,"beta":false,"specUrl":"https://github.com/workos/auth.md/blob/main/AUTH.md","recommendation":"Publish RFC 9728 protected-resource metadata at /.well-known/oauth-protected-resource on your resource server (the host that actually serves the API, e.g. api.<apex>) with `resource` and `authorization_servers`. Publish RFC 8414 authorization-server metadata at /.well-known/oauth-authorization-server on the AS origin, and include the WorkOS auth.md `agent_auth` block with `identity_endpoint`, `identity_types_supported` drawn from the spec enum (`anonymous`, `identity_assertion`, `service_auth` - the assertion variant, the ID-JAG URN `urn:ietf:params:oauth:token-type:id-jag`, belongs inside `identity_assertion.assertion_types_supported`, not at the top level), and the `identity_assertion.assertion_types_supported` block when you advertise that type, so agents can check their assertion shape is accepted before minting. Cross-link by listing the AS origin in PRM `authorization_servers`, and point `agent_auth.skill` back at your published /auth.md. Spec: https://github.com/workos/auth.md."},{"id":"agent-auth-www-authenticate","name":"Agent auth WWW-Authenticate hint","description":"When an agent hits a 401 on your API, the response should point at the metadata explaining how to authenticate. One WWW-Authenticate header turns a dead end into a signpost.","layer":"usability","maxScore":1,"bonus":true,"applicability":"domain-only","appliesTo":["domain"],"tier":"recommended","maturity":"verified","draft":true,"beta":false,"specUrl":"https://github.com/workos/auth.md/blob/main/AUTH.md","recommendation":"Return a 401 carrying a spec-shaped `WWW-Authenticate: Bearer resource_metadata=\"<your protected-resource metadata URL>\"` header on your API's primary entry points, so an agent learns your auth requirements from one request instead of hunting for the well-known document. Point the metadata URL at /.well-known/oauth-protected-resource on the host that serves the API. Spec: https://github.com/workos/auth.md."},{"id":"agent-auth-endpoints-reachable","name":"agent_auth endpoints reachable","description":"The registration, claim, and revocation surfaces your auth docs advertise actually respond. Stale discovery data is worse than none: it sends agents to doors that no longer exist.","layer":"usability","maxScore":2,"bonus":true,"applicability":"domain-only","appliesTo":["domain"],"tier":"recommended","maturity":"verified","draft":true,"beta":false,"specUrl":"https://github.com/workos/auth.md/blob/main/AUTH.md","recommendation":"Make sure the URIs you advertise (in the AS metadata agent_auth block OR in your /auth.md prose) for identity_endpoint, claim_endpoint, and events_endpoint actually resolve. An OPTIONS preflight should return any HTTP status (2xx/3xx/4xx that isn't 404). DNS-level failure or a 404 means the discovery block / prose is stale - either remove the URI or stand up the endpoint."},{"id":"mcp-server","name":"MCP server / manifest","description":"MCP is how agents plug directly into your product, the way apps plug into an app store. We check for a Model Context Protocol server or manifest.","layer":"usability","maxScore":6,"bonus":false,"applicability":"all","appliesTo":["domain","mcp","mcp-app"],"tier":"required","maturity":"verified","draft":false,"beta":false,"recommendation":"Build an MCP (Model Context Protocol) server exposing your API as tools. Use Streamable HTTP transport for full score. This lets Claude, ChatGPT, and other AI agents call your product natively."},{"id":"mcp-error-handling","name":"MCP error handling","description":"When an agent sends your MCP server a bad request, the answer should be a structured error it can correct from, not a silent failure.","layer":"usability","maxScore":2,"bonus":true,"applicability":"mcp","appliesTo":["domain","mcp","mcp-app"],"tier":"recommended","maturity":"verified","draft":false,"beta":false,"recommendation":"Return structured JSON-RPC errors (with code and message) when agents call invalid tools or pass bad arguments. Don't crash or return empty responses."},{"id":"mcp-transport-modern","name":"MCP modern transport","description":"Your MCP server speaks the current transport (Streamable HTTP), not just the legacy one. New agent clients increasingly expect it.","layer":"usability","maxScore":1,"bonus":true,"applicability":"mcp","appliesTo":["domain","mcp","mcp-app"],"tier":"recommended","maturity":"verified","draft":false,"beta":false,"recommendation":"Upgrade your MCP server from legacy SSE to Streamable HTTP transport. HTTP+SSE is formally deprecated with a year-long offramp; Streamable HTTP is the current standard and supports bidirectional communication."},{"id":"webmcp","name":"WebMCP support","description":"WebMCP (a W3C draft) exposes tools to agents right on your web pages, no separate server needed. Chrome and the ChatGPT desktop browser now discover and call these tools, so agents browsing your site can act, not just read.","layer":"usability","maxScore":5,"bonus":false,"applicability":"domain-only","appliesTo":["domain"],"tier":"required","maturity":"verified","draft":false,"beta":false,"recommendation":"Expose in-page tools through WebMCP, a proposed web standard for browser agents. Register tools with document.modelContext.registerTool() and use navigator.modelContext only as a trailing compatibility fallback. Declarative forms with toolname and tooldescription provide server-rendered evidence, but remain a preview and should not be your only tool surface. Chrome's origin trial covers versions 149-156, with shipping currently targeted for 157. ChatGPT can discover and call WebMCP site tools in the desktop app's built-in browser when the feature is available."},{"id":"markdown-negotiation","name":"Markdown agent docs","description":"Agents prefer markdown: the same content at a fraction of the noise. We check whether your docs are available as markdown, via content negotiation or .md routes.","layer":"accessibility","maxScore":1,"bonus":false,"applicability":"domain-only","appliesTo":["domain"],"tier":"emerging","maturity":"emerging","draft":false,"beta":false,"recommendation":"Pick one: (a) return Content-Type: text/markdown on GET <homepage> when the request sends Accept: text/markdown, or (b) publish a static /llms.md, /auth.md, or /agents.md file at your root with real markdown content. Option (b) is usually a single static file. This is the cold-discovery path for agents that land at your homepage from web search without reading llms.txt first."},{"id":"markdown-negotiation-vary","name":"Markdown content negotiation (acceptmarkdown.com)","description":"The homepage serves Markdown when requested and HTML for browsers, with Vary: Accept on the Markdown response. Markdown support on a docs page alone does not satisfy this homepage check.","layer":"accessibility","maxScore":1,"bonus":true,"applicability":"domain-only","appliesTo":["domain"],"tier":"recommended","maturity":"verified","draft":false,"beta":false,"recommendation":"Enable Markdown negotiation on the scanned homepage. Supporting it only on /docs or a separate .md URL does not satisfy this check. Requests with Accept: text/markdown must receive a nonempty Markdown body with Content-Type: text/markdown and Vary: Accept. Keep serving HTML for Accept: text/html. Adding Vary alone does not create a Markdown response. Verify both with `curl -sS -L -i -H 'Accept: text/markdown' https://yourdomain.com/` and `curl -sS -L -i -H 'Accept: text/html' https://yourdomain.com/`. Check the final response headers and body: Markdown with Vary: Accept for the first request, HTML for the second."},{"id":"rate-limit-headers","name":"Rate limit response headers","description":"Standard RateLimit headers tell agents how much room they have left, so they slow down gracefully instead of hitting errors and giving up on you.","layer":"usability","maxScore":2,"bonus":false,"applicability":"api","protocol":"either","appliesTo":["domain"],"tier":"recommended","maturity":"verified","draft":false,"beta":false,"recommendation":"Return standard rate-limit headers on your API responses (the RFC RateLimit headers, plus Retry-After on a 429) so agents can self-throttle in real time, and document the conventions alongside your API."},{"id":"idempotency-key-support","name":"Idempotency-Key support","description":"Networks fail mid-request. Idempotency keys let an agent retry a payment or an order safely, without doubling it. We check that write endpoints accept the header.","layer":"usability","maxScore":3,"bonus":false,"applicability":"api","protocol":"either","appliesTo":["domain"],"tier":"recommended","maturity":"verified","draft":false,"beta":false,"recommendation":"Support an idempotency key on your write operations and declare it where agents can read it: an Idempotency-Key header parameter on your POST/PUT/PATCH operations in your OpenAPI spec for REST, or a client-supplied id argument on your GraphQL mutations. Agents retry on network failures, and without this a retry can double-charge or duplicate a record."},{"id":"json-error-responses","name":"JSON error responses","description":"When something breaks, agents need a structured JSON error, not an HTML error page. One is recoverable, the other is a dead end.","layer":"usability","maxScore":4,"bonus":false,"applicability":"domain-only","appliesTo":["domain"],"tier":"required","maturity":"verified","draft":false,"beta":false,"recommendation":"Return structured JSON error responses with error codes, messages, and resolution hints. Agents can't parse HTML error pages."},{"id":"api-error-model","name":"REST typed error model","description":"A typed error schema in your OpenAPI spec, so agents know every failure shape in advance and can handle each one deliberately.","layer":"usability","maxScore":3,"bonus":false,"applicability":"api","protocol":"rest","appliesTo":["domain"],"tier":"recommended","maturity":"verified","draft":false,"beta":false,"recommendation":"Document your error responses in your OpenAPI spec: give 4xx and 5xx responses a typed error schema (or use RFC 9457 application/problem+json). A consistent error object with a machine-readable code and a human-readable message lets agents handle failures without guessing."},{"id":"api-versioning-policy","name":"REST versioning / deprecation policy","description":"Agents integrate once and then run unattended. A versioning and deprecation policy is your promise about when things will break and how much warning they get.","layer":"usability","maxScore":3,"bonus":false,"applicability":"api","protocol":"rest","appliesTo":["domain"],"tier":"recommended","maturity":"verified","draft":false,"beta":false,"recommendation":"Declare a versioning policy agents can rely on: version your API (in the URL path or a version header) and publish how you signal deprecation (a Sunset/Deprecation header or a documented timeline). Agents avoid integrating against a surface that can change without warning."},{"id":"pagination-shape","name":"REST pagination pattern","description":"A predictable way to page through lists, cursor-based preferred. Without one, agents read page one and quietly miss the rest of your data.","layer":"usability","maxScore":2,"bonus":false,"applicability":"api","protocol":"rest","appliesTo":["domain"],"tier":"recommended","maturity":"verified","draft":false,"beta":false,"recommendation":"Use a consistent, documented pagination shape on your list endpoints (cursor-based preferred) and define the pagination fields in your OpenAPI response schemas, so agents can page through results without guessing the shape."},{"id":"async-job-pattern","name":"REST async-job pattern","description":"Long-running operations should return 202 Accepted with a way to poll for the result. Otherwise agents time out and retry work that was still running.","layer":"usability","maxScore":2,"bonus":false,"applicability":"api","protocol":"rest","appliesTo":["domain"],"tier":"recommended","maturity":"verified","draft":false,"beta":false,"recommendation":"For long-running operations, return 202 Accepted and point agents at where to poll for the result (a status/location reference plus a job identifier in the body), documented in your OpenAPI spec, so work that does not finish in one request is still followable."},{"id":"cli-tool","name":"CLI tool available","description":"An official CLI. Coding agents live in the terminal, so a CLI makes your product directly operable by the fastest-growing class of agents.","layer":"usability","maxScore":3,"bonus":false,"applicability":"domain-only","appliesTo":["domain"],"tier":"recommended","maturity":"verified","draft":false,"beta":false,"recommendation":"Publish an official CLI tool on npm, PyPI, or Homebrew. A CLI lets agents and developers script interactions with your product without building API integrations from scratch."},{"id":"rest-sdk-packages","name":"Multi-language SDK packages","description":"Official SDKs across ecosystems (npm, PyPI, Go). Each one is an integration an agent does not have to hand-roll, in the language it is already working in.","layer":"usability","maxScore":3,"bonus":false,"applicability":"domain-only","appliesTo":["domain"],"tier":"recommended","maturity":"verified","draft":false,"beta":false,"recommendation":"Publish official SDK packages across multiple language ecosystems (npm, PyPI, Go modules, RubyGems). Auto-generate them from your OpenAPI spec using tools like openapi-generator. For each package set the project URL or homepage to your product domain (package.json `repository`/`homepage`, PyPI `Home-Page` or `project_urls`, RubyGems `homepage_uri`) - this is how agents verify the package is your official SDK."},{"id":"nlweb-ask","name":"NLWeb /ask endpoint","description":"An /ask endpoint (Microsoft's NLWeb protocol) that answers natural-language questions about your site directly, no crawling needed.","layer":"usability","maxScore":1,"bonus":false,"applicability":"domain-only","appliesTo":["domain"],"tier":"emerging","maturity":"emerging","draft":false,"beta":false,"recommendation":"Implement Microsoft's NLWeb protocol by adding a POST /ask endpoint that accepts natural-language queries and returns JSON with _meta (response_type, version). See github.com/microsoft/NLWeb."},{"id":"nlweb-streaming","name":"NLWeb streaming support","description":"Your /ask endpoint streams results as they are found, so agents can show progress instead of a spinner.","layer":"usability","maxScore":1,"bonus":false,"applicability":"domain-only","appliesTo":["domain"],"tier":"emerging","maturity":"emerging","draft":false,"beta":false,"recommendation":"Add SSE streaming to your NLWeb /ask endpoint. Accept prefer.streaming: true and respond with Content-Type: text/event-stream using NLWeb event types (start, result, complete)."},{"id":"response-schema-coverage","name":"REST response schema coverage","description":"Typed response schemas on most of your API operations, so agents know the shape of what comes back before they call.","layer":"usability","maxScore":2,"bonus":false,"applicability":"api","protocol":"rest","appliesTo":["domain"],"tier":"recommended","maturity":"verified","draft":false,"beta":false,"recommendation":"Define typed JSON response schemas for every endpoint in your OpenAPI spec. Agents rely on these to know what fields they will get back; missing or partial schemas force trial-and-error."},{"id":"mcp-tool-annotations","name":"MCP tool annotations","description":"Labels that tell agents which tools are safe to call freely and which change or destroy things (readOnlyHint, destructiveHint). Essential when your MCP server can mutate real data.","layer":"usability","maxScore":2,"bonus":true,"applicability":"mcp","appliesTo":["domain","mcp","mcp-app"],"tier":"recommended","maturity":"verified","draft":false,"beta":false,"recommendation":"Add behavioral annotations (readOnlyHint, destructiveHint) to your MCP tools. Agents use these to avoid destructive actions without user confirmation."},{"id":"mcp-server-card","name":"MCP server-card.json","description":"A server card at /.well-known/mcp/server-card.json that describes your MCP server (name, transport, tools) before an agent even connects.","layer":"usability","maxScore":2,"bonus":true,"applicability":"mcp","appliesTo":["domain","mcp","mcp-app"],"tier":"recommended","maturity":"verified","draft":false,"beta":false,"recommendation":"Publish a server card at /.well-known/mcp/server-card.json describing your MCP server. Required fields: name, description, version, serverUrl, tools[]. This lets agents preview your server before opening a transport connection."},{"id":"mcp-multi-surface-coverage","name":"Product + docs MCP coverage","description":"Two MCP servers, cleanly split: one for taking actions in your product, one for answering questions from your docs. The mature pattern for brands that have both.","layer":"usability","maxScore":2,"bonus":true,"applicability":"domain-only","appliesTo":["domain"],"tier":"recommended","maturity":"verified","draft":false,"beta":false,"recommendation":"Beyond your product MCP server, expose a documentation MCP surface so agents can pull your docs and reference material over the same protocol they use to act. Covering both the 'do' and the 'learn' surfaces over MCP earns this."},{"id":"sandbox-environment","name":"Sandbox / test environment","description":"A sandbox or test mode where agents can build an integration without touching production data. It lowers the stakes of every first call.","layer":"usability","maxScore":2,"bonus":true,"applicability":"domain-only","appliesTo":["domain"],"tier":"recommended","maturity":"verified","draft":false,"beta":false,"recommendation":"Provide a sandbox or test mode so agents can exercise your API without touching production data, and document how to reach it - this lowers the risk of a destructive call against live data."},{"id":"batch-endpoints","name":"REST batch / bulk endpoint","description":"Batch operations let an agent do a thousand things in one request instead of a thousand requests. We look for a /batch endpoint or array request bodies.","layer":"usability","maxScore":2,"bonus":true,"applicability":"api","protocol":"rest","appliesTo":["domain"],"tier":"recommended","maturity":"verified","draft":false,"beta":false,"recommendation":"Offer a batch endpoint that accepts an array of operations in one request, documented in your spec, so an agent acting on many items can do it in bulk instead of looping one call at a time."},{"id":"mcp-resource-listing","name":"MCP resources exposed","description":"If your MCP server claims to offer resources, resources/list should return some. Advertising a capability and delivering nothing erodes agent trust.","layer":"usability","maxScore":3,"bonus":false,"applicability":"mcp","appliesTo":["domain","mcp","mcp-app"],"tier":"recommended","maturity":"verified","draft":false,"beta":false,"recommendation":"If your MCP server advertises the resources capability in its initialize handshake, make sure resources/list returns at least one resource. If you don't intend to expose resources, omit the capability - the check returns na with no penalty for tool-only servers. Quality of the resources you do return is scored separately by mcp-resource-quality."},{"id":"graphql-error-type-definition","name":"GraphQL typed error model","description":"Typed errors in your GraphQL schema (userErrors, error unions), so agents can tell 'bad input' from 'try again later' and react correctly.","layer":"usability","maxScore":3,"bonus":false,"applicability":"api","protocol":"graphql","appliesTo":["domain"],"tier":"recommended","maturity":"verified","draft":false,"beta":false,"recommendation":"Model your GraphQL errors in the schema: define an error type and surface it through your mutation payloads (or a result union) instead of relying only on the top-level errors array, so agents can handle failures by type."},{"id":"graphql-versioning-policy","name":"GraphQL versioning / deprecation policy","description":"Deprecations declared in the schema (@deprecated) or a documented evolution policy, so agents learn about breaking changes before the break.","layer":"usability","maxScore":2,"bonus":false,"applicability":"api","protocol":"graphql","appliesTo":["domain"],"tier":"recommended","maturity":"verified","draft":false,"beta":false,"recommendation":"Adopt a GraphQL evolution policy: mark retiring fields with @deprecated (with a reason) and document how you sunset schema elements. @deprecated is the standard signal agents read."},{"id":"graphql-pagination-pattern","name":"GraphQL pagination pattern","description":"Relay-style cursor pagination (Connection and PageInfo types), the pattern every GraphQL client and agent already knows how to walk.","layer":"usability","maxScore":2,"bonus":false,"applicability":"api","protocol":"graphql","appliesTo":["domain"],"tier":"recommended","maturity":"verified","draft":false,"beta":false,"recommendation":"Paginate GraphQL lists with the standard Relay connection pattern (Connection and PageInfo types with cursors), a shape agents recognize and can traverse without custom handling."},{"id":"graphql-async-job-pattern","name":"GraphQL async-job pattern","description":"Async job mutations with status types or progress subscriptions, so long-running work looks like progress instead of a hang.","layer":"usability","maxScore":2,"bonus":false,"applicability":"api","protocol":"graphql","appliesTo":["domain"],"tier":"recommended","maturity":"verified","draft":false,"beta":false,"recommendation":"For long-running GraphQL work, model it as an async job: return a job/task type the agent can query for status, and consider a subscription for progress, so a mutation does not block on slow work."},{"id":"graphql-schema-completeness","name":"GraphQL schema description coverage","description":"Descriptions on at least 80% of your GraphQL types and fields. A well-described schema documents itself to any agent that introspects it.","layer":"usability","maxScore":3,"bonus":true,"applicability":"api","protocol":"graphql","appliesTo":["domain"],"tier":"recommended","maturity":"verified","draft":false,"beta":false,"recommendation":"Document your GraphQL schema thoroughly - descriptions on your types, fields, and arguments - so agents can decide how to call your API from the schema alone."},{"id":"graphql-batch-mutations","name":"GraphQL batch mutations","description":"Bulk mutation fields (createMany, updateMany) so agents can act at scale in one round trip instead of hundreds.","layer":"usability","maxScore":2,"bonus":true,"applicability":"api","protocol":"graphql","appliesTo":["domain"],"tier":"recommended","maturity":"verified","draft":false,"beta":false,"recommendation":"Offer batch or bulk mutations (a mutation that accepts many inputs at once) so agents can apply changes to many records in a single round trip instead of one mutation per item."},{"id":"agent-ua-markdown","name":"Bot-UA markdown serving","description":"You recognize AI bots by their user-agent and serve them markdown even when they ask for HTML. Proactive courtesy for machine readers.","layer":"accessibility","maxScore":1,"bonus":true,"applicability":"domain-only","appliesTo":["domain"],"tier":"emerging","maturity":"emerging","draft":false,"beta":false,"recommendation":"Optionally detect AI-bot User-Agents (GPTBot, ClaudeBot, PerplexityBot) server-side and serve them a markdown representation of the page directly, even when they send Accept: text/html. Verify with `curl -A \"ClaudeBot/1.0\" https://yourdomain.com/` - a markdown body earns this bonus. Accept-header negotiation is scored separately."},{"id":"agent-friendly-404","name":"Agent-friendly 404s","description":"A real 404/410 status earns partial credit. Full credit also requires a Markdown error body, so agents can read what happened and where to go next.","layer":"usability","maxScore":2,"bonus":false,"applicability":"domain-only","appliesTo":["domain"],"tier":"recommended","maturity":"verified","draft":false,"beta":false,"specUrl":"https://www.rfc-editor.org/rfc/rfc9110#name-404-not-found","recommendation":"This check awards partial credit for a real HTTP 404/410 status and full credit when a Markdown error body is also available. If the status is already correct, keep it and add the Markdown body. Include at least 20 characters explaining the error and point agents to your docs, sitemap, or llms.txt. Verify with `curl -sS -L -i -H 'Accept: text/markdown' https://yourdomain.com/some-path-that-does-not-exist`. Check both the final 404/410 status and the Markdown body, served with Content-Type: text/markdown. A correct status with an HTML error page still earns only partial credit."},{"id":"ax-document-structure","name":"Accessible document structure","description":"Agents navigate your page the way screen readers do: by landmarks and headings. We check your HTML is a real document, with a main region, nav, and a sane heading order.","layer":"usability","maxScore":3,"bonus":true,"applicability":"domain-only","appliesTo":["domain"],"tier":"recommended","maturity":"verified","draft":false,"beta":false},{"id":"ax-native-controls","name":"Native interactive controls","description":"Buttons should be buttons. Clickable divs are invisible to agents that target elements by role and name, so they cannot click what your users can.","layer":"usability","maxScore":3,"bonus":true,"applicability":"domain-only","appliesTo":["domain"],"tier":"recommended","maturity":"verified","draft":false,"beta":false},{"id":"ax-accessible-names","name":"Accessible names on controls","description":"Every control needs a name a machine can compute (text, label, aria-label, alt). An unnamed icon button cannot be referenced, so it cannot be used.","layer":"usability","maxScore":2,"bonus":true,"applicability":"domain-only","appliesTo":["domain"],"tier":"recommended","maturity":"verified","draft":false,"beta":false},{"id":"ax-form-labeling","name":"Form control labeling","description":"Form fields with real labels, so agents know what each one expects. Placeholder text disappears on focus and never counts. N/A when a page has no forms.","layer":"usability","maxScore":2,"bonus":true,"applicability":"domain-only","appliesTo":["domain"],"tier":"recommended","maturity":"verified","draft":false,"beta":false},{"id":"ax-tree-injection-safe","name":"Accessibility-tree injection safety (bonus)","description":"We scan for hidden instructions in aria-labels, alt text, and off-screen content that could hijack an agent reading your page (prompt injection). Upside only; never costs points.","layer":"usability","maxScore":2,"bonus":true,"applicability":"domain-only","appliesTo":["domain"],"tier":"recommended","maturity":"verified","draft":false,"beta":false},{"id":"mcp-app-registry","name":"MCP Apps support","description":"MCP Apps let you ship real interactive UI inside ChatGPT and Claude, not just text answers. We check whether your server exposes any. N/A for pure API and data services.","layer":"usability","maxScore":4,"bonus":false,"applicability":"mcp-app","appliesTo":["domain","mcp","mcp-app"],"tier":"recommended","maturity":"verified","draft":false,"beta":false,"recommendation":"Add MCP Apps support to your MCP server using @modelcontextprotocol/ext-apps. Expose ui:// resources and add _meta.ui.resourceUri to tools so agents can render interactive UIs directly in conversation."},{"id":"a2ui-support","name":"A2UI / generative UI support","description":"Your product can render UI inside an agent conversation, via MCP Apps, the OpenAI Apps SDK, or generative UI patterns. Where users see you when they never visit your site.","layer":"usability","maxScore":2,"bonus":false,"applicability":"domain-only","appliesTo":["domain"],"tier":"emerging","maturity":"emerging","draft":false,"beta":false,"recommendation":"Support Agent-to-UI rendering via MCP Apps (ui:// resources), OpenAI Apps SDK, or generative UI patterns that let agents render interactive UIs in conversation."},{"id":"mcp-apps-ui-quality","name":"MCP Apps UI quality","description":"Your in-agent UI holds up to scrutiny: correct MIME type, valid HTML, dark mode support, and no hardcoded secrets in the markup.","layer":"usability","maxScore":4,"bonus":true,"applicability":"mcp-app","appliesTo":["domain","mcp","mcp-app"],"tier":"recommended","maturity":"verified","draft":false,"beta":false,"recommendation":"Ensure your MCP Apps resources use MIME type text/html;profile=mcp-app, include <!DOCTYPE html>, and add <meta name=\"color-scheme\" content=\"light dark\"> for dark mode. Never hardcode secrets in resource HTML."},{"id":"mcp-view-domain","name":"MCP App view reachable","description":"The view your MCP App points at loads publicly and serves HTML with no auth wall. A broken or gated view is worse than none: it fails in front of the user.","layer":"usability","maxScore":4,"bonus":false,"applicability":"mcp-app","appliesTo":["domain","mcp","mcp-app"],"tier":"recommended","maturity":"verified","draft":false,"beta":false,"recommendation":"Make sure your MCP App view is reachable and public. For inline ui:// resources: return HTML with <!DOCTYPE html> and no login form. For external HTTP origins (referenced via <base href> or <meta refresh>): return 200 OK + text/html without requiring auth (no 401/403, no password input in the body)."},{"id":"mcp-view-csp","name":"MCP App view CSP","description":"Your view's Content-Security-Policy has to satisfy the ChatGPT and Claude sandboxes, or your UI silently fails to render there. We check the directives they require.","layer":"usability","maxScore":4,"bonus":false,"applicability":"mcp-app","appliesTo":["domain","mcp","mcp-app"],"tier":"recommended","maturity":"verified","draft":false,"beta":false,"recommendation":"Add a Content-Security-Policy (via HTTP header or <meta http-equiv>) that scopes 4 directive categories: connect-src includes your MCP server origin; frame-ancestors includes both https://chatgpt.com and https://claude.ai; form-action (or connect-src) scopes redirect targets; img-src / script-src / style-src list specific origins (not *). Permissive default-src * receives partial credit but loses points compared to a properly-scoped policy."},{"id":"api-schema-analysis","name":"API schema complexity analysis","description":"Is your API simple enough for an agent to use without a human explaining it? Deeply nested, ambiguous schemas fail silently in agent hands.","layer":"usability","maxScore":2,"bonus":false,"applicability":"api","protocol":"either","appliesTo":["domain"],"tier":"recommended","maturity":"verified","draft":false,"beta":false,"recommendation":"Make your API spec self-describing: a unique operationId and a description on every operation, typed parameters, and response schemas. For GraphQL, a fully typed schema with a documented cost or rate limit reads best."},{"id":"agent-crawler-reachability","name":"Agent crawler reachability","description":"Whether the homepage is reachable to the major AI crawler/agent User-Agents (ChatGPT-User, ClaudeBot, Google-Extended, ora-agent, DeepSeekBot). A site that blocks these UAs is invisible to those agents from step one.","layer":"accessibility","maxScore":2,"bonus":false,"applicability":"domain-only","appliesTo":["domain"],"tier":"recommended","maturity":"verified","draft":false,"beta":false,"recommendation":"Allowlist the major AI crawler/agent User-Agents (ChatGPT-User, ClaudeBot, Google-Extended, ora-agent, DeepSeekBot) in your WAF, bot-detection rules, and robots.txt so agents can reach your homepage."},{"id":"function-calling-compat","name":"Function calling compatibility","description":"Whether your API spec translates cleanly into the function-calling format ChatGPT, Claude, and Gemini actually consume. Incompatible specs mean agents cannot call you even when they want to.","layer":"usability","maxScore":2,"bonus":false,"applicability":"domain-only","appliesTo":["domain"],"tier":"recommended","maturity":"verified","draft":false,"beta":false,"recommendation":"Ensure API endpoints have unique operation IDs, typed schemas, and descriptions compatible with LLM function-calling formats."},{"id":"mcp-resource-quality","name":"MCP resource quality","description":"The MCP resources you declare should actually read: valid type, non-empty content. We grade the share that works.","layer":"usability","maxScore":3,"bonus":false,"applicability":"mcp","appliesTo":["domain","mcp","mcp-app"],"tier":"recommended","maturity":"verified","draft":false,"beta":false,"recommendation":"Ensure every resource returned by resources/list reads cleanly via resources/read: declare a valid mimeType, return non-empty content, and make sure any URIs in the content resolve. Broken or empty resources break agent UX silently."}]}