From 6aa647e5409eeb42e3acc77c01462b992871aa4e Mon Sep 17 00:00:00 2001 From: Himanshu Soni Date: Tue, 24 Feb 2026 11:18:06 +0530 Subject: [PATCH] fix(core): create new McpClient on restart to apply updated config --- .../core/src/tools/mcp-client-manager.test.ts | 34 ++++++++++++++++ packages/core/src/tools/mcp-client-manager.ts | 39 +++++++++---------- 2 files changed, 52 insertions(+), 21 deletions(-) diff --git a/packages/core/src/tools/mcp-client-manager.test.ts b/packages/core/src/tools/mcp-client-manager.test.ts index 352c2c12f03..9dd86fc1897 100644 --- a/packages/core/src/tools/mcp-client-manager.test.ts +++ b/packages/core/src/tools/mcp-client-manager.test.ts @@ -264,6 +264,40 @@ describe('McpClientManager', () => { 'No MCP server registered with the name "non-existent"', ); }); + + it('should create a new McpClient with updated config on restart', async () => { + const originalConfig = { command: 'node', args: ['--port', '8000'] }; + const updatedConfig = { command: 'node', args: ['--port', '9000'] }; + + mockConfig.getMcpServers.mockReturnValue({ + 'test-server': originalConfig, + }); + + // Track McpClient constructor calls + const constructorCalls: unknown[][] = []; + vi.mocked(McpClient).mockImplementation((...args: unknown[]) => { + constructorCalls.push(args); + return mockedMcpClient; + }); + mockedMcpClient.getServerConfig.mockReturnValue(originalConfig); + + const manager = new McpClientManager('0.0.1', toolRegistry, mockConfig); + await manager.startConfiguredMcpServers(); + + // First call should use the original config + expect(constructorCalls).toHaveLength(1); + expect(constructorCalls[0][1]).toBe(originalConfig); + + // Simulate config file change and hot-reload + mockConfig.getMcpServers.mockReturnValue({ + 'test-server': updatedConfig, + }); + await manager.startConfiguredMcpServers(); + + // A NEW McpClient should have been constructed with the updated config + expect(constructorCalls).toHaveLength(2); + expect(constructorCalls[1][1]).toBe(updatedConfig); + }); }); describe('getMcpInstructions', () => { diff --git a/packages/core/src/tools/mcp-client-manager.ts b/packages/core/src/tools/mcp-client-manager.ts index a6783788e88..23a37a8ca90 100644 --- a/packages/core/src/tools/mcp-client-manager.ts +++ b/packages/core/src/tools/mcp-client-manager.ts @@ -218,30 +218,27 @@ export class McpClientManager { (async () => { try { if (existing) { + this.clients.delete(name); await existing.disconnect(); } - const client = - existing ?? - new McpClient( - name, - config, - this.toolRegistry, - this.cliConfig.getPromptRegistry(), - this.cliConfig.getResourceRegistry(), - this.cliConfig.getWorkspaceContext(), - this.cliConfig, - this.cliConfig.getDebugMode(), - this.clientVersion, - async () => { - debugLogger.log('Tools changed, updating Gemini context...'); - await this.scheduleMcpContextRefresh(); - }, - ); - if (!existing) { - this.clients.set(name, client); - this.eventEmitter?.emit('mcp-client-update', this.clients); - } + const client = new McpClient( + name, + config, + this.toolRegistry, + this.cliConfig.getPromptRegistry(), + this.cliConfig.getResourceRegistry(), + this.cliConfig.getWorkspaceContext(), + this.cliConfig, + this.cliConfig.getDebugMode(), + this.clientVersion, + async () => { + debugLogger.log('Tools changed, updating Gemini context...'); + await this.scheduleMcpContextRefresh(); + }, + ); + this.clients.set(name, client); + this.eventEmitter?.emit('mcp-client-update', this.clients); try { await client.connect(); await client.discover(this.cliConfig);