From cba0933d336c75414a651e734aaeb96c7be6130c Mon Sep 17 00:00:00 2001 From: dsarno Date: Thu, 8 Jan 2026 07:14:44 -0800 Subject: [PATCH] Fixes Windows installation failures caused by long path issues when cloning the full repository via git URL (MAX_PATH 260 char limit exceeded by files in TestProjects/). (#534) * fix: use PyPI as default server source instead of git URL Fixes Windows installation failures caused by long path issues when cloning the full repository (MAX_PATH 260 char limit exceeded). - Change default from git+https://github.com/CoplayDev/unity-mcp to mcpforunityserver=={version} PyPI package - Rename GetMcpServerGitUrl() to GetMcpServerPackageSource() - Keep deprecated wrapper for backwards compatibility - Update UI help text to show local dev override example only - Update tests to expect PyPI package reference * fix: use forward slashes in deployment path display Fixes UI rendering issue where backslashes in Windows paths were interpreted as escape sequences (e.g. \U, \u showing as boxes). Convert backslashes to forward slashes for display in: - Target path label - Backup path label --- .../Clients/McpClientConfiguratorBase.cs | 8 ++-- .../Editor/Helpers/AssetPathUtility.cs | 38 +++++++++++-------- .../Services/PackageDeploymentService.cs | 7 ++-- .../Components/Settings/McpSettingsSection.cs | 3 +- .../Settings/McpSettingsSection.uxml | 5 +-- .../Helpers/CodexConfigHelperTests.cs | 8 ++-- 6 files changed, 39 insertions(+), 30 deletions(-) diff --git a/MCPForUnity/Editor/Clients/McpClientConfiguratorBase.cs b/MCPForUnity/Editor/Clients/McpClientConfiguratorBase.cs index c0ab869..ed8d6a6 100644 --- a/MCPForUnity/Editor/Clients/McpClientConfiguratorBase.cs +++ b/MCPForUnity/Editor/Clients/McpClientConfiguratorBase.cs @@ -148,7 +148,7 @@ namespace MCPForUnity.Editor.Clients bool matches = false; if (args != null && args.Length > 0) { - string expectedUvxUrl = AssetPathUtility.GetMcpServerGitUrl(); + string expectedUvxUrl = AssetPathUtility.GetMcpServerPackageSource(); string configuredUvxUrl = McpConfigurationHelper.ExtractUvxUrl(args); matches = !string.IsNullOrEmpty(configuredUvxUrl) && McpConfigurationHelper.PathsEqual(configuredUvxUrl, expectedUvxUrl); @@ -250,7 +250,7 @@ namespace MCPForUnity.Editor.Clients } else if (args != null && args.Length > 0) { - string expected = AssetPathUtility.GetMcpServerGitUrl(); + string expected = AssetPathUtility.GetMcpServerPackageSource(); string configured = McpConfigurationHelper.ExtractUvxUrl(args); matches = !string.IsNullOrEmpty(configured) && McpConfigurationHelper.PathsEqual(configured, expected); @@ -585,12 +585,12 @@ namespace MCPForUnity.Editor.Clients return "# Error: Configuration not available - check paths in Advanced Settings"; } - string gitUrl = AssetPathUtility.GetMcpServerGitUrl(); + string packageSource = AssetPathUtility.GetMcpServerPackageSource(); // Use central helper that checks both DevModeForceServerRefresh AND local path detection. string devFlags = AssetPathUtility.ShouldForceUvxRefresh() ? "--no-cache --refresh " : string.Empty; return "# Register the MCP server with Claude Code:\n" + - $"claude mcp add --transport stdio UnityMCP -- \"{uvxPath}\" {devFlags}--from \"{gitUrl}\" mcp-for-unity\n\n" + + $"claude mcp add --transport stdio UnityMCP -- \"{uvxPath}\" {devFlags}--from \"{packageSource}\" mcp-for-unity\n\n" + "# Unregister the MCP server:\n" + "claude mcp remove UnityMCP\n\n" + "# List registered servers:\n" + diff --git a/MCPForUnity/Editor/Helpers/AssetPathUtility.cs b/MCPForUnity/Editor/Helpers/AssetPathUtility.cs index f7a6b47..34c9ea4 100644 --- a/MCPForUnity/Editor/Helpers/AssetPathUtility.cs +++ b/MCPForUnity/Editor/Helpers/AssetPathUtility.cs @@ -149,30 +149,38 @@ namespace MCPForUnity.Editor.Helpers } /// - /// Gets just the git URL part for the MCP server package - /// Checks for EditorPrefs override first, then falls back to package version + /// Gets the package source for the MCP server (used with uvx --from). + /// Checks for EditorPrefs override first (supports git URLs, file:// paths, etc.), + /// then falls back to PyPI package reference. /// - /// Git URL string, or empty string if version is unknown and no override - public static string GetMcpServerGitUrl() + /// Package source string for uvx --from argument + public static string GetMcpServerPackageSource() { - // Check for Git URL override first - string gitUrlOverride = EditorPrefs.GetString(EditorPrefKeys.GitUrlOverride, ""); - if (!string.IsNullOrEmpty(gitUrlOverride)) + // Check for override first (supports git URLs, file:// paths, local paths) + string sourceOverride = EditorPrefs.GetString(EditorPrefKeys.GitUrlOverride, ""); + if (!string.IsNullOrEmpty(sourceOverride)) { - return gitUrlOverride; + return sourceOverride; } - // Fall back to default package version + // Default to PyPI package (avoids Windows long path issues with git clone) string version = GetPackageVersion(); if (version == "unknown") { - // Fall back to main repo without pinned version so configs remain valid in test scenarios - return "git+https://github.com/CoplayDev/unity-mcp#subdirectory=Server"; + // Fall back to latest PyPI version so configs remain valid in test scenarios + return "mcpforunityserver"; } - return $"git+https://github.com/CoplayDev/unity-mcp@v{version}#subdirectory=Server"; + return $"mcpforunityserver=={version}"; } + /// + /// Deprecated: Use GetMcpServerPackageSource() instead. + /// Kept for backwards compatibility. + /// + [System.Obsolete("Use GetMcpServerPackageSource() instead")] + public static string GetMcpServerGitUrl() => GetMcpServerPackageSource(); + /// /// Gets structured uvx command parts for different client configurations /// @@ -180,7 +188,7 @@ namespace MCPForUnity.Editor.Helpers public static (string uvxPath, string fromUrl, string packageName) GetUvxCommandParts() { string uvxPath = MCPServiceLocator.Paths.GetUvxPath(); - string fromUrl = GetMcpServerGitUrl(); + string fromUrl = GetMcpServerPackageSource(); string packageName = "mcp-for-unity"; return (uvxPath, fromUrl, packageName); @@ -208,7 +216,7 @@ namespace MCPForUnity.Editor.Helpers /// public static bool IsLocalServerPath() { - string fromUrl = GetMcpServerGitUrl(); + string fromUrl = GetMcpServerPackageSource(); if (string.IsNullOrEmpty(fromUrl)) return false; @@ -226,7 +234,7 @@ namespace MCPForUnity.Editor.Helpers if (!IsLocalServerPath()) return null; - string fromUrl = GetMcpServerGitUrl(); + string fromUrl = GetMcpServerPackageSource(); if (fromUrl.StartsWith("file://", StringComparison.OrdinalIgnoreCase)) { // Strip file:// prefix diff --git a/MCPForUnity/Editor/Services/PackageDeploymentService.cs b/MCPForUnity/Editor/Services/PackageDeploymentService.cs index 3024ded..7c0e27c 100644 --- a/MCPForUnity/Editor/Services/PackageDeploymentService.cs +++ b/MCPForUnity/Editor/Services/PackageDeploymentService.cs @@ -69,9 +69,10 @@ namespace MCPForUnity.Editor.Services public string GetTargetDisplayPath() { string target = GetTargetPath(); - return string.IsNullOrEmpty(target) - ? "Not found (check Packages/manifest.json)" - : target; + if (string.IsNullOrEmpty(target)) + return "Not found (check Packages/manifest.json)"; + // Use forward slashes to avoid backslash escape sequence issues in UI text + return target.Replace('\\', '/'); } public string GetLastBackupPath() diff --git a/MCPForUnity/Editor/Windows/Components/Settings/McpSettingsSection.cs b/MCPForUnity/Editor/Windows/Components/Settings/McpSettingsSection.cs index c732052..7f782f8 100644 --- a/MCPForUnity/Editor/Windows/Components/Settings/McpSettingsSection.cs +++ b/MCPForUnity/Editor/Windows/Components/Settings/McpSettingsSection.cs @@ -308,7 +308,8 @@ namespace MCPForUnity.Editor.Windows.Components.Settings string backupPath = deployService.GetLastBackupPath(); if (deployService.HasBackup()) { - deployBackupLabel.text = $"Last backup: {backupPath}"; + // Use forward slashes to avoid backslash escape sequence issues in UI text + deployBackupLabel.text = $"Last backup: {backupPath?.Replace('\\', '/')}"; } else { diff --git a/MCPForUnity/Editor/Windows/Components/Settings/McpSettingsSection.uxml b/MCPForUnity/Editor/Windows/Components/Settings/McpSettingsSection.uxml index 50038f3..1f15748 100644 --- a/MCPForUnity/Editor/Windows/Components/Settings/McpSettingsSection.uxml +++ b/MCPForUnity/Editor/Windows/Components/Settings/McpSettingsSection.uxml @@ -38,9 +38,8 @@ - - - + + diff --git a/TestProjects/UnityMCPTests/Assets/Tests/EditMode/Helpers/CodexConfigHelperTests.cs b/TestProjects/UnityMCPTests/Assets/Tests/EditMode/Helpers/CodexConfigHelperTests.cs index 4054174..95d1a04 100644 --- a/TestProjects/UnityMCPTests/Assets/Tests/EditMode/Helpers/CodexConfigHelperTests.cs +++ b/TestProjects/UnityMCPTests/Assets/Tests/EditMode/Helpers/CodexConfigHelperTests.cs @@ -248,7 +248,7 @@ namespace MCPForUnityTests.Editor.Helpers var thirdArg = (args[2] as TomlString).Value; Assert.AreEqual("--from", firstArg, "First arg should be --from"); - Assert.IsTrue(secondArg.Contains("git+https://github.com/CoplayDev/unity-mcp"), "Second arg should be git URL"); + Assert.IsTrue(secondArg.Contains("mcpforunityserver"), "Second arg should be PyPI package reference"); Assert.AreEqual("mcp-for-unity", thirdArg, "Third arg should be mcp-for-unity"); // Verify env.SystemRoot is present on Windows @@ -313,7 +313,7 @@ namespace MCPForUnityTests.Editor.Helpers var thirdArg = (args[2] as TomlString).Value; Assert.AreEqual("--from", firstArg, "First arg should be --from"); - Assert.IsTrue(secondArg.Contains("git+https://github.com/CoplayDev/unity-mcp"), "Second arg should be git URL"); + Assert.IsTrue(secondArg.Contains("mcpforunityserver"), "Second arg should be PyPI package reference"); Assert.AreEqual("mcp-for-unity", thirdArg, "Third arg should be mcp-for-unity"); // Verify env is NOT present on non-Windows platforms @@ -380,7 +380,7 @@ namespace MCPForUnityTests.Editor.Helpers var thirdArg = (args[2] as TomlString).Value; Assert.AreEqual("--from", firstArg, "First arg should be --from"); - Assert.IsTrue(secondArg.Contains("git+https://github.com/CoplayDev/unity-mcp"), "Second arg should be git URL"); + Assert.IsTrue(secondArg.Contains("mcpforunityserver"), "Second arg should be PyPI package reference"); Assert.AreEqual("mcp-for-unity", thirdArg, "Third arg should be mcp-for-unity"); // Verify env.SystemRoot is present on Windows @@ -454,7 +454,7 @@ namespace MCPForUnityTests.Editor.Helpers var thirdArg = (args[2] as TomlString).Value; Assert.AreEqual("--from", firstArg, "First arg should be --from"); - Assert.IsTrue(secondArg.Contains("git+https://github.com/CoplayDev/unity-mcp"), "Second arg should be git URL"); + Assert.IsTrue(secondArg.Contains("mcpforunityserver"), "Second arg should be PyPI package reference"); Assert.AreEqual("mcp-for-unity", thirdArg, "Third arg should be mcp-for-unity"); // Verify env is NOT present on non-Windows platforms