From dadf05809c4978455a646ab4ef95421fbe758657 Mon Sep 17 00:00:00 2001 From: Mikhail Aksenov Date: Wed, 6 Aug 2025 00:02:16 +0200 Subject: [PATCH] feat: mcp - support audiences for OAuth2 (#5265) --- docs/tools/mcp-server.md | 1 + packages/core/src/mcp/oauth-provider.test.ts | 2 ++ packages/core/src/mcp/oauth-provider.ts | 13 +++++++++++++ 3 files changed, 16 insertions(+) diff --git a/docs/tools/mcp-server.md b/docs/tools/mcp-server.md index 1222c693..850c228e 100644 --- a/docs/tools/mcp-server.md +++ b/docs/tools/mcp-server.md @@ -169,6 +169,7 @@ Use the `/mcp auth` command to manage OAuth authentication: - **`scopes`** (string[]): Required OAuth scopes - **`redirectUri`** (string): Custom redirect URI (defaults to `http://localhost:7777/oauth/callback`) - **`tokenParamName`** (string): Query parameter name for tokens in SSE URLs +- **`audiences`** (string[]): Audiences the token is valid for #### Token Management diff --git a/packages/core/src/mcp/oauth-provider.test.ts b/packages/core/src/mcp/oauth-provider.test.ts index 74eb42c0..3991aecc 100644 --- a/packages/core/src/mcp/oauth-provider.test.ts +++ b/packages/core/src/mcp/oauth-provider.test.ts @@ -48,6 +48,7 @@ describe('MCPOAuthProvider', () => { tokenUrl: 'https://auth.example.com/token', scopes: ['read', 'write'], redirectUri: 'http://localhost:7777/oauth/callback', + audiences: ['https://api.example.com'], }; const mockToken: MCPOAuthToken = { @@ -722,6 +723,7 @@ describe('MCPOAuthProvider', () => { expect(capturedUrl!).toContain('code_challenge_method=S256'); expect(capturedUrl!).toContain('scope=read+write'); expect(capturedUrl!).toContain('resource=https%3A%2F%2Fauth.example.com'); + expect(capturedUrl!).toContain('audience=https%3A%2F%2Fapi.example.com'); }); it('should correctly append parameters to an authorization URL that already has query params', async () => { diff --git a/packages/core/src/mcp/oauth-provider.ts b/packages/core/src/mcp/oauth-provider.ts index 5052e8af..c86478c6 100644 --- a/packages/core/src/mcp/oauth-provider.ts +++ b/packages/core/src/mcp/oauth-provider.ts @@ -22,6 +22,7 @@ export interface MCPOAuthConfig { authorizationUrl?: string; tokenUrl?: string; scopes?: string[]; + audiences?: string[]; redirectUri?: string; tokenParamName?: string; // For SSE connections, specifies the query parameter name for the token } @@ -297,6 +298,10 @@ export class MCPOAuthProvider { params.append('scope', config.scopes.join(' ')); } + if (config.audiences && config.audiences.length > 0) { + params.append('audience', config.audiences.join(' ')); + } + // Add resource parameter for MCP OAuth spec compliance // Use the MCP server URL if provided, otherwise fall back to authorization URL const resourceUrl = mcpServerUrl || config.authorizationUrl!; @@ -346,6 +351,10 @@ export class MCPOAuthProvider { params.append('client_secret', config.clientSecret); } + if (config.audiences && config.audiences.length > 0) { + params.append('audience', config.audiences.join(' ')); + } + // Add resource parameter for MCP OAuth spec compliance // Use the MCP server URL if provided, otherwise fall back to token URL const resourceUrl = mcpServerUrl || config.tokenUrl!; @@ -404,6 +413,10 @@ export class MCPOAuthProvider { params.append('scope', config.scopes.join(' ')); } + if (config.audiences && config.audiences.length > 0) { + params.append('audience', config.audiences.join(' ')); + } + // Add resource parameter for MCP OAuth spec compliance // Use the MCP server URL if provided, otherwise fall back to token URL const resourceUrl = mcpServerUrl || tokenUrl;