Finding Hookbase Without a Human: Server Cards, Agent Cards, and DNS
An agent can now find Hookbase on its own: an MCP Server Card (SEP-2127) and an A2A Agent Card at well-known URLs, an ARD manifest that lists both, mirrors on api.hookbase.app and www.hookbase.app, and DNS-based discovery records under _agents.hookbase.app on a DNSSEC-signed zone.
The Part Before the First Tool Call
In Built to Be Used by Agents, Not Just Read by Them we made the public site readable and usable by agents that land on it: llms.txt, raw-markdown docs, and WebMCP-annotated free tools. That covered an agent that already knows where to look.
This update covers the step before that. If an agent starts from nothing but the name "hookbase.app", how does it learn that there's an MCP server, where it lives, which protocol versions it speaks, and how to authenticate? Until now the answer was "a person reads the docs and pastes a URL into a connector." Now the answer is published in machine-readable places that discovery tooling already checks: well-known URLs on the web, and records in DNS.
What's New
- MCP Server Card (SEP-2127) at
https://mcp.hookbase.app/mcp/server-card, the location the spec reserves, and the same document at/.well-known/mcp/server-card.json - A2A Agent Card at
https://mcp.hookbase.app/.well-known/agent-card.json, describing a real A2A v1.0 JSON-RPC endpoint at/a2awith three read-only skills - An ARD manifest at
/.well-known/ard.json(and its predecessor path/.well-known/ai-catalog.json) that lists the MCP server and the A2A agent, each pointing at its own card - The same documents on api.hookbase.app and www.hookbase.app, because discovery tools only look on the host they were given
- DNS discovery records under
_agents.hookbase.app, on a zone that is now signed with DNSSEC
The Server Card: What It Says, and What It Leaves Out
The Server Card is a small static JSON document that names the server and tells a client how to reach it:
{
"$schema": "https://static.modelcontextprotocol.io/schemas/v1/server-card.schema.json",
"name": "app.hookbase/mcp",
"version": "…",
"description": "Webhook relay: manage sources, destinations, routes, deliveries, and tunnels.",
"title": "Hookbase",
"websiteUrl": "https://hookbase.app",
"repository": { "url": "https://github.com/HookbaseApp/mcp-server", "source": "github" },
"remotes": [
{
"type": "streamable-http",
"url": "https://mcp.hookbase.app/mcp",
"supportedProtocolVersions": ["2025-06-18", "2025-03-26", "2024-11-05"]
}
]
}
It's served as application/mcp-server-card+json, with Access-Control-Allow-Origin: * and a one-hour public cache, so a browser-based client can read it too.
Some early write-ups describe a different shape for this document, with a serverInfo wrapper and a static list of tools, resources and prompts. We followed the ratified extension's schema instead, which leaves primitives out on purpose: the tool list depends on who is asking, so a client should discover it live with tools/list. We didn't want the card to list capabilities that the endpoint doesn't actually have. That review showed that the hosted transport answered only tools/list and tools/call. So we didn't advertise more. We implemented the rest. The remote endpoint now answers resources/list, resources/templates/list, resources/read, prompts/list and prompts/get, and its initialize response declares tools, resources and prompts, all backed by the same registries the local npx server uses.
The spec's reserved location is <endpoint>/server-card, which is why the canonical copy is at /mcp/server-card. The .well-known copy is the identical document for tooling that looks there.
The A2A Agent Card and Its Three Skills
The A2A Agent Card describes a different kind of interface: agent-to-agent messages instead of tool calls. Our endpoint is intentionally small. It's a stateless, message-only agent: POST /a2a accepts the JSON-RPC method SendMessage and answers with a direct message. There are no long-running tasks, so the card declares streaming: false and pushNotifications: false.
It exposes three read-only skills, each one a thin wrapper over an existing MCP tool, so the input schema and the behavior are shared rather than copied:
| Skill id | Wraps | What it does |
|---|---|---|
| check-delivery-status | hookbase_get_delivery | One delivery in detail, including the response body and error |
| list-recent-deliveries | hookbase_list_deliveries | Recent deliveries, filterable by destination, event and status |
| list-sources | hookbase_list_sources | All webhook sources in the organization |
These skills don't route natural-language requests. A caller names the skill in a single data part:
curl https://mcp.hookbase.app/a2a \
-H "Authorization: Bearer whr_your_api_key" \
-H "Content-Type: application/json" \
-d '{
"jsonrpc": "2.0",
"id": 1,
"method": "SendMessage",
"params": {
"message": {
"messageId": "b6f1c3e2-0000-4000-8000-000000000001",
"role": "ROLE_USER",
"parts": [
{ "data": { "skill": "list-recent-deliveries", "input": { "status": "failed", "limit": 10 } } }
]
}
}
}'
The reply is a ROLE_AGENT message with one application/json data part holding the tool's result. An unknown skill id gets a JSON-RPC error. So does input that fails the tool's schema. Neither one gets a best-effort guess.
Authentication is the same whr_ API key used by the REST API and the MCP server, sent as a Bearer token. The Agent Card declares it as a Bearer security scheme, and both ARD entries mention it, so an agent knows what credential to send before it makes a call. A request without the header gets a 401.
One Manifest, Three Hosts
The ARD manifest at /.well-known/ard.json is a short index with two entries: the MCP server, which points at /mcp/server-card, and the A2A agent, which points at /.well-known/agent-card.json. Each entry references its card instead of repeating it, so the index can't disagree with the cards. The A2A entry's capability list is generated from the same skill registry as the Agent Card. The root of mcp.hookbase.app also advertises the manifest in an RFC 8288 Link header.
Discovery tools check one host at a time, and the documents live on mcp.hookbase.app. Someone pointing a tool at api.hookbase.app or hookbase.app (which redirects to www) would have found nothing. Both of those Workers now serve the Server Card, Agent Card and ARD manifest at the same well-known paths. They fetch each document from the MCP Worker over a Cloudflare service binding and pass the body through unchanged, so there's one source of truth and no copy to fall out of date. On the API host, these routes are registered ahead of the global CORS middleware, which would otherwise replace the wildcard Access-Control-Allow-Origin with the dashboard's origin.
Discovery in DNS
The last layer doesn't need HTTP at all. Following the DNS-AID draft, the hookbase.app zone now publishes HTTPS records (RFC 9460) under an _agents label:
_mcp._agents.hookbase.app: a ServiceMode record that points atmcp.hookbase.app, withalpn="h2,h3"andport=443_a2a._agents.hookbase.app: a ServiceMode record that points at the same host, where the A2A endpoint lives_index._agents.hookbase.app: an AliasMode entry point that points at_mcp._agents.hookbase.app
Because discovery is per hostname, the same three names also exist under _agents.api.hookbase.app. Each record describes a service that is already running. We don't publish a record for something that isn't live yet.
DNS answers are only worth trusting if they can't be forged in transit, so the zone is now signed with DNSSEC (ECDSA P-256 with SHA-256, algorithm 13), with the DS record published at the .app registry. A validating resolver can check the whole chain from the root down to these records.
You can look them up yourself:
dig +dnssec HTTPS _mcp._agents.hookbase.app
What We Deliberately Didn't Publish
Agent-readiness checklists also ask for OAuth authorization-server metadata and protected-resource metadata. Hookbase authenticates agents with API keys, not an OAuth authorization server, so publishing that metadata would point clients at endpoints that don't exist. Those checks stay unmet until there's a real OAuth flow to describe. The A2A agent is also read-only for now. Replays and other changes still go through the MCP server.
Try It
Fetch https://mcp.hookbase.app/mcp/server-card or https://mcp.hookbase.app/.well-known/agent-card.json to see what an agent sees. To connect a client, the MCP server docs cover both the hosted endpoint and the local npx server, and an API key from your dashboard works for MCP and A2A alike.