feat(agents): auth.md, Web Bot Auth, A2A Agent Card, OAuth discovery

Merged
RI
2d ago
+541-98

Summary

Agent-readiness discovery surfaces on capgo.app (isitagentready checks), each describing something that actually exists:

  • /auth.md: how agents get credentials: OAuth 2.1 + PKCE for the hosted MCP server (api.capgo.app/mcp), API keys, and CLI login. Also lists the headers to send. Linked from llms.txt guidance and the markdown 404.
  • Web Bot Auth: /.well-known/http-message-signatures-directory serves an Ed25519 JWKS (application/http-message-signatures-directory+json). The response is signed (tag="http-message-signatures-directory") when the WEB_BOT_AUTH_PRIVATE_JWK secret is set. The worker's outbound fetches (GitHub sponsors, status.capgo.app) are signed via Cloudflare's web-bot-auth library. Without the secret, behaviour is unchanged (unsigned).
  • A2A Agent Card: /.well-known/agent-card.json (+ legacy /.well-known/agent.json) describes the hosted MCP server. The interface uses a custom binding URI (A2A spec §5.8) for MCP Streamable HTTP, so A2A clients don't send JSON-RPC calls to an endpoint that can't answer them. Skills come from the same tool groups as mcp.json. Security schemes are OAuth (PKCE) and a Bearer API key.
  • RFC 9728: /.well-known/oauth-protected-resource with resource: https://capgo.app (must match the origin), authorization_servers: [https://capgo.app], scope capgo.
  • RFC 8414, capgo.app as issuer: /.well-known/oauth-authorization-server serves the hosted MCP authorization server's metadata. The API generates it (Cap-go/capgo.app#3803 sets MCP_OAUTH_ISSUER=https://capgo.app). The response is cached for 1h with a stale fallback, and is only served when issuer === "https://capgo.app"; until then it returns 503. Endpoints stay on api.capgo.app. No jwks_uri: access tokens are opaque API keys, so nothing is signed.

Not implemented on purpose: ACP, AP2, UCP and x402 (no agent checkout or payment flow exists), and DNS-AID (Cloudflare DNS, not in this repo).

Deploy order

Deploy this PR before Cap-go/capgo.app#3803. That PR points MCP clients at https://capgo.app as the issuer, so this route must already be live.

Deploy follow-up

Enable Web Bot Auth signing with the matching private key (kept outside the repo):

cd apps/web && bunx wrangler secret put WEB_BOT_AUTH_PRIVATE_JWK < ~/.config/capgo/web-bot-auth-ed25519.private.jwk

A key that doesn't match the published public key is ignored.

Test plan

  • bun test apps/web/test apps/web/src/worker: 254 pass
  • bun run lint
  • astro check: 0 errors
  • astro build emits dist/auth.md
  • Request signatures verified with web-bot-auth verify(). The directory signature verifies for capgo.app and fails for another authority.
  • OAuth metadata loader tested for the capgo.app issuer and rejects any other issuer
  • After deploy: run the isitagentready scan for capgo.app

🤖 Generated with Claude Code


View with [code]smith Autofix with [code]smith
Need help on this PR? Tag @codesmith-bot with what you need.