From 81072b2c928493b229f402ec3cf3b5b948ad4ecb Mon Sep 17 00:00:00 2001 From: Marcus Sanatan Date: Wed, 22 Oct 2025 21:44:29 -0400 Subject: [PATCH 01/30] Remove legacy UI and correct priority ordering of menu items --- MCPForUnity/Editor/Setup/SetupWizard.cs | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/MCPForUnity/Editor/Setup/SetupWizard.cs b/MCPForUnity/Editor/Setup/SetupWizard.cs index 691e482f..f9fe1ee3 100644 --- a/MCPForUnity/Editor/Setup/SetupWizard.cs +++ b/MCPForUnity/Editor/Setup/SetupWizard.cs @@ -109,7 +109,7 @@ public static void ShowSetupWizardManual() /// /// Check dependencies and show status /// - [MenuItem("Window/MCP For Unity/Check Dependencies", priority = 3)] + [MenuItem("Window/MCP For Unity/Check Dependencies", priority = 2)] public static void CheckDependencies() { var result = DependencyManager.CheckAllDependencies(); @@ -141,19 +141,10 @@ public static void CheckDependencies() /// /// Open MCP Client Configuration window /// - [MenuItem("Window/MCP For Unity/Open MCP Window %#m", priority = 4)] + [MenuItem("Window/MCP For Unity/Open MCP Window %#m", priority = 3)] public static void OpenClientConfiguration() { Windows.MCPForUnityEditorWindowNew.ShowWindow(); } - - /// - /// Open legacy MCP Client Configuration window - /// - [MenuItem("Window/MCP For Unity/Open Legacy MCP Window", priority = 5)] - public static void OpenLegacyClientConfiguration() - { - Windows.MCPForUnityEditorWindow.ShowWindow(); - } } } From eddfafac962fa24252fda409d510d74f7ea94c45 Mon Sep 17 00:00:00 2001 From: Marcus Sanatan Date: Wed, 22 Oct 2025 21:55:57 -0400 Subject: [PATCH 02/30] Remove old UI screen Users now have the new UI alone, less confusing and more predictable --- MCPForUnity/Editor/Setup/SetupWizard.cs | 2 +- .../Editor/Windows/MCPForUnityEditorWindow.cs | 1993 +++++------------ .../Windows/MCPForUnityEditorWindow.cs.meta | 8 +- ...dowNew.uss => MCPForUnityEditorWindow.uss} | 0 ....meta => MCPForUnityEditorWindow.uss.meta} | 0 ...wNew.uxml => MCPForUnityEditorWindow.uxml} | 0 ...meta => MCPForUnityEditorWindow.uxml.meta} | 0 .../Windows/MCPForUnityEditorWindowNew.cs | 860 ------- .../MCPForUnityEditorWindowNew.cs.meta | 11 - .../Windows/ManualConfigEditorWindow.cs | 303 --- .../Windows/ManualConfigEditorWindow.cs.meta | 11 - .../Editor/Windows/VSCodeManualSetupWindow.cs | 291 --- .../Windows/VSCodeManualSetupWindow.cs.meta | 11 - 13 files changed, 597 insertions(+), 2893 deletions(-) rename MCPForUnity/Editor/Windows/{MCPForUnityEditorWindowNew.uss => MCPForUnityEditorWindow.uss} (100%) rename MCPForUnity/Editor/Windows/{MCPForUnityEditorWindowNew.uss.meta => MCPForUnityEditorWindow.uss.meta} (100%) rename MCPForUnity/Editor/Windows/{MCPForUnityEditorWindowNew.uxml => MCPForUnityEditorWindow.uxml} (100%) rename MCPForUnity/Editor/Windows/{MCPForUnityEditorWindowNew.uxml.meta => MCPForUnityEditorWindow.uxml.meta} (100%) delete mode 100644 MCPForUnity/Editor/Windows/MCPForUnityEditorWindowNew.cs delete mode 100644 MCPForUnity/Editor/Windows/MCPForUnityEditorWindowNew.cs.meta delete mode 100644 MCPForUnity/Editor/Windows/ManualConfigEditorWindow.cs delete mode 100644 MCPForUnity/Editor/Windows/ManualConfigEditorWindow.cs.meta delete mode 100644 MCPForUnity/Editor/Windows/VSCodeManualSetupWindow.cs delete mode 100644 MCPForUnity/Editor/Windows/VSCodeManualSetupWindow.cs.meta diff --git a/MCPForUnity/Editor/Setup/SetupWizard.cs b/MCPForUnity/Editor/Setup/SetupWizard.cs index f9fe1ee3..3ac2d063 100644 --- a/MCPForUnity/Editor/Setup/SetupWizard.cs +++ b/MCPForUnity/Editor/Setup/SetupWizard.cs @@ -144,7 +144,7 @@ public static void CheckDependencies() [MenuItem("Window/MCP For Unity/Open MCP Window %#m", priority = 3)] public static void OpenClientConfiguration() { - Windows.MCPForUnityEditorWindowNew.ShowWindow(); + Windows.MCPForUnityEditorWindow.ShowWindow(); } } } diff --git a/MCPForUnity/Editor/Windows/MCPForUnityEditorWindow.cs b/MCPForUnity/Editor/Windows/MCPForUnityEditorWindow.cs index fdbfcbb5..017df843 100644 --- a/MCPForUnity/Editor/Windows/MCPForUnityEditorWindow.cs +++ b/MCPForUnity/Editor/Windows/MCPForUnityEditorWindow.cs @@ -1,1669 +1,860 @@ using System; -using System.Collections.Generic; using System.Diagnostics; -using System.Security.Cryptography; -using System.Text; -using System.Net.Sockets; -using System.Net; using System.IO; using System.Linq; using System.Runtime.InteropServices; -using Newtonsoft.Json; -using Newtonsoft.Json.Linq; using UnityEditor; +using UnityEditor.UIElements; // For Unity 2021 compatibility using UnityEngine; +using UnityEngine.UIElements; using MCPForUnity.Editor.Data; using MCPForUnity.Editor.Helpers; using MCPForUnity.Editor.Models; +using MCPForUnity.Editor.Services; namespace MCPForUnity.Editor.Windows { public class MCPForUnityEditorWindow : EditorWindow { - private bool isUnityBridgeRunning = false; - private Vector2 scrollPosition; - private string pythonServerInstallationStatus = "Not Installed"; - private Color pythonServerInstallationStatusColor = Color.red; - private const int mcpPort = 6500; // MCP port (still hardcoded for MCP server) + // Protocol enum for future HTTP support + private enum ConnectionProtocol + { + Stdio, + // HTTPStreaming // Future + } + + // Settings UI Elements + private Label versionLabel; + private Toggle debugLogsToggle; + private EnumField validationLevelField; + private Label validationDescription; + private Foldout advancedSettingsFoldout; + private TextField mcpServerPathOverride; + private TextField uvPathOverride; + private Button browsePythonButton; + private Button clearPythonButton; + private Button browseUvButton; + private Button clearUvButton; + private VisualElement mcpServerPathStatus; + private VisualElement uvPathStatus; + + // Connection UI Elements + private EnumField protocolDropdown; + private TextField unityPortField; + private TextField serverPortField; + private VisualElement statusIndicator; + private Label connectionStatusLabel; + private Button connectionToggleButton; + private VisualElement healthIndicator; + private Label healthStatusLabel; + private Button testConnectionButton; + private VisualElement serverStatusBanner; + private Label serverStatusMessage; + private Button downloadServerButton; + private Button rebuildServerButton; + + // Client UI Elements + private DropdownField clientDropdown; + private Button configureAllButton; + private VisualElement clientStatusIndicator; + private Label clientStatusLabel; + private Button configureButton; + private VisualElement claudeCliPathRow; + private TextField claudeCliPath; + private Button browseClaudeButton; + private Foldout manualConfigFoldout; + private TextField configPathField; + private Button copyPathButton; + private Button openFileButton; + private TextField configJsonField; + private Button copyJsonButton; + private Label installationStepsLabel; + + // Data private readonly McpClients mcpClients = new(); - private bool autoRegisterEnabled; - private bool lastClientRegisteredOk; - private bool lastBridgeVerifiedOk; - private string pythonDirOverride = null; - private bool debugLogsEnabled; - - // Script validation settings - private int validationLevelIndex = 1; // Default to Standard - private readonly string[] validationLevelOptions = new string[] - { - "Basic - Only syntax checks", - "Standard - Syntax + Unity practices", - "Comprehensive - All checks + semantic analysis", - "Strict - Full semantic validation (requires Roslyn)" - }; - - // UI state private int selectedClientIndex = 0; + private ValidationLevel currentValidationLevel = ValidationLevel.Standard; - public static void ShowWindow() + // Validation levels matching the existing enum + private enum ValidationLevel { - GetWindow("MCP For Unity"); + Basic, + Standard, + Comprehensive, + Strict } - private void OnEnable() + public static void ShowWindow() + { + var window = GetWindow("MCP For Unity"); + window.minSize = new Vector2(500, 600); + } + public void CreateGUI() { - UpdatePythonServerInstallationStatus(); + // Determine base path (Package Manager vs Asset Store install) + string basePath = AssetPathUtility.GetMcpPackageRootPath(); - // Refresh bridge status - isUnityBridgeRunning = MCPForUnityBridge.IsRunning; - autoRegisterEnabled = EditorPrefs.GetBool("MCPForUnity.AutoRegisterEnabled", true); - debugLogsEnabled = EditorPrefs.GetBool("MCPForUnity.DebugLogs", false); - if (debugLogsEnabled) - { - LogDebugPrefsState(); - } - foreach (McpClient mcpClient in mcpClients.clients) + // Load UXML + var visualTree = AssetDatabase.LoadAssetAtPath( + $"{basePath}/Editor/Windows/MCPForUnityEditorWindow.uxml" + ); + + if (visualTree == null) { - CheckMcpConfiguration(mcpClient); + McpLog.Error($"Failed to load UXML at: {basePath}/Editor/Windows/MCPForUnityEditorWindow.uxml"); + return; } - // Load validation level setting - LoadValidationLevelSetting(); + visualTree.CloneTree(rootVisualElement); - // First-run auto-setup only if Claude CLI is available - if (autoRegisterEnabled && !string.IsNullOrEmpty(ExecPath.ResolveClaude())) - { - AutoFirstRunSetup(); - } - } + // Load USS + var styleSheet = AssetDatabase.LoadAssetAtPath( + $"{basePath}/Editor/Windows/MCPForUnityEditorWindow.uss" + ); - private void OnFocus() - { - // Refresh bridge running state on focus in case initialization completed after domain reload - isUnityBridgeRunning = MCPForUnityBridge.IsRunning; - if (mcpClients.clients.Count > 0 && selectedClientIndex < mcpClients.clients.Count) + if (styleSheet != null) { - McpClient selectedClient = mcpClients.clients[selectedClientIndex]; - CheckMcpConfiguration(selectedClient); + rootVisualElement.styleSheets.Add(styleSheet); } - Repaint(); + + // Cache UI elements + CacheUIElements(); + + // Initialize UI + InitializeUI(); + + // Register callbacks + RegisterCallbacks(); + + // Initial update + UpdateConnectionStatus(); + UpdateServerStatusBanner(); + UpdateClientStatus(); + UpdatePathOverrides(); + // Technically not required to connect, but if we don't do this, the UI will be blank + UpdateManualConfiguration(); + UpdateClaudeCliPathVisibility(); } - private Color GetStatusColor(McpStatus status) + private void OnEnable() { - // Return appropriate color based on the status enum - return status switch - { - McpStatus.Configured => Color.green, - McpStatus.Running => Color.green, - McpStatus.Connected => Color.green, - McpStatus.IncorrectPath => Color.yellow, - McpStatus.CommunicationError => Color.yellow, - McpStatus.NoResponse => Color.yellow, - _ => Color.red, // Default to red for error states or not configured - }; + EditorApplication.update += OnEditorUpdate; } - private void UpdatePythonServerInstallationStatus() + private void OnDisable() { - try - { - string installedPath = ServerInstaller.GetServerPath(); - bool installedOk = !string.IsNullOrEmpty(installedPath) && File.Exists(Path.Combine(installedPath, "server.py")); - if (installedOk) - { - pythonServerInstallationStatus = "Installed"; - pythonServerInstallationStatusColor = Color.green; - return; - } - - // Fall back to embedded/dev source via our existing resolution logic - string embeddedPath = FindPackagePythonDirectory(); - bool embeddedOk = !string.IsNullOrEmpty(embeddedPath) && File.Exists(Path.Combine(embeddedPath, "server.py")); - if (embeddedOk) - { - pythonServerInstallationStatus = "Installed (Embedded)"; - pythonServerInstallationStatusColor = Color.green; - } - else - { - pythonServerInstallationStatus = "Not Installed"; - pythonServerInstallationStatusColor = Color.red; - } - } - catch - { - pythonServerInstallationStatus = "Not Installed"; - pythonServerInstallationStatusColor = Color.red; - } + EditorApplication.update -= OnEditorUpdate; } - - private void DrawStatusDot(Rect statusRect, Color statusColor, float size = 12) + private void OnFocus() { - float offsetX = (statusRect.width - size) / 2; - float offsetY = (statusRect.height - size) / 2; - Rect dotRect = new(statusRect.x + offsetX, statusRect.y + offsetY, size, size); - Vector3 center = new( - dotRect.x + (dotRect.width / 2), - dotRect.y + (dotRect.height / 2), - 0 - ); - float radius = size / 2; - - // Draw the main dot - Handles.color = statusColor; - Handles.DrawSolidDisc(center, Vector3.forward, radius); + // Only refresh data if UI is built + if (rootVisualElement == null || rootVisualElement.childCount == 0) + return; - // Draw the border - Color borderColor = new( - statusColor.r * 0.7f, - statusColor.g * 0.7f, - statusColor.b * 0.7f - ); - Handles.color = borderColor; - Handles.DrawWireDisc(center, Vector3.forward, radius); + RefreshAllData(); } - private void OnGUI() + private void OnEditorUpdate() { - scrollPosition = EditorGUILayout.BeginScrollView(scrollPosition); - - // Header - DrawHeader(); - - // Compute equal column widths for uniform layout - float horizontalSpacing = 2f; - float outerPadding = 20f; // approximate padding - // Make columns a bit less wide for a tighter layout - float computed = (position.width - outerPadding - horizontalSpacing) / 2f; - float colWidth = Mathf.Clamp(computed, 220f, 340f); - // Use fixed heights per row so paired panels match exactly - float topPanelHeight = 190f; - float bottomPanelHeight = 230f; - - // Top row: Server Status (left) and Unity Bridge (right) - EditorGUILayout.BeginHorizontal(); - { - EditorGUILayout.BeginVertical(GUILayout.Width(colWidth), GUILayout.Height(topPanelHeight)); - DrawServerStatusSection(); - EditorGUILayout.EndVertical(); + // Only update UI if it's built + if (rootVisualElement == null || rootVisualElement.childCount == 0) + return; - EditorGUILayout.Space(horizontalSpacing); + UpdateConnectionStatus(); + } + + private void RefreshAllData() + { + // Update connection status + UpdateConnectionStatus(); - EditorGUILayout.BeginVertical(GUILayout.Width(colWidth), GUILayout.Height(topPanelHeight)); - DrawBridgeSection(); - EditorGUILayout.EndVertical(); + // Auto-verify bridge health if connected + if (MCPServiceLocator.Bridge.IsRunning) + { + VerifyBridgeConnection(); } - EditorGUILayout.EndHorizontal(); - EditorGUILayout.Space(10); + // Update path overrides + UpdatePathOverrides(); - // Second row: MCP Client Configuration (left) and Script Validation (right) - EditorGUILayout.BeginHorizontal(); + // Refresh selected client (may have been configured externally) + if (selectedClientIndex >= 0 && selectedClientIndex < mcpClients.clients.Count) { - EditorGUILayout.BeginVertical(GUILayout.Width(colWidth), GUILayout.Height(bottomPanelHeight)); - DrawUnifiedClientConfiguration(); - EditorGUILayout.EndVertical(); - - EditorGUILayout.Space(horizontalSpacing); - - EditorGUILayout.BeginVertical(GUILayout.Width(colWidth), GUILayout.Height(bottomPanelHeight)); - DrawValidationSection(); - EditorGUILayout.EndVertical(); + var client = mcpClients.clients[selectedClientIndex]; + MCPServiceLocator.Client.CheckClientStatus(client); + UpdateClientStatus(); + UpdateManualConfiguration(); + UpdateClaudeCliPathVisibility(); } - EditorGUILayout.EndHorizontal(); + } - // Minimal bottom padding - EditorGUILayout.Space(2); + private void CacheUIElements() + { + // Settings + versionLabel = rootVisualElement.Q