Please be gentle with me here, this is a .md that I had generated with Claude that documented the steps I had to take to get this project working. This is also my first GitHub issue I've ever made. Let me know if I did alright? lol
Note: Tested against the official Docker image ghcr.io/freema/openclaw-mcp:1.4.1 pulled from GHCR with no modifications prior to applying the fixes described below.
Description
Two bugs prevent openclaw-mcp from connecting to Claude.ai when running behind a reverse proxy (Cloudflare Tunnel, ngrok, etc.).
Note: MCP_ISSUER_URL was correctly set to the public HTTPS tunnel URL per the README. These bugs occur independently of that setting.
Bug 1: X-Forwarded-For validation error crashes OAuth token endpoint
Symptoms: docker compose logs shows a repeating ValidationError from express-rate-limit:
ValidationError: The 'X-Forwarded-For' header is set but the Express 'trust proxy'
setting is false (default). This could indicate a misconfiguration...
ERR_ERL_UNEXPECTED_X_FORWARDED_FOR
This causes the /token endpoint to fail, breaking the OAuth flow entirely.
Root cause: Express's trust proxy setting is false by default. When running behind a proxy that sets X-Forwarded-For, express-rate-limit throws a ValidationError.
Fix: Add app.set('trust proxy', 1) immediately after createMcpExpressApp() in src/server/sse.ts:
const app = createMcpExpressApp({ host: config.host });
app.set('trust proxy', 1); // ← add this
Suggested improvement: Support a TRUST_PROXY environment variable so users can configure this without patching the source.
Bug 2: Claude.ai connects to / (root) instead of /mcp
Symptoms: After OAuth completes successfully, Claude.ai hits POST / and GET / which return 404, and the connector shows as failed.
Root cause: Claude.ai uses the resource URL from /.well-known/oauth-protected-resource as the MCP endpoint. This resolves to the server root (/), but the MCP streamable HTTP handler is only registered at /mcp.
Fix: Register the streamable HTTP handler at / in addition to /mcp in src/server/sse.ts:
// Existing
app.get('/mcp', ...withAuth(handleStreamableRequest));
app.post('/mcp', ...withAuth(handleStreamableRequest));
app.delete('/mcp', ...withAuth(handleStreamableRequest));
// Add these for Claude.ai compatibility
app.get('/', ...withAuth(handleStreamableRequest));
app.post('/', ...withAuth(handleStreamableRequest));
app.delete('/', ...withAuth(handleStreamableRequest));
Environment
- openclaw-mcp version:
1.4.1
- Deployment: Docker behind Cloudflare Tunnel
- Client: Claude.ai custom MCP connector
- OS: Debian 13
Steps to Reproduce
- Deploy openclaw-mcp with
AUTH_ENABLED=true behind Cloudflare Tunnel or ngrok
- Add a custom MCP connector in Claude.ai pointing to the tunnel URL
- Click Connect — OAuth flow fails with
ValidationError (Bug 1), or succeeds but MCP connection fails with 404 (Bug 2)
Both fixes were verified working together. Happy to open a PR if helpful!
Please be gentle with me here, this is a .md that I had generated with Claude that documented the steps I had to take to get this project working. This is also my first GitHub issue I've ever made. Let me know if I did alright? lol
Description
Two bugs prevent openclaw-mcp from connecting to Claude.ai when running behind a reverse proxy (Cloudflare Tunnel, ngrok, etc.).
Bug 1:
X-Forwarded-Forvalidation error crashes OAuth token endpointSymptoms:
docker compose logsshows a repeatingValidationErrorfromexpress-rate-limit:This causes the
/tokenendpoint to fail, breaking the OAuth flow entirely.Root cause: Express's
trust proxysetting isfalseby default. When running behind a proxy that setsX-Forwarded-For,express-rate-limitthrows aValidationError.Fix: Add
app.set('trust proxy', 1)immediately aftercreateMcpExpressApp()insrc/server/sse.ts:Suggested improvement: Support a
TRUST_PROXYenvironment variable so users can configure this without patching the source.Bug 2: Claude.ai connects to
/(root) instead of/mcpSymptoms: After OAuth completes successfully, Claude.ai hits
POST /andGET /which return 404, and the connector shows as failed.Root cause: Claude.ai uses the resource URL from
/.well-known/oauth-protected-resourceas the MCP endpoint. This resolves to the server root (/), but the MCP streamable HTTP handler is only registered at/mcp.Fix: Register the streamable HTTP handler at
/in addition to/mcpinsrc/server/sse.ts:Environment
1.4.1Steps to Reproduce
AUTH_ENABLED=truebehind Cloudflare Tunnel or ngrokValidationError(Bug 1), or succeeds but MCP connection fails with 404 (Bug 2)Both fixes were verified working together. Happy to open a PR if helpful!