diff --git a/packages/coding-agent/CHANGELOG.md b/packages/coding-agent/CHANGELOG.md index 5cbb09c44..2f9ad861a 100644 --- a/packages/coding-agent/CHANGELOG.md +++ b/packages/coding-agent/CHANGELOG.md @@ -2,6 +2,10 @@ ## [Unreleased] +### Fixed + +- Fixed Windows stdio MCP server launches showing a separate `cmd.exe` window for direct executable servers; MCP subprocesses now set `windowsHide` on every Windows spawn path. ([#3535](https://github.com/can1357/oh-my-pi/issues/3535)) + ## [16.1.21] - 2026-06-26 ### Fixed diff --git a/packages/coding-agent/src/mcp/transports/stdio.test.ts b/packages/coding-agent/src/mcp/transports/stdio.test.ts new file mode 100644 index 000000000..3e668796f --- /dev/null +++ b/packages/coding-agent/src/mcp/transports/stdio.test.ts @@ -0,0 +1,28 @@ +import { describe, expect, it } from "bun:test"; + +import { resolveStdioSpawnCommand } from "./stdio"; + +describe("resolveStdioSpawnCommand", () => { + it("hides direct Windows executable MCP servers", async () => { + await expect( + resolveStdioSpawnCommand( + { command: "server.exe", args: ["--stdio"] }, + { cwd: process.cwd(), env: {}, platform: "win32" }, + ), + ).resolves.toEqual({ + cmd: ["server.exe", "--stdio"], + windowsHide: true, + }); + }); + + it("keeps off-Windows spawn options unchanged", async () => { + await expect( + resolveStdioSpawnCommand( + { command: "server.exe", args: ["--stdio"] }, + { cwd: process.cwd(), env: {}, platform: "linux" }, + ), + ).resolves.toEqual({ + cmd: ["server.exe", "--stdio"], + }); + }); +}); diff --git a/packages/coding-agent/src/mcp/transports/stdio.ts b/packages/coding-agent/src/mcp/transports/stdio.ts index 23b46f0e3..1e7f0cf47 100644 --- a/packages/coding-agent/src/mcp/transports/stdio.ts +++ b/packages/coding-agent/src/mcp/transports/stdio.ts @@ -239,12 +239,15 @@ export async function resolveStdioSpawnCommand( // Direct-spawn only when we resolved to a concrete file AND its extension // is not a batch script. Everything else (resolved .cmd/.bat, or an // unresolved extensionless command) goes through cmd.exe so PATHEXT runs. + // Every Windows stdio server launch hides its console window; otherwise + // direct .exe servers pop a visible cmd window while the MCP server lives. + const windowsHide = true; const needsCmdExe = resolved === null || isWindowsBatchCommand(resolvedCommand); - if (!needsCmdExe) return { cmd: [resolvedCommand, ...args] }; + if (!needsCmdExe) return { cmd: [resolvedCommand, ...args], windowsHide }; return { cmd: [resolveComSpec(options.env), "/d", "/s", "/c", buildCmdExeCommand(resolvedCommand, args)], - windowsHide: true, + windowsHide, }; }