From 3f0642d8fb2028aad469e625000a763167a18158 Mon Sep 17 00:00:00 2001 From: Diarica <3501108459@qq.com> Date: Mon, 15 Jun 2026 09:42:35 +0800 Subject: [PATCH] fix: don't truncate MCP paths containing spaces Two code paths were splitting MCP server commands on whitespace without the shouldSplitPluginCommand guard that NormalizePluginCommandLine has, which truncated any command path with spaces. 1. Frontend AddServerForm / EditServerForm (CapabilitiesPanel.tsx): split(/\s+/) on the command field before sending to the Go backend. A path like "C:\Program Files\MyApp\server.exe" became command "C:\Program" with args ["Files\MyApp\server.exe"]. 2. Legacy config parser (mcpjson.go parseLegacyMCPSpec): Always split the body on spaces. The v0.x config.json format uses "name=command args..." lines; for paths with spaces like "ida=C:\PersonalData\Software\Learn\IDA Pro\ida_bridge.bat", this truncated the command to "C:\PersonalData\Software\Learn\IDA". Fix: in the frontend, pass the full command string through and let NormalizePluginCommandLine handle the split on the Go side. In parseLegacyMCPSpec, only split when shouldSplitPluginCommand returns true (known runner like npx/node, or quoted command), otherwise keep the full body as the command. Fixes e.g. IDA Pro MCP server configuration where the binary path contains spaces. --- desktop/frontend/src/components/CapabilitiesPanel.tsx | 10 ++++------ internal/config/mcpjson.go | 5 ++++- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/desktop/frontend/src/components/CapabilitiesPanel.tsx b/desktop/frontend/src/components/CapabilitiesPanel.tsx index 7a869dd7e..68bbd030a 100644 --- a/desktop/frontend/src/components/CapabilitiesPanel.tsx +++ b/desktop/frontend/src/components/CapabilitiesPanel.tsx @@ -1244,13 +1244,12 @@ function EditServerForm({ const ready = isStdio ? command.trim() !== "" : url.trim() !== ""; const submit = () => { - const parts = command.trim().split(/\s+/).filter(Boolean); const envText = env.trim(); onSave({ name: s.name, transport, - command: isStdio ? (parts[0] ?? "") : "", - args: isStdio ? parts.slice(1) : [], + command: isStdio ? command.trim() : "", + args: [], url: isStdio ? "" : url.trim(), env: envText === "" ? null : parseEnvText(envText), }); @@ -1625,7 +1624,6 @@ function AddServerForm({ const ready = name.trim() !== "" && (isStdio ? command.trim() !== "" : url.trim() !== ""); const submit = () => { - const parts = command.trim().split(/\s+/).filter(Boolean); const envMap: Record = {}; for (const line of env.split("\n")) { const eq = line.indexOf("="); @@ -1634,8 +1632,8 @@ function AddServerForm({ onAdd({ name: name.trim(), transport, - command: isStdio ? (parts[0] ?? "") : "", - args: isStdio ? parts.slice(1) : [], + command: isStdio ? command.trim() : "", + args: [], url: isStdio ? "" : url.trim(), env: envMap, }); diff --git a/internal/config/mcpjson.go b/internal/config/mcpjson.go index ce25bd379..f891ea4e2 100644 --- a/internal/config/mcpjson.go +++ b/internal/config/mcpjson.go @@ -158,7 +158,10 @@ func parseLegacyMCPSpec(raw string) (PluginEntry, bool) { if !ok || len(parts) == 0 { return PluginEntry{}, false } - return PluginEntry{Name: name, Command: parts[0], Args: parts[1:]}, true + if shouldSplitPluginCommand(body, parts[0]) { + return PluginEntry{Name: name, Command: parts[0], Args: parts[1:]}, true + } + return PluginEntry{Name: name, Command: body}, true } // anonymousMCPName names a v0.x spec that carried no name= prefix (its tools