Skip to content

Commit 9a9267c

Browse files
committed
Windows: prefer WinGet Links uv.exe and preserve existing absolute uv command during config writes
1 parent b09a86f commit 9a9267c

File tree

2 files changed

+81
-9
lines changed

2 files changed

+81
-9
lines changed

UnityMcpBridge/Editor/Helpers/ServerInstaller.cs

Lines changed: 19 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -270,19 +270,29 @@ internal static string FindUvPath()
270270
string[] candidates;
271271
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
272272
{
273+
string localAppData = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData) ?? string.Empty;
274+
string programFiles = Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles) ?? string.Empty;
275+
string appData = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) ?? string.Empty;
276+
273277
candidates = new[]
274278
{
279+
// Preferred: WinGet Links shims (stable entrypoints)
280+
Path.Combine(localAppData, "Microsoft", "WinGet", "Links", "uv.exe"),
281+
Path.Combine(programFiles, "WinGet", "Links", "uv.exe"),
282+
275283
// Common per-user installs
276-
Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData) ?? string.Empty, @"Programs\Python\Python313\Scripts\uv.exe"),
277-
Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData) ?? string.Empty, @"Programs\Python\Python312\Scripts\uv.exe"),
278-
Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData) ?? string.Empty, @"Programs\Python\Python311\Scripts\uv.exe"),
279-
Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData) ?? string.Empty, @"Programs\Python\Python310\Scripts\uv.exe"),
280-
Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) ?? string.Empty, @"Python\Python313\Scripts\uv.exe"),
281-
Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) ?? string.Empty, @"Python\Python312\Scripts\uv.exe"),
282-
Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) ?? string.Empty, @"Python\Python311\Scripts\uv.exe"),
283-
Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) ?? string.Empty, @"Python\Python310\Scripts\uv.exe"),
284+
Path.Combine(localAppData, @"Programs\Python\Python313\Scripts\uv.exe"),
285+
Path.Combine(localAppData, @"Programs\Python\Python312\Scripts\uv.exe"),
286+
Path.Combine(localAppData, @"Programs\Python\Python311\Scripts\uv.exe"),
287+
Path.Combine(localAppData, @"Programs\Python\Python310\Scripts\uv.exe"),
288+
Path.Combine(appData, @"Python\Python313\Scripts\uv.exe"),
289+
Path.Combine(appData, @"Python\Python312\Scripts\uv.exe"),
290+
Path.Combine(appData, @"Python\Python311\Scripts\uv.exe"),
291+
Path.Combine(appData, @"Python\Python310\Scripts\uv.exe"),
292+
284293
// Program Files style installs (if a native installer was used)
285-
Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles) ?? string.Empty, @"uv\uv.exe"),
294+
Path.Combine(programFiles, @"uv\uv.exe"),
295+
286296
// Try simple name resolution later via PATH
287297
"uv.exe",
288298
"uv"

UnityMcpBridge/Editor/Windows/UnityMcpEditorWindow.cs

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1023,6 +1023,68 @@ private string WriteToConfig(string pythonDir, string configPath, McpClient mcpC
10231023
break;
10241024
}
10251025

1026+
// If config already has a working absolute uv path, avoid rewriting it on refresh
1027+
try
1028+
{
1029+
if (mcpClient?.mcpType != McpTypes.ClaudeCode)
1030+
{
1031+
// Inspect existing command for stability (Windows absolute path that exists)
1032+
string existingCommand = null;
1033+
if (mcpClient?.mcpType == McpTypes.VSCode)
1034+
{
1035+
existingCommand = existingConfig?.servers?.unityMCP?.command?.ToString();
1036+
}
1037+
else
1038+
{
1039+
existingCommand = existingConfig?.mcpServers?.unityMCP?.command?.ToString();
1040+
}
1041+
1042+
if (!string.IsNullOrEmpty(existingCommand))
1043+
{
1044+
bool keep = false;
1045+
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
1046+
{
1047+
// Consider absolute, existing paths as stable; prefer WinGet Links
1048+
if (Path.IsPathRooted(existingCommand) && File.Exists(existingCommand))
1049+
{
1050+
keep = true;
1051+
}
1052+
}
1053+
else
1054+
{
1055+
// On Unix, keep absolute existing path as well
1056+
if (Path.IsPathRooted(existingCommand) && File.Exists(existingCommand))
1057+
{
1058+
keep = true;
1059+
}
1060+
}
1061+
1062+
if (keep)
1063+
{
1064+
// Merge without replacing the existing command
1065+
if (mcpClient?.mcpType == McpTypes.VSCode)
1066+
{
1067+
existingConfig.servers.unityMCP.args =
1068+
JsonConvert.DeserializeObject<Newtonsoft.Json.Linq.JToken>(
1069+
JsonConvert.SerializeObject(unityMCPConfig.args)
1070+
);
1071+
}
1072+
else
1073+
{
1074+
existingConfig.mcpServers.unityMCP.args =
1075+
JsonConvert.DeserializeObject<Newtonsoft.Json.Linq.JToken>(
1076+
JsonConvert.SerializeObject(unityMCPConfig.args)
1077+
);
1078+
}
1079+
string mergedKeep = JsonConvert.SerializeObject(existingConfig, jsonSettings);
1080+
File.WriteAllText(configPath, mergedKeep);
1081+
return "Configured successfully";
1082+
}
1083+
}
1084+
}
1085+
}
1086+
catch { /* fall back to normal write */ }
1087+
10261088
// Write the merged configuration back to file
10271089
string mergedJson = JsonConvert.SerializeObject(existingConfig, jsonSettings);
10281090
File.WriteAllText(configPath, mergedJson);

0 commit comments

Comments
 (0)