--- category: reference tags: - P1 - infrastructure - oauth - mcp last_updated: 2026-03-13 --- # P1-9: Fix MCP OAuth Discovery Routing ## Problem Claude.ai needs to discover OAuth endpoints via `/.well-known/oauth-authorization-server` to initiate the OAuth flow with the MCP server. Two issues prevented this: 1. **Missing API Gateway route:** `/.well-known/*` paths hit the Otterwiki Lambda (`$default` catch-all) instead of the MCP Lambda, returning HTML instead of OAuth metadata JSON. 2. **Double path in resource URL:** `MCP_BASE_URL` was set to `https://dev.wikibot.io/mcp`, but FastMCP's `_get_resource_url()` appends the `mcp_path` parameter (`/mcp`) to the base URL, producing `https://dev.wikibot.io/mcp/mcp`. ## Solution Two infrastructure changes, no code changes: 1. **Added API Gateway route** `ANY /.well-known/{proxy+}` pointing to the MCP Lambda integration. This routes OAuth discovery requests to the correct Lambda. 2. **Changed `MCP_BASE_URL`** from `https://dev.wikibot.io/mcp` to `https://dev.wikibot.io`. FastMCP now computes the correct resource URL `https://dev.wikibot.io/mcp` via `_get_resource_url("/mcp")`. ## Verification All endpoints tested after deploy: | Endpoint | Expected | Actual | |----------|----------|--------| | `GET /.well-known/oauth-authorization-server` | WorkOS OAuth metadata JSON | Pass | | `GET /.well-known/oauth-protected-resource/mcp` | Protected resource metadata JSON | Pass | | `POST /mcp` (with bearer token) | MCP initialize response (200) | Pass | | `POST /mcp` (no auth) | 401 Unauthorized | Pass | | `GET /Home` | Otterwiki HTML | Pass | ## Files Changed - `infra/Pulumi.dev.yaml` — `mcp_base_url` value - `infra/__main__.py` — new `mcp-route-well-known` API Gateway route ## How It Works ``` Client → GET /.well-known/oauth-authorization-server → API Gateway route: ANY /.well-known/{proxy+} → MCP Lambda → Starlette route: /.well-known/oauth-authorization-server → AuthKitProvider forwards WorkOS metadata Client → GET /.well-known/oauth-protected-resource/mcp → API Gateway route: ANY /.well-known/{proxy+} → MCP Lambda → Starlette route: /.well-known/oauth-protected-resource/mcp → Returns resource metadata with authorization_servers Client → POST /mcp (MCP protocol) → API Gateway route: ANY /mcp → MCP Lambda → Starlette route: /mcp → StreamableHTTP handler ``` ## Commit `e46ef4a` on `main` branch (not pushed)