From c966f14a6274b1dccac31867452b67dcdad92202 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20L=C3=BCdemann?= Date: Thu, 26 Feb 2026 16:31:49 +0100 Subject: [PATCH] add tests for oauth error check --- .../src/mcp/__tests__/MCPConnection.test.ts | 22 +++++++++++++ .../__tests__/MCPConnectionFactory.test.ts | 33 +++++++++++++++++++ 2 files changed, 55 insertions(+) diff --git a/packages/api/src/mcp/__tests__/MCPConnection.test.ts b/packages/api/src/mcp/__tests__/MCPConnection.test.ts index 4cca1b3316..f665693001 100644 --- a/packages/api/src/mcp/__tests__/MCPConnection.test.ts +++ b/packages/api/src/mcp/__tests__/MCPConnection.test.ts @@ -82,6 +82,10 @@ describe('MCPConnection Error Detection', () => { if (message.includes('authentication required') || message.includes('unauthorized')) { return true; } + // Check for missing authorization values (e.g., Amazon Ads MCP returns HTTP 400 with this) + if (message.includes('no authorization')) { + return true; + } } return false; @@ -171,6 +175,24 @@ describe('MCPConnection Error Detection', () => { }; expect(isOAuthError(error)).toBe(true); }); + + it('should detect OAuth error for "no authorization" in message (HTTP 400)', () => { + const error = { + message: + 'Either no authorization values are specified or it could not be derived from the request', + }; + expect(isOAuthError(error)).toBe(true); + }); + + it('should detect OAuth error for "No authorization" with different casing', () => { + const error = { message: 'No Authorization header provided' }; + expect(isOAuthError(error)).toBe(true); + }); + + it('should not detect OAuth error for unrelated 400 errors', () => { + const error = { code: 400, message: 'Bad request: missing required field' }; + expect(isOAuthError(error)).toBe(false); + }); }); describe('error type differentiation', () => { diff --git a/packages/api/src/mcp/__tests__/MCPConnectionFactory.test.ts b/packages/api/src/mcp/__tests__/MCPConnectionFactory.test.ts index 263c84357a..599f19c32a 100644 --- a/packages/api/src/mcp/__tests__/MCPConnectionFactory.test.ts +++ b/packages/api/src/mcp/__tests__/MCPConnectionFactory.test.ts @@ -474,6 +474,39 @@ describe('MCPConnectionFactory', () => { expect.stringContaining('OAuth required, stopping connection attempts'), ); }); + + it('should identify "no authorization" errors as OAuth errors (HTTP 400)', async () => { + const basicOptions = { + serverName: 'test-server', + serverConfig: mockServerConfig, + }; + + const oauthOptions = { + useOAuth: true as const, + user: mockUser, + flowManager: mockFlowManager, + tokenMethods: { + findToken: jest.fn(), + createToken: jest.fn(), + updateToken: jest.fn(), + deleteTokens: jest.fn(), + }, + }; + + const noAuthError = new Error( + 'Either no authorization values are specified or it could not be derived from the request', + ); + + mockConnectionInstance.connect.mockRejectedValue(noAuthError); + mockConnectionInstance.isConnected.mockResolvedValue(false); + + await expect(MCPConnectionFactory.create(basicOptions, oauthOptions)).rejects.toThrow( + 'no authorization', + ); + expect(mockLogger.info).toHaveBeenCalledWith( + expect.stringContaining('OAuth required, stopping connection attempts'), + ); + }); }); describe('discoverTools static method', () => {