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

fix(client): OAuth well-known fallback on 4xx and authorization-server origin#2785
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

🦋 Changeset detected

Latest commit: 72454b8

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 6 packages
Name Type
@modelcontextprotocol/client Patch
@modelcontextprotocol/codemod Patch
@modelcontextprotocol/core Patch
@modelcontextprotocol/server-legacy Patch
@modelcontextprotocol/server Patch
@modelcontextprotocol/core-internal Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

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

Open in StackBlitz

@modelcontextprotocol/client

npm i https://pkg.pr.new/@modelcontextprotocol/client@2785

@modelcontextprotocol/codemod

npm i https://pkg.pr.new/@modelcontextprotocol/codemod@2785

@modelcontextprotocol/core

npm i https://pkg.pr.new/@modelcontextprotocol/core@2785

@modelcontextprotocol/server

npm i https://pkg.pr.new/@modelcontextprotocol/server@2785

@modelcontextprotocol/server-legacy

npm i https://pkg.pr.new/@modelcontextprotocol/server-legacy@2785

@modelcontextprotocol/express

npm i https://pkg.pr.new/@modelcontextprotocol/express@2785

@modelcontextprotocol/fastify

npm i https://pkg.pr.new/@modelcontextprotocol/fastify@2785

@modelcontextprotocol/hono

npm i https://pkg.pr.new/@modelcontextprotocol/hono@2785

@modelcontextprotocol/node

npm i https://pkg.pr.new/@modelcontextprotocol/node@2785

commit: 72454b8

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