From afc5e7bf8284e16f313e1a56d25e36fcc6c5d1a1 Mon Sep 17 00:00:00 2001 From: Roo Code Date: Sat, 9 Aug 2025 20:52:13 +0000 Subject: [PATCH] fix: prevent duplicate MCP server instances on refresh/restart - Added proper cleanup in restartConnection to ensure old instances are fully closed - Added safeguards in connectToServer to check for existing connections - Improved deleteConnection to handle null checks for transport and client - Added delays to ensure cleanup completes before creating new connections This fixes the issue where refreshing MCP servers or clicking the refresh button on individual servers was causing new instances to start without closing old ones. --- src/services/mcp/McpHub.ts | 34 +++++++++++++++++++++++++++------- 1 file changed, 27 insertions(+), 7 deletions(-) diff --git a/src/services/mcp/McpHub.ts b/src/services/mcp/McpHub.ts index 271c6e1fb3f..ff657bd348b 100644 --- a/src/services/mcp/McpHub.ts +++ b/src/services/mcp/McpHub.ts @@ -618,8 +618,14 @@ export class McpHub { config: z.infer, source: "global" | "project" = "global", ): Promise { - // Remove existing connection if it exists with the same source - await this.deleteConnection(name, source) + // Check if a connection already exists with the same name and source + const existingConnection = this.findConnection(name, source) + if (existingConnection) { + // Ensure complete cleanup of existing connection + await this.deleteConnection(name, source) + // Wait a moment to ensure cleanup is complete + await delay(100) + } // Check if MCP is globally enabled const mcpEnabled = await this.isMcpEnabled() @@ -1007,8 +1013,14 @@ export class McpHub { for (const connection of connections) { try { if (connection.type === "connected") { - await connection.transport.close() - await connection.client.close() + // Close transport first + if (connection.transport) { + await connection.transport.close() + } + // Then close client + if (connection.client) { + await connection.client.close() + } } } catch (error) { console.error(`Failed to close transport for ${name}:`, error) @@ -1186,9 +1198,17 @@ export class McpHub { connection.server.status = "connecting" connection.server.error = "" await this.notifyWebviewOfServerChanges() - await delay(500) // artificial delay to show user that server is restarting + try { - await this.deleteConnection(serverName, connection.server.source) + // Store the source before deleting + const serverSource = connection.server.source || "global" + + // Ensure complete cleanup of the old connection + await this.deleteConnection(serverName, serverSource) + + // Wait a bit to ensure cleanup is complete + await delay(500) + // Parse the config to validate it const parsedConfig = JSON.parse(config) try { @@ -1196,7 +1216,7 @@ export class McpHub { const validatedConfig = this.validateServerConfig(parsedConfig, serverName) // Try to connect again using validated config - await this.connectToServer(serverName, validatedConfig, connection.server.source || "global") + await this.connectToServer(serverName, validatedConfig, serverSource) vscode.window.showInformationMessage(t("mcp:info.server_connected", { serverName })) } catch (validationError) { this.showErrorMessage(`Invalid configuration for MCP server "${serverName}"`, validationError)