Skip to content

fix: preserve exact resource URI from protected resource metadata#1991

Open
Christian-Sidak wants to merge 1 commit intomodelcontextprotocol:mainfrom
Christian-Sidak:fix/issue-1968
Open

fix: preserve exact resource URI from protected resource metadata#1991
Christian-Sidak wants to merge 1 commit intomodelcontextprotocol:mainfrom
Christian-Sidak:fix/issue-1968

Conversation

@Christian-Sidak
Copy link
Copy Markdown
Contributor

Summary

  • selectResourceURL() was returning new URL(resourceMetadata.resource), which normalizes pathless URIs like https://example.com to https://example.com/ via URL.href
  • Both the authorization request and token request then serialized the resource with .href, further cementing the trailing slash
  • Changed selectResourceURL() to return the original metadata string directly (preserving the exact value), and updated all serialization to use String(resource) instead of resource.href
  • Updated the return type of selectResourceURL and the resource parameter in startAuthorization, executeTokenRequest, exchangeAuthorization, refreshAuthorization, and fetchToken from URL to URL | string to accommodate both metadata strings and custom validateResourceURL URL objects

Test plan

  • Existing 350 tests pass (updated one test expectation that was asserting the old incorrect normalized behavior)
  • Added new regression test: preserves pathless resource URI from PRM without adding trailing slash
  • Manually verified: new URL("https://example.com").href === "https://example.com/" (the bug), and that returning the string directly preserves "https://example.com"

Fixes #1968

…alization

When protected resource metadata contains a pathless URI like
"https://example.com", the SDK was normalizing it to "https://example.com/"
via URL.href. This broke OAuth with providers like Microsoft Entra ID that
require the resource parameter to exactly match the scopes' audience.

Change selectResourceURL to return the original metadata string directly
instead of wrapping it in new URL(), and update all serialization sites to
use String() instead of .href so URL objects are still handled correctly.

Fixes modelcontextprotocol#1968

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@Christian-Sidak Christian-Sidak requested a review from a team as a code owner April 30, 2026 08:27
@changeset-bot
Copy link
Copy Markdown

changeset-bot Bot commented Apr 30, 2026

🦋 Changeset detected

Latest commit: 60993b2

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

This PR includes changesets to release 1 package
Name Type
@modelcontextprotocol/client 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

@pkg-pr-new
Copy link
Copy Markdown

pkg-pr-new Bot commented Apr 30, 2026

Open in StackBlitz

@modelcontextprotocol/client

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

@modelcontextprotocol/server

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

@modelcontextprotocol/express

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

@modelcontextprotocol/fastify

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

@modelcontextprotocol/hono

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

@modelcontextprotocol/node

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

commit: 60993b2

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

OAuth resource indicator from protected resource metadata is normalized with a trailing slash

1 participant