Check C4, machine endpoints and agent manifests, is the check most sites score zero on and the one rated High effort, because for most sites it means building something. A developer tools company has already built it. There is an API, there is very probably an OpenAPI document somewhere in the build, and there is a documentation site. What is usually missing is the last hundred metres: the spec is not at a URL anyone links, the docs live on a subdomain the homepage never mentions, and nothing tells an agent any of it exists. Closing that gap is an afternoon, and it takes C4 from zero to five. This post covers that, then the two checks a developer tools site tends to lose next, A7 on the docs and A4 on the text file that should be generated from them.
We use our own surfaces as the worked example, because they are the ones we can vouch for: /docs, /api/v1/openapi.json, /mcp and /agents.json.
The pages an agent fetches
A developer's agent arrives with a task: work out whether this tool does the thing, how to authenticate, what the call looks like, what it costs, and whether it has changed recently. So it fetches the docs index, the quickstart, the authentication page, the API reference for the one endpoint it cares about, the pricing page and the changelog. The homepage matters only as the place it learns where they are, and each fetch is a plain GET of raw HTML, which is why A7 appears below.
C4, nearly free
C4 is 5 points. The scanner tests for four surfaces and awards three points for one and five for two or more; the evidence field is found, a list of which it saw. The tests are literal, and knowing them exactly is most of the fix.
/agents.jsonreturns 200 and parses as JSON.- The homepage HTML contains the string
openapi.json,openapi.yaml,openapi.ymlor theswaggerequivalents, anywhere in the markup. - The homepage HTML contains
/.well-known/mcp,mcp.jsonormodelcontextprotocol. - The homepage HTML contains an
hrefwith/docs,/docor/api-docsin it, or a hostname beginningdeveloper.ordevelopers.. A link tohttps://docs.example.com/satisfies this, because the string/docsoccurs in it.
Only the homepage is read for the middle three, and nothing is fetched or validated, so a spec referenced from nowhere scores nothing.
For a developer tools site the fourth surface is almost certainly already present, since the homepage links the docs. That is three points. The second is the afternoon's work: serve the OpenAPI document your API already has at a stable URL and link it from the homepage footer, labelled as what it is. That is five. Publishing an OpenAPI spec for a site that has no API covers what a good document contains, and the OpenAPI 3.1 specification is the reference. The summary and description strings are what an agent reads to choose an operation, and no generator writes them for you.
Our homepage footer links the spec and the docs, and /agents.json parses, so found on our report lists three surfaces. It does not list an MCP manifest, because a link to /mcp matches none of the strings in the third test, and we have not added a modelcontextprotocol reference to the homepage just to trip it.
The MCP server as the next step
An MCP server is the machine surface that sounds like the most work and, for read-only data, is not. The Model Context Protocol is JSON-RPC over HTTP: a client asks tools/list, reads each tool's name, description and argument schema, and calls tools/call when the model decides a tool answers the question. Ours is a single POST route with five read-only tools over the same data layer as the REST API, stateless and unauthenticated because everything it returns is already public; building an MCP server for a marketing site describes it as the code does it.
For a developer tools company the tools follow from the docs. search_docs with a query and get_doc with a path, returning the page text rather than a link to it, so the model saves a fetch. get_endpoint with an operation id, returning the reference entry for one call. get_changelog with a version or a date. Each is a thin function over content you already serve, and each is more reliable for an agent than scraping the rendered page. Keep the first version read-only; anything that creates a key or changes an account is a different design, with consent in it. Declare the server in agents.json with its transport and authentication, as ours does.
A7 on the docs
A7, server-rendered content parity, is 5 points. The scanner takes the visible text of the raw homepage HTML and divides its length by the length of the text after a headless render. At or above 0.8 scores five; between 0.5 and 0.8 scores three; below 0.5 scores zero. The evidence is rawTextLength, renderedTextLength and ratio.
The scan measures the homepage only, and a developer tools homepage is usually fine. The docs are where the ratio collapses, and the docs are what the agent came for. Several documentation frameworks ship the page as a shell and hydrate the content, or render the reference for an endpoint from a spec in the browser, so a plain fetch of the authentication page returns a navigation tree and nothing else. A docs subdomain is not in the scan at all, so this failure is invisible on the report and entirely real for the agent.
Measure it yourself. Measuring server-rendered parity gives the method, and the one-line version is to fetch a reference page with curl, strip the tags, and see whether the parameter table is there. If it is not, the fix is at the framework level: static generation or server rendering for every docs route, with the reference rendered to HTML at build time rather than in the browser. Most documentation frameworks can do this; not all of them do it by default, and the framework's own docs say which.
An llms.txt generated from the docs tree
A4 is 4 points, Low effort. The scanner fetches /llms.txt and counts lines of the form - [title](url): description, a markdown link followed by a colon and a description. Three or more scores three points; a file with fewer scores one; an /llms-full.txt that returns 200 adds the fourth. The evidence is present, describedLinks, anyLinks and llmsFullTxt.
A docs tree already has a title and a summary per page, which is exactly the raw material, so do not write the file by hand. Generate it from the docs index at build time: an h1, a blockquote saying what the tool is and who it is for, then one described link per docs page, grouped by section, with the quickstart and authentication pages first. Generate llms-full.txt from the same tree as the concatenated page text in markdown, so an agent that needs the substance can read the documentation in one fetch. The llms.txt convention is short and worth reading in full.
Ours is built that way, from the route registry that also feeds the sitemap and site search, and ends with notes for agents naming the search URL template, the OpenAPI document and the MCP endpoint. How to write an llms.txt that earns its place is the general guide.
The fixes, in order of effort
| Effort | Fix | Check |
|---|---|---|
| Minutes | Link the docs from the homepage, with /docs in the path |
C4 |
| An hour | Serve the existing OpenAPI document at a stable URL and link it from the footer | C4 |
| An hour | Publish /agents.json listing the spec, the docs and the API base URL |
C4 |
| A morning | Generate llms.txt and llms-full.txt from the docs tree at build time |
A4 |
| A day | A read-only MCP server over docs search, the reference and the changelog | C4 |
| Days | Static or server rendering for every docs route, reference included | A7 |
The first two take C4 to full marks; the last is the only item that is genuinely High effort.
Check your own site
Run the free scan on your marketing domain and read found under C4 and ratio under A7, then run the parity test above against a docs page by hand, since the scan will not visit it. The definitions are under actionability and discovery and access on the methodology page, and everything described here is live on our own report.