fix(client): OAuth well-known fallback on 4xx and authorization-server origin by tiagovilasboas · Pull Request #2785 · modelcontextprotocol/typescript-sdk · GitHub
Skip to content

fix(client): OAuth well-known fallback on 4xx and authorization-server origin - #2785

Open
tiagovilasboas wants to merge 4 commits into
modelcontextprotocol:mainfrom
tiagovilasboas:cursor/oauth-well-known-fallback-6ad7
Open

tiagovilasboas wants to merge 4 commits into
modelcontextprotocol:mainfrom
tiagovilasboas:cursor/oauth-well-known-fallback-6ad7

Conversation

@tiagovilasboas

@tiagovilasboas tiagovilasboas commented Sep 10, 2026

Copy link
Copy Markdown

Summary

Fixes OAuth well-known metadata discovery for remote MCP servers behind CDNs / split resource vs authorization-server hosts.

#2783 — fallback on 4xx, not only 404

Path-inserted well-known URLs (/.well-known/oauth-protected-resource/<path>, /.well-known/oauth-authorization-server/<path>) are often answered with 401 or 403 by CDNs / bot protection instead of 404. Discovery already treated any 4xx (plus 502) as a miss and retried the root well-known document; this change keeps that predicate and adds coverage so 401/403/404 fall back, 200 short-circuits, and non-502 5xx does not fall back.

Repro: Retool https://hashnote.retool.com/mcp — path-aware PRM returns 401, root PRM returns 200.

#2784 — fallback URL must use the authorization-server host

When the resource URL and the authorization server are on different hosts, the root fallback was built from the resource URL (new URL('/.well-known/…', issuer)). That fetched an unrelated metadata document.

The fallback is now built from metadataServerUrl (the authorization server / issuer host). discoverOAuthMetadata(resourceUrl, { authorizationServerUrl }) again uses the resource path only as the well-known suffix and keeps the retry on the AS origin.

Repro: Superhuman — path-aware AS https://id.superhuman.com/.well-known/oauth-authorization-server/apis/mcp → 403; root https://id.superhuman.com/.well-known/oauth-authorization-server → 200. The client must not fall back to https://docs.superhuman.com/.well-known/oauth-authorization-server.

Test plan

  • Unit tests with mocked fetch in packages/client/test/client/auth.test.ts
    • 401 / 403 / 404 on path-aware discovery fall back to root
    • 200 on path-aware discovery does not fall back
    • 500 does not fall back (existing)
    • AS fallback URLs stay on the authorization-server origin
  • pnpm --filter @modelcontextprotocol/client test — 884 passed (full client suite)
  • vitest run test/client/auth.test.ts — 268 passed

Fixes #2783
Fixes #2784

Path-inserted well-known discovery already retries on 4xx, but the root
fallback URL was built from the resource/issuer URL. When the
authorization server lives on a different host, that fetched the wrong
metadata document.

Build the fallback from metadataServerUrl (the AS) and pass the resource
URL only as the path prefix in discoverOAuthMetadata.

Fixes modelcontextprotocol#2783
Fixes modelcontextprotocol#2784

Co-authored-by: Tiago Vilas Boas <tcarvalhovb@gmail.com>
Add mocked-fetch cases for 401/403/404 path-aware fallback, 200
short-circuit when resource and authorization-server hosts differ, and
continuation on 4xx during authorization-server metadata discovery.

Co-authored-by: Tiago Vilas Boas <tcarvalhovb@gmail.com>
@tiagovilasboas
tiagovilasboas requested a review from a team as a code owner September 10, 2026 23:15
@changeset-bot

changeset-bot Bot commented Sep 10, 2026

Copy link
Copy Markdown

Co-authored-by: Tiago Vilas Boas <tcarvalhovb@gmail.com>
Co-authored-by: Tiago Vilas Boas <tcarvalhovb@gmail.com>
@pkg-pr-new

pkg-pr-new Bot commented Sep 10, 2026

Copy link
Copy Markdown

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

1 participant