turva.dev

Agent readiness brief

# Your documentation vendor publishes an MCP Server Card on your domain, and your MCP server does not

How agents could be used, and a measured starting point.

Prepared for HubSpot. By turva.dev, 28 August 2026.

## The shape of the opportunity

HubSpot ships an agentic layer rather than a chatbot bolted onto a CRM. The llms.txt at www.hubspot.com names six agent product pages and carries a section titled AEO, agentic engine optimization, and mcp.hubspot.com answers a request from an agent that holds no token. The people who buy that surface are the teams who integrate, and increasingly the assistants those teams work through. Agent readiness touches you in one place, and it is not inside any of those products. It is what an agent can find out about HubSpot before it holds a single token.

## Where agents act

- A developer's assistant deciding whether the HubSpot API covers a task, and needing to cite the reference page it read.
- A customer's assistant finding out that a HubSpot MCP server exists for it at all, and which scopes it may ask for.
- A partner's agent resolving where the platform documents itself, starting from the address your product site publishes.

## What agents need before they can act

An agent can only act on what is machine readable and bounded by a clear decision envelope. The products, the specifications and any data interface have to be readable by a machine, through structured data, a markdown form and a documented API, and the agent has to operate inside explicit guardrails. This is the measurable core of agent readiness, and where the work lives.

## A measured starting point

On 28 August 2026 I ran an independent agent readiness scanner against www.hubspot.com.

isitagentready: Level 1 / 5, basic web presence

| discoverability | content accessibility | bot access control | api, auth, mcp and a2a discovery |
| --- | --- | --- | --- |
| 2/4 | 0/1 | 1/2 | 0/9 |

The measurement is from 28 August 2026. You can run the same scanner yourself at isitagentready.com.

## What this means

The scanner reads three of sixteen applicable checks as passing on www.hubspot.com, which is Level 1 of 5. I ran it twice against that address and the two readings agree category by category. The three that pass are robots.txt, a sitemap at the conventional address, and the absence of any AI specific rule, so whatever the wildcard allows reaches AI crawlers as well. All nine checks in the group the scanner labels api, auth, mcp and a2a discovery fail. The scanner reads your root, and your root is not where your best work is, which is most of what follows.

The part you already do well comes first, because it is the reason the rest is worth fixing. mcp.hubspot.com publishes OAuth discovery to the specification, and I measured it three consecutive times with the same result each time. An unauthenticated request to that host answers 401 with a WWW-Authenticate header carrying a resource_metadata parameter that names /.well-known/oauth-protected-resource, which is what RFC 9728 asks for. That document answers 200 with 174 bytes of JSON. Its sibling /.well-known/oauth-authorization-server answers 200 with 813 bytes naming authorization_endpoint, token_endpoint, an introspection endpoint and code_challenge_methods_supported S256. api.hubapi.com serves both documents at the same sizes and the same digests, so the same metadata answers on your API host as well.

Two fields in those documents stop an agent anyway. In both, scopes_supported is an empty list, so an agent learns that authorization exists and not one thing it may ask for. Neither document carries a registration_endpoint, so dynamic client registration is not advertised. And mcp.hubspot.com/.well-known/mcp/server-card.json answers 404, so the host that runs the server does not describe it.

All three of those gaps are answered elsewhere on your domain, and not by you. developers.hubspot.com/docs/.well-known/mcp/server-card.json answers 200 with 336 bytes. Its sibling oauth-protected-resource answers 200 with 140 bytes and the authorization server document answers 200 with 615 bytes, and that one does carry a registration_endpoint and a scopes_supported that is not empty. Every one of the three names the host hubspot.mintlify-auth-docs.com rather than a hubspot.com host, so what answers there is your documentation platform describing its own search server. It carries the marks of a platform default: the card is named HubSpot docs Docs MCP, its tools array is empty while its capabilities say tools are supported, and the endpoint it names answers a GET with 405. So the document an agent needs is being served on your domain, and it describes someone else's server.

Location is what makes this hard to see from inside. Each of those documents sits under /docs/, one directory below the origin root where the specifications put them. I asked all eight hosts I measured for a Server Card at the address the specification names, three requests each, and all eight answered 404, mcp.hubspot.com among them. At the origin root of developers.hubspot.com the two OAuth documents answer 404 as well, and so do api-catalog, agent-card.json, ai-catalog.json and agent-skills/index.json. At www.hubspot.com the same well known addresses answer 404, and so do auth.md and an address I invented, so that host does tell a missing file apart from a page. Your 404 is honest to a request that accepts HTML. An agent that follows the specification and asks at the root finds nothing, and an agent that happens to try a documentation prefix finds a working layer.

One behaviour is worth fixing on its own, whatever else changes. www.hubspot.com/.well-known/api-catalog answers 404 to a request that sends Accept text/html, and the same to a request that accepts anything. The same address answers 406 and zero bytes when the request sends Accept application/linkset+json, which is the media type RFC 9727 tells an agent to send, and it answers 406 and zero bytes to Accept application/json as well. I measured that matrix three requests per combination, with my own user agent and again with a browser user agent, and the answer follows the Accept header rather than the user agent. A correctly written agent therefore receives less than a browser receives, and it receives a status that means the server refused the format rather than one that means the document is not there.

You publish two llms.txt files and they do not know about each other. developers.hubspot.com/docs/llms.txt answers 200 with 28 966 bytes across 346 lines, all 52 of its links end in a .md address, and it names your developer MCP server on three lines. That is a good file. www.hubspot.com/llms.txt answers 200 with 30 688 bytes across 292 lines and 27 sections, and it is a catalogue of the product site: 197 of its 201 markdown links point back to www.hubspot.com, two point to developers.hubspot.com and the remaining two go to ecosystem.hubspot.com and academy.hubspot.com. It names six agent product pages and carries a section titled AEO, agentic engine optimization. The string mcp does not appear in it once, no address in it ends in .md, and it does not name the other file. Its own last line says it was updated on 16 July 2026. Neither host names either file in robots.txt, and www.hubspot.com/robots.txt is 12 606 bytes with 356 Disallow lines and not one Sitemap line, while its sitemap exists at the conventional address and carries 3 030 addresses.

The same split runs through content negotiation, and it is why the reading above understates you. Requesting developers.hubspot.com/docs/apps/developer-platform/overview with the header Accept: text/markdown returns 200 and 14 499 bytes of text/markdown, and the docs index returns 200 and 11 536 bytes the same way. Both held still across three requests. The same header returns HTML at www.hubspot.com, at a product page, at a knowledge base article and at developers.hubspot.com/ai-tools/mcp. So content accessibility reads 0 of 1 because the scanner asked your root, and your documentation would have answered.

Scope. This looks only at public surfaces as they answered on 28 August 2026. The measured hosts are www.hubspot.com, hubspot.com, developers.hubspot.com, knowledge.hubspot.com, ecosystem.hubspot.com, mcp.hubspot.com, api.hubapi.com and app.hubspot.com. Every request was an anonymous GET to a public address, three consecutive requests per address, and every code and size quoted above was identical on all three. No HTML page size is quoted anywhere in this brief, because that number moves by a byte between requests and none of the claims here needs it. I did not log in, create a portal, install an agent, connect a connector, issue an API key, register an OAuth application, start an MCP session, run a command line tool or send one authenticated call. I make no claim about anything behind authentication, about which tools either MCP server exposes, about credits, about portal settings, about pricing, about product behaviour, about your arrangements with any vendor, or about your marketplace listings, whose pages render in the client and which this measurement cannot read. The readings from the scanner are its own and are not byte measurements. The commerce checks are set aside, because the scanner does not read a product and documentation site as a shop.

## The bigger opportunity

Three changes, and none of them is a new system. The first is to stop answering an agent shaped Accept header with 406 and zero bytes, because that is the one place where a correct agent does worse than a browser. The second is an MCP Server Card for your own server, at mcp.hubspot.com/.well-known/mcp/server-card.json, so that the card an agent finds on your domain is one you wrote. The third is to state in your own metadata which scopes the server accepts and how a client registers, because those are the two questions an agent has to answer before it can ask for a token, and because the vendor's document on your domain already answers both. None of this is work you have not done. It is work that is published one directory down and under someone else's name.

I can send the full per check breakdown and a short readiness map for www.hubspot.com. No call needed for any of it.

There is a larger piece of work behind this one, and it is a different job from the three changes above. Every organisation running your agents, your workflows and your connectors has to be able to say what those agents can do, on which data, in whose name, under which approval, at what cost, and how a wrong action is stopped and reversed. Those teams look for that answer in your published documentation, and it is spread across several of your own sites rather than gathered in one place. I have written a scoped outline for an independent review of exactly that, built only from your public sources, and I am happy to send it to whoever owns that question at your end. If you want either of those, write tell me more. If this is not something you want, write no thanks and I will not come back to it.

For reference, the same isitagentready scanner scores turva.dev 100/100 and Level 5 of 5, agent-native. It passes 21/21 checks.

| discoverability | content accessibility | bot access control | api, auth, mcp and a2a discovery | commerce |
| --- | --- | --- | --- | --- |
| 4/4 | 1/1 | 2/2 | 9/9 | 5/5 |
