Repository navigation
Description
Summary
On Windows, stdio MCP servers whose command is a batch shim (npx, uvx, …) fail to start with spawn npx ENOENT on the v2 engine (default since 0.33.0). The v1 engine does not have this problem because it delegates spawning to the official MCP SDK, which internally uses cross-spawn.
Environment
- Windows 11, Kimi Code CLI 0.38.0 (v2 engine, the default)
- Node v24.18.0 via nvm4w
- User-level
~/.kimi-code/mcp.jsonfollowing the official docs:
{
"mcpServers": {
"playwright": {
"command": "npx",
"args": ["-y", "@playwright/mcp@latest"]
}
}
}Steps to reproduce
- On Windows, configure any stdio MCP server with
command: "npx"as above. - Start Kimi Code.
- The server never comes up; the log shows:
ERROR mcp server unavailable server=playwright status=failed reason="spawn npx ENOENT"
Root cause
npx on Windows is a batch file (npx.cmd). node:child_process.spawn without shell: true goes through CreateProcess, which cannot execute batch files and does not consult PATHEXT → ENOENT. (Node ≥ 20.12 tightened batch-file spawning further after CVE-2024-27980.) This is not a Node version issue — it reproduces on Node v24.18.0.
Engine comparison (verified on main @ f4dc9ba, identical in 0.38.0):
- v1 works:
packages/agent-core/src/mcp/client-stdio.ts:65uses the officialStdioClientTransportfrom@modelcontextprotocol/sdk(1.29). The SDK spawns viacross-spawn, which resolves.cmdviaPATHEXTand launches batch files throughcmd.exewith proper escaping — the standard post-CVE-2024-27980 approach. - v2 fails:
packages/agent-core-v2/src/mcpCore/client-stdio.ts:188implements its ownRuntimeStdioTransportoverIHostProcess→HostProcessService.spawn(packages/agent-core-v2/src/os/backends/node-local/hostProcessService.ts:174), which calls rawnode:child_process.spawnwithshellunset →.cmdcommands can never start on Windows.
Since 0.33.0 defaults to v2, this is a v2 regression relative to v1. Other clients (e.g. Claude Code) handle .cmd resolution internally; Kimi Code v2 does not.
Suggested fix
- Minimal: in the v2 stdio transport, spawn via
cross-spawn(already in the dependency tree via the MCP SDK), or resolve.cmd/.batviaPATHEXTand launch throughcmd.exewith correct argument escaping. - Broader: swap
node:child_process.spawnforcross-spawninsideHostProcessServiceso every local spawn (MCP,rg, git context, external hooks, workspace fs) benefits uniformly on Windows. Larger blast radius — needs regression testing. - Avoid
shell: trueas the fix (argument-escaping / injection surface).
Secondary items
mcp.jsonis only loaded at session start; edits don't hot-apply. Note that a full exit is not required —/reloador/newpicks up the changes (this is what the TUI hint already says,apps/kimi-code/src/tui/commands/plugins.ts:164). A config file watcher, or a hint when the file changes, would still help discoverability.- Failure-reason visibility is already addressed in 0.38.0:
/mcprenders anerror: …line (including the captured stderr tail) for failed servers (apps/kimi-code/src/tui/components/messages/mcp-status-panel.ts:139-145).
Workarounds (verified by the reporter)
Bypass npx — install globally and point command at node.exe with the absolute entry path:
npm i -g @playwright/mcp{
"mcpServers": {
"playwright": {
"command": "C:\\nvm4w\\nodejs\\node.exe",
"args": ["C:\\nvm4w\\nodejs\\node_modules\\@playwright\\mcp\\cli.js", "…其他参数"],
"startupTimeoutMs": 120000
}
}
}Or wrap with cmd /c: "command": "cmd", "args": ["/c", "npx", "-y", "@playwright/mcp@latest", ...]. Restart (or /reload) to apply.
Original report
Forwarded user feedback (Chinese original):
【反馈】Windows 下配置 Playwright MCP 一直不生效,排查结论 + 临时解法
环境:Windows 11 + Kimi Code CLI + nvm4w(Node v24.18.0),按官方文档在用户级 ~/.kimi-code/mcp.json 配置 playwright server。
踩了三个坑:
- 配置只在会话启动时加载。改完 mcp.json 当前会话不会生效,必须完全退出重开(文档有写,但容易忽略,建议加载失败时在 TUI 里给个提示)。
- Windows 下 spawn npx ENOENT(核心问题)。日志里报错:
ERROR mcp server unavailable server=playwright status=failed reason="spawn npx ENOENT"。原因:npx 本体是批处理 npx.cmd,Node 的 spawn() 不带 shell: true 时走 CreateProcess,执行不了批处理、也不会按 PATHEXT 补后缀。这不是 Node 版本问题(我用 v24.18.0 照样复现),Node 20.12+ 因 CVE-2024-27980 对批处理 spawn 更严格了。Claude Code 等客户端在 Windows 上内部处理了 .cmd 的情况,建议 Kimi Code 也跟进:Windows 下 spawn MCP server 时加 shell: true 或自行解析 .cmd。- 排查入口不方便。最后是自己翻 ~/.kimi-code/logs/kimi-code.log 才看到报错,如果 /mcp 能直接显示失败原因会好很多。
临时解法(已验证可用):绕过 npx,全局安装后用绝对路径直指 node + 入口文件,或者用 cmd /c 包装。改完重启 Kimi Code 生效。
Activity
losewayy commentedon Sep 26, 2026
Traced the failure path on current
main— root cause confirmed in-tree, and the regression window checks out at commit level.packages/agent-core-v2/src/os/backends/node-local/hostProcessService.ts:190callsspawn(command, args, spawnOptions)wherespawnOptions.shellis only set when the caller passesoptions.shell(:29-31). The MCP stdio transport (packages/agent-core-v2/src/mcpCore/client-stdio.ts:188-192) callsruntime.process.spawn(this.config.command, this.config.args, { cwd, env })— noshelloption. On Windows,CreateProcessonly auto-resolves*.exe;npx,pnpm,codegraphand other package-manager binaries on PATH are*.cmdshims, so the spawn failsENOENTbefore any process exists.Why 0.36.x worked: both the legacy engine and earlier v2 snapshots spawned stdio via the MCP SDK's
StdioClientTransport, which usescross-spawn— the library that resolves.cmd/.batshims and routes them throughcmd.exe.84da6629(#2961, runtime-binding decouple) replaced it withRuntimeStdioTransportcalling the barespawnabove, and that commit first shipped in@moonshot-ai/kimi-code@0.37.0— squarely inside the reported regression window.Two related hazards sit in the same fix: a bare name gets
ENOENT, but an explicitly-resolved.cmd/.batgetsEINVAL(Node refuses batch files withoutshellsince the CVE-2024-27980 fix) — so the command needs both PATH/PATHEXT resolution and shell routing on win32. The repo already documents this class:apps/kimi-code/src/cli/update/preflight.ts:594-601explains the.cmd-without-shell EINVAL, andsource.ts:77,84resolvesnpm.cmdexplicitly viaresolveCommandPath(with the note at :80-82 that resolving ahead ofcmd.exeavoids picking up a CWD-planted shim).Proposed scope for a focused bug-fix PR, inside
hostProcessService.spawnon Windows whenoptions.shellis unset (external hooks passshell: truewith full command lines and must keep their semantics):command(no directory separator) againstPATH/PATHEXTin PATHEXT order —.exeresults spawn directly, only.cmd/.batresults route throughprocess.env.ComSpecwith argv quoted for cmd's rules — resolved against the effective child env (PATH/PATHEXT looked up case-insensitively on win32), keepingresolveCommandPath's cwd-hit refusal (same binary-plant concern the update path guards).resolveCommandPathlives inapps/kimi-code, so the logic gets reimplemented inagent-core-v2, not imported.runtime.process.spawnconsumer — MCP stdio (including plugin-shipped servers andkimi mcpprobing) and ACP sessions, whose process service delegates non-terminal spawns to the same service. POSIX behavior untouched.describeinpackages/agent-core-v2/test/os/backends/node-local/hostProcessService.test.tswith a.cmd-shim spawn case.Per
CONTRIBUTING.md, could a maintainer/approvethis scope?ConradLu2740 commentedon Sep 27, 2026
Additional data point: this also affects plugin-declared MCP servers, not just user-level
mcp.json— users hit it with zero custom config.The official
cloudbaseplugin (v0.2.0) declares in itskimi.plugin.json:Simply installing this plugin produces the failure on every app launch:
Observed on Windows 11 (build 26200), Node v26.2.0 (on system PATH), Kimi Code desktop app. 31 occurrences over 10 days — exactly one per launch, correlated with app start times.
Minimal repro of the underlying behavior on this machine (nodejs on PATH, no shell):
Workarounds that work today:
"command": "cmd.exe", "args": ["/c", "npx", ...]— this is exactly what the officialkimi-cu-winplugin does (cmd.exe /c bin\kimi-cu-mcp.cmd)./plugins mcp disable cloudbase cloudbase(keeps the plugin's skills, drops the broken server).Since the official docs example itself uses
"command": "npx"(https://www.kimi.com/code/docs/en/kimi-code-cli/customization/mcp.html), every Windows user following the docs hits this. Suggest fixing the v2 spawner (resolve via PATHEXT, or use cross-spawn like the v1 engine's MCP SDK, or auto-wrap batch shims incmd /c), and/or warning at plugin-install time when a declared stdio command has no.exeon Windows.KaiOnCode commentedon Oct 21, 2026
我准备接这个 bug 修复,先把证据和方案贴在 issue 里,方便维护者判断。
复现(真实 Windows 机器,Windows 10 build 19045 / Node v22.20.0,三次一致)
根因与 issue 一致:v2 的 stdio MCP 走
packages/agent-core-v2/src/mcpCore/client-stdio.ts里自研的RuntimeStdioTransport→lease.runtime.process.spawn→packages/agent-core-v2/src/os/backends/node-local/hostProcessService.ts的原生node:child_process.spawn;Windows 上CreateProcess只自动补.exe、不查PATHEXT,裸npx(实际是npx.cmd)只能 ENOENT,Node ≥ 20.12 还会直接拒绝.cmd/.bat(EINVAL)。同一棵树上 MCP SDK 自带的 stdio client 用的就是cross-spawn(@modelcontextprotocol/sdk的client/stdio.js第一行),v2 这条自研 transport 少了这一步。打算怎么改
在
HostProcessService.spawn里加一步 Windows 专用的回退:先照旧原生 spawn;只有它以 ENOENT / EINVAL 失败(Windows 上找不到.exe、或 Node 拒绝.cmd/.bat)时,才按PATHEXT去找同名.bat/.cmd(也支持配置里直接写npx.cmd或相对路径),找到就改由cross-spawn启动(负责PATHEXT与参数转义)。这样正常命令完全不受影响,也不会改跑别的可执行文件;POSIX 行为与错误语义都不变。顺带修一处 Windows 下的环境变量合并:
{...process.env, ...覆盖}在 Windows 上会留下PATH与Path两个同名变量(Windows 里它们其实是同一个),改成按不区分大小写合并。测试
.cmdshim,分别用显式路径和 PATH 上的裸命令名 spawn 它,断言 stdout 与退出码。red→green 已在真实 Windows 机器(Win10 build 19045 / Node v24.15.0 / pnpm 10.33.0)上验过:换回修复前的文件,该测试文件 24 个用例里 18 个失败(两条 Windows 集成用例分别报
spawn EINVAL和spawn kimi-probe ENOENT);换回修复后的文件,24 个用例全绿。补充一点:仓库目前把 Windows CI 关着(ci.yml里test-windows是if: false),所以那两条 Windows 专用用例在 CI 里不会自动跑,红绿是我在真机上跑出来的。PR 已开:#4309。
@liruifengv 能否给个
/approve?