---
title: What it actually took to make a monitoring platform agent-ready
description: AI agents are becoming real API consumers, and scanners now grade how usable your product is for them. We spent a week taking WatchFor from a mediocre agent-readiness score to 100/100 — two MCP servers, OAuth 2.1, signed probes, a no-auth sandbox, and a pile of lessons about what agents (and their scanners) actually check. Here's all of it, including what didn't work.
canonical: https://watchfor.io/blog/what-it-took-to-make-monitoring-agent-ready
---

# What it actually took to make a monitoring platform agent-ready

2026-08-28 · WatchFor Team · Engineering · engineering, architecture, monitoring

AI agents are becoming real API consumers, and scanners now grade how usable your product is for them. We spent a week taking WatchFor from a mediocre agent-readiness score to 100/100 — two MCP servers, OAuth 2.1, signed probes, a no-auth sandbox, and a pile of lessons about what agents (and their scanners) actually check. Here's all of it, including what didn't work.

**Update, 11 September 2026:** the score below is from August. On 10 September
ora.ai rated watchfor.io **100/100** and listed it first — the last six points,
and what the number does not mean, are in
[a follow-up](/blog/100-on-ora-ai).

A growing share of the traffic hitting SaaS products isn't a person in a browser — it's an agent acting for one. "Set up uptime monitoring for my API" is now a sentence people type into Claude or ChatGPT, and whichever product the agent can actually *operate* wins that customer.

There are now scanners that grade exactly this — automated audits that crawl a domain the way an agent would and score how usable it is for them. When we first pointed one at watchfor.io, we scored **40/100**. A week of focused work later we're at **A-grade on orank** (ora.ai's agent-readiness index — [see our live report](https://ora.ai/score/watchfor.io)) and **[100/100 on is-agentic.com](https://is-agentic.com/scan/watchfor.io)** — and, more importantly, an agent can go from *never having heard of WatchFor* to *running its first authenticated API call* with no human in the loop.

This post is the honest engineering log: what we built, what each piece is for, and the measurement quirks we hit along the way.

## What "agent-ready" actually means

Strip away the buzzwords and an agent needs the same things a good developer needs, minus patience:

1. **Discovery** — can it find out what you offer without clicking through marketing pages?
2. **Authentication** — can it get scoped credentials without a sales call?
3. **Usability** — do your APIs behave predictably: typed schemas, structured errors, rate-limit headers, pagination?
4. **Trust** — can both sides verify who they're talking to?

Everything below maps to one of those four.

## The agent stack, in one table

If half these acronyms are new — that was us three months ago. Quick reference for everything this post touches:

| Term | What it is |
| --- | --- |
| **MCP** (Model Context Protocol) | An open protocol that lets AI assistants (Claude, ChatGPT, Cursor…) call a product's "tools" directly — think USB for AI integrations. A product runs an *MCP server*; the assistant is the *client*. |
| **A2A** (Agent2Agent) | A protocol for agent-to-agent delegation: instead of calling individual endpoints, one agent hands another a whole task ("diagnose what's broken") described in its Agent Card. |
| **Function calling** | How LLMs invoke external code: the model picks a function and fills its typed arguments. OpenAPI specs get converted into these function definitions automatically. |
| **OpenAPI 3.1** | The machine-readable description of a REST API — every operation, parameter and schema. For agents it doubles as the function-calling contract. |
| **OAuth 2.1** | The current consolidation of OAuth: authorization-code flow with mandatory PKCE. MCP clients use it to get scoped tokens with zero copy-pasted API keys. |
| **DCR** (Dynamic Client Registration) | Lets an OAuth client register itself programmatically — required so any MCP client can connect without us pre-approving it. |
| **llms.txt** | A convention (llmstxt.org): a markdown site guide at `/llms.txt` that tells language models what a site offers and where. |
| **agents.md** | A companion convention: an instruction card for agents — when to use the product, how to authenticate, first calls to make. |
| **ARD** (Agentic Resource Discovery) | A `/.well-known` catalog listing every machine surface a domain offers (APIs, MCP servers, agents, SDKs) with stable identifiers. |
| **Web Bot Auth / RFC 9421** | HTTP message signatures: a bot signs its requests with a private key and publishes the public key, so anyone can verify the traffic is genuine — not a spoofed User-Agent. |
| **JSON-RPC** | The lightweight request/response format both MCP and A2A speak: `{"method": …, "params": …}` over HTTP. |

## Discovery: files agents actually read

The entry points are boring text files at predictable URLs:

- [`/llms.txt`](/llms.txt) — a structured site guide. One hard lesson: there's a soft **30,000-character budget** for a navigation index. Ours crept to 30.5k and got flagged; we now treat it like a performance budget.
- [`/agents.md`](/agents.md) — an instruction card: when to use WatchFor, when *not* to (we explicitly say "not for log aggregation or APM"), how to authenticate, and the first three calls to make.
- [`/.well-known/ai-catalog.json`](/.well-known/ai-catalog.json) — an ARD catalog listing every machine surface (API, MCP servers, A2A, SDKs) with stable URN identifiers.
- **Markdown twins** — every content page is also served as clean markdown: append `.md` to the path, send `Accept: text/markdown`, or add `?mode=agent`. Browsers and Googlebot still get HTML, so there's no SEO impact; agents skip the DOM parsing entirely.

A Next.js gotcha that cost us real hours: a rewrite whose *destination* contains a `.well-known` dot-segment silently 404s. Everything under `/.well-known/` on our site is rewritten to clean `/api/well-known/*` routes for that reason.

## The OpenAPI spec is a function-calling contract now

Agents don't read your API docs — their frameworks convert your OpenAPI spec into tool definitions for function calling. That conversion is stricter than any human reader:

- **Every operation needs an `operationId`** — it becomes the function name.
- **Responses should be `$ref`s to named schemas.** We moved every list envelope from inline objects to named `List` components.
- The subtle one: **path-level `parameters` are invisible** to most converters. OpenAPI lets you declare shared parameters on the path item, and we did — which made `GET /monitors/{id}` look like a *function with no arguments*. A scanner insisted only 30 of our 57 operations were typed until we hoisted every path-level parameter down into the operations. If your detail endpoints look argless to agents, this is probably why.

We also changed `DELETE` endpoints from `204 No Content` to `200` with `{"object": "deleted", "id": …}` — Stripe semantics. An empty 204 is fine for humans; an agent wants a schema'd confirmation it can assert on.

## Two MCP servers, not one

Our [MCP server](/docs/api/mcp) exposes 40 tools over the same REST API — same auth, same rate limits, same validation. Design choices that mattered:

- **Anonymous discovery.** `initialize` and `tools/list` work without credentials. Scanners, registries and curious agents can inspect the full tool inventory before anyone creates an account. Tool *calls* still require auth.
- **Structured errors.** An unknown tool returns a JSON-RPC `-32602` with the available tool names; tool-level failures return `{"error": {"code", "message"}}`. Prose errors are where agent loops go to die.
- **Resources and prompts, not just tools.** The monitor-type catalog, the OpenAPI spec and the quickstart are MCP *resources*; common jobs ("diagnose what's broken") are parameterized *prompts*.

Then we added a second, read-only **documentation MCP server** at [`/api/docs-mcp`](/docs/api/mcp#documentation-mcp-server) — `list_docs`, `search_docs`, `read_doc` over all 67 docs pages, no auth at all. Agents use one protocol to *act* and the same protocol to *learn*.

## OAuth 2.1: zero-key onboarding

API keys assume a human in a dashboard. For MCP clients we run a full OAuth 2.1 authorization server: dynamic client registration, PKCE (S256 only), and a mandatory consent screen. Add `https://watchfor.io/api/mcp` to Claude and it discovers the auth server, opens a browser consent page, and gets scoped tokens — **no key is ever copied**. The same tokens work on the REST API, with `write` scope gating anything that mutates.

For agents that would rather delegate whole tasks than call endpoints, there's also an [A2A agent](/.well-known/agent-card.json) exposing task-level skills ("diagnose incidents", "reliability report") over JSON-RPC. The agent card is generated from the live skill registry, so it always lists the current set.

## A sandbox agents can find

Every payload of our no-auth sandbox returns sample data in the *exact* production shapes, marked `"sandbox": true`. Two discoverability lessons:

1. We documented it in `agents.md` — scanners still couldn't "verify a sandbox exists". They don't follow prose links reliably.
2. What worked: serving it at the **conventional paths** scanners actually probe — [`/sandbox`](/sandbox) and `/api/sandbox` — and declaring it as a second `server` in the OpenAPI spec.

If you build a thing for agents, put it where conventions say it should be, not just where your docs say it is.

## Signed probes: trust in both directions

The trust question runs both ways. Our probes hit customer infrastructure millions of times a day identifying as `WatchForBot` — and a User-Agent string is trivially spoofable.

So every HTTP(S) probe request is now **signed with the fleet's Ed25519 key** using [RFC 9421](https://www.rfc-editor.org/rfc/rfc9421) HTTP message signatures (the Web Bot Auth profile):

```
Signature-Agent: "https://watchfor.io"
Signature-Input: sig1=("@authority" "signature-agent");created=…;expires=…;
                 keyid="BOtvqWNOvlmOUZNVE2MMbkWVpAz9QVgZIOSsMJTivg0";alg="ed25519";tag="web-bot-auth"
Signature: sig1=:…:
```

Public keys live at [`/.well-known/http-message-signatures-directory`](/.well-known/http-message-signatures-directory). Before enabling it fleet-wide we captured a live probe request with tcpdump and verified the signature against the published key — it checks out end to end. Bot-management platforms that support Web Bot Auth can now allowlist WatchFor probes on cryptographic proof instead of substring-matching a User-Agent. Details on [/bot](/bot).

## Registries, SDKs, and the long tail

The rest is distribution: the MCP server is listed on [Smithery](https://smithery.ai/servers/hello-65wl/watchfor); official zero-dependency SDKs with a `watchfor` CLI ship on [npm](https://www.npmjs.com/package/watchfor), [PyPI](https://pypi.org/project/watchfor/) and [RubyGems](https://rubygems.org/gems/watchfor); and our [agent-toolkit repo](https://github.com/watchfor-io/agent-toolkit) carries `AGENTS.md`, installable agent skills and an Agent Plugins manifest.

## What didn't move the needle (yet)

Honesty section. Two things resisted a week of engineering:

- **Brand search.** Scanners literally Google (and Bing) your name. Our site is young; "WatchFor" doesn't reliably crack the top results yet. No amount of code fixes that — only indexing time and mentions. If you're launching something agent-facing, submit to Google Search Console *and* Bing (ChatGPT search runs on Bing) on day one, not month two.
- **Live onboarding tests.** One scanner runs an actual agent through your signup flow. It's a genuinely good check that's genuinely hard to fully satisfy — and that's fine. The point was never the score; it's that the friction it measures is real.

## Takeaways

- Agent-readiness is mostly **normal API craftsmanship**, applied ruthlessly: typed everything, structured errors, predictable URLs, self-serve auth.
- **Conventions beat documentation.** Agents and scanners probe well-known paths; being *described* somewhere is worth far less than being *where expected*.
- The exotic-sounding parts — MCP, A2A, signed requests — are each a few hundred lines on top of a clean REST API. If your API is a mess, no protocol adapter saves you.
- Scanners are imperfect proxies, but arguing with the mirror misses the point: every gap they flagged was something a real agent would also trip on.

Want to poke at any of this? Start at [/agents.md](/agents.md) — no account needed for the interesting parts.

---

Canonical page: https://watchfor.io/blog/what-it-took-to-make-monitoring-agent-ready · All articles: https://watchfor.io/blog/all.md · Site guide: https://watchfor.io/llms.txt
