Bug: add resource parameter to MCP OAuth Flow (#4981)
Co-authored-by: Your Name <you@example.com>
This commit is contained in:
parent
576cebc928
commit
c45c14ee0e
|
@ -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,
|
||||
);
|
||||
});
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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(),
|
||||
};
|
||||
|
||||
|
|
Loading…
Reference in New Issue