summaryrefslogtreecommitdiff
path: root/packages/core/src
diff options
context:
space:
mode:
authorBrian Ray <[email protected]>2025-07-27 14:09:45 -0400
committerGitHub <[email protected]>2025-07-27 18:09:45 +0000
commitc45c14ee0ea7c3b6c9f66816e82671adf7cde54e (patch)
tree608085113327eb6eeed8ffef3d7f1cc00799b422 /packages/core/src
parent576cebc9282cfbe57d45321105d72cc61597ce9b (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.ts2
-rw-r--r--packages/core/src/mcp/oauth-provider.ts53
-rw-r--r--packages/core/src/mcp/oauth-token-storage.ts4
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(),
};