diff --git a/MCPForUnity/Editor/Windows/Components/Connection/McpConnectionSection.cs b/MCPForUnity/Editor/Windows/Components/Connection/McpConnectionSection.cs index a95cdd3d..6bc47992 100644 --- a/MCPForUnity/Editor/Windows/Components/Connection/McpConnectionSection.cs +++ b/MCPForUnity/Editor/Windows/Components/Connection/McpConnectionSection.cs @@ -44,6 +44,14 @@ private enum TransportProtocol private Button testConnectionButton; private bool connectionToggleInProgress; + private Task verificationTask; + private string lastHealthStatus; + + // Health status constants + private const string HealthStatusUnknown = "Unknown"; + private const string HealthStatusHealthy = "Healthy"; + private const string HealthStatusPingFailed = "Ping Failed"; + private const string HealthStatusUnhealthy = "Unhealthy"; // Events public event Action OnManualConfigUpdateRequested; @@ -173,7 +181,7 @@ public void UpdateConnectionStatus() statusIndicator.AddToClassList("disconnected"); connectionToggleButton.text = "Start Session"; - healthStatusLabel.text = "Unknown"; + healthStatusLabel.text = HealthStatusUnknown; healthIndicator.RemoveFromClassList("healthy"); healthIndicator.RemoveFromClassList("warning"); healthIndicator.AddToClassList("unknown"); @@ -408,15 +416,33 @@ private async void OnTestConnectionClicked() } public async Task VerifyBridgeConnectionAsync() + { + // Prevent concurrent verification calls + if (verificationTask != null && !verificationTask.IsCompleted) + { + return; + } + + verificationTask = VerifyBridgeConnectionInternalAsync(); + await verificationTask; + } + + private async Task VerifyBridgeConnectionInternalAsync() { var bridgeService = MCPServiceLocator.Bridge; if (!bridgeService.IsRunning) { - healthStatusLabel.text = "Disconnected"; + healthStatusLabel.text = HealthStatusUnknown; healthIndicator.RemoveFromClassList("healthy"); healthIndicator.RemoveFromClassList("warning"); healthIndicator.AddToClassList("unknown"); - McpLog.Warn("Cannot verify connection: Bridge is not running"); + + // Only log if state changed + if (lastHealthStatus != HealthStatusUnknown) + { + McpLog.Warn("Cannot verify connection: Bridge is not running"); + lastHealthStatus = HealthStatusUnknown; + } return; } @@ -426,23 +452,45 @@ public async Task VerifyBridgeConnectionAsync() healthIndicator.RemoveFromClassList("warning"); healthIndicator.RemoveFromClassList("unknown"); + string newStatus; if (result.Success && result.PingSucceeded) { - healthStatusLabel.text = "Healthy"; + newStatus = HealthStatusHealthy; + healthStatusLabel.text = newStatus; healthIndicator.AddToClassList("healthy"); - McpLog.Debug($"Connection verification successful: {result.Message}"); + + // Only log if state changed + if (lastHealthStatus != newStatus) + { + McpLog.Debug($"Connection verification successful: {result.Message}"); + lastHealthStatus = newStatus; + } } else if (result.HandshakeValid) { - healthStatusLabel.text = "Ping Failed"; + newStatus = HealthStatusPingFailed; + healthStatusLabel.text = newStatus; healthIndicator.AddToClassList("warning"); - McpLog.Warn($"Connection verification warning: {result.Message}"); + + // Log once per distinct warning state + if (lastHealthStatus != newStatus) + { + McpLog.Warn($"Connection verification warning: {result.Message}"); + lastHealthStatus = newStatus; + } } else { - healthStatusLabel.text = "Unhealthy"; + newStatus = HealthStatusUnhealthy; + healthStatusLabel.text = newStatus; healthIndicator.AddToClassList("warning"); - McpLog.Error($"Connection verification failed: {result.Message}"); + + // Log once per distinct error state + if (lastHealthStatus != newStatus) + { + McpLog.Error($"Connection verification failed: {result.Message}"); + lastHealthStatus = newStatus; + } } } } diff --git a/MCPForUnity/Editor/Windows/MCPForUnityEditorWindow.cs b/MCPForUnity/Editor/Windows/MCPForUnityEditorWindow.cs index ccc47ca9..10663737 100644 --- a/MCPForUnity/Editor/Windows/MCPForUnityEditorWindow.cs +++ b/MCPForUnity/Editor/Windows/MCPForUnityEditorWindow.cs @@ -21,6 +21,8 @@ public class MCPForUnityEditorWindow : EditorWindow private static readonly HashSet OpenWindows = new(); private bool guiCreated = false; + private double lastRefreshTime = 0; + private const double RefreshDebounceSeconds = 0.5; public static void ShowWindow() { @@ -181,6 +183,14 @@ private void OnEditorUpdate() private void RefreshAllData() { + // Debounce rapid successive calls (e.g., from OnFocus being called multiple times) + double currentTime = EditorApplication.timeSinceStartup; + if (currentTime - lastRefreshTime < RefreshDebounceSeconds) + { + return; + } + lastRefreshTime = currentTime; + connectionSection?.UpdateConnectionStatus(); if (MCPServiceLocator.Bridge.IsRunning)