Skip to content

Conversation

@waltmayf
Copy link

@waltmayf waltmayf commented Feb 3, 2026

Summary

Fixes resource metadata URL extraction from WWW-Authenticate headers during initial OAuth connection, enabling the SDK to work with MCP servers that use separate authorization servers (AWS Cognito, Auth0, Okta, etc.).

Closes #1450

Motivation and Context

When connecting to MCP servers using OAuth with separate authorization servers, the SDK was failing during token exchange with an "Invalid api path" error.

Root Cause: The resourceMetadataUrl from the WWW-Authenticate header was not being extracted during the initial connection attempt. This caused finishAuth() to fall back to using the MCP server URL as the authorization server URL, resulting in incorrect token endpoint construction.

Example Flow (Before Fix):

1. Connect to AWS Bedrock MCP server
2. Get 401 (but resource_metadata URL NOT extracted)
3. User authorizes via Cognito
4. finishAuth() called with resourceMetadataUrl = undefined
5. SDK falls back to: https://bedrock-agentcore.us-east-1.amazonaws.com/token
6. POST fails → "Invalid api path" error

Example Flow (After Fix):

1. Connect to AWS Bedrock MCP server
2. Get 401 → Extract resource_metadata URL from WWW-Authenticate header
3. Fetch protected resource metadata → Discover Cognito authorization server
4. User authorizes via Cognito
5. finishAuth() called with correct resourceMetadataUrl
6. SDK uses: https://cognito-domain.auth.us-east-1.amazoncognito.com/oauth2/token
7. POST succeeds → Tokens received ✅

This fix is critical for enterprise deployments where MCP servers use managed identity providers separate from the MCP endpoint.

How Has This Been Tested?

Unit Tests ✅

  • All 245 client tests passing
  • 27 SSE-specific tests verified
  • 123 auth-related tests verified

Integration Tests ✅

  • All 487 integration tests passing

Real-World Testing ✅

Verified with AWS Bedrock MCP server + AWS Cognito OAuth:

  • Initial 401 response correctly extracts resource metadata URL
  • Protected resource metadata fetched successfully
  • Cognito authorization server discovered via OpenID configuration
  • Authorization URL correctly uses Cognito domain (not Bedrock)
  • User authorization flow completed successfully
  • Authorization code received from callback

Test Environment:

  • MCP Server: AWS Bedrock Agent Runtime
  • Authorization Server: AWS Cognito User Pool
  • OAuth Flow: Authorization Code with PKCE
  • Standards: RFC 9728 (Protected Resource Metadata), RFC 8707 (Resource Indicators), RFC 7636 (PKCE)

Manual Verification

Used curl to verify each step of the OAuth discovery chain:

  1. Initial 401 with WWW-Authenticate header containing resource_metadata URL
  2. Protected resource metadata fetch returning authorization_servers array
  3. OpenID configuration discovery from Cognito
  4. Token endpoint verification

Breaking Changes

None. This is a bug fix that maintains backward compatibility with existing OAuth flows.

Types of changes

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to change)
  • Documentation update

Checklist

  • I have read the MCP Documentation
  • My code follows the repository's style guidelines
  • New and existing tests pass locally (732/732 tests passing)
  • I have added appropriate error handling
  • I have added or updated documentation as needed

Additional context

Files Modified

Source Code:

  1. packages/client/src/client/streamableHttp.ts - Extract metadata in _startOrAuthSse()

Documentation:

  • .changeset/fix-resource-metadata-extraction.md - Changeset for release notes

Implementation Details

The fix adds resource metadata URL and scope extraction when receiving a 401 response during initial connection:

if (response.status === 401 && this._authProvider) {
    this._resourceMetadataUrl = extractResourceMetadataUrl(response);
    const scope = extractScope(response);
    return await this._authThenStart(scope);
}

This ensures the metadata is available when finishAuth() is called later in the OAuth flow.

Impact

This fix enables the TypeScript SDK to work with all MCP servers that use:

  • ✅ Separate authorization servers (AWS Cognito, Auth0, Okta, Azure AD, Keycloak, etc.)
  • ✅ RFC 9728 Protected Resource Metadata
  • ✅ OAuth 2.0 with resource_metadata parameter in WWW-Authenticate headers
  • ✅ RFC 8707 Resource Indicators
  • ✅ PKCE (RFC 7636)

Affected Use Cases

  1. AWS Bedrock MCP servers using Cognito for authentication
  2. Enterprise MCP servers using corporate identity providers
  3. Multi-tenant MCP servers with separate authorization servers per tenant
  4. Cloud-hosted MCP servers using managed identity services

Design Decisions

  • Minimal change: Only 4 lines added per transport class
  • Reuses existing helpers: Uses extractResourceMetadataUrl() and extractScope() functions
  • Early extraction: Metadata extracted during initial connection, not deferred to later stages
  • Backward compatible: Existing OAuth flows continue to work unchanged

Fixes the extraction of resource metadata URL during OAuth connection to prevent 'Invalid api path' errors. Ensures the SDK correctly handles 401 responses to discover token endpoints for OAuth flows using separate authorization servers.
Extract resource metadata URL and scope from WWW-Authenticate header on 401 response.
@waltmayf waltmayf requested a review from a team as a code owner February 3, 2026 19:58
@changeset-bot
Copy link

changeset-bot bot commented Feb 3, 2026

🦋 Changeset detected

Latest commit: 261fe74

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

pkg-pr-new bot commented Feb 3, 2026

Open in StackBlitz

@modelcontextprotocol/client

npm i https://pkg.pr.new/modelcontextprotocol/typescript-sdk/@modelcontextprotocol/client@1472

@modelcontextprotocol/server

npm i https://pkg.pr.new/modelcontextprotocol/typescript-sdk/@modelcontextprotocol/server@1472

@modelcontextprotocol/express

npm i https://pkg.pr.new/modelcontextprotocol/typescript-sdk/@modelcontextprotocol/express@1472

@modelcontextprotocol/hono

npm i https://pkg.pr.new/modelcontextprotocol/typescript-sdk/@modelcontextprotocol/hono@1472

@modelcontextprotocol/node

npm i https://pkg.pr.new/modelcontextprotocol/typescript-sdk/@modelcontextprotocol/node@1472

commit: 261fe74

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 Token Exchange Fails with Separate Authorization Servers

1 participant