From b954897efd3dd5490b546bbb2b4f53e91fccb533 Mon Sep 17 00:00:00 2001 From: Shutong Wu <51266340+Scriptwonder@users.noreply.github.com> Date: Tue, 28 Jul 2026 12:05:19 -0400 Subject: [PATCH] fix: redirect stdin from NUL when launching the server on Windows (#1279) The Editor is a console-less GUI process. TerminalLauncher spawned cmd.exe with UseShellExecute=false and CreateNoWindow=true and never redirected stdin, so uvx.exe inherited an invalid stdin handle and died with "The handle is invalid. (os error 6)" before the server could start. Redirect stdin from NUL inside the cmd.exe payload so the child gets a valid handle regardless of whether the Editor has a console. Regression from #1201, shipped in v10.1.0. --- .../Editor/Services/Server/TerminalLauncher.cs | 7 +++++-- .../Services/Server/TerminalLauncherTests.cs | 13 +++++++++++++ 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/MCPForUnity/Editor/Services/Server/TerminalLauncher.cs b/MCPForUnity/Editor/Services/Server/TerminalLauncher.cs index 764c82f6d..0d2c23616 100644 --- a/MCPForUnity/Editor/Services/Server/TerminalLauncher.cs +++ b/MCPForUnity/Editor/Services/Server/TerminalLauncher.cs @@ -42,10 +42,13 @@ public System.Diagnostics.ProcessStartInfo CreateHeadlessProcessStartInfo(string } #if UNITY_EDITOR_WIN - // cmd.exe /c " >> "" 2>&1" + // cmd.exe /c " < NUL >> "" 2>&1" // The whole payload after /c is wrapped in one outer pair of quotes; cmd strips the // outermost quotes, so inner quotes around the log path survive for paths with spaces. - string winRedirect = $"{command} >> \"{logFilePath}\" 2>&1"; + // stdin is redirected from NUL because the Editor is a console-less GUI process: with + // CreateNoWindow and no console handle, uvx.exe would inherit an invalid stdin and die + // with "The handle is invalid. (os error 6)" before launching the server. + string winRedirect = $"{command} < NUL >> \"{logFilePath}\" 2>&1"; return new System.Diagnostics.ProcessStartInfo { FileName = "cmd.exe", diff --git a/TestProjects/UnityMCPTests/Assets/Tests/EditMode/Services/Server/TerminalLauncherTests.cs b/TestProjects/UnityMCPTests/Assets/Tests/EditMode/Services/Server/TerminalLauncherTests.cs index 8426643d5..63f17071b 100644 --- a/TestProjects/UnityMCPTests/Assets/Tests/EditMode/Services/Server/TerminalLauncherTests.cs +++ b/TestProjects/UnityMCPTests/Assets/Tests/EditMode/Services/Server/TerminalLauncherTests.cs @@ -212,6 +212,19 @@ public void CreateHeadlessProcessStartInfo_RedirectsOutputToLogFile() StringAssert.Contains(">>", startInfo.Arguments, "output should be appended to the log via >>"); } +#if UNITY_EDITOR_WIN + [Test] + public void CreateHeadlessProcessStartInfo_RedirectsStdinFromNul() + { + // Regression guard for #1279: the Editor is a console-less GUI process, so a child + // launched with CreateNoWindow inherits an invalid stdin and uvx.exe fails with + // "The handle is invalid. (os error 6)". stdin must come from NUL instead. + var startInfo = _launcher.CreateHeadlessProcessStartInfo("uvx run-server", LogPath()); + + StringAssert.Contains("< NUL", startInfo.Arguments, "stdin should be redirected from NUL"); + } +#endif + [Test] public void CreateHeadlessProcessStartInfo_LogPathWithSpaces_IsQuoted() {