Description
discoverAuthorizationServerMetadata() in packages/client/src/client/auth.ts tries multiple well-known URLs in sequence (RFC 8414 path-insert, OIDC path-insert, OIDC path-appended), but throws immediately on 5xx responses instead of continuing to the next URL. Only 4xx responses trigger the fallback.
This breaks MCP servers deployed at a subpath behind a reverse proxy or API gateway (e.g., Azure Application Gateway, nginx, Traefik) when the proxy returns 502 for paths it does not route.
Reproduction
- Deploy an MCP server at a subpath, e.g.
https://example.com/my-app/mcp
- The server's Protected Resource Metadata correctly advertises the authorization server as
https://example.com/my-app
- The server correctly serves metadata at
https://example.com/my-app/.well-known/oauth-authorization-server (200 ✅)
- The reverse proxy has no rule for the root-level
/.well-known/ path, so https://example.com/.well-known/oauth-authorization-server/my-app returns 502 (no backend)
The SDK tries URLs in this order:
https://example.com/.well-known/oauth-authorization-server/my-app → 502 → ❌ throws immediately
https://example.com/.well-known/openid-configuration/my-app → never reached
https://example.com/my-app/.well-known/openid-configuration → never reached (would have worked)
Expected Behavior
A 5xx from a reverse proxy for a non-existent well-known path is semantically equivalent to a 404 — the endpoint does not exist. The discovery loop should continue to the next fallback URL, not throw.
Root Cause
Two locations in auth.ts:
1. discoverAuthorizationServerMetadata() (~line 1017):
if (response.status >= 400 && response.status < 500) {
continue; // Try next URL — but ONLY for 4xx
}
throw new Error(\`HTTP \${response.status}...\`); // 5xx throws immediately
2. shouldAttemptFallback() (~line 820):
function shouldAttemptFallback(response: Response | undefined, pathname: string): boolean {
}
Both functions only treat 4xx as "try next". A 502/503/504 from a reverse proxy kills the entire discovery.
Suggested Fix
Change the condition to continue on any non-OK response:
// In discoverAuthorizationServerMetadata:
await response.text?.().catch(() => {});
continue; // Try next URL for any non-OK status
}
// In shouldAttemptFallback:
function shouldAttemptFallback(response: Response | undefined, pathname: string): boolean {
}
Environment
@modelcontextprotocol/sdk version: 1.25.3 (bundled in mcp-remote 0.1.38)
- MCP server: ASP.NET Core with
ModelContextProtocol.AspNetCore v1.0.0, deployed on AKS behind Azure Application Gateway Ingress Controller (AGIC)
- The server correctly implements RFC 9728 Protected Resource Metadata and serves OAuth metadata at the subpath, but cannot serve at the RFC 8414 path-insert URL because the reverse proxy does not route
/.well-known/* to the app
Related
Description
discoverAuthorizationServerMetadata()inpackages/client/src/client/auth.tstries multiple well-known URLs in sequence (RFC 8414 path-insert, OIDC path-insert, OIDC path-appended), but throws immediately on 5xx responses instead of continuing to the next URL. Only 4xx responses trigger the fallback.This breaks MCP servers deployed at a subpath behind a reverse proxy or API gateway (e.g., Azure Application Gateway, nginx, Traefik) when the proxy returns 502 for paths it does not route.
Reproduction
https://example.com/my-app/mcphttps://example.com/my-apphttps://example.com/my-app/.well-known/oauth-authorization-server(200 ✅)/.well-known/path, sohttps://example.com/.well-known/oauth-authorization-server/my-appreturns 502 (no backend)The SDK tries URLs in this order:
https://example.com/.well-known/oauth-authorization-server/my-app→ 502 → ❌ throws immediatelyhttps://example.com/.well-known/openid-configuration/my-app→ never reachedhttps://example.com/my-app/.well-known/openid-configuration→ never reached (would have worked)Expected Behavior
A 5xx from a reverse proxy for a non-existent well-known path is semantically equivalent to a 404 — the endpoint does not exist. The discovery loop should
continueto the next fallback URL, not throw.Root Cause
Two locations in
auth.ts:1.
discoverAuthorizationServerMetadata()(~line 1017):2.
shouldAttemptFallback()(~line 820):Both functions only treat 4xx as "try next". A 502/503/504 from a reverse proxy kills the entire discovery.
Suggested Fix
Change the condition to continue on any non-OK response:
Environment
@modelcontextprotocol/sdkversion: 1.25.3 (bundled inmcp-remote0.1.38)ModelContextProtocol.AspNetCorev1.0.0, deployed on AKS behind Azure Application Gateway Ingress Controller (AGIC)/.well-known/*to the appRelated
geelen/mcp-remoteDoes not support web native/WinterCG Request/Response model #207 — same underlying issue, path-insert metadata URL is non-compliantgeelen/mcp-remoteAdd ways for server processes to self-terminate when host is gone #208 — open PR fixinggetMetadataUrlfor path componentsgeelen/mcp-remotestderr is not available until after start is called #174 — reports missing{baseUrl}/.well-known/oauth-authorization-serverfallback