Skip to content

RFC 9728 compliance: protected resource metadata URL mismatches when resource identifier has a path #1400

@shulkx

Description

@shulkx

Initial Checks

Description

Environment

  • Client: VS Code MCP (http)
  • Server: examples/servers/simple-auth
  • Config:
    {
      "servers": {
        "Get-Time": {
          "url": "http://localhost:8001/mcp",
          "type": "http"
        }
      }
    }

Problem 1: Protected Resource Metadata “resource” mismatch

On startup, VS Code shows:

Connection state: Error Error sending message to http://localhost:8001/mcp: Error: Protected Resource Metadata resource "http://localhost:8001/" does not match MCP server resolved resource "http://localhost:8001/mcp". The MCP server must follow OAuth spec https://datatracker.ietf.org/doc/html/rfc9728#PRConfigurationValidation

Per RFC 9728 validation, the example should set the resource identifier to include the path component:

  • Expected in example: resource_server_url=AnyHttpUrl(f"{settings.server_url}mcp"), # <--- add mcp
  • File:
    app = FastMCP(
    name="MCP Resource Server",
    instructions="Resource Server that validates tokens via Authorization Server introspection",
    host=settings.host,
    port=settings.port,
    debug=True,
    # Auth configuration for RS mode
    token_verifier=token_verifier,
    auth=AuthSettings(
    issuer_url=settings.auth_server_url,
    required_scopes=[settings.mcp_scope],
    resource_server_url=settings.server_url,
    ),
    )

When I include /mcp in resource_server_url, this error goes away.

Problem 2: WWW-Authenticate resource_metadata vs actual route

The server builds resource_metadata_url for the WWW-Authenticate header and also registers the well-known route. These two do not match when the resource identifier has a path.

Result: the client follows the WWW-Authenticate header to http://localhost:8001/mcp/.well-known/oauth-protected-resource, but the server only serves the route at the root.

Problem 3: Well-known URL construction (RFC 9728 §3.1)

RFC 9728 §3.1 states that when the resource identifier contains a path, the well-known suffix must be inserted between the host and the path:

If the resource identifier value contains a path or query component, any terminating slash (/) following the host component MUST be removed before inserting /.well-known/ and the well-known URI path suffix between the host component and the path and/or query components.

Current implementation:

Expected behavior (RFC 9728)

RFC 9728 §3.1: insert /.well-known/oauth-protected-resource between the host and the resource path.

  • If resource_server_url = http://localhost:8001 (no path):

    • Header should point to: http://localhost:8001/.well-known/oauth-protected-resource
    • Route should be served at: http://localhost:8001/.well-known/oauth-protected-resource
  • If resource_server_url = http://localhost:8001/mcp (has path /mcp):

    • Header should point to: http://localhost:8001/.well-known/oauth-protected-resource/mcp
    • Route should be served at: http://localhost:8001/.well-known/oauth-protected-resource/mcp

Example Code

Python & MCP Python SDK

Python 3.11
MCP Python SDK v1.15.0

Metadata

Metadata

Assignees

No one assigned

    Labels

    P1Significant bug affecting many users, highly requested featureauthIssues and PRs related to Authentication / OAuthbugSomething isn't workingready for workEnough information for someone to start working on

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions