Methodology
What we count, how we probe, and what the numbers mean. Full spec: source repository.
Harvest
Every source on the Sources page is pulled in full on a schedule. A listing is one record in one source. A remote endpoint is an HTTP(S) URL a third party could actually call: an MCP Streamable-HTTP URL, an A2A agent card, an ARD ai-catalog.json, an OpenAPI document, an OpenAI-compatible model API. Package-only listings (npm, PyPI, Docker, stdio transport) are counted as listings but are unprobeable by definition. URLs are normalised (scheme and host lower-cased, default ports and fragments dropped) before deduplication, so overlap between sources is exact-URL overlap.
Probe
Each endpoint kind gets the smallest real protocol interaction that proves it is what it claims to be. Nothing is executed and nothing is changed on the far side.
| kind | request sequence | score weights |
|---|---|---|
| mcp | POST initialize (Streamable HTTP, JSON or SSE response) → notifications/initialized → tools/list, resources/list, prompts/list → DELETE session. 401/403 + /.well-known/oauth-protected-resource = auth-required. GET returning text/event-stream = legacy HTTP+SSE. | reachable 20 · initialize ok 30 · protocolVersion 10 · serverInfo 10 · tools/list ok 20 · ≥1 tool 10 |
| a2a | GET /.well-known/agent-card.json (fallback agent.json) → validate required fields → JSON-RPC message/send with a labelled ping. | card fetched 20 · JSON 10 · required fields 20 · protocolVersion 10 · endpoint reachable 20 · send accepted or auth-required 20 |
| ard | GET /.well-known/ai-catalog.json, count resources by type. | fetched+JSON 60 · ≥1 resource 20 · version/$schema 20 |
| llm-api | GET /v1/models without credentials. | 200 with data[] 100 · 401/403 (alive, keyed) 70 |
| openapi | GET the document, check openapi/swagger, count operations. | valid 60 · ≥1 operation 40 |
| llms-txt agents-txt robots sigdir | Per-host conventions fetched once per host: llmstxt.org format check, agents.txt directives, robots.txt AI-bot rules and Content-Usage lines, Web Bot Auth /.well-known/http-message-signatures-directory. | format checks only; not part of the alive/conformant headline |
Outcomes
| outcome | meaning | counts as |
|---|---|---|
| ok | handshake completed and the protocol behaved as declared | alive, conformant |
| auth-required | reachable; the protocol step needs credentials we do not have | alive |
| card-invalid | manifest fetched but fails required-field validation | not alive |
| protocol-mismatch | reachable, but does not speak the declared protocol | not alive |
| http-error timeout tls-fail connect-fail dns-fail | transport-level failure on the primary fetch | not alive |
| blocked | resolves to a private, loopback, link-local or metadata address — we refuse to connect | excluded |
| unprobeable | no remote endpoint exists for this listing | excluded |
Politeness and safety
User-Agent agentprobe/x.y (+https://agentprobe.org/methodology). At most 2 concurrent requests and ≥0.5 s between requests per host. Bodies capped at 2 MiB, 5 redirects, 30 s total per fetch. DNS is resolved first and private ranges are refused on every hop. The A2A ping message identifies itself and asks to be ignored. To be excluded, block the User-Agent; we re-check robots.txt every run.
Limitations
A single vantage point (eu-central) — regional outages look like global ones. Auth-required endpoints are alive but we cannot see their capabilities. Registries that only expose HTML are harvested best-effort or not at all, and are marked unverified on the Sources page. The time series is incomplete by construction: endpoints enter when a source first lists them.