Skip to content

fix(core): preserve pathless MCP OAuth resources - #60125

Open
wozhenbang2004 wants to merge 4 commits into
anomalyco:devfrom
wozhenbang2004:oauth-resource
Open

wozhenbang2004 wants to merge 4 commits into
anomalyco:devfrom
wozhenbang2004:oauth-resource

Conversation

@wozhenbang2004

@wozhenbang2004 wozhenbang2004 commented Oct 29, 2026 •

Copy link
Copy Markdown

Issue for this PR

Closes #58956

Type of change

  • Bug fix
  • New feature
  • Refactor / code improvement
  • Documentation

What does this PR do?

Preserve a pathless OAuth resource such as https://example.com through custom provider validation. The existing SDK patch now keeps the metadata string when the selected URL represents that same resource. A provider's deliberate query or path change still takes precedence.

How did you verify your code works?

With Bun 1.4.4 and the locked MCP SDK 2.3.1, the regression in mcp-oauth.test.ts exercises the real McpOAuth.connectProvider. It fails with the old SDK condition, which adds a trailing / to the token-request resource, and passes with the patch. All 23 tests in the file pass.

The full core suite finished with 6,991 passed, 33 skipped, and 12 failed. Focused reruns reproduced the same 12 failures on the original PR head (25d60caf) and with the updated tests.

Core bun typecheck passed using Bun’s checker. Root bun run check did not complete because Astro typechecking was killed with SIGKILL. The separate core bun run typecheck:tsc also did not complete (SIGKILL).

Visual

<svg xmlns="http://www.w3.org/2000/svg" width="240" height="72" viewBox="0 0 240 72">
  <style>.flow{animation:flow 2s linear infinite}@keyframes flow{to{stroke-dashoffset:-12}}@media(prefers-reduced-motion:reduce){.flow{animation:none}}</style>
  <g fill="none" stroke="currentColor" opacity=".5"><rect x="8" y="17" width="89" height="38" rx="4"/><rect x="143" y="17" width="89" height="38" rx="4"/></g>
  <g fill="currentColor" font-family="monospace" font-size="10" text-anchor="middle"><text x="52" y="32" opacity=".6">resource</text><text x="52" y="45">https://host</text><text x="188" y="32" opacity=".6">token</text><text x="188" y="45">https://host</text></g>
  <path class="flow" d="M103 36h32m-5-5 5 5-5 5" fill="none" stroke="currentColor" stroke-dasharray="4 2"/>
</svg>

Screenshots / recordings

No interface change.

Checklist

  • I have tested my changes locally
  • I have not included unrelated changes in this PR

@opencodejr opencodejr Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The patch fixes #58956: a pathless resource like http://host:8080 now reaches the token request without the extra /. I'm asking for one test change before merge.

How I checked it: I wrote a throwaway test using opencode's real provider (McpOAuth.connectProvider), config URL /mcp and resource metadata set to the bare origin. On the base, the refresh token request sent http://localhost:PORT/. With this change it sends http://localhost:PORT. Your new test fails on the base only in the pathless case and passes 6/6 with the change. mcp-oauth.test.ts and mcp.test.ts pass except one test that fails the same way on the base.

Providers without validateResourceURL behave as before: the SDK returns new URL(metadata.resource), so the href comparison always matches. The extra new URL(...) can't throw in practice, because opencode's validator already parses the same string.

The public API is unchanged.

The one concern is the new test file (inline comment).

import { expect, test } from "bun:test"
import { auth, type OAuthClientProvider } from "@modelcontextprotocol/client"

test.each([

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This test drives the SDK's auth() with a hand-built provider that mimics opencode's validator, and it branches on the case name inside the test body. Four of the six cases (explicit /, parent, changed query, rejected) cover behaviour this change doesn't touch.

Could you replace it with one case in test/mcp-oauth.test.ts, next to "keeps the configured URL as the resource when metadata echoes the dialed query"? It would serve metadata { resource: url.origin } for /mcp and expect tokenRequests[0]?.get("resource") to be server.url.origin. That goes through the real McpOAuth.connectProvider, fails on the base and passes with this patch (I checked). Then this file can be dropped.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Replaced the standalone test with a case in mcp-oauth.test.ts using the real McpOAuth.connectProvider, next to the query-resource case. It fails with the old SDK condition and passes with the patch. All 23 tests in that file pass.

@opencodejr opencodejr Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My earlier test comment is addressed: the separate test file is gone, replaced by one case in mcp-oauth.test.ts that uses the real McpOAuth.connectProvider. That case passes with this pull request and fails on the base, where the token request gets the resource with a trailing /. The whole mcp-oauth.test.ts file passes (23/23). The SDK patch hasn't changed since my last review, and the public API is unchanged. No further concerns.

This branch has not been deployed

No deployments
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.

Forward slash is being added on root resource URIs with oauth challenge

1 participant