From 3f03bc720a4998f367d9eb540e8ca7e1abeea405 Mon Sep 17 00:00:00 2001 From: 777genius Date: Thu, 16 Apr 2026 22:32:47 +0300 Subject: [PATCH] fix(extensions): dedupe MCP detail API key lookups --- .../extensions/mcp/McpServerDetailDialog.tsx | 32 ---------------- .../mcp/McpServerDetailDialog.test.ts | 38 +++++++++++++++++++ 2 files changed, 38 insertions(+), 32 deletions(-) diff --git a/src/renderer/components/extensions/mcp/McpServerDetailDialog.tsx b/src/renderer/components/extensions/mcp/McpServerDetailDialog.tsx index 7ddeb82c..256b4cc2 100644 --- a/src/renderer/components/extensions/mcp/McpServerDetailDialog.tsx +++ b/src/renderer/components/extensions/mcp/McpServerDetailDialog.tsx @@ -128,38 +128,6 @@ export const McpServerDetailDialog = ({ ); }, [server?.id, open]); // eslint-disable-line react-hooks/exhaustive-deps - // Auto-fill env vars from saved API keys - useEffect(() => { - if (!server || server.envVars.length === 0 || !api.apiKeys) return; - - const envVarNames = server.envVars.map((env) => env.name); - void api.apiKeys.lookup(envVarNames).then( - (results) => { - if (results.length === 0) return; - const filled = new Set(); - const updates: Record = {}; - for (const r of results) { - updates[r.envVarName] = r.value; - filled.add(r.envVarName); - } - setEnvValues((prev) => { - const next = { ...prev }; - for (const [k, v] of Object.entries(updates)) { - // Only auto-fill if the field is empty - if (!next[k]) { - next[k] = v; - } - } - return next; - }); - setAutoFilledFields(filled); - }, - () => { - // Silently ignore lookup failures - } - ); - }, [server?.id]); // eslint-disable-line react-hooks/exhaustive-deps - if (!server) return <>; const canAutoInstall = !!server.installSpec; diff --git a/test/renderer/components/extensions/mcp/McpServerDetailDialog.test.ts b/test/renderer/components/extensions/mcp/McpServerDetailDialog.test.ts index 5329963a..8835a9dd 100644 --- a/test/renderer/components/extensions/mcp/McpServerDetailDialog.test.ts +++ b/test/renderer/components/extensions/mcp/McpServerDetailDialog.test.ts @@ -219,4 +219,42 @@ describe('McpServerDetailDialog installed entry handling', () => { await Promise.resolve(); }); }); + + it('looks up saved API keys only once per dialog open', async () => { + const host = document.createElement('div'); + document.body.appendChild(host); + const root = createRoot(host); + const server = makeServer(); + server.envVars = [{ name: 'CONTEXT7_API_KEY', isSecret: true }]; + lookupMock.mockResolvedValue([ + { + envVarName: 'CONTEXT7_API_KEY', + value: 'secret', + }, + ]); + + await act(async () => { + root.render( + React.createElement(McpServerDetailDialog, { + server, + isInstalled: false, + installedEntry: null, + diagnostic: null, + diagnosticsLoading: false, + open: true, + onClose: vi.fn(), + }) + ); + await Promise.resolve(); + await Promise.resolve(); + }); + + expect(lookupMock).toHaveBeenCalledTimes(1); + expect(lookupMock).toHaveBeenCalledWith(['CONTEXT7_API_KEY']); + + await act(async () => { + root.unmount(); + await Promise.resolve(); + }); + }); });