Skip to content

Conversation

Copy link
Contributor

Copilot AI commented Jul 11, 2025

Problem

MCP (Model Context Protocol) OAuth authentication was failing when the Protected Resource Metadata (PRM) resource field and the resolved MCP server URL had semantically equivalent but textually different URLs. Specifically:

  • PRM resource: https://A.B.C (no trailing slash, uppercase hostname)
  • Resolved resource: https://a.b.c/ (trailing slash, lowercase hostname)

This caused authentication to fail with the error:

Protected Resource Metadata resource "https://A.B.C" does not match MCP server resolved resource "https://a.b.c/". The MCP server must follow OAuth spec https://datatracker.ietf.org/doc/html/rfc9728#PRConfigurationValidation

Root Cause

The issue was in extHostMcp.ts where a direct string comparison (body.resource !== resolvedResource) was used without accounting for URL normalization. The getResourceServerBaseUrlFromDiscoveryUrl function correctly normalizes URLs by:

  1. Converting hostnames to lowercase (via URL constructor)
  2. Adding trailing slashes for root paths

However, the comparison logic didn't normalize the PRM resource field before comparison.

Solution

Added URL normalization for comparison:

  1. New normalizeUrlForComparison() function in oauth.ts:

    export function normalizeUrlForComparison(url: string): string {
        const parsed = new URL(url);
        
        // Ensure root paths have a trailing slash
        if (!parsed.pathname || parsed.pathname === '') {
            parsed.pathname = '/';
        }
        
        return parsed.toString();
    }
  2. Updated comparison logic in extHostMcp.ts:

    // Before: body.resource !== resolvedResource
    // After: normalizeUrlForComparison(body.resource) !== normalizeUrlForComparison(resolvedResource)

Validation

The fix handles these scenarios correctly:

  • https://A.B.Chttps://a.b.c/ (original issue)
  • https://EXAMPLE.COMhttps://example.com/ (case differences)
  • https://api.example.com/v1https://api.example.com/v1 (subpaths preserved)

Security is maintained - these still correctly fail to match:

  • https://example.comhttps://evil.com (different domains)
  • https://example.com:8080https://example.com:8443 (different ports)
  • http://example.comhttps://example.com (different protocols)

Impact

Users no longer need to manually adjust their OAuth Protected Resource Metadata configuration to match URL formatting. The authentication flow now handles URL equivalence according to RFC 3986 standards.

Fixes #255255.

Warning

Firewall rules blocked me from connecting to one or more addresses

I tried to connect to the following addresses, but was blocked by firewall rules:

  • electronjs.org
    • Triggering command: node-gyp (dns block)

If you need me to access, download, or install something from one of these locations, you can either:


💬 Share your feedback on Copilot coding agent for the chance to win a $200 gift card! Click here to start the survey.

Co-authored-by: TylerLeonhardt <2644648+TylerLeonhardt@users.noreply.github.com>
Copilot AI changed the title [WIP] MCP Auth PRM resource URL included / at end for 1.102.0 and 1.103.0-insider Fix MCP OAuth URL normalization - handle trailing slash and hostname case differences Jul 11, 2025
Copilot AI requested a review from TylerLeonhardt July 11, 2025 15:45
…or handles all normalization

Co-authored-by: TylerLeonhardt <2644648+TylerLeonhardt@users.noreply.github.com>
Copy link
Contributor Author

Copilot AI commented Jul 11, 2025

Just as a heads up, I was blocked by some firewall rules while working on your feedback. Expand below for details.

Warning

Firewall rules blocked me from connecting to one or more addresses

I tried to connect to the following addresses, but was blocked by firewall rules:

  • electronjs.org
    • Triggering command: node-gyp (dns block)

If you need me to access, download, or install something from one of these locations, you can either:

Copilot AI requested a review from TylerLeonhardt July 11, 2025 16:01
@TylerLeonhardt TylerLeonhardt marked this pull request as ready for review July 11, 2025 19:17
@TylerLeonhardt TylerLeonhardt enabled auto-merge (squash) July 11, 2025 19:17
@vs-code-engineering vs-code-engineering bot added this to the July 2025 milestone Jul 11, 2025
@TylerLeonhardt TylerLeonhardt merged commit 029bf69 into main Jul 12, 2025
28 of 29 checks passed
@TylerLeonhardt TylerLeonhardt deleted the copilot/fix-255255 branch July 12, 2025 17:39
@vs-code-engineering vs-code-engineering bot locked and limited conversation to collaborators Aug 26, 2025
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

MCP Auth PRM resource URL included / at end for 1.102.0 and 1.103.0-insider

4 participants