Skip to content

[v2] Client accepts a parent-path protected resource metadata, is this intended given RFC 9728? #3077

Open

Description

@PhysicallyActive

What happened?

Question

Is it intended that the client accepts Protected Resource Metadata (PRM) whose resource is a parent path of the server URL? And if so, how should that be reconciled with RFC 9728 §3.3?

Current behaviour

selectResourceURL validates resourceMetadata.resource with checkResourceAllowed, which accepts any same-origin resource whose path is a prefix of the server URL's path (authUtils.ts). The less specific URL is then returned and sent as the RFC 8707 resource parameter.

Example:

  • Server URL: https://host/mcp/gateway/bundle/my-bundle
  • 401 with WWW-Authenticate: Bearer resource_metadata="https://host/mcp/gateway/.well-known/oauth-protected-resource/bundle/my-bundle"
  • PRM: {"resource": "https://host/mcp/gateway", ...}

The SDK accepts this and requests a token for https://host/mcp/gateway. VS Code rejects the same metadata (oauth.ts: "Per RFC 9728, these MUST match"), so a server that works with SDK-based clients fails in VS Code.

Why I'm asking

RFC 9728 §3.3:

If the protected resource metadata was retrieved from a URL returned by the protected resource via the WWW-Authenticate resource_metadata parameter, then the resource value returned MUST be identical to the URL that the client used to make the request to the resource server. If these values are not identical, the data contained in the response MUST NOT be used.

§7.3 gives impersonation as the reason for the identical-match rule. The MCP spec adopts RFC 9728 and asks clients to "provide the most specific URI that they can" (2025-11-25, Canonical Server URI).

The prefix matching was introduced in #638. Its description says resource URIs are used as-is "to allow having different MCP servers under different subpaths … w/o spilling their resource authorization to each other". It also warns that a non-specific resource lets a "bad apple" server benefit from resource confusion with its siblings. Accepting a parent-path resource from the PRM seems to allow exactly that: a server at /a/b can get the client to request a token for /a. I couldn't find a rationale for the prefix rule in the PR or its review.

#2751 already notes in passing that this leniency hides non-compliant server setups.
#3041 covers the trailing-slash asymmetry in the same function. Neither asks whether the prefix rule itself is intended.

Questions

  1. Is accepting a parent-path resource on the client side intentional?
  2. If yes, is it meant to apply to metadata discovered via WWW-Authenticate, where §3.3 requires identity? Or only to the root well-known fallback?
  3. If no, would you accept a change that makes selectResourceURL require equality? This would be normalized equality, tolerant of a trailing slash as in checkResourceAllowed rejects a protected resource that differs from the server URL only by a trailing slash (one direction only) #3041, possibly with an opt-in for lenient matching to avoid breaking existing servers.

Note: downstream clients reuse checkResourceAllowed in their own validateResourceURL hooks (e.g. OpenCode), so the answer also determines what they should do.

What did you expect?

No response

Code to reproduce

SDK version

No response

Area

Auth

Activity

  1. added
    v2Ideas, requests and plans for v2 of the SDK which will incorporate major changes and fixes
    on Oct 23, 2026
  2. arhancanli commented on Oct 23, 2026

    @arhancanli

    I read checkResourceAllowed in authUtils.ts (didn't run anything). The comment on it describes a prefix check on path segments, and the /api vs /api123 guard is correct for that purpose. So the helper does what it says; the open question is whether selectResourceURL should be using a prefix check for PRM at all.

    On your question 2, my reading of §3.3 is that the identity rule isn't limited to the WWW-Authenticate path. The section has two cases: when the document came from resource_metadata, resource must equal the URL the client requested; when it came from the well-known URL, resource must equal the identifier the well-known suffix was inserted into. Both end with "MUST NOT be used" if they differ. If that reading holds, a parent-path resource is invalid in both discovery routes, and a "lenient for root fallback only" carve-out would not be spec-backed either.

    If the maintainers want to avoid breaking existing servers, I'd make the lenient mode opt-in and say in the changelog which previously accepted setups stop working, rather than keep it as the default. The #638 sibling-isolation reasoning actually argues for strict: with equality, a server at /a/b can never obtain a token audience of /a.

    One edge for the equality version: normalization. new URL() leaves https://host and https://host/ as the same pathname (/), but /mcp and /mcp/ stay different, so #3041's tolerance should be limited to a single trailing slash and not collapse repeated slashes or dot segments.

    Do you know whether any of the conformance servers publish a PRM whose resource is a parent path, or is VS Code's rejection the only case reported so far?

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    v2Ideas, requests and plans for v2 of the SDK which will incorporate major changes and fixes

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions