From 51333d11e6449a0dcdfb52059a0403fd9ba8b44b Mon Sep 17 00:00:00 2001 From: David Sarno Date: Wed, 14 Jan 2026 19:15:40 -0800 Subject: [PATCH 1/2] Fix local HTTP server UI check --- .../Services/IServerManagementService.cs | 6 ++ .../Services/ServerManagementService.cs | 70 +++++++++++++++++++ .../Connection/McpConnectionSection.cs | 8 +-- 3 files changed, 80 insertions(+), 4 deletions(-) diff --git a/MCPForUnity/Editor/Services/IServerManagementService.cs b/MCPForUnity/Editor/Services/IServerManagementService.cs index f38014a88..299fad511 100644 --- a/MCPForUnity/Editor/Services/IServerManagementService.cs +++ b/MCPForUnity/Editor/Services/IServerManagementService.cs @@ -35,6 +35,12 @@ public interface IServerManagementService /// bool IsLocalHttpServerRunning(); + /// + /// Fast reachability check: returns true if a local TCP listener is accepting connections + /// for the configured local URL/port (used for UI state without process inspection). + /// + bool IsLocalHttpServerReachable(); + /// /// Attempts to get the command that will be executed when starting the local HTTP server /// diff --git a/MCPForUnity/Editor/Services/ServerManagementService.cs b/MCPForUnity/Editor/Services/ServerManagementService.cs index b77bbd357..cd62258d3 100644 --- a/MCPForUnity/Editor/Services/ServerManagementService.cs +++ b/MCPForUnity/Editor/Services/ServerManagementService.cs @@ -3,6 +3,7 @@ using System.Linq; using System.Collections.Generic; using System.Globalization; +using System.Net.Sockets; using System.Security.Cryptography; using System.Text; using MCPForUnity.Editor.Constants; @@ -600,6 +601,75 @@ public bool IsLocalHttpServerRunning() } } + public bool IsLocalHttpServerReachable() + { + try + { + string httpUrl = HttpEndpointUtility.GetBaseUrl(); + if (!IsLocalUrl(httpUrl)) + { + return false; + } + + if (!Uri.TryCreate(httpUrl, UriKind.Absolute, out var uri) || uri.Port <= 0) + { + return false; + } + + return TryConnectToLocalPort(uri.Host, uri.Port, timeoutMs: 50); + } + catch + { + return false; + } + } + + private static bool TryConnectToLocalPort(string host, int port, int timeoutMs) + { + try + { + if (string.IsNullOrEmpty(host)) + { + host = "127.0.0.1"; + } + + var hosts = new HashSet(StringComparer.OrdinalIgnoreCase) { host }; + if (host == "localhost" || host == "0.0.0.0") + { + hosts.Add("127.0.0.1"); + } + if (host == "::" || host == "0:0:0:0:0:0:0:0") + { + hosts.Add("::1"); + } + + foreach (var target in hosts) + { + try + { + using (var client = new TcpClient()) + { + var connectTask = client.ConnectAsync(target, port); + if (connectTask.Wait(timeoutMs) && client.Connected) + { + return true; + } + } + } + catch + { + // Ignore per-host failures. + } + } + } + catch + { + // Ignore probe failures and treat as unreachable. + } + + return false; + } + private bool StopLocalHttpServerInternal(bool quiet, int? portOverride = null, bool allowNonLocalUrl = false) { string httpUrl = HttpEndpointUtility.GetBaseUrl(); diff --git a/MCPForUnity/Editor/Windows/Components/Connection/McpConnectionSection.cs b/MCPForUnity/Editor/Windows/Components/Connection/McpConnectionSection.cs index 282280324..75ff073c7 100644 --- a/MCPForUnity/Editor/Windows/Components/Connection/McpConnectionSection.cs +++ b/MCPForUnity/Editor/Windows/Components/Connection/McpConnectionSection.cs @@ -482,14 +482,14 @@ private void UpdateStartHttpButtonState() bool canStartLocalServer = httpLocalSelected && MCPServiceLocator.Server.IsLocalUrl(); bool localServerRunning = false; - // Avoid running expensive port/PID checks every UI tick. + // Avoid running expensive port/PID checks every UI tick; use a fast socket probe for UI state. if (httpLocalSelected) { double now = EditorApplication.timeSinceStartup; if ((now - lastLocalServerRunningPollTime) > 0.75f || httpServerToggleInProgress) { lastLocalServerRunningPollTime = now; - lastLocalServerRunning = MCPServiceLocator.Server.IsLocalHttpServerRunning(); + lastLocalServerRunning = MCPServiceLocator.Server.IsLocalHttpServerReachable(); } localServerRunning = lastLocalServerRunning; } @@ -531,7 +531,7 @@ private async void OnHttpServerToggleClicked() try { // Check if a local server is running. - bool serverRunning = IsHttpLocalSelected() && MCPServiceLocator.Server.IsLocalHttpServerRunning(); + bool serverRunning = IsHttpLocalSelected() && MCPServiceLocator.Server.IsLocalHttpServerReachable(); if (serverRunning) { @@ -591,7 +591,7 @@ private async Task TryAutoStartSessionAsync() var delay = attempt < 6 ? shortDelay : longDelay; // Check if server is actually accepting connections - bool serverDetected = MCPServiceLocator.Server.IsLocalHttpServerRunning(); + bool serverDetected = MCPServiceLocator.Server.IsLocalHttpServerReachable(); if (serverDetected) { From 22bac8ab8b73f8695fd6e06eadef9d6bbdee7ef5 Mon Sep 17 00:00:00 2001 From: David Sarno Date: Wed, 14 Jan 2026 19:54:41 -0800 Subject: [PATCH 2/2] Fix connection section cleanup --- .../Windows/Components/Connection/McpConnectionSection.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/MCPForUnity/Editor/Windows/Components/Connection/McpConnectionSection.cs b/MCPForUnity/Editor/Windows/Components/Connection/McpConnectionSection.cs index 75ff073c7..ab5c9036a 100644 --- a/MCPForUnity/Editor/Windows/Components/Connection/McpConnectionSection.cs +++ b/MCPForUnity/Editor/Windows/Components/Connection/McpConnectionSection.cs @@ -1,5 +1,4 @@ using System; -using System.Net.Sockets; using System.Threading.Tasks; using MCPForUnity.Editor.Constants; using MCPForUnity.Editor.Helpers; @@ -531,7 +530,7 @@ private async void OnHttpServerToggleClicked() try { // Check if a local server is running. - bool serverRunning = IsHttpLocalSelected() && MCPServiceLocator.Server.IsLocalHttpServerReachable(); + bool serverRunning = IsHttpLocalSelected() && MCPServiceLocator.Server.IsLocalHttpServerReachable(); if (serverRunning) {