From 57b3477903f7282951c0be660038e8ca57dad1e2 Mon Sep 17 00:00:00 2001 From: Rune Olsen Date: Wed, 26 Aug 2026 14:02:17 +0200 Subject: [PATCH] Fix External MCP server bugs; add npx/Node.js detection and install help MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Root-caused two real issues Rune hit with Obsidian/Homepage external MCP servers: 1. Toggling a server's enable switch silently wiped transportKind/env/ url/bearerToken/headers back to stdio defaults (only id/name/command/ args/isEnabled/timeout/createdAt were preserved) — almost certainly how Obsidian's config got corrupted into an empty-command stdio entry despite never being edited directly. Fixed via ExternalMCPServer.withEnabledToggled(), which flips only isEnabled. 2. npx (installed via Homebrew) was invisible to Confab because GUI apps only inherit launchd's minimal PATH, not the Terminal PATH. Tried spawning the user's login shell to ask for its real PATH — this caused two real hangs in one session (first an -ilc pipe deadlock, then a waitUntilExit()/CFRunLoop reentrancy issue even after fixing that) and was abandoned entirely in favor of LoginShellEnvironment: deterministic, subprocess-free directory probing (Homebrew, MacPorts, Volta, nvm's alias file) that can't hang by construction. Also added: - Edit capability for existing External MCP servers (previously only Add/Toggle/Delete) — the second thing Rune explicitly asked for, and the way to fix a corrupted entry like Obsidian's without deleting it. - MCPClientError.commandNotFound: a stdio server's command is checked against PATH up front in StdioMCPTransport.prepare() and fails immediately with a clear reason instead of cycling through 3 rounds of crash/restart backoff (5s/15s/30s) for a permanently-missing binary. - A "Get Node.js" button appears when this happens, opening a sheet with a copyable `brew install node`, a one-click install (via NodeInstallHelper, using the terminationHandler/readabilityHandler pattern already proven safe elsewhere in this file — deliberately not waitUntilExit()), or a nodejs.org link if Homebrew isn't present. - ExternalMCPManager.retryClient(id:) to manually retry after fixing the underlying cause. - Help book: new "Servers That Use npx" section, updated Server Status section, updated Settings blurb. 37 new/changed tests covering the toggle fix, PATH probing, the commandNotFound fast-fail path, and missing-command detection — full suite (374 tests) passes clean. --- .../Contents/Resources/en.lproj/index.html | 11 +- oAI/Services/ExternalMCPClient.swift | 14 +- oAI/Services/ExternalMCPManager.swift | 12 ++ oAI/Services/ExternalMCPModels.swift | 17 ++ oAI/Services/MCPTransport.swift | 101 ++++++++++- oAI/Services/NodeInstallHelper.swift | 79 +++++++++ oAI/Services/SettingsService.swift | 6 +- oAI/Views/Screens/NodeInstallHelpSheet.swift | 138 +++++++++++++++ oAI/Views/Screens/SettingsView.swift | 111 ++++++++++++- oAITests/ExternalMCPModelsTests.swift | 110 ++++++++++++ oAITests/MCPTransportTests.swift | 157 ++++++++++++++++++ 11 files changed, 736 insertions(+), 20 deletions(-) create mode 100644 oAI/Services/NodeInstallHelper.swift create mode 100644 oAI/Views/Screens/NodeInstallHelpSheet.swift diff --git a/oAI/Resources/Confab.help/Contents/Resources/en.lproj/index.html b/oAI/Resources/Confab.help/Contents/Resources/en.lproj/index.html index 2df69a3..d1ec3af 100644 --- a/oAI/Resources/Confab.help/Contents/Resources/en.lproj/index.html +++ b/oAI/Resources/Confab.help/Contents/Resources/en.lproj/index.html @@ -1516,6 +1516,13 @@ Whenever the user asks you to translate something, translate it to Norwegian Bok 💡 Tip: Arguments containing spaces can be quoted, e.g. --root "/Users/you/My Documents". +

Servers That Use npx (Node.js Required)

+

Many community MCP servers are npm packages, launched with a command like npx -y some-mcp-server. npx ships bundled with Node.js — if Node.js isn't installed on your Mac at all, npx won't exist and the server can't start.

+

If Node.js is installed but the server still shows as failing, this is usually a different, more subtle issue: macOS apps launched from Finder or the Dock (including Confab) don't automatically see the same PATH your Terminal does — so a copy of npx installed via Homebrew, MacPorts, Volta, or nvm can be invisible to Confab even though it works fine when you type the same command yourself in Terminal. Confab automatically checks these common install locations before giving up, so this should already work in most setups.

+
+ 💡 If a server still can't find its command: its status shows a Get Node.js button. Click it for a guided fix — a copyable brew install node command, a one-click Install Now button if Homebrew is detected, or a link to the official Node.js installer otherwise. After installing, click Retry Connection in the same sheet. +
+

Adding an HTTP Server

For remote MCP servers, choose the HTTP transport instead and provide: