diff options
| author | Brian Ray <[email protected]> | 2025-07-27 14:09:45 -0400 |
|---|---|---|
| committer | GitHub <[email protected]> | 2025-07-27 18:09:45 +0000 |
| commit | c45c14ee0ea7c3b6c9f66816e82671adf7cde54e (patch) | |
| tree | 608085113327eb6eeed8ffef3d7f1cc00799b422 /packages/core/src | |
| parent | 576cebc9282cfbe57d45321105d72cc61597ce9b (diff) | |
Bug: add resource parameter to MCP OAuth Flow (#4981)
Co-authored-by: Your Name <[email protected]>
Diffstat (limited to 'packages/core/src')
| -rw-r--r-- | packages/core/src/mcp/oauth-provider.test.ts | 2 | ||||
| -rw-r--r-- | packages/core/src/mcp/oauth-provider.ts | 53 | ||||
| -rw-r--r-- | packages/core/src/mcp/oauth-token-storage.ts | 4 |
3 files changed, 49 insertions, 10 deletions
diff --git a/packages/core/src/mcp/oauth-provider.test.ts b/packages/core/src/mcp/oauth-provider.test.ts index 41938969..20dc9fab 100644 --- a/packages/core/src/mcp/oauth-provider.test.ts +++ b/packages/core/src/mcp/oauth-provider.test.ts @@ -151,6 +151,7 @@ describe('MCPOAuthProvider', () => { expect.objectContaining({ accessToken: 'access_token_123' }), 'test-client-id', 'https://auth.example.com/token', + undefined, ); }); @@ -551,6 +552,7 @@ describe('MCPOAuthProvider', () => { expect.objectContaining({ accessToken: 'new_access_token' }), 'test-client-id', 'https://auth.example.com/token', + undefined, ); }); diff --git a/packages/core/src/mcp/oauth-provider.ts b/packages/core/src/mcp/oauth-provider.ts index 51f5b2d6..2f65f051 100644 --- a/packages/core/src/mcp/oauth-provider.ts +++ b/packages/core/src/mcp/oauth-provider.ts @@ -272,11 +272,13 @@ export class MCPOAuthProvider { * * @param config OAuth configuration * @param pkceParams PKCE parameters + * @param mcpServerUrl The MCP server URL to use as the resource parameter * @returns The authorization URL */ private static buildAuthorizationUrl( config: MCPOAuthConfig, pkceParams: PKCEParams, + mcpServerUrl?: string, ): string { const redirectUri = config.redirectUri || @@ -296,10 +298,15 @@ export class MCPOAuthProvider { } // Add resource parameter for MCP OAuth spec compliance - params.append( - 'resource', - OAuthUtils.buildResourceParameter(config.authorizationUrl!), - ); + // Use the MCP server URL if provided, otherwise fall back to authorization URL + const resourceUrl = mcpServerUrl || config.authorizationUrl!; + try { + params.append('resource', OAuthUtils.buildResourceParameter(resourceUrl)); + } catch (error) { + throw new Error( + `Invalid resource URL: "${resourceUrl}". ${getErrorMessage(error)}`, + ); + } return `${config.authorizationUrl}?${params.toString()}`; } @@ -310,12 +317,14 @@ export class MCPOAuthProvider { * @param config OAuth configuration * @param code Authorization code * @param codeVerifier PKCE code verifier + * @param mcpServerUrl The MCP server URL to use as the resource parameter * @returns The token response */ private static async exchangeCodeForToken( config: MCPOAuthConfig, code: string, codeVerifier: string, + mcpServerUrl?: string, ): Promise<OAuthTokenResponse> { const redirectUri = config.redirectUri || @@ -334,10 +343,15 @@ export class MCPOAuthProvider { } // Add resource parameter for MCP OAuth spec compliance - params.append( - 'resource', - OAuthUtils.buildResourceParameter(config.tokenUrl!), - ); + // Use the MCP server URL if provided, otherwise fall back to token URL + const resourceUrl = mcpServerUrl || config.tokenUrl!; + try { + params.append('resource', OAuthUtils.buildResourceParameter(resourceUrl)); + } catch (error) { + throw new Error( + `Invalid resource URL: "${resourceUrl}". ${getErrorMessage(error)}`, + ); + } const response = await fetch(config.tokenUrl!, { method: 'POST', @@ -362,12 +376,15 @@ export class MCPOAuthProvider { * * @param config OAuth configuration * @param refreshToken The refresh token + * @param tokenUrl The token endpoint URL + * @param mcpServerUrl The MCP server URL to use as the resource parameter * @returns The new token response */ static async refreshAccessToken( config: MCPOAuthConfig, refreshToken: string, tokenUrl: string, + mcpServerUrl?: string, ): Promise<OAuthTokenResponse> { const params = new URLSearchParams({ grant_type: 'refresh_token', @@ -384,7 +401,15 @@ export class MCPOAuthProvider { } // Add resource parameter for MCP OAuth spec compliance - params.append('resource', OAuthUtils.buildResourceParameter(tokenUrl)); + // Use the MCP server URL if provided, otherwise fall back to token URL + const resourceUrl = mcpServerUrl || tokenUrl; + try { + params.append('resource', OAuthUtils.buildResourceParameter(resourceUrl)); + } catch (error) { + throw new Error( + `Invalid resource URL: "${resourceUrl}". ${getErrorMessage(error)}`, + ); + } const response = await fetch(tokenUrl, { method: 'POST', @@ -534,7 +559,11 @@ export class MCPOAuthProvider { const pkceParams = this.generatePKCEParams(); // Build authorization URL - const authUrl = this.buildAuthorizationUrl(config, pkceParams); + const authUrl = this.buildAuthorizationUrl( + config, + pkceParams, + mcpServerUrl, + ); console.log('\nOpening browser for OAuth authentication...'); console.log('If the browser does not open, please visit:'); @@ -584,6 +613,7 @@ export class MCPOAuthProvider { config, code, pkceParams.codeVerifier, + mcpServerUrl, ); // Convert to our token format @@ -605,6 +635,7 @@ export class MCPOAuthProvider { token, config.clientId, config.tokenUrl, + mcpServerUrl, ); console.log('Authentication successful! Token saved.'); @@ -664,6 +695,7 @@ export class MCPOAuthProvider { config, token.refreshToken, credentials.tokenUrl, + credentials.mcpServerUrl, ); // Update stored token @@ -683,6 +715,7 @@ export class MCPOAuthProvider { newToken, config.clientId, credentials.tokenUrl, + credentials.mcpServerUrl, ); return newToken.accessToken; diff --git a/packages/core/src/mcp/oauth-token-storage.ts b/packages/core/src/mcp/oauth-token-storage.ts index fc9da8af..0500b43e 100644 --- a/packages/core/src/mcp/oauth-token-storage.ts +++ b/packages/core/src/mcp/oauth-token-storage.ts @@ -28,6 +28,7 @@ export interface MCPOAuthCredentials { token: MCPOAuthToken; clientId?: string; tokenUrl?: string; + mcpServerUrl?: string; updatedAt: number; } @@ -91,12 +92,14 @@ export class MCPOAuthTokenStorage { * @param token The OAuth token to save * @param clientId Optional client ID used for this token * @param tokenUrl Optional token URL used for this token + * @param mcpServerUrl Optional MCP server URL */ static async saveToken( serverName: string, token: MCPOAuthToken, clientId?: string, tokenUrl?: string, + mcpServerUrl?: string, ): Promise<void> { await this.ensureConfigDir(); @@ -107,6 +110,7 @@ export class MCPOAuthTokenStorage { token, clientId, tokenUrl, + mcpServerUrl, updatedAt: Date.now(), }; |
