// Mock openid-client before importing services jest.mock('openid-client', () => ({ discovery: jest.fn(), dynamicClientRegistration: jest.fn(), ClientSecretPost: jest.fn(() => jest.fn()), ClientSecretBasic: jest.fn(() => jest.fn()), None: jest.fn(() => jest.fn()), calculatePKCECodeChallenge: jest.fn(), randomPKCECodeVerifier: jest.fn(), buildAuthorizationUrl: jest.fn(), authorizationCodeGrant: jest.fn(), refreshTokenGrant: jest.fn(), })); import { Server } from 'http'; import { AppServer } from '../../src/server.js'; import { TestServerHelper } from '../utils/testServerHelper.js'; import * as mockSettings from '../utils/mockSettings.js'; import { Client } from '@modelcontextprotocol/sdk/client/index.js'; import { SSEClientTransport } from '@modelcontextprotocol/sdk/client/sse.js'; import { StreamableHTTPClientTransport } from '@modelcontextprotocol/sdk/client/streamableHttp.js'; import { cleanupAllServers } from '../../src/services/mcpService.js'; describe('Real Client Transport Integration Tests', () => { let _appServer: AppServer; let httpServer: Server; let baseURL: string; let testServerHelper: TestServerHelper; beforeAll(async () => { const settings = mockSettings.createMockSettings(); testServerHelper = new TestServerHelper(); const result = await testServerHelper.createTestServer(settings); _appServer = result.appServer; httpServer = result.httpServer; baseURL = result.baseURL; }, 60000); afterAll(async () => { // Clean up all MCP server connections first cleanupAllServers(); // Close the test server properly using the helper if (testServerHelper) { await testServerHelper.closeTestServer(); } else if (httpServer) { // Fallback to direct close if helper is not available await new Promise((resolve) => { httpServer.close(() => resolve()); }); } // Wait a bit to ensure all async operations complete await new Promise((resolve) => setTimeout(resolve, 100)); }); describe('SSE Client Transport Tests', () => { it('should connect using real SSEClientTransport', async () => { const sseUrl = new URL(`${baseURL}/sse`); const options = { requestInit: { headers: { Authorization: 'Bearer test-auth-token-123', }, }, }; const transport = new SSEClientTransport(sseUrl, options); const client = new Client( { name: 'real-sse-test-client', version: '1.0.0', }, { capabilities: { tools: {}, resources: {}, prompts: {}, }, }, ); let isConnected = false; let error: any = null; try { await client.connect(transport, {}); isConnected = true; console.log('SSE Client connected successfully'); // Test list tools const tools = await client.listTools({}); console.log('Available tools (SSE):', JSON.stringify(tools, null, 2)); await client.close(); console.log('SSE Client closed successfully'); } catch (err) { error = err; console.error('SSE Client test failed:', err); if (isConnected) { try { await client.close(); } catch (closeErr) { console.error('Error closing client:', closeErr); } } } expect(error).toBeNull(); expect(isConnected).toBe(true); }, 60000); it('should connect using real SSEClientTransport with group', async () => { const testGroup = 'integration-test-group'; const options = { requestInit: { headers: { Authorization: 'Bearer test-auth-token-123', }, }, }; const sseUrl = new URL(`${baseURL}/sse/${testGroup}`); const transport = new SSEClientTransport(sseUrl, options); const client = new Client( { name: 'real-sse-group-test-client', version: '1.0.0', }, { capabilities: { tools: {}, resources: {}, prompts: {}, }, }, ); let isConnected = false; let error: any = null; try { await client.connect(transport, {}); isConnected = true; console.log(`SSE Client with group ${testGroup} connected successfully`); // Test basic operations const tools = await client.listTools({}); console.log('Available tools (SSE with group):', JSON.stringify(tools, null, 2)); await client.close(); } catch (err) { error = err; console.error('SSE Client with group test failed:', err); if (isConnected) { try { await client.close(); } catch (closeErr) { console.error('Error closing client:', closeErr); } } } expect(error).toBeNull(); expect(isConnected).toBe(true); }, 60000); }); describe('StreamableHTTP Client Transport Tests', () => { it('should connect using real StreamableHTTPClientTransport', async () => { const mcpUrl = new URL(`${baseURL}/mcp`); const options: any = { requestInit: { headers: { Authorization: `Bearer test-auth-token-123`, }, }, }; const transport = new StreamableHTTPClientTransport(mcpUrl, options); const client = new Client( { name: 'real-http-test-client', version: '1.0.0', }, { capabilities: { tools: {}, resources: {}, prompts: {}, }, }, ); let isConnected = false; let error: any = null; try { await client.connect(transport, {}); isConnected = true; console.log('HTTP Client connected successfully'); // Test list tools const tools = await client.listTools({}); console.log('Available tools (HTTP):', JSON.stringify(tools, null, 2)); await client.close(); console.log('HTTP Client closed successfully'); } catch (err) { error = err; console.error('HTTP Client test failed:', err); if (isConnected) { try { await client.close(); } catch (closeErr) { console.error('Error closing client:', closeErr); } } } expect(error).toBeNull(); expect(isConnected).toBe(true); }, 60000); it('should connect using real StreamableHTTPClientTransport with group', async () => { const testGroup = 'integration-test-group'; const mcpUrl = new URL(`${baseURL}/mcp/${testGroup}`); const options: any = { requestInit: { headers: { Authorization: `Bearer test-auth-token-123`, }, }, }; const transport = new StreamableHTTPClientTransport(mcpUrl, options); const client = new Client( { name: 'real-http-group-test-client', version: '1.0.0', }, { capabilities: { tools: {}, resources: {}, prompts: {}, }, }, ); let isConnected = false; let error: any = null; try { await client.connect(transport, {}); isConnected = true; console.log(`HTTP Client with group ${testGroup} connected successfully`); // Test basic operations const tools = await client.listTools({}); console.log('Available tools (HTTP with group):', JSON.stringify(tools, null, 2)); await client.close(); } catch (err) { error = err; console.error('HTTP Client with group test failed:', err); if (isConnected) { try { await client.close(); } catch (closeErr) { console.error('Error closing client:', closeErr); } } } expect(error).toBeNull(); expect(isConnected).toBe(true); }, 60000); }); describe('Real Client Authentication Tests', () => { let _authAppServer: AppServer; let _authHttpServer: Server; let authBaseURL: string; beforeAll(async () => { const authSettings = mockSettings.createMockSettingsWithAuth(); const authTestServerHelper = new TestServerHelper(); const authResult = await authTestServerHelper.createTestServer(authSettings); _authAppServer = authResult.appServer; _authHttpServer = authResult.httpServer; authBaseURL = authResult.baseURL; }, 60000); afterAll(async () => { if (_authHttpServer) { _authHttpServer.close(); } }); it('should fail to connect with SSEClientTransport without auth', async () => { const sseUrl = new URL(`${authBaseURL}/sse`); const options = { requestInit: { headers: { Authorization: 'Bearer test-auth-token-123', }, }, }; const transport = new SSEClientTransport(sseUrl, options); const client = new Client( { name: 'real-sse-test-client-no-auth', version: '1.0.0', }, { capabilities: { tools: {}, resources: {}, prompts: {}, }, }, ); let error: any = null; try { await client.connect(transport, {}); // Should not reach here due to auth failure await client.listTools({}); await client.close(); } catch (err) { error = err; console.log('Expected auth error:', err); try { await client.close(); } catch (closeErr) { // Ignore close errors after connection failure } } expect(error).toBeDefined(); if (error) { expect(error.message).toContain('401'); } }, 60000); it('should connect with SSEClientTransport with valid auth', async () => { const sseUrl = new URL(`${authBaseURL}/sse`); const options = { requestInit: { headers: { Authorization: 'Bearer test-auth-token-123', }, }, }; const transport = new SSEClientTransport(sseUrl, options); const client = new Client( { name: 'real-sse-auth-test-client', version: '1.0.0', }, { capabilities: { tools: {}, resources: {}, prompts: {}, }, }, ); let isConnected = false; let error: any = null; try { await client.connect(transport, {}); isConnected = true; console.log('SSE Client with auth connected successfully'); // Test basic operations const tools = await client.listTools({}); console.log('Available tools (SSE with auth):', JSON.stringify(tools, null, 2)); await client.close(); } catch (err) { error = err; console.error('SSE Client with auth test failed:', err); if (isConnected) { try { await client.close(); } catch (closeErr) { console.error('Error closing client:', closeErr); } } } expect(error).toBeNull(); expect(isConnected).toBe(true); }, 60000); it('should connect with StreamableHTTPClientTransport with auth', async () => { const mcpUrl = new URL(`${authBaseURL}/mcp`); const options = { requestInit: { headers: { Authorization: 'Bearer test-auth-token-123', }, }, }; const transport = new StreamableHTTPClientTransport(mcpUrl, options); const client = new Client( { name: 'real-http-auth-test-client', version: '1.0.0', }, { capabilities: { tools: {}, resources: {}, prompts: {}, }, }, ); let isConnected = false; let error: any = null; try { await client.connect(transport, {}); isConnected = true; console.log('HTTP Client with auth connected successfully'); // Test basic operations const tools = await client.listTools({}); console.log('Available tools (HTTP with auth):', JSON.stringify(tools, null, 2)); await client.close(); } catch (err) { error = err; console.error('HTTP Client with auth test failed:', err); if (isConnected) { try { await client.close(); } catch (closeErr) { console.error('Error closing client:', closeErr); } } } expect(error).toBeNull(); expect(isConnected).toBe(true); }, 60000); }); });