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
main
dsarno 2026-01-08 07:14:44 -08:00 committed by GitHub
parent 275422e765
commit cba0933d33
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 39 additions and 30 deletions

View File

@ -148,7 +148,7 @@ namespace MCPForUnity.Editor.Clients
bool matches = false; bool matches = false;
if (args != null && args.Length > 0) if (args != null && args.Length > 0)
{ {
string expectedUvxUrl = AssetPathUtility.GetMcpServerGitUrl(); string expectedUvxUrl = AssetPathUtility.GetMcpServerPackageSource();
string configuredUvxUrl = McpConfigurationHelper.ExtractUvxUrl(args); string configuredUvxUrl = McpConfigurationHelper.ExtractUvxUrl(args);
matches = !string.IsNullOrEmpty(configuredUvxUrl) && matches = !string.IsNullOrEmpty(configuredUvxUrl) &&
McpConfigurationHelper.PathsEqual(configuredUvxUrl, expectedUvxUrl); McpConfigurationHelper.PathsEqual(configuredUvxUrl, expectedUvxUrl);
@ -250,7 +250,7 @@ namespace MCPForUnity.Editor.Clients
} }
else if (args != null && args.Length > 0) else if (args != null && args.Length > 0)
{ {
string expected = AssetPathUtility.GetMcpServerGitUrl(); string expected = AssetPathUtility.GetMcpServerPackageSource();
string configured = McpConfigurationHelper.ExtractUvxUrl(args); string configured = McpConfigurationHelper.ExtractUvxUrl(args);
matches = !string.IsNullOrEmpty(configured) && matches = !string.IsNullOrEmpty(configured) &&
McpConfigurationHelper.PathsEqual(configured, expected); McpConfigurationHelper.PathsEqual(configured, expected);
@ -585,12 +585,12 @@ namespace MCPForUnity.Editor.Clients
return "# Error: Configuration not available - check paths in Advanced Settings"; 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. // Use central helper that checks both DevModeForceServerRefresh AND local path detection.
string devFlags = AssetPathUtility.ShouldForceUvxRefresh() ? "--no-cache --refresh " : string.Empty; string devFlags = AssetPathUtility.ShouldForceUvxRefresh() ? "--no-cache --refresh " : string.Empty;
return "# Register the MCP server with Claude Code:\n" + 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" + "# Unregister the MCP server:\n" +
"claude mcp remove UnityMCP\n\n" + "claude mcp remove UnityMCP\n\n" +
"# List registered servers:\n" + "# List registered servers:\n" +

View File

@ -149,30 +149,38 @@ namespace MCPForUnity.Editor.Helpers
} }
/// <summary> /// <summary>
/// Gets just the git URL part for the MCP server package /// Gets the package source for the MCP server (used with uvx --from).
/// Checks for EditorPrefs override first, then falls back to package version /// Checks for EditorPrefs override first (supports git URLs, file:// paths, etc.),
/// then falls back to PyPI package reference.
/// </summary> /// </summary>
/// <returns>Git URL string, or empty string if version is unknown and no override</returns> /// <returns>Package source string for uvx --from argument</returns>
public static string GetMcpServerGitUrl() public static string GetMcpServerPackageSource()
{ {
// Check for Git URL override first // Check for override first (supports git URLs, file:// paths, local paths)
string gitUrlOverride = EditorPrefs.GetString(EditorPrefKeys.GitUrlOverride, ""); string sourceOverride = EditorPrefs.GetString(EditorPrefKeys.GitUrlOverride, "");
if (!string.IsNullOrEmpty(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(); string version = GetPackageVersion();
if (version == "unknown") if (version == "unknown")
{ {
// Fall back to main repo without pinned version so configs remain valid in test scenarios // Fall back to latest PyPI version so configs remain valid in test scenarios
return "git+https://github.com/CoplayDev/unity-mcp#subdirectory=Server"; return "mcpforunityserver";
} }
return $"git+https://github.com/CoplayDev/unity-mcp@v{version}#subdirectory=Server"; return $"mcpforunityserver=={version}";
} }
/// <summary>
/// Deprecated: Use GetMcpServerPackageSource() instead.
/// Kept for backwards compatibility.
/// </summary>
[System.Obsolete("Use GetMcpServerPackageSource() instead")]
public static string GetMcpServerGitUrl() => GetMcpServerPackageSource();
/// <summary> /// <summary>
/// Gets structured uvx command parts for different client configurations /// Gets structured uvx command parts for different client configurations
/// </summary> /// </summary>
@ -180,7 +188,7 @@ namespace MCPForUnity.Editor.Helpers
public static (string uvxPath, string fromUrl, string packageName) GetUvxCommandParts() public static (string uvxPath, string fromUrl, string packageName) GetUvxCommandParts()
{ {
string uvxPath = MCPServiceLocator.Paths.GetUvxPath(); string uvxPath = MCPServiceLocator.Paths.GetUvxPath();
string fromUrl = GetMcpServerGitUrl(); string fromUrl = GetMcpServerPackageSource();
string packageName = "mcp-for-unity"; string packageName = "mcp-for-unity";
return (uvxPath, fromUrl, packageName); return (uvxPath, fromUrl, packageName);
@ -208,7 +216,7 @@ namespace MCPForUnity.Editor.Helpers
/// </summary> /// </summary>
public static bool IsLocalServerPath() public static bool IsLocalServerPath()
{ {
string fromUrl = GetMcpServerGitUrl(); string fromUrl = GetMcpServerPackageSource();
if (string.IsNullOrEmpty(fromUrl)) if (string.IsNullOrEmpty(fromUrl))
return false; return false;
@ -226,7 +234,7 @@ namespace MCPForUnity.Editor.Helpers
if (!IsLocalServerPath()) if (!IsLocalServerPath())
return null; return null;
string fromUrl = GetMcpServerGitUrl(); string fromUrl = GetMcpServerPackageSource();
if (fromUrl.StartsWith("file://", StringComparison.OrdinalIgnoreCase)) if (fromUrl.StartsWith("file://", StringComparison.OrdinalIgnoreCase))
{ {
// Strip file:// prefix // Strip file:// prefix

View File

@ -69,9 +69,10 @@ namespace MCPForUnity.Editor.Services
public string GetTargetDisplayPath() public string GetTargetDisplayPath()
{ {
string target = GetTargetPath(); string target = GetTargetPath();
return string.IsNullOrEmpty(target) if (string.IsNullOrEmpty(target))
? "Not found (check Packages/manifest.json)" return "Not found (check Packages/manifest.json)";
: target; // Use forward slashes to avoid backslash escape sequence issues in UI text
return target.Replace('\\', '/');
} }
public string GetLastBackupPath() public string GetLastBackupPath()

View File

@ -308,7 +308,8 @@ namespace MCPForUnity.Editor.Windows.Components.Settings
string backupPath = deployService.GetLastBackupPath(); string backupPath = deployService.GetLastBackupPath();
if (deployService.HasBackup()) 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 else
{ {

View File

@ -38,9 +38,8 @@
<ui:Button name="browse-git-url-button" text="Select" class="icon-button" /> <ui:Button name="browse-git-url-button" text="Select" class="icon-button" />
<ui:Button name="clear-git-url-button" text="Clear" class="icon-button" /> <ui:Button name="clear-git-url-button" text="Clear" class="icon-button" />
</ui:VisualElement> </ui:VisualElement>
<ui:Label text="Examples:" class="help-text" style="margin-top: 5px;" /> <ui:Label text="Override example (default uses PyPI):" class="help-text" style="margin-top: 5px;" />
<ui:Label text="• Local: /Users/you/Projects/unity-mcp/Server" class="help-text" /> <ui:Label text="• Local dev: /path/to/unity-mcp/Server" class="help-text" />
<ui:Label text="• Remote: git+https://github.com/CoplayDev/unity-mcp@v6.3.0#subdirectory=Server" class="help-text" />
<ui:Label text="Dev Mode:" class="advanced-label" style="margin-top: 10px;" /> <ui:Label text="Dev Mode:" class="advanced-label" style="margin-top: 10px;" />
<ui:Label text="When enabled, generated uvx commands add '--no-cache --refresh' before launching (slower startup, but avoids stale cached builds while iterating on the Server)." class="help-text" /> <ui:Label text="When enabled, generated uvx commands add '--no-cache --refresh' before launching (slower startup, but avoids stale cached builds while iterating on the Server)." class="help-text" />

View File

@ -248,7 +248,7 @@ namespace MCPForUnityTests.Editor.Helpers
var thirdArg = (args[2] as TomlString).Value; var thirdArg = (args[2] as TomlString).Value;
Assert.AreEqual("--from", firstArg, "First arg should be --from"); 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"); Assert.AreEqual("mcp-for-unity", thirdArg, "Third arg should be mcp-for-unity");
// Verify env.SystemRoot is present on Windows // Verify env.SystemRoot is present on Windows
@ -313,7 +313,7 @@ namespace MCPForUnityTests.Editor.Helpers
var thirdArg = (args[2] as TomlString).Value; var thirdArg = (args[2] as TomlString).Value;
Assert.AreEqual("--from", firstArg, "First arg should be --from"); 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"); Assert.AreEqual("mcp-for-unity", thirdArg, "Third arg should be mcp-for-unity");
// Verify env is NOT present on non-Windows platforms // Verify env is NOT present on non-Windows platforms
@ -380,7 +380,7 @@ namespace MCPForUnityTests.Editor.Helpers
var thirdArg = (args[2] as TomlString).Value; var thirdArg = (args[2] as TomlString).Value;
Assert.AreEqual("--from", firstArg, "First arg should be --from"); 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"); Assert.AreEqual("mcp-for-unity", thirdArg, "Third arg should be mcp-for-unity");
// Verify env.SystemRoot is present on Windows // Verify env.SystemRoot is present on Windows
@ -454,7 +454,7 @@ namespace MCPForUnityTests.Editor.Helpers
var thirdArg = (args[2] as TomlString).Value; var thirdArg = (args[2] as TomlString).Value;
Assert.AreEqual("--from", firstArg, "First arg should be --from"); 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"); Assert.AreEqual("mcp-for-unity", thirdArg, "Third arg should be mcp-for-unity");
// Verify env is NOT present on non-Windows platforms // Verify env is NOT present on non-Windows platforms