---
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)
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9