feat(mcp): use https://capgo.app as the OAuth issuer

Merged
RI
2d ago
+114-13

Summary

Make https://capgo.app the OAuth issuer of the hosted MCP authorization server. Scanners and OAuth clients can then discover it on the main domain, as RFC 8414 requires. The endpoints don't move.

  • New MCP_OAUTH_ISSUER var (set to https://capgo.app in the prod wrangler env). When unset, the issuer falls back to the request origin, so preprod, alpha and local behave exactly as before.
  • New MCP_OAUTH_API_ORIGIN var (prod: https://api.capgo.app): the only API origin advertised for MCP OAuth (endpoints, resource, PRM URL), whichever hostname the request arrives on (e.g. api.usecapgo.com). Unset → request origin.
  • getIssuer() → config. A new getApiOrigin() keeps serving the authorize/token/register/revoke endpoints, the MCP resource and the WWW-Authenticate resource_metadata URL on the API origin.
  • Uses of the issuer: issuer in /.well-known/oauth-authorization-server, authorization_servers in the protected resource metadata, the RFC 9207 iss redirect parameter, and the issuer stored on mcp_oauth_requests (so approve/deny redirects send the same iss).
  • RFC 8414 §3.3: when the issuer is another origin, /.well-known/oauth-authorization-server (and its /mcp variant) on the API returns 404 instead of metadata with a mismatched issuer. The metadata is exposed at /mcp/oauth/metadata for capgo.app to serve.
  • Tokens are unchanged: still opaque API keys, and existing connections keep working.

⚠️ Deploy order

capgo.app must serve /.well-known/oauth-authorization-server from /mcp/oauth/metadata before this ships. Cap-go/website#1244 (merged) added the route, and Cap-go/website#1245 reads the new endpoint with a fallback. Deploy website#1245 first, then this PR. Otherwise the PRM points clients at an issuer with no metadata, and new MCP logins fail.

Note: very old MCP clients that skip protected resource metadata and read api.capgo.app/.well-known/oauth-authorization-server directly now get 404. Current clients use PRM and are unaffected.

Test plan

  • vitest run tests/mcp-oauth-issuer.unit.test.ts tests/mcp-remote.unit.test.ts: 31 pass (covers the single api.capgo.app origin across hostnames, the configured issuer, the 404 at the API well-known URL, /mcp/oauth/metadata, PRM and the WWW-Authenticate challenge)
  • bun run lint:backend
  • bun run typecheck:backend
  • After both deploys: connect an MCP client to https://api.capgo.app/mcp and complete the OAuth login
  • 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.