diff --git a/src/core/webview/__tests__/webviewMessageHandler.spec.ts b/src/core/webview/__tests__/webviewMessageHandler.spec.ts index 8e61f3f0d97..7ba7128bb95 100644 --- a/src/core/webview/__tests__/webviewMessageHandler.spec.ts +++ b/src/core/webview/__tests__/webviewMessageHandler.spec.ts @@ -35,7 +35,6 @@ const mockClineProvider = { getCurrentCline: vi.fn(), getTaskWithId: vi.fn(), initClineWithHistoryItem: vi.fn(), - getMcpHub: vi.fn(), } as unknown as ClineProvider import { t } from "../../../i18n" @@ -589,138 +588,43 @@ describe("webviewMessageHandler - mcpEnabled", () => { handleMcpEnabledChange: vi.fn().mockResolvedValue(undefined), } - // Mock the getMcpHub method to return our mock McpHub - mockClineProvider.getMcpHub = vi.fn().mockReturnValue(mockMcpHub) - - // Reset the contextProxy getValue mock - vi.mocked(mockClineProvider.contextProxy.getValue).mockReturnValue(undefined) + // Ensure provider exposes getMcpHub and returns our mock + ;(mockClineProvider as any).getMcpHub = vi.fn().mockReturnValue(mockMcpHub) }) - it("should not refresh MCP servers when value does not change (true to true)", async () => { - // Setup: mcpEnabled is already true - vi.mocked(mockClineProvider.contextProxy.getValue).mockReturnValue(true) - - // Act: Send mcpEnabled message with same value + it("delegates enable=true to McpHub and posts updated state", async () => { await webviewMessageHandler(mockClineProvider, { type: "mcpEnabled", bool: true, }) - // Assert: handleMcpEnabledChange should not be called - expect(mockMcpHub.handleMcpEnabledChange).not.toHaveBeenCalled() - expect(mockClineProvider.contextProxy.setValue).toHaveBeenCalledWith("mcpEnabled", true) - expect(mockClineProvider.postStateToWebview).toHaveBeenCalled() - }) - - it("should not refresh MCP servers when value does not change (false to false)", async () => { - // Setup: mcpEnabled is already false - vi.mocked(mockClineProvider.contextProxy.getValue).mockReturnValue(false) - - // Act: Send mcpEnabled message with same value - await webviewMessageHandler(mockClineProvider, { - type: "mcpEnabled", - bool: false, - }) - - // Assert: handleMcpEnabledChange should not be called - expect(mockMcpHub.handleMcpEnabledChange).not.toHaveBeenCalled() - expect(mockClineProvider.contextProxy.setValue).toHaveBeenCalledWith("mcpEnabled", false) - expect(mockClineProvider.postStateToWebview).toHaveBeenCalled() - }) - - it("should refresh MCP servers when value changes from true to false", async () => { - // Setup: mcpEnabled is true - vi.mocked(mockClineProvider.contextProxy.getValue).mockReturnValue(true) - - // Act: Send mcpEnabled message with false - await webviewMessageHandler(mockClineProvider, { - type: "mcpEnabled", - bool: false, - }) - - // Assert: handleMcpEnabledChange should be called - expect(mockMcpHub.handleMcpEnabledChange).toHaveBeenCalledWith(false) - expect(mockClineProvider.contextProxy.setValue).toHaveBeenCalledWith("mcpEnabled", false) - expect(mockClineProvider.postStateToWebview).toHaveBeenCalled() - }) - - it("should refresh MCP servers when value changes from false to true", async () => { - // Setup: mcpEnabled is false - vi.mocked(mockClineProvider.contextProxy.getValue).mockReturnValue(false) - - // Act: Send mcpEnabled message with true - await webviewMessageHandler(mockClineProvider, { - type: "mcpEnabled", - bool: true, - }) - - // Assert: handleMcpEnabledChange should be called + expect((mockClineProvider as any).getMcpHub).toHaveBeenCalledTimes(1) + expect(mockMcpHub.handleMcpEnabledChange).toHaveBeenCalledTimes(1) expect(mockMcpHub.handleMcpEnabledChange).toHaveBeenCalledWith(true) - expect(mockClineProvider.contextProxy.setValue).toHaveBeenCalledWith("mcpEnabled", true) - expect(mockClineProvider.postStateToWebview).toHaveBeenCalled() - }) - - it("should handle undefined values with defaults correctly", async () => { - // Setup: mcpEnabled is undefined (defaults to true) - vi.mocked(mockClineProvider.contextProxy.getValue).mockReturnValue(undefined) - - // Act: Send mcpEnabled message with undefined (defaults to true) - await webviewMessageHandler(mockClineProvider, { - type: "mcpEnabled", - bool: undefined, - }) - - // Assert: Should use default value (true) and not trigger refresh since both are true - expect(mockClineProvider.contextProxy.setValue).toHaveBeenCalledWith("mcpEnabled", true) - expect(mockMcpHub.handleMcpEnabledChange).not.toHaveBeenCalled() - expect(mockClineProvider.postStateToWebview).toHaveBeenCalled() + expect(mockClineProvider.postStateToWebview).toHaveBeenCalledTimes(1) }) - it("should handle when mcpEnabled changes from undefined to false", async () => { - // Setup: mcpEnabled is undefined (defaults to true) - vi.mocked(mockClineProvider.contextProxy.getValue).mockReturnValue(undefined) - - // Act: Send mcpEnabled message with false + it("delegates enable=false to McpHub and posts updated state", async () => { await webviewMessageHandler(mockClineProvider, { type: "mcpEnabled", bool: false, }) - // Assert: Should trigger refresh since undefined defaults to true and we're changing to false - expect(mockClineProvider.contextProxy.setValue).toHaveBeenCalledWith("mcpEnabled", false) + expect((mockClineProvider as any).getMcpHub).toHaveBeenCalledTimes(1) + expect(mockMcpHub.handleMcpEnabledChange).toHaveBeenCalledTimes(1) expect(mockMcpHub.handleMcpEnabledChange).toHaveBeenCalledWith(false) - expect(mockClineProvider.postStateToWebview).toHaveBeenCalled() - }) - - it("should not call handleMcpEnabledChange when McpHub is not available", async () => { - // Setup: No McpHub instance available - mockClineProvider.getMcpHub = vi.fn().mockReturnValue(null) - vi.mocked(mockClineProvider.contextProxy.getValue).mockReturnValue(true) - - // Act: Send mcpEnabled message with false - await webviewMessageHandler(mockClineProvider, { - type: "mcpEnabled", - bool: false, - }) - - // Assert: State should be updated but handleMcpEnabledChange should not be called - expect(mockClineProvider.contextProxy.setValue).toHaveBeenCalledWith("mcpEnabled", false) - expect(mockClineProvider.postStateToWebview).toHaveBeenCalled() - // No error should be thrown + expect(mockClineProvider.postStateToWebview).toHaveBeenCalledTimes(1) }) - it("should always update state even when value doesn't change", async () => { - // Setup: mcpEnabled is true - vi.mocked(mockClineProvider.contextProxy.getValue).mockReturnValue(true) + it("handles missing McpHub instance gracefully and still posts state", async () => { + ;(mockClineProvider as any).getMcpHub = vi.fn().mockReturnValue(undefined) - // Act: Send mcpEnabled message with same value await webviewMessageHandler(mockClineProvider, { type: "mcpEnabled", bool: true, }) - // Assert: State should still be updated to ensure consistency - expect(mockClineProvider.contextProxy.setValue).toHaveBeenCalledWith("mcpEnabled", true) - expect(mockClineProvider.postStateToWebview).toHaveBeenCalled() + expect((mockClineProvider as any).getMcpHub).toHaveBeenCalledTimes(1) + expect(mockClineProvider.postStateToWebview).toHaveBeenCalledTimes(1) }) }) diff --git a/src/core/webview/webviewMessageHandler.ts b/src/core/webview/webviewMessageHandler.ts index e2c6d6a475b..f5dc6a467f1 100644 --- a/src/core/webview/webviewMessageHandler.ts +++ b/src/core/webview/webviewMessageHandler.ts @@ -900,19 +900,12 @@ export const webviewMessageHandler = async ( } case "mcpEnabled": const mcpEnabled = message.bool ?? true - const currentMcpEnabled = getGlobalState("mcpEnabled") ?? true - - // Always update the state to ensure consistency await updateGlobalState("mcpEnabled", mcpEnabled) - // Only refresh MCP connections if the value actually changed - // This prevents expensive MCP server refresh operations when saving unrelated settings - if (currentMcpEnabled !== mcpEnabled) { - // Delegate MCP enable/disable logic to McpHub - const mcpHubInstance = provider.getMcpHub() - if (mcpHubInstance) { - await mcpHubInstance.handleMcpEnabledChange(mcpEnabled) - } + // Delegate MCP enable/disable logic to McpHub + const mcpHubInstance = provider.getMcpHub() + if (mcpHubInstance) { + await mcpHubInstance.handleMcpEnabledChange(mcpEnabled) } await provider.postStateToWebview() diff --git a/src/services/mcp/McpHub.ts b/src/services/mcp/McpHub.ts index 646236b5d56..271c6e1fb3f 100644 --- a/src/services/mcp/McpHub.ts +++ b/src/services/mcp/McpHub.ts @@ -1212,7 +1212,6 @@ export class McpHub { public async refreshAllConnections(): Promise { if (this.isConnecting) { - vscode.window.showInformationMessage(t("mcp:info.already_refreshing")) return } @@ -1234,7 +1233,6 @@ export class McpHub { } this.isConnecting = true - vscode.window.showInformationMessage(t("mcp:info.refreshing_all")) try { const globalPath = await this.getMcpSettingsFilePath() @@ -1244,11 +1242,6 @@ export class McpHub { const globalConfig = JSON.parse(globalContent) globalServers = globalConfig.mcpServers || {} const globalServerNames = Object.keys(globalServers) - vscode.window.showInformationMessage( - t("mcp:info.global_servers_active", { - mcpServers: `${globalServerNames.join(", ") || "none"}`, - }), - ) } catch (error) { console.log("Error reading global MCP config:", error) } @@ -1261,11 +1254,6 @@ export class McpHub { const projectConfig = JSON.parse(projectContent) projectServers = projectConfig.mcpServers || {} const projectServerNames = Object.keys(projectServers) - vscode.window.showInformationMessage( - t("mcp:info.project_servers_active", { - mcpServers: `${projectServerNames.join(", ") || "none"}`, - }), - ) } catch (error) { console.log("Error reading project MCP config:", error) } @@ -1285,8 +1273,6 @@ export class McpHub { await delay(100) await this.notifyWebviewOfServerChanges() - - vscode.window.showInformationMessage(t("mcp:info.all_refreshed")) } catch (error) { this.showErrorMessage("Failed to refresh MCP servers", error) } finally {