AI Agent Readiness and LLM Visibility: Tools, Results and Lessons for the Visibilio Website Builder

Illustration: screens with integration diagrams send data streams through a glass sphere to a team working on laptops

Agent readiness means that an AI agent can find a site's interfaces, read its pages without the visual layout and learn from standard documents what it may and may not do. On 17 October 2026 we measured kondevs.com with five public scanners, fixed what they found and recorded what we refused to fake. This is what they measure, what we built and what it means for the Visibilio Website Builder.

Agent-ready or agent-adjacent

If an AI agent cannot discover your APIs, read your content without parsing a visual layout and understand what it may and may not do, your site is not agent-ready. It is agent-adjacent. The difference matters because agents are becoming non-human actors in enterprise workflows, and the integration boundary is where policy either holds or fails silently.

The bottleneck is rarely the model. In McKinsey's State of AI survey for 2025, 62 percent of respondents said their organizations were at least experimenting with AI agents (23 percent scaling, 39 percent experimenting), yet in no business function did more than 10 percent report scaling them. Deloitte's Tech Trends 2026 cites a 2025 survey in which 48 percent of organizations named the searchability of data and 47 percent its reusability as challenges to AI automation. Microsoft's Cloud Adoption Framework guidance on agents (April 2026) asks that every agent be observable, governed and secure, and names the Model Context Protocol and Agent-to-Agent as the protocols to standardize on.

kondevs.com is the reference implementation of the Visibilio Website Builder: what we learn here becomes a proposal for every site the builder generates. On 17 October 2026 we ran the public agent-readiness scanners against it, read their source or methodology, fixed what they found and recorded what we chose not to fix. This article measures the technical preconditions for LLM visibility. Whether AI assistants actually find and cite a company is a separate measurement, covered in our article on LLM visibility. What an agent can do on the site is in How we made kondevs.com usable by AI agents.

The tools and what each one measures

Agent readiness has no single standard yet. Each scanner encodes its own view of what an agent needs.

ScannerWhat it checksResult on 17 October
Is It Agent ReadyDiscovery documents (robots.txt, sitemap, Link headers, API catalog, OAuth metadata, MCP server card, A2A agent card, agent skills, WebMCP, ARD), markdown negotiation, bot rules, commerce protocols93, Level 5; the one failing check, DNS-based agent discovery, waits for a DNSSEC record at the domain registrar
Is AgenticWhether agent user agents can reach the site, content without JavaScript, llms.txt, auth.md, page sizes against a context budget100/100
Mintlify Score (the open-source AFDocs checks)llms.txt quality and coverage, markdown at .md URLs, directives that point agents to llms.txt, page size, parity between HTML and markdown82 in the morning, 98 after the first set of changes
Ora132 checks in nine goals, from discovery and trust to integration, authentication and payments; many concern listings outside the site90 at 14:51 UTC, 93 at 16:17 UTC; the changes in sections 3 to 7 went live after that scan and wait for its next one
PageSpeed Insights, with the browser and security toolsPageSpeed's Agentic Browsing category beside performance, accessibility and SEO; WebPageTest, MDN HTTP Observatory, SSL Labs, SecurityHeaders and Internet.nl for speed, headers and TLSPageSpeed 99 mobile and 100 desktop, 100 for Accessibility, Best Practices and SEO, Agentic Browsing 4 of 4 applicable audits; Observatory 145/100, 12 of 12 tests; SSL Labs A+ on all four addresses

Two lessons came before any code. Read how a check works before fixing it: Mintlify publishes its checks as the AFDocs project and Ora documents each check's method, and more than once the fix we would have guessed was not the one the check rewards. And a report can be stale: two scanners showed results computed before the deployment we wanted measured.

1. One page, many readers

A markdown twin at every address

An agent that reads a web page pays in tokens for every menu, footer and script. Since July 2026 our pages have answered markdown when a client sends Accept: text/markdown. The documentation checks look for something simpler, an .md address. Both now work:

curl -s https://www.kondevs.com/about.md
curl -s -H "Accept: text/markdown" https://www.kondevs.com/about/

The .md address is not a second copy. When no file exists at that path, the site's middleware requests the page itself with Accept: text/markdown and returns that answer, with a canonical Link header back to the HTML page and noindex, so search engines keep indexing the page and not its twin. /about/index.md, /index.md and /de/index.md resolve too; real files such as /auth.md keep priority; an .md address with no page behind it answers a 404 in markdown. The home page's markdown is 6,865 bytes, and the server's x-markdown-tokens header estimates it at 1,714 tokens, so an agent can decide before it reads.

Telling agents where to look

Every page now points agents to llms.txt in both representations. In the HTML, the first element of the body is a short note with the addresses of llms.txt, llms-full.txt and the page's own .md twin; it is visually hidden, aria-hidden and out of the tab order, so screen-reader and keyboard users never meet it. In the markdown, the answer opens with the page's frontmatter (title, description, canonical, language, dates) and one quote line:

> For the complete index of this site, see [llms.txt](https://www.kondevs.com/llms.txt); the whole site in one file: [llms-full.txt](https://www.kondevs.com/llms-full.txt).

Every page also carries <link rel="alternate" type="text/markdown" href="/about.md"> in its head, and the HTTP response the same link. The not-found page carries none: an advertisement that points to nothing is worse than none.

2. llms.txt as an index, not a dump

llms.txt is a markdown file at the root of a site that tells language models what the site is and where its important pages are. Three findings changed ours.

Links to markdown. Every page link now uses the .md address: all 30 same-site links lead to markdown, 25 of them .md addresses and five text indexes. The JSON and XML documents (OpenAPI, the API catalog, the feeds, the sitemap) cannot be markdown, so they stay in llms.txt as plain URLs.

Coverage. Mintlify compares the pages linked from llms.txt, and from the text files it links, with the sitemap's pages that it counts as documentation: the English ones, without the German twins and without paths it treats as company pages, such as /about/ and /pricing/. Of the 60 sitemap entries, that is 33 pages. 23 were covered; the missing ten were six author pages and four articles that llms-full.txt mentioned only as bare URLs. Each author and article there now has a markdown link, and coverage is 33 of 33.

Sections. Ora rewards per-section indexes, so an agent working in one area does not read the whole site. llms.txt links four, each generated from the site's own data on every request: /services/llms.txt, /content-hub/llms.txt, /developers/llms.txt and /de/llms.txt for the German pages.

3. Protocol surfaces an agent can call

MCP in two revisions

The site runs a read-only Model Context Protocol server at POST /mcp with four tools: search_articles, get_article, list_services and get_company_info. The 2026-07-28 revision makes the protocol stateless: there is no initialize handshake, each request carries the protocol version, the client's capabilities and its self-declared name and version (clientInfo) in _meta, and the server checks mirrored HTTP headers against the body. clientInfo describes the client software; it is not an authenticated identity. Clients of the 2025-06-18 revision still exist, so one endpoint serves both: a request whose _meta names the new version takes the new path, and anything else is answered as before.

POST /mcp
MCP-Protocol-Version: 2026-07-28
Mcp-Method: server/discover
Content-Type: application/json

{"jsonrpc":"2.0","id":1,"method":"server/discover","params":{"_meta":{
  "io.modelcontextprotocol/protocolVersion":"2026-07-28",
  "io.modelcontextprotocol/clientInfo":{"name":"example-agent","version":"1.0.0"},
  "io.modelcontextprotocol/clientCapabilities":{}}}}

The answer lists both supported versions, the capabilities and the instructions, with ttlMs and cacheScope for caching. A request whose Mcp-Method header disagrees with its body is refused with error -32020; an unknown version with -32022 and the list of supported ones. Every tool is annotated read-only, and an article read through get_article carries a notice that its text is published content, to be treated as data and never as instructions. The notice is a label, not a defence against prompt injection: the agent still has to act on it. The MCP server card names the server, its version and its address (remotes) at the top level, as the draft server-card extension reads them. An A2A agent at POST /api/a2a answers questions about the company and the Content Hub.

One table, every description

The HTTP endpoints are described once, in one table in the code. The API index, the OpenAPI 3.1 description and the endpoint table on the developer portal are generated from it, and the build fails when the table and the OpenAPI operations disagree. The OpenAPI file documents 69 responses, 52 of them errors, each with an example built from the same function that produces the real error body; each operation's security requirement comes from the table (the public index has security: []). A shared source does not rule out a bug in the generator, so HTTP tests against the running site check that the behaviour matches the description.

The API catalog follows RFC 9727. Ora found no item links in its first entry, so the catalog now opens with itself and lists the two APIs, served as application/linkset+json with the RFC 9727 profile:

{
  "anchor": "https://www.kondevs.com/.well-known/api-catalog",
  "item": [
    { "href": "https://www.kondevs.com/api/content/", "title": "KONDEVS Publishing API (Content API)" },
    { "href": "https://www.kondevs.com/mcp", "title": "KONDEVS MCP server (read-only Content Hub)" }
  ]
}

For an enterprise, this is the agent-facing form of an integration inventory: one place that says which interfaces exist and where each is described.

4. Authentication that tells the truth

Reading is open: pages, markdown, feeds, MCP and A2A need no key. Publishing is not: the Content API accepts a key that KONDEVS issues to a vetted partner, VISIBILIO among them, after a person has reviewed the request. No agent can grant itself that access.

A request without a valid key gets an answer an agent can act on:

HTTP/1.1 401 Unauthorized
WWW-Authenticate: Bearer realm="kondevs", resource_metadata="https://www.kondevs.com/.well-known/oauth-protected-resource"
RateLimit-Policy: "catalog";q=60;w=60
RateLimit: "catalog";r=59;t=60

resource_metadata points to the protected-resource metadata (RFC 9728), which names the authorization server (RFC 8414). A token that was sent but is invalid adds error="invalid_token"; a valid token without the needed scope gets 403 with error="insufficient_scope" (RFC 6750).

auth.md follows the eight steps of the auth.md profile (discover, pick a method, register, claim, exchange, use the token, errors, revocation) and says at each step what KONDEVS offers and what it does not. There is one method, OAuth client credentials with an issued key; anonymous registration, email-based registration and identity assertions from an outside provider are not offered; there is no claim ceremony, because the human review is the human step; there is no revocation endpoint, because a token lives one hour and a key is revoked by rotation. The agent_auth block in the authorization-server metadata matches: it names the registration endpoint (identity_endpoint) and an empty identity_types_supported. A scanner rewards a full list. An honest empty one is the right architecture decision.

The same rule decided the Personal Agent Protocol document. Its draft lets a company declare APIs and sign-in flows, but every declared API must accept the protocol's own session tokens. Ours do not, so /.well-known/poppy.json declares the website only:

{ "protocol_version": "0.1", "organization": { "name": "KONDEVS", "domain": "www.kondevs.com" }, "web": {} }

5. Pagination and rate limits an agent can plan with

Ora suggested cursor-based pagination for the catalog. Changing the existing contract would break the partners that use it, so the cursor is an addition: GET /api/content/catalog accepts ?cursor= and answers next_cursor, null on the last page, and without a cursor the answer is what it was. A token the catalog did not issue is a 400, never a silent restart from the top.

Every rate-limited answer carries the IETF RateLimit header fields and their X-RateLimit-* counterparts, and a 429 adds Retry-After. The catalog used to check the key first and count the request second, so its 401 carried no rate-limit headers. It now counts first: the 401 tells an agent how much room it has, and repeated attempts with a wrong key are counted against the same policy.

That counter has limits worth stating. It keeps recent request times per client in KV, and KV is eventually consistent with no atomic increment, so concurrent requests, especially from different Cloudflare locations, can read the same count and all pass. It slows a brute-force attempt to roughly the policy's pace; it is not a hard ceiling. A strict limit needs an atomic counter, such as a Durable Object or the platform's own rate-limiting feature. We did not add a limit to the public index or the health endpoint: they touch no storage, so an anonymous caller cannot make them spend storage operations, only the processing of a request.

6. Structured data that matches the page

The organization is typed Organization and LocalBusiness, with its Sofia address, service area and two contact points; the previous type, ProfessionalService, is deprecated by schema.org. The home page lists its three services as Service nodes in an ItemList, each with the same @id as the node on its own service page. Technical articles are TechArticle, and articles written with VISIBILIO name VISIBILIO as the author and KONDEVS as the publisher, the same byline a reader sees and an agent receives through MCP.

Ora also checks whether an agent can find pricing. KONDEVS prices every engagement for its own scope, and inventing a price list to satisfy a scanner was not an option. The new pricing page says how each way of working is priced (embedded specialists by the day, end-to-end delivery as a fixed quote for a defined scope) and lists the steps from a first conversation to a quote. Its structured data is an OfferCatalog in which the only price is the one that is true: the first conversation, at 0 EUR.

7. Freshness: dates that track real changes

Ora found lastmod on only 26 percent of our sitemap entries: the articles had them, the pages did not, because the easy value, the deployment date, changes on every deployment and teaches search engines to ignore the field. The sitemaps protocol asks for the date the page last changed.

Our approach: for a page that is code, the build takes the date of the last commit that touched the page's own source files (its template, its copy, its data), and an uncommitted change counts as changed on the day of the build. An article carries its own last change; the home page, the Content Hub and each category listing carry the later of their code's date and their newest article. All 60 entries now have a date, and none is the deployment date. Git is a proxy with known gaps: a commit can change only layout, and a change in a shared component or a removed article can change a page without touching its listed sources. The dates are as good as the source lists behind them, so those lists are checked by a test.

For natural-language indexers built on NLWeb, robots.txt now names a schema map, a short XML file that lists the site's four full-text feeds (RSS and JSON Feed, English and German).

8. What we deliberately did not do

Ora alone runs 132 checks. Some reward signals a site can send without doing the work behind them; we declined those, and some real ones whose cost is not justified yet.

SuggestionWhy we did not do it
Answer 401 on public endpoints so a probe finds a WWW-Authenticate headerThe endpoints are public by design; a fake 401 would break every client that reads them
Serve markdown to AI crawlers that asked for HTMLThe answer would depend on the user agent rather than on what the client asked for; explicit negotiation (Accept or .md) treats every client alike and avoids anything that could look like cloaking
Declare anonymous or email-based agent registration, a claim ceremony or a revocation endpointWe do not run them; declaring them would send agents into flows that fail
Declare our APIs in the Personal Agent ProtocolThey do not accept the protocol's session tokens
Replace page-and-limit pagination with cursorsPartners depend on the current contract; the cursor is an addition instead
A ?mode=agent view, an NLWeb /ask endpoint, batch endpoints, a sandboxLittle value for a site of this size in October 2026; the markdown twins and MCP already serve agents
A price listEngagements are priced per scope; the only true price on the site is the free first conversation

Some remaining findings are not code: an entry in the MCP registries, a Wikidata item, and the DNSSEC record at the registrar. Those are on the company's list, not the site's.

9. The outage the scans exposed

In the afternoon, after many full test runs and every scanner crawling the sitemap, the sitemap and the German Content Hub started answering 500.

The load exposed an architectural dependency on a capped operation. The site runs on Cloudflare Workers with Workers KV for its articles, on the Workers Free plan: 100,000 KV reads but only 1,000 list operations a day. Three code paths listed keys on every request: the sitemap and the author pages listed the article index, and every German page and feed fell back to listing it because the German archive key did not exist yet (there is no German article). Ordinary traffic had never reached the cap. A day of scanners, link checkers and our own test runs did, and Cloudflare answered that the account had reached the free usage limit for that operation for the day.

The fix was one commit. The sitemap and the author pages read the published archive, one key read each, instead of listing the index, and a missing archive whose list fails reads as empty and is logged instead of failing the request. With the quota still exhausted, every affected address answered 200 on the preview, and production followed the same evening. The lessons apply to any integration platform:

  • Keep list operations off public request paths. A list is a maintenance operation; reading a precomputed key is a request operation.
  • Measuring a system is load. Scanners, link checkers and test suites on preview deployments share the account's quota.
  • Know your platform's caps before a spike finds them. Workers Paid includes a million list operations a month and bills further ones; the free plan's 1,000 writes a day matter too, because a rate limiter that writes a counter on every call spends them.

10. Results

MeasureBeforeAfter
Mintlify Score8298
Ora90 (14:51 UTC)93 (16:17 UTC, before the changes in sections 3 to 7)
Documentation pages of the sitemap covered by llms.txt23 of 3333 of 33
Same-site llms.txt links that lead to markdownpage links led to HTML30 of 30
Pages with a markdown twin at .mdnoneevery page
Sitemap entries with a lastmod26 percent60 of 60

Is Agentic (100/100) and Is It Agent Ready (93, Level 5, with DNSSEC pending) were at those values at the end of the day. The scores use different criteria and are not comparable with each other.

LLM visibility: what the scores do not measure

Every tool above measures whether an agent can reach the site, read it cheaply and call it safely. None measures what a buyer sees: whether ChatGPT, Claude, Perplexity, Copilot or an AI Overview names KONDEVS when someone asks about enterprise integration, and whether it describes the company correctly. This article reports no such answers.

The work above supplies the inputs. Markdown an assistant can read without the layout, an llms.txt that covers every page, structured data that matches the visible page, full-text feeds and a consistent byline make a site easier to find, quote and attribute. Whether that turns into citations is measured by asking the assistants the questions buyers ask, at regular intervals, and recording which sources they name; our method and first results are in the article on LLM visibility.

Lessons for the Visibilio Website Builder

kondevs.com is the builder's reference site, so each lesson is a proposal for the base template every generated site starts from. Together they are also a checklist for any site:

  1. Markdown twins by default: every page at its .md address and by Accept: text/markdown, announced with rel="alternate", with the llms.txt directive at the top of the HTML and the markdown.
  2. llms.txt from the site's data: an index of markdown links plus one per section, generated on request and checked against the sitemap.
  3. Discovery documents from one table: OpenAPI, the API catalog with item links and the developer docs generated together, an example for every error, and tests that the running site behaves as described.
  4. Refusals that explain: 401 with WWW-Authenticate and resource_metadata, 403 with insufficient_scope, and RateLimit headers on every limited answer, the 401 included.
  5. Limits that say what they are: a KV counter is a brake, not a ceiling; where a strict limit matters, use an atomic counter.
  6. No list operation on a public request, and a hosting plan sized to the traffic, scanners included.
  7. Sitemap dates that track real changes: never the deployment date, with the method's gaps covered by tests.
  8. Honest declarations: empty lists where a capability is not run, a website-only Personal Agent Protocol document unless sessions exist, and a pricing page that states how work is priced when there is no price list.
  9. Measure like the outside world, carefully: read each scanner's method, rescan after deploying, and remember that every test run spends the site's quota.

Beyond the website

A corporate website is a small integration boundary, but once agents call it, it raises the questions an ERP, a B2B gateway or an internal API platform raises: who is calling, what may it do, how much may it do, and can an operator see what it did. The last question needs more than annotations and notices; it needs request logs, identifiers that follow a call across systems, monitoring and alerts. Every declared capability is a contract, and none should be declared that the team cannot back up at 02:00 on a Tuesday. Agent readiness is an integration architecture question, and the answer is the one it has always been: if it is not governable, it is not production-ready.

Frequently asked questions

What does "agent-ready" mean for a company website?

An AI agent can find the site's content and interfaces, read pages without parsing the visual layout, call its tools, and understand what it may and may not do, all from documents the site publishes in standard places. A person and an agent get the same facts, each in the format they read best.

Why serve a page at a `.md` address when content negotiation already works?

Not every client can set request headers. Agents that follow links from llms.txt, and tools that fetch URLs as given, need an address that returns markdown by itself. The `.md` address gives them one, while the canonical link keeps search engines on the HTML page.

Can AI agents publish on kondevs.com?

No agent can grant itself publishing rights. Reading is open to every agent; publishing goes through the Content API with a key that KONDEVS issues to vetted partners such as VISIBILIO after a person has reviewed the request. A partner's agent that holds a valid key can then publish automatically within its scope, so any review of each individual article happens in the partner's own workflow, not on the site.

What does Cloudflare's free plan limit for a site like this?

On Workers Free, KV allows 100,000 reads, 1,000 writes and 1,000 list operations per day. A site that reads precomputed keys stays far below the read limit; one that lists keys on every request, or writes a rate-limit counter on every call, can reach the list or write limit on a busy day.

Sources

  1. McKinsey, The state of AI in 2025: Agents, innovation, and transformation
  2. Deloitte Insights, The agentic reality check (Tech Trends 2026)
  3. Microsoft Cloud Adoption Framework, Govern and secure AI agents across the organization
  4. RFC 9727, api-catalog
  5. RFC 9728, OAuth 2.0 Protected Resource Metadata
  6. RFC 8414, OAuth 2.0 Authorization Server Metadata
  7. RFC 6750, OAuth 2.0 Bearer Token Usage
  8. RateLimit header fields for HTTP (IETF draft)
  9. Model Context Protocol, revision 2026-07-28
  10. The llms.txt proposal
  11. auth.md, agent registration profile
  12. Personal Agent Protocol, draft 0.1
  13. AFDocs, the checks behind the Mintlify Score
  14. Sitemaps protocol
  15. Cloudflare Workers KV limits
  16. How Cloudflare Workers KV works (eventual consistency)
  17. schema.org OfferCatalog

Related concepts & services

Key terms: Model Context Protocol (MCP), Large Language Model (LLM), AI Agent, Middleware

Explore our service: AI Agent Development

Related articles

Case Studies

How we made kondevs.com usable by AI agents

What an AI agent can read, call and publish on kondevs.com, how it is built on Cloudflare, and the rules that kept it honest: read-only by default, one table per contract, errors and limits a machine can act on.

12 min read

Facing a similar challenge?

Tell us about your systems and goals, and we'll share how we would approach it.

Talk to an integration architect