diff --git a/MCPForUnity/Editor/Clients/IMcpClientConfigurator.cs b/MCPForUnity/Editor/Clients/IMcpClientConfigurator.cs index 02bc41e72..9fdea29c8 100644 --- a/MCPForUnity/Editor/Clients/IMcpClientConfigurator.cs +++ b/MCPForUnity/Editor/Clients/IMcpClientConfigurator.cs @@ -17,6 +17,12 @@ public interface IMcpClientConfigurator /// Current status cached by the configurator. McpStatus Status { get; } + /// + /// The transport type the client is currently configured for. + /// Returns Unknown if the client is not configured or the transport cannot be determined. + /// + ConfiguredTransport ConfiguredTransport { get; } + /// True if this client supports auto-configure. bool SupportsAutoConfigure { get; } diff --git a/MCPForUnity/Editor/Clients/McpClientConfiguratorBase.cs b/MCPForUnity/Editor/Clients/McpClientConfiguratorBase.cs index 897e7dfd8..00e440cc1 100644 --- a/MCPForUnity/Editor/Clients/McpClientConfiguratorBase.cs +++ b/MCPForUnity/Editor/Clients/McpClientConfiguratorBase.cs @@ -28,6 +28,7 @@ protected McpClientConfiguratorBase(McpClient client) public string Id => client.name.Replace(" ", "").ToLowerInvariant(); public virtual string DisplayName => client.name; public McpStatus Status => client.status; + public ConfiguredTransport ConfiguredTransport => client.configuredTransport; public virtual bool SupportsAutoConfigure => true; public virtual string GetConfigureActionLabel() => "Configure"; @@ -94,6 +95,7 @@ public override McpStatus CheckStatus(bool attemptAutoRewrite = true) if (!File.Exists(path)) { client.SetStatus(McpStatus.NotConfigured); + client.configuredTransport = Models.ConfiguredTransport.Unknown; return client.status; } @@ -135,6 +137,7 @@ public override McpStatus CheckStatus(bool attemptAutoRewrite = true) if (standardConfig?.mcpServers?.unityMCP != null) { args = standardConfig.mcpServers.unityMCP.args; + configuredUrl = standardConfig.mcpServers.unityMCP.url; configExists = true; } } @@ -142,9 +145,24 @@ public override McpStatus CheckStatus(bool attemptAutoRewrite = true) if (!configExists) { client.SetStatus(McpStatus.MissingConfig); + client.configuredTransport = Models.ConfiguredTransport.Unknown; return client.status; } + // Determine and set the configured transport type + if (args != null && args.Length > 0) + { + client.configuredTransport = Models.ConfiguredTransport.Stdio; + } + else if (!string.IsNullOrEmpty(configuredUrl)) + { + client.configuredTransport = Models.ConfiguredTransport.Http; + } + else + { + client.configuredTransport = Models.ConfiguredTransport.Unknown; + } + bool matches = false; if (args != null && args.Length > 0) { @@ -171,6 +189,9 @@ public override McpStatus CheckStatus(bool attemptAutoRewrite = true) if (result == "Configured successfully") { client.SetStatus(McpStatus.Configured); + // Update transport after rewrite based on current server setting + bool useHttp = EditorPrefs.GetBool(EditorPrefKeys.UseHttpTransport, true); + client.configuredTransport = useHttp ? Models.ConfiguredTransport.Http : Models.ConfiguredTransport.Stdio; } else { @@ -185,6 +206,7 @@ public override McpStatus CheckStatus(bool attemptAutoRewrite = true) catch (Exception ex) { client.SetStatus(McpStatus.Error, ex.Message); + client.configuredTransport = Models.ConfiguredTransport.Unknown; } return client.status; @@ -198,6 +220,9 @@ public override void Configure() if (result == "Configured successfully") { client.SetStatus(McpStatus.Configured); + // Set transport based on current server setting + bool useHttp = EditorPrefs.GetBool(EditorPrefKeys.UseHttpTransport, true); + client.configuredTransport = useHttp ? Models.ConfiguredTransport.Http : Models.ConfiguredTransport.Stdio; } else { @@ -237,12 +262,27 @@ public override McpStatus CheckStatus(bool attemptAutoRewrite = true) if (!File.Exists(path)) { client.SetStatus(McpStatus.NotConfigured); + client.configuredTransport = Models.ConfiguredTransport.Unknown; return client.status; } string toml = File.ReadAllText(path); if (CodexConfigHelper.TryParseCodexServer(toml, out _, out var args, out var url)) { + // Determine and set the configured transport type + if (!string.IsNullOrEmpty(url)) + { + client.configuredTransport = Models.ConfiguredTransport.Http; + } + else if (args != null && args.Length > 0) + { + client.configuredTransport = Models.ConfiguredTransport.Stdio; + } + else + { + client.configuredTransport = Models.ConfiguredTransport.Unknown; + } + bool matches = false; if (!string.IsNullOrEmpty(url)) { @@ -262,6 +302,10 @@ public override McpStatus CheckStatus(bool attemptAutoRewrite = true) return client.status; } } + else + { + client.configuredTransport = Models.ConfiguredTransport.Unknown; + } if (attemptAutoRewrite) { @@ -269,6 +313,9 @@ public override McpStatus CheckStatus(bool attemptAutoRewrite = true) if (result == "Configured successfully") { client.SetStatus(McpStatus.Configured); + // Update transport after rewrite based on current server setting + bool useHttp = EditorPrefs.GetBool(EditorPrefKeys.UseHttpTransport, true); + client.configuredTransport = useHttp ? Models.ConfiguredTransport.Http : Models.ConfiguredTransport.Stdio; } else { @@ -283,6 +330,7 @@ public override McpStatus CheckStatus(bool attemptAutoRewrite = true) catch (Exception ex) { client.SetStatus(McpStatus.Error, ex.Message); + client.configuredTransport = Models.ConfiguredTransport.Unknown; } return client.status; @@ -296,6 +344,9 @@ public override void Configure() if (result == "Configured successfully") { client.SetStatus(McpStatus.Configured); + // Set transport based on current server setting + bool useHttp = EditorPrefs.GetBool(EditorPrefKeys.UseHttpTransport, true); + client.configuredTransport = useHttp ? Models.ConfiguredTransport.Http : Models.ConfiguredTransport.Stdio; } else { @@ -363,6 +414,7 @@ internal McpStatus CheckStatusWithProjectDir(string projectDir, bool useHttpTran if (string.IsNullOrEmpty(claudePath)) { client.SetStatus(McpStatus.NotConfigured, "Claude CLI not found"); + client.configuredTransport = Models.ConfiguredTransport.Unknown; return client.status; } @@ -415,6 +467,20 @@ internal McpStatus CheckStatusWithProjectDir(string projectDir, bool useHttpTran bool registeredWithHttp = getStdout.Contains("Type: http", StringComparison.OrdinalIgnoreCase); bool registeredWithStdio = getStdout.Contains("Type: stdio", StringComparison.OrdinalIgnoreCase); + // Set the configured transport based on what we detected + if (registeredWithHttp) + { + client.configuredTransport = Models.ConfiguredTransport.Http; + } + else if (registeredWithStdio) + { + client.configuredTransport = Models.ConfiguredTransport.Stdio; + } + else + { + client.configuredTransport = Models.ConfiguredTransport.Unknown; + } + // Check for transport mismatch bool hasTransportMismatch = (currentUseHttp && registeredWithStdio) || (!currentUseHttp && registeredWithHttp); @@ -479,10 +545,12 @@ internal McpStatus CheckStatusWithProjectDir(string projectDir, bool useHttpTran } client.SetStatus(McpStatus.NotConfigured); + client.configuredTransport = Models.ConfiguredTransport.Unknown; } catch (Exception ex) { client.SetStatus(McpStatus.Error, ex.Message); + client.configuredTransport = Models.ConfiguredTransport.Unknown; } return client.status; @@ -558,6 +626,7 @@ private void RegisterWithCapturedValues( McpLog.Info($"Successfully registered with Claude Code using {(useHttpTransport ? "HTTP" : "stdio")} transport."); client.SetStatus(McpStatus.Configured); + client.configuredTransport = useHttpTransport ? Models.ConfiguredTransport.Http : Models.ConfiguredTransport.Stdio; } /// @@ -577,6 +646,7 @@ private void UnregisterWithCapturedValues(string projectDir, string claudePath, McpLog.Info("MCP server successfully unregistered from Claude Code."); client.SetStatus(McpStatus.NotConfigured); + client.configuredTransport = Models.ConfiguredTransport.Unknown; } private void Register() @@ -645,6 +715,7 @@ private void Register() // Set status to Configured immediately after successful registration // The UI will trigger an async verification check separately to avoid blocking client.SetStatus(McpStatus.Configured); + client.configuredTransport = useHttpTransport ? Models.ConfiguredTransport.Http : Models.ConfiguredTransport.Stdio; } private void Unregister() @@ -675,6 +746,7 @@ private void Unregister() McpLog.Info("MCP server successfully unregistered from Claude Code."); client.SetStatus(McpStatus.NotConfigured); + client.configuredTransport = Models.ConfiguredTransport.Unknown; } public override string GetManualSnippet() diff --git a/MCPForUnity/Editor/Constants/HealthStatus.cs b/MCPForUnity/Editor/Constants/HealthStatus.cs new file mode 100644 index 000000000..7506caaae --- /dev/null +++ b/MCPForUnity/Editor/Constants/HealthStatus.cs @@ -0,0 +1,14 @@ +namespace MCPForUnity.Editor.Constants +{ + /// + /// Constants for health check status values. + /// Used for coordinating health state between Connection and Advanced sections. + /// + public static class HealthStatus + { + public const string Unknown = "Unknown"; + public const string Healthy = "Healthy"; + public const string PingFailed = "Ping Failed"; + public const string Unhealthy = "Unhealthy"; + } +} diff --git a/MCPForUnity/Editor/Windows/Components/Settings/McpSettingsSection.cs.meta b/MCPForUnity/Editor/Constants/HealthStatus.cs.meta similarity index 83% rename from MCPForUnity/Editor/Windows/Components/Settings/McpSettingsSection.cs.meta rename to MCPForUnity/Editor/Constants/HealthStatus.cs.meta index 3056afc90..a08698caf 100644 --- a/MCPForUnity/Editor/Windows/Components/Settings/McpSettingsSection.cs.meta +++ b/MCPForUnity/Editor/Constants/HealthStatus.cs.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: b945a3de2cb2683448d686c0f3174faa +guid: c15ed2426f43860479f1b8a99a343d16 MonoImporter: externalObjects: {} serializedVersion: 2 diff --git a/MCPForUnity/Editor/Helpers/GameObjectLookup.cs b/MCPForUnity/Editor/Helpers/GameObjectLookup.cs index 60d2b0967..bd23bbd7a 100644 --- a/MCPForUnity/Editor/Helpers/GameObjectLookup.cs +++ b/MCPForUnity/Editor/Helpers/GameObjectLookup.cs @@ -69,7 +69,9 @@ public static GameObject FindByTarget(JToken target, string searchMethod, bool i /// public static GameObject FindById(int instanceId) { +#pragma warning disable CS0618 // Type or member is obsolete return EditorUtility.InstanceIDToObject(instanceId) as GameObject; +#pragma warning restore CS0618 } /// @@ -103,7 +105,9 @@ public static List SearchGameObjects(SearchMethod method, string searchTerm case SearchMethod.ById: if (int.TryParse(searchTerm, out int instanceId)) { +#pragma warning disable CS0618 // Type or member is obsolete var obj = EditorUtility.InstanceIDToObject(instanceId) as GameObject; +#pragma warning restore CS0618 if (obj != null && (includeInactive || obj.activeInHierarchy)) { results.Add(instanceId); diff --git a/MCPForUnity/Editor/Models/MCPConfigServer.cs b/MCPForUnity/Editor/Models/MCPConfigServer.cs index fbffed371..25f1163d8 100644 --- a/MCPForUnity/Editor/Models/MCPConfigServer.cs +++ b/MCPForUnity/Editor/Models/MCPConfigServer.cs @@ -15,5 +15,9 @@ public class McpConfigServer // VSCode expects a transport type; include only when explicitly set [JsonProperty("type", NullValueHandling = NullValueHandling.Ignore)] public string type; + + // URL for HTTP transport mode + [JsonProperty("url", NullValueHandling = NullValueHandling.Ignore)] + public string url; } } diff --git a/MCPForUnity/Editor/Models/McpClient.cs b/MCPForUnity/Editor/Models/McpClient.cs index f09352a0d..8cb9e724c 100644 --- a/MCPForUnity/Editor/Models/McpClient.cs +++ b/MCPForUnity/Editor/Models/McpClient.cs @@ -10,6 +10,7 @@ public class McpClient public string linuxConfigPath; public string configStatus; public McpStatus status = McpStatus.NotConfigured; + public ConfiguredTransport configuredTransport = ConfiguredTransport.Unknown; // Capability flags/config for JSON-based configurators public bool IsVsCodeLayout; // Whether the config file follows VS Code layout (env object at root) diff --git a/MCPForUnity/Editor/Models/McpStatus.cs b/MCPForUnity/Editor/Models/McpStatus.cs index d041667dd..4fb84265e 100644 --- a/MCPForUnity/Editor/Models/McpStatus.cs +++ b/MCPForUnity/Editor/Models/McpStatus.cs @@ -14,5 +14,16 @@ public enum McpStatus UnsupportedOS, // OS is not supported Error, // General error state } + + /// + /// Represents the transport type a client is configured to use. + /// Used to detect mismatches between server and client transport settings. + /// + public enum ConfiguredTransport + { + Unknown, // Could not determine transport type + Stdio, // Client configured for stdio transport + Http // Client configured for HTTP transport + } } diff --git a/MCPForUnity/Editor/Windows/Components/Settings.meta b/MCPForUnity/Editor/Windows/Components/Advanced.meta similarity index 77% rename from MCPForUnity/Editor/Windows/Components/Settings.meta rename to MCPForUnity/Editor/Windows/Components/Advanced.meta index e9fe9b850..9c3d02468 100644 --- a/MCPForUnity/Editor/Windows/Components/Settings.meta +++ b/MCPForUnity/Editor/Windows/Components/Advanced.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: 3e753cf64be77814d8074be7a9451338 +guid: 7723ed5eaaccb104e93acb9fd2d8cd32 folderAsset: yes DefaultImporter: externalObjects: {} diff --git a/MCPForUnity/Editor/Windows/Components/Settings/McpSettingsSection.cs b/MCPForUnity/Editor/Windows/Components/Advanced/McpAdvancedSection.cs similarity index 76% rename from MCPForUnity/Editor/Windows/Components/Settings/McpSettingsSection.cs rename to MCPForUnity/Editor/Windows/Components/Advanced/McpAdvancedSection.cs index e4f07db45..26f610167 100644 --- a/MCPForUnity/Editor/Windows/Components/Settings/McpSettingsSection.cs +++ b/MCPForUnity/Editor/Windows/Components/Advanced/McpAdvancedSection.cs @@ -5,24 +5,18 @@ using MCPForUnity.Editor.Helpers; using MCPForUnity.Editor.Services; using UnityEditor; -using UnityEditor.UIElements; using UnityEngine; using UnityEngine.UIElements; -namespace MCPForUnity.Editor.Windows.Components.Settings +namespace MCPForUnity.Editor.Windows.Components.Advanced { /// - /// Controller for the Settings section of the MCP For Unity editor window. - /// Handles version display, debug logs, validation level, and advanced path overrides. + /// Controller for the Advanced Settings section. + /// Handles path overrides, server source configuration, dev mode, and package deployment. /// - public class McpSettingsSection + public class McpAdvancedSection { // UI Elements - private Label versionLabel; - private Toggle debugLogsToggle; - private EnumField validationLevelField; - private Label validationDescription; - private Foldout advancedSettingsFoldout; private TextField uvxPathOverride; private Button browseUvxButton; private Button clearUvxButton; @@ -30,6 +24,7 @@ public class McpSettingsSection private TextField gitUrlOverride; private Button browseGitUrlButton; private Button clearGitUrlButton; + private Toggle debugLogsToggle; private Toggle devModeForceRefreshToggle; private TextField deploySourcePath; private Button browseDeploySourceButton; @@ -39,26 +34,18 @@ public class McpSettingsSection private Label deployTargetLabel; private Label deployBackupLabel; private Label deployStatusLabel; - - // Data - private ValidationLevel currentValidationLevel = ValidationLevel.Standard; + private VisualElement healthIndicator; + private Label healthStatus; + private Button testConnectionButton; // Events public event Action OnGitUrlChanged; public event Action OnHttpServerCommandUpdateRequested; - - // Validation levels - private enum ValidationLevel - { - Basic, - Standard, - Comprehensive, - Strict - } + public event Action OnTestConnectionRequested; public VisualElement Root { get; private set; } - public McpSettingsSection(VisualElement root) + public McpAdvancedSection(VisualElement root) { Root = root; CacheUIElements(); @@ -68,11 +55,6 @@ public McpSettingsSection(VisualElement root) private void CacheUIElements() { - versionLabel = Root.Q