diff --git a/MCPForUnity/Editor/Services/StdioBridgeReloadHandler.cs b/MCPForUnity/Editor/Services/StdioBridgeReloadHandler.cs index cfa4d7286..868c94dcb 100644 --- a/MCPForUnity/Editor/Services/StdioBridgeReloadHandler.cs +++ b/MCPForUnity/Editor/Services/StdioBridgeReloadHandler.cs @@ -70,7 +70,9 @@ private static void OnBeforeAssemblyReload() // Stop only stdio before reload. This is centralized here so resume-flag updates // and teardown cannot race each other via separate beforeAssemblyReload handlers. var stopTask = MCPServiceLocator.TransportManager.StopAsync(TransportMode.Stdio); - try { stopTask.Wait(500); } catch { } + // Match StdioBridgeHost.Stop's 2s socket-release wait; 500ms is too short on + // Windows and lets the next reload bind the same port before the OS frees it. + try { stopTask.Wait(2000); } catch { } // Legacy safety: stdio may have been started outside TransportManager state. try { StdioBridgeHost.Stop(); } catch { } diff --git a/MCPForUnity/Editor/Services/Transport/Transports/StdioBridgeHost.cs b/MCPForUnity/Editor/Services/Transport/Transports/StdioBridgeHost.cs index 66721f7b9..2a2cd96ff 100644 --- a/MCPForUnity/Editor/Services/Transport/Transports/StdioBridgeHost.cs +++ b/MCPForUnity/Editor/Services/Transport/Transports/StdioBridgeHost.cs @@ -396,8 +396,10 @@ public static void Stop() if (toWait != null) { - // CTS is already cancelled; give the listener task a brief moment to exit. - try { toWait.Wait(500); } catch { } + // Windows needs the full 2s for the socket to release after Dispose; with 500ms + // the next Start() can hit AddressAlreadyInUse and silently fall back to a new + // port, orphaning the listener. See #1173 / #688. + try { toWait.Wait(2000); } catch { } } // ProcessCommands stays permanently hooked (guarded by _processCommandsHooked)