Skip to content

Commit ead8191

Browse files
built-by-asclaude
andcommitted
Fix MCP server removal and execAsync shell invocation
- Fix execInLoginShell to properly wrap commands instead of malformed shell option - Fix serverMap accumulating deleted servers by clearing on each poll - Add optimistic UI removal for instant feedback when removing servers - Add refresh after add operation with loading spinner - Remove recently removed servers tracking (unnecessary with proper serverMap clear) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]>
1 parent 45f2aae commit ead8191

File tree

2 files changed

+20
-11
lines changed

2 files changed

+20
-11
lines changed

main.ts

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -150,7 +150,8 @@ function spawnMcpPoller(sessionId: string, projectDir: string) {
150150
try {
151151
const servers = parseMcpOutput(outputBuffer);
152152

153-
// Merge servers into the map (upsert by name)
153+
// Clear and replace the server map with current results
154+
serverMap.clear();
154155
servers.forEach(server => {
155156
serverMap.set(server.name, server);
156157
});
@@ -639,9 +640,9 @@ function getUserShell(): string {
639640
// Execute command in user's login shell
640641
async function execInLoginShell(command: string): Promise<string> {
641642
const userShell = getUserShell();
642-
const { stdout } = await execAsync(command, {
643-
shell: `${userShell} -l -c`
644-
});
643+
// Wrap command to execute in login shell
644+
const wrappedCommand = `${userShell} -l -c '${command.replace(/'/g, "'\\''")}'`;
645+
const { stdout } = await execAsync(wrappedCommand);
645646
return stdout;
646647
}
647648

renderer.ts

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -973,11 +973,16 @@ function renderMcpServers() {
973973
removeBtn?.addEventListener("click", async (e) => {
974974
e.stopPropagation();
975975
if (confirm(`Remove MCP server "${server.name}"?`)) {
976+
// Optimistically remove from UI
977+
mcpServers = mcpServers.filter(s => s.name !== server.name);
978+
renderMcpServers();
979+
976980
try {
977981
await ipcRenderer.invoke("remove-mcp-server", server.name);
978-
await refreshMcpServers();
979982
} catch (error) {
980983
alert(`Failed to remove server: ${error}`);
984+
// Refresh to restore correct state on error
985+
await refreshMcpServers();
981986
}
982987
}
983988
});
@@ -1193,23 +1198,28 @@ removeMcpDetailsBtn?.addEventListener("click", async () => {
11931198
if (!serverName) return;
11941199

11951200
if (confirm(`Remove MCP server "${serverName}"?`)) {
1201+
// Close modal immediately
1202+
mcpDetailsModal?.classList.add("hidden");
1203+
1204+
// Optimistically remove from UI
1205+
mcpServers = mcpServers.filter(s => s.name !== serverName);
1206+
renderMcpServers();
1207+
11961208
try {
11971209
await ipcRenderer.invoke("remove-mcp-server", serverName);
1198-
mcpDetailsModal?.classList.add("hidden");
1199-
await refreshMcpServers();
12001210
} catch (error) {
12011211
alert(`Failed to remove server: ${error}`);
1212+
// Refresh to restore correct state on error
1213+
await refreshMcpServers();
12021214
}
12031215
}
12041216
});
12051217

12061218
// Listen for MCP polling started event
12071219
ipcRenderer.on("mcp-polling-started", (_event, sessionId: string) => {
1208-
console.log(`[MCP UI] Polling started for session ${sessionId}, active: ${activeSessionId}`);
12091220
if (sessionId === activeSessionId) {
12101221
const addMcpServerBtn = document.getElementById("add-mcp-server");
12111222
if (addMcpServerBtn) {
1212-
console.log("[MCP UI] Setting add button to loading state");
12131223
addMcpServerBtn.innerHTML = '<span class="loading-spinner"></span>';
12141224
addMcpServerBtn.classList.add("pointer-events-none");
12151225
}
@@ -1218,14 +1228,12 @@ ipcRenderer.on("mcp-polling-started", (_event, sessionId: string) => {
12181228

12191229
// Listen for MCP server updates from main process
12201230
ipcRenderer.on("mcp-servers-updated", (_event, sessionId: string, servers: McpServer[]) => {
1221-
console.log(`[MCP UI] Received update for session ${sessionId}, active: ${activeSessionId}`);
12221231
// Only update if this is for the active session
12231232
if (sessionId === activeSessionId) {
12241233
mcpServers = servers;
12251234
renderMcpServers();
12261235

12271236
// Restore add button
1228-
console.log("[MCP UI] Restoring add button from loading state");
12291237
const addMcpServerBtn = document.getElementById("add-mcp-server");
12301238
if (addMcpServerBtn) {
12311239
addMcpServerBtn.innerHTML = '+';

0 commit comments

Comments
 (0)