# mcp-proxy
Proxy fronting the Apollo MCP server, including auth application_family: user-platform

## nginx variant — testing locally

The nginx rules live in `nginx/templates/default.conf.template` (built by the root
`Dockerfile`). The proxy is a full OAuth facade: it serves the PRM and AS/OIDC
metadata with its own origin as issuer, bridges `/authorize` (302/307), `/token`
(forwarded POST) and static `/register` to Auth0, and streams `/mcp` through to
apollo-mcp (re-issuing 401 challenges with its own resource_metadata URL).

### 1. Config syntax check

The stock image entrypoint env-substitutes the template before `nginx -t` runs:

```sh
make build
make check
```

### 2. Run it and curl each rule

Two local gotchas:

- `RESOLVER` defaults to `169.254.169.253` (the AWS VPC DNS — same resolver in every
  VPC; nginx needs an explicit `resolver` for variable `proxy_pass`, it does not read
  `/etc/resolv.conf`). Locally, override it with Docker's embedded DNS `127.0.0.11`,
  which only exists on a **user-defined** network.
- Be on VPN so the container can resolve/reach `qa-apollo-mcp.theorchard.io`.

```sh
make run-local     # compose + local overrides (docker DNS, PROXY_ORIGIN=http://localhost:8080)
make logs
```

```sh
curl -s localhost:8080/health                                          # ok
curl -si -X POST localhost:8080/register | head -3                     # 201 + static client JSON
curl -si 'localhost:8080/authorize?client_id=x&scope=openid' | grep -i '^location'
                                                                       # 302 → qa-orchard.auth0.com, query intact
curl -si -X POST localhost:8080/authorize | head -1                    # 307
curl -si localhost:8080/.well-known/oauth-authorization-server | grep -i '^location'  # 302 → Auth0
curl -s -X POST localhost:8080/token -d 'grant_type=authorization_code&code=fake&client_id=fake'
                                                                       # Auth0 JSON error (invalid_grant/client)
                                                                       # = the POST forward reached Auth0
curl -s localhost:8080/.well-known/oauth-protected-resource            # PRM JSON from qa-apollo-mcp (VPN)
curl -si -X POST localhost:8080/mcp -H 'content-type: application/json' \
  -d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{}}'      # 401 + WWW-Authenticate
```

The last two prove the passthrough: the PRM body means the upstream proxy leg works,
and the `/mcp` 401 with `WWW-Authenticate` is apollo-mcp's own challenge arriving
through the proxy.

### 3. Real client end-to-end

```sh
npx @modelcontextprotocol/inspector
```

Streamable HTTP → `http://localhost:8080/mcp`. Full OAuth discovery works locally:
the proxy serves its own PRM + AS metadata advertising `PROXY_ORIGIN`
(`http://localhost:8080` via `docker-compose.local.yaml`), so clients never see the
upstream's origin. Or run a throwaway Claude Code session (session-only MCP config):

```sh
make claude-test
```

Watching `make logs` during auth should show the full ladder: `POST /mcp` 401 →
PRM → AS metadata → `/authorize` 302 → `POST /token` 200 → `POST /mcp` 200.
