How to make a website agent-ready
Published:
"Agent-ready" means three different things to three different kinds of AI agent — and they stack. Here is exactly how we made this validator agent-ready, with the code we shipped, so you can copy the pattern.
There are three independent layers. Adopt any one on its own; together they cover a crawler reading your site, an agent driving your UI in the browser, and another agent calling you over the network.
Layer 1 — llms.txt: context for crawlers
The baseline. A plain-text llms.txt at your root tells an AI crawler what your site is and which pages matter, in priority order. It's read at fetch time — no JavaScript, no protocol. Start here: how to create one.
Layer 2 — WebMCP: tools for in-browser agents
WebMCP lets a page expose callable tools to an AI agent running inside the browser, so the agent invokes a typed action instead of guessing at your form. There are two ways, and we ship both.
Declarative — annotate a real form and the browser synthesizes a tool from it:
<form toolname="open_llms_txt_report"
tooldescription="Validate a site's llms.txt and open its report.">
<input name="url" toolparamdescription="Domain or URL to validate">
</form>
Imperative — register a tool in JavaScript that returns structured data directly:
navigator.modelContext?.registerTool({
name: "validate_llms_txt",
description: "Validate a website's llms.txt; returns a 0-100 score and findings.",
inputSchema: { type: "object", properties: { url: { type: "string" } }, required: ["url"] },
execute: (input) => fetch("/api/validate?url=" + encodeURIComponent(input.url))
.then(r => r.json())
.then(data => ({ content: [{ type: "text", text: JSON.stringify(data) }] }))
});
Guard the imperative call behind if (navigator.modelContext) so it's a no-op where WebMCP is absent. It's a Chrome origin trial today, so real reach is small — treat it as a forward signal, not traffic.
Layer 3 — A2A: a callable agent for other agents
The Agent2Agent (A2A) protocol lets other agents discover and call your service. You publish an agent card and back it with a JSON-RPC endpoint:
// GET /.well-known/agent-card.json
{
"name": "llms.txt Validator",
"url": "https://llms-txt-validator.dev/a2a",
"skills": [{ "id": "validate_llms_txt", "name": "Validate llms.txt" }]
}
The url must point at a working endpoint that speaks A2A — we implement the synchronous message/send method, wrapping the same validation logic as a skill. The card is a contract, not a meta tag.
The one rule: don't publish a signal you can't back
It's tempting to drop an empty agent card or fake form annotations to turn an audit green. Don't. An agent that fetches your card and calls a dead endpoint — or invokes a tool that does nothing — trusts you less afterward. Every signal here should resolve to something real. That's why this validator reports a WebMCP or A2A signal as "present" only when a working implementation backs it.
How to verify each layer
- llms.txt — paste your domain into the validator; aim for 100/100 with no broken links.
- WebMCP — in Chrome 149+, enable
chrome://flags/#enable-webmcp-testingand run Lighthouse's Agentic Browsing audit; your tools should be listed. - A2A — fetch your
/.well-known/agent-card.json, then POST amessage/sendcall to itsurland confirm you get a completed task back.