diff --git a/MCPForUnity/Editor/Clients/McpClientConfiguratorBase.cs b/MCPForUnity/Editor/Clients/McpClientConfiguratorBase.cs index c0ab8695b..ed8d6a690 100644 --- a/MCPForUnity/Editor/Clients/McpClientConfiguratorBase.cs +++ b/MCPForUnity/Editor/Clients/McpClientConfiguratorBase.cs @@ -148,7 +148,7 @@ public override McpStatus CheckStatus(bool attemptAutoRewrite = true) 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 @@ public override McpStatus CheckStatus(bool attemptAutoRewrite = true) } 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 @@ public override string GetManualSnippet() 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 f7a6b4782..34c9ea49d 100644 --- a/MCPForUnity/Editor/Helpers/AssetPathUtility.cs +++ b/MCPForUnity/Editor/Helpers/AssetPathUtility.cs @@ -149,30 +149,38 @@ public static JObject GetPackageJson() } /// - /// 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 @@ public static string GetMcpServerGitUrl() 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 @@ public static bool ShouldForceUvxRefresh() /// public static bool IsLocalServerPath() { - string fromUrl = GetMcpServerGitUrl(); + string fromUrl = GetMcpServerPackageSource(); if (string.IsNullOrEmpty(fromUrl)) return false; @@ -226,7 +234,7 @@ public static string GetLocalServerPath() 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 3024ded38..7c0e27c65 100644 --- a/MCPForUnity/Editor/Services/PackageDeploymentService.cs +++ b/MCPForUnity/Editor/Services/PackageDeploymentService.cs @@ -69,9 +69,10 @@ public string GetTargetPath() 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 c732052eb..7f782f8ae 100644 --- a/MCPForUnity/Editor/Windows/Components/Settings/McpSettingsSection.cs +++ b/MCPForUnity/Editor/Windows/Components/Settings/McpSettingsSection.cs @@ -308,7 +308,8 @@ private void UpdateDeploymentSection() 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 50038f3ce..1f15748c6 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 405417427..95d1a0407 100644 --- a/TestProjects/UnityMCPTests/Assets/Tests/EditMode/Helpers/CodexConfigHelperTests.cs +++ b/TestProjects/UnityMCPTests/Assets/Tests/EditMode/Helpers/CodexConfigHelperTests.cs @@ -248,7 +248,7 @@ public void BuildCodexServerBlock_OnWindows_IncludesSystemRootEnv() 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 @@ public void BuildCodexServerBlock_OnNonWindows_ExcludesEnv() 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 @@ public void UpsertCodexServerBlock_OnWindows_IncludesSystemRootEnv() 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 @@ public void UpsertCodexServerBlock_OnNonWindows_ExcludesEnv() 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