From 96f4ce375b7b969d7614163a2d19325e580a83ba Mon Sep 17 00:00:00 2001 From: Hashibutogarasu Date: Sat, 29 Nov 2025 15:28:41 +0900 Subject: [PATCH 1/5] fix: Changed flag management to EditorPrefs --- .../Editor/Setup/SetupWindowService.cs | 29 ++++++++++++++----- 1 file changed, 21 insertions(+), 8 deletions(-) diff --git a/MCPForUnity/Editor/Setup/SetupWindowService.cs b/MCPForUnity/Editor/Setup/SetupWindowService.cs index 2045ba45..99a037a2 100644 --- a/MCPForUnity/Editor/Setup/SetupWindowService.cs +++ b/MCPForUnity/Editor/Setup/SetupWindowService.cs @@ -18,7 +18,11 @@ public static class SetupWindowService { private const string SETUP_COMPLETED_KEY = EditorPrefKeys.SetupCompleted; private const string SETUP_DISMISSED_KEY = EditorPrefKeys.SetupDismissed; - private static bool _hasCheckedThisSession = false; + + // Use SessionState to persist "checked this editor session" across domain reloads. + // SessionState survives assembly reloads within the same Editor session, which prevents + // the setup window from reappearing after code reloads / playmode transitions. + private const string SessionCheckedKey = "MCPForUnity.SetupWindowCheckedThisEditorSession"; static SetupWindowService() { @@ -35,10 +39,12 @@ static SetupWindowService() /// private static void CheckSetupNeeded() { - if (_hasCheckedThisSession) + // Ensure we only run once per Editor session (survives domain reloads). + // This avoids showing the setup dialog repeatedly when scripts recompile or Play mode toggles. + if (SessionState.GetBool(SessionCheckedKey, false)) return; - _hasCheckedThisSession = true; + SessionState.SetBool(SessionCheckedKey, true); try { @@ -48,11 +54,16 @@ private static void CheckSetupNeeded() bool userOverrodeHttpUrl = EditorPrefs.HasKey(EditorPrefKeys.HttpBaseUrl); // In Asset Store builds with a remote default URL (and no user override), skip the local setup wizard. - if (!userOverrodeHttpUrl + if ( + !userOverrodeHttpUrl && McpDistribution.Settings.skipSetupWindowWhenRemoteDefault - && McpDistribution.Settings.IsRemoteDefault) + && McpDistribution.Settings.IsRemoteDefault + ) { - McpLog.Info("Skipping Setup Window because this distribution ships with a hosted MCP URL. Open Window/MCP For Unity/Setup Window if you want to configure a local runtime.", always: false); + McpLog.Info( + "Skipping Setup Window because this distribution ships with a hosted MCP URL. Open Window/MCP For Unity/Setup Window if you want to configure a local runtime.", + always: false + ); return; } @@ -66,7 +77,10 @@ private static void CheckSetupNeeded() } else { - McpLog.Info("Setup Window skipped - previously completed or dismissed", always: false); + McpLog.Info( + "Setup Window skipped - previously completed or dismissed", + always: false + ); } } catch (Exception ex) @@ -108,6 +122,5 @@ public static void MarkSetupDismissed() EditorPrefs.SetBool(SETUP_DISMISSED_KEY, true); McpLog.Info("Setup marked as dismissed"); } - } } From ed02bf56f7e88899856ab97fd171066e412a55bd Mon Sep 17 00:00:00 2001 From: Hashibutogarasu Date: Sat, 29 Nov 2025 15:59:23 +0900 Subject: [PATCH 2/5] refactor: Improve code readability and error handling in MCP window toggle --- .../Editor/MenuItems/MCPForUnityMenu.cs | 41 +++++++++++-------- 1 file changed, 25 insertions(+), 16 deletions(-) diff --git a/MCPForUnity/Editor/MenuItems/MCPForUnityMenu.cs b/MCPForUnity/Editor/MenuItems/MCPForUnityMenu.cs index 32fde720..1e74e550 100644 --- a/MCPForUnity/Editor/MenuItems/MCPForUnityMenu.cs +++ b/MCPForUnity/Editor/MenuItems/MCPForUnityMenu.cs @@ -5,35 +5,45 @@ namespace MCPForUnity.Editor.MenuItems { - /// - /// Centralized menu items for MCP For Unity - /// public static class MCPForUnityMenu { - // ======================================== - // Main Menu Items - // ======================================== - - /// - /// Show the Setup Window - /// [MenuItem("Window/MCP For Unity/Setup Window", priority = 1)] public static void ShowSetupWindow() { SetupWindowService.ShowSetupWindow(); } - /// - /// Toggle the main MCP For Unity window - /// [MenuItem("Window/MCP For Unity/Toggle MCP Window %#m", priority = 2)] public static void ToggleMCPWindow() { if (EditorWindow.HasOpenInstances()) { - foreach (var window in UnityEngine.Resources.FindObjectsOfTypeAll()) + foreach ( + var window in UnityEngine.Resources.FindObjectsOfTypeAll() + ) { - window.Close(); + if (window == null) + continue; + + try + { + // Try the normal Close + window.Close(); + } + catch (System.Exception ex) + { + Debug.LogWarning( + $"MCP window Close() threw: {ex.GetType().Name}: {ex.Message}\nFalling back to DestroyImmediate." + ); + try + { + UnityEngine.Object.DestroyImmediate(window); + } + catch + { + // Ignore any exceptions during DestroyImmediate + } + } } } else @@ -41,6 +51,5 @@ public static void ToggleMCPWindow() MCPForUnityEditorWindow.ShowWindow(); } } - } } From 9aea8e7a88e9a47a0217e5f38a2f163e0fe16737 Mon Sep 17 00:00:00 2001 From: Hashibutogarasu Date: Sat, 29 Nov 2025 16:12:06 +0900 Subject: [PATCH 3/5] fix: Refactor MCP window toggle logic to use new helper methods for better readability and maintainability --- .../Editor/MenuItems/MCPForUnityMenu.cs | 30 ++----------------- .../Editor/Windows/MCPForUnityEditorWindow.cs | 27 +++++++++++++++++ 2 files changed, 29 insertions(+), 28 deletions(-) diff --git a/MCPForUnity/Editor/MenuItems/MCPForUnityMenu.cs b/MCPForUnity/Editor/MenuItems/MCPForUnityMenu.cs index 1e74e550..10f05248 100644 --- a/MCPForUnity/Editor/MenuItems/MCPForUnityMenu.cs +++ b/MCPForUnity/Editor/MenuItems/MCPForUnityMenu.cs @@ -16,35 +16,9 @@ public static void ShowSetupWindow() [MenuItem("Window/MCP For Unity/Toggle MCP Window %#m", priority = 2)] public static void ToggleMCPWindow() { - if (EditorWindow.HasOpenInstances()) + if (MCPForUnityEditorWindow.HasAnyOpenWindow()) { - foreach ( - var window in UnityEngine.Resources.FindObjectsOfTypeAll() - ) - { - if (window == null) - continue; - - try - { - // Try the normal Close - window.Close(); - } - catch (System.Exception ex) - { - Debug.LogWarning( - $"MCP window Close() threw: {ex.GetType().Name}: {ex.Message}\nFalling back to DestroyImmediate." - ); - try - { - UnityEngine.Object.DestroyImmediate(window); - } - catch - { - // Ignore any exceptions during DestroyImmediate - } - } - } + MCPForUnityEditorWindow.CloseAllOpenWindows(); } else { diff --git a/MCPForUnity/Editor/Windows/MCPForUnityEditorWindow.cs b/MCPForUnity/Editor/Windows/MCPForUnityEditorWindow.cs index 1dfada10..354b4299 100644 --- a/MCPForUnity/Editor/Windows/MCPForUnityEditorWindow.cs +++ b/MCPForUnity/Editor/Windows/MCPForUnityEditorWindow.cs @@ -26,6 +26,33 @@ public static void ShowWindow() var window = GetWindow("MCP For Unity"); window.minSize = new Vector2(500, 600); } + + // Helper to check and manage open windows from other classes + public static bool HasAnyOpenWindow() + { + return OpenWindows.Count > 0; + } + + public static void CloseAllOpenWindows() + { + if (OpenWindows.Count == 0) + return; + + // Copy to array to avoid modifying the collection while iterating + var arr = new MCPForUnityEditorWindow[OpenWindows.Count]; + OpenWindows.CopyTo(arr); + foreach (var window in arr) + { + try + { + window?.Close(); + } + catch (Exception ex) + { + Debug.LogWarning($"Error closing MCP window: {ex.Message}"); + } + } + } public void CreateGUI() { string basePath = AssetPathUtility.GetMcpPackageRootPath(); From f6c6a3adae4d15977cb6a45097bed1e297e43996 Mon Sep 17 00:00:00 2001 From: Hashibutogarasu Date: Tue, 2 Dec 2025 00:40:11 +0900 Subject: [PATCH 4/5] fix: Reorder using directives and improve error logging format in MCP window --- .../Editor/Windows/MCPForUnityEditorWindow.cs | 28 +++++++++++-------- 1 file changed, 17 insertions(+), 11 deletions(-) diff --git a/MCPForUnity/Editor/Windows/MCPForUnityEditorWindow.cs b/MCPForUnity/Editor/Windows/MCPForUnityEditorWindow.cs index 354b4299..380d5932 100644 --- a/MCPForUnity/Editor/Windows/MCPForUnityEditorWindow.cs +++ b/MCPForUnity/Editor/Windows/MCPForUnityEditorWindow.cs @@ -1,14 +1,14 @@ using System; using System.Collections.Generic; using System.Threading.Tasks; -using UnityEditor; -using UnityEngine; -using UnityEngine.UIElements; using MCPForUnity.Editor.Helpers; using MCPForUnity.Editor.Services; -using MCPForUnity.Editor.Windows.Components.Settings; -using MCPForUnity.Editor.Windows.Components.Connection; using MCPForUnity.Editor.Windows.Components.ClientConfig; +using MCPForUnity.Editor.Windows.Components.Connection; +using MCPForUnity.Editor.Windows.Components.Settings; +using UnityEditor; +using UnityEngine; +using UnityEngine.UIElements; namespace MCPForUnity.Editor.Windows { @@ -53,6 +53,7 @@ public static void CloseAllOpenWindows() } } } + public void CreateGUI() { string basePath = AssetPathUtility.GetMcpPackageRootPath(); @@ -64,7 +65,9 @@ public void CreateGUI() if (visualTree == null) { - McpLog.Error($"Failed to load UXML at: {basePath}/Editor/Windows/MCPForUnityEditorWindow.uxml"); + McpLog.Error( + $"Failed to load UXML at: {basePath}/Editor/Windows/MCPForUnityEditorWindow.uxml" + ); return; } @@ -105,8 +108,10 @@ public void CreateGUI() var settingsRoot = settingsTree.Instantiate(); sectionsContainer.Add(settingsRoot); settingsSection = new McpSettingsSection(settingsRoot); - settingsSection.OnGitUrlChanged += () => clientConfigSection?.UpdateManualConfiguration(); - settingsSection.OnHttpServerCommandUpdateRequested += () => connectionSection?.UpdateHttpServerCommandDisplay(); + settingsSection.OnGitUrlChanged += () => + clientConfigSection?.UpdateManualConfiguration(); + settingsSection.OnHttpServerCommandUpdateRequested += () => + connectionSection?.UpdateHttpServerCommandDisplay(); } // Load and initialize Connection section @@ -118,7 +123,8 @@ public void CreateGUI() var connectionRoot = connectionTree.Instantiate(); sectionsContainer.Add(connectionRoot); connectionSection = new McpConnectionSection(connectionRoot); - connectionSection.OnManualConfigUpdateRequested += () => clientConfigSection?.UpdateManualConfiguration(); + connectionSection.OnManualConfigUpdateRequested += () => + clientConfigSection?.UpdateManualConfiguration(); } // Load and initialize Client Configuration section @@ -190,11 +196,11 @@ private void ScheduleHealthCheck() { EditorApplication.delayCall += async () => { - if (this == null) + if (this == null || connectionSection == null) { return; } - await connectionSection?.VerifyBridgeConnectionAsync(); + await connectionSection.VerifyBridgeConnectionAsync(); }; } } From f8bc576dbe64240d06e32206bf030886af81a78b Mon Sep 17 00:00:00 2001 From: David Sarno Date: Mon, 1 Dec 2025 19:33:42 -0800 Subject: [PATCH 5/5] Address CodeRabbit feedback: use McpLog.Warn and guard against repeated CreateGUI calls --- MCPForUnity/Editor/Windows/MCPForUnityEditorWindow.cs | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/MCPForUnity/Editor/Windows/MCPForUnityEditorWindow.cs b/MCPForUnity/Editor/Windows/MCPForUnityEditorWindow.cs index 380d5932..ccc47ca9 100644 --- a/MCPForUnity/Editor/Windows/MCPForUnityEditorWindow.cs +++ b/MCPForUnity/Editor/Windows/MCPForUnityEditorWindow.cs @@ -20,6 +20,7 @@ public class MCPForUnityEditorWindow : EditorWindow private McpClientConfigSection clientConfigSection; private static readonly HashSet OpenWindows = new(); + private bool guiCreated = false; public static void ShowWindow() { @@ -49,13 +50,17 @@ public static void CloseAllOpenWindows() } catch (Exception ex) { - Debug.LogWarning($"Error closing MCP window: {ex.Message}"); + McpLog.Warn($"Error closing MCP window: {ex.Message}"); } } } public void CreateGUI() { + // Guard against repeated CreateGUI calls (e.g., domain reloads) + if (guiCreated) + return; + string basePath = AssetPathUtility.GetMcpPackageRootPath(); // Load main window UXML @@ -138,6 +143,8 @@ public void CreateGUI() clientConfigSection = new McpClientConfigSection(clientConfigRoot); } + guiCreated = true; + // Initial updates RefreshAllData(); } @@ -152,6 +159,7 @@ private void OnDisable() { EditorApplication.update -= OnEditorUpdate; OpenWindows.Remove(this); + guiCreated = false; } private void OnFocus()