Skip to content

fix(plugin): enrich + memoize shell PATH for MCP stdio subprocesses#4268

Merged
esengine merged 2 commits into
main-v2from
fix/4220-mcp-shell-path
Jun 13, 2026
Merged

fix(plugin): enrich + memoize shell PATH for MCP stdio subprocesses#4268
esengine merged 2 commits into
main-v2from
fix/4220-mcp-shell-path

Conversation

@esengine

Copy link
Copy Markdown
Owner

Lands #4220 (by @weikejia123) and adds probe memoization. Closes #4220.

The bug (#4220)

An MCP stdio server launched by absolute path (e.g. a wrapper.sh) ran with a PATH that lacked the user's interactive-shell directories (/opt/homebrew/bin, …). GUI launches (Finder / Dock / open(1)) don't inherit ~/.zshrc's PATH, so the wrapper's exec uvx/npx failed with exec: uvx: not found.

resolveStdioExecutable only enriched PATH from the shell on the command-not-found fallback path, so absolute-path commands (which resolve immediately) never got it — even though their child processes need it just as much.

Fix (commit 1, @weikejia123)

Hoist the shell-PATH enrichment into an unconditional first step (enrichStdioShellPATH) so every stdio subprocess inherits the interactive PATH. Bare-command and Windows paths are unchanged.

Memoization (commit 2)

Because the probe now runs for every stdio plugin, and defaultStdioShellPATH spawns an interactive login shell (zsh -l -i -c …, 2s timeout), N servers meant N shell spawns at startup. The interactive PATH is stable for the process, so the first non-empty probe is cached behind the injectable stdioShellPATH seam — one login shell per process instead of per server. Empty probes aren't cached, so a shell that becomes resolvable later is still picked up. Tests override the seam, so isolation is preserved.

Validation

  • go build ./internal/plugin/, go vet, go test ./internal/plugin/ (existing 11 + 2 new cache tests) all pass.

weikejia123 and others added 2 commits June 13, 2026 00:16
MCP plugin 使用绝对路径命令(如 /path/to/wrapper.sh)时,
resolveStdioExecutable 识别到路径中含分隔符后直接返回,
跳过了 defaultStdioShellPATH 对子进程环境变量 PATH 的富化。

这导致 wrapper 脚本中 exec 的子工具(如 uvx、npx)在
macOS GUI 启动环境下找不到,报类似这样的错误:
  plugin "MiniMax": read: EOF: stderr: uvx: not found

将 shell PATH 探测从"命令查找失败的回退路径"提升为
resolveStdioExecutable 中独立的、无条件的初始化步骤。
新辅助函数 enrichStdioShellPATH 在 hasPathSeparator 检查
和 lookPathInEnv 之前执行,确保每个 MCP stdio 子进程
都继承用户交互式 shell 的完整 PATH。

影响范围:
- 使用绝对/相对路径命令的 MCP stdio plugins 获得完整 shell PATH
- 裸命令名路径不受影响(之前已能正确查找)
- Windows 行为不变(由独立的 windowsStdioFallbackPATH 处理)
- shell 探测有 2 秒超时保护,无 shell 环境无副作用
- 向后兼容:现有工作配置不受影响
resolveStdioExecutable now probes the login shell for every stdio plugin, not
just on a not-found fallback. The interactive PATH is stable for the process,
so cache the first non-empty probe behind the injectable stdioShellPATH seam —
one login shell per process instead of one per server. Empty probes are not
cached, so a shell that becomes resolvable later is still picked up.
@esengine esengine requested a review from SivanCola as a code owner June 13, 2026 07:19
@github-actions github-actions Bot added mcp MCP servers / plugins (internal/plugin, codegraph) v2 Go rewrite (1.x) — main-v2 branch, active development labels Jun 13, 2026
@esengine esengine merged commit 6b115e1 into main-v2 Jun 13, 2026
14 checks passed
@esengine esengine deleted the fix/4220-mcp-shell-path branch June 13, 2026 07:23
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

mcp MCP servers / plugins (internal/plugin, codegraph) v2 Go rewrite (1.x) — main-v2 branch, active development

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants