Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
ee23346
feat: installer cleanup, auto-migration, logging normalization
dsarno Aug 24, 2025
f21c2ce
fix(installer): skip legacy deletion when still referenced in prefs o…
dsarno Aug 24, 2025
175d5ae
chore(editor): WriteToConfig honors pythonDir; robust config match; r…
dsarno Aug 24, 2025
742d168
sec(installer): escape server path in pgrep pattern to prevent inject…
dsarno Aug 24, 2025
576dba4
Merge branch 'main' of https://github.com/CoplayDev/unity-mcp into fi…
dsarno Aug 24, 2025
4da30cc
bump server version
dsarno Aug 24, 2025
58ed4d4
chore(server): bump server_version.txt to 3.0.4
dsarno Aug 24, 2025
86b4dc1
chore(logging): include OS and server version in MCP bridge start log
dsarno Aug 24, 2025
48c1b7a
fix(installer): use Application.platform for OS detection; add canoni…
dsarno Aug 24, 2025
755e1d7
chore(version): bump server_version.txt to 3.0.5
dsarno Aug 24, 2025
ce1104e
feat(installer): rewire known configs (EditorPrefs, Cursor mcp.json) …
dsarno Aug 24, 2025
01ea2f4
refactor(installer): revert to lean installer logic from ee23346c; fi…
dsarno Aug 24, 2025
ad5c311
MCP: Fix macOS paths and VSCode manual setup
dsarno Aug 24, 2025
aa4fc1c
Server: set server_version.txt to 3.0.1
dsarno Aug 24, 2025
daa105d
Fix Claude Desktop config path and atomic write issues
dsarno Aug 25, 2025
99d7a12
Editor: use macConfigPath on macOS for MCP client config writes (Clau…
dsarno Aug 25, 2025
88b6390
Models: add macConfigPath to McpClient for macOS config path selectio…
dsarno Aug 25, 2025
a7d7bcd
Editor: on macOS, prefer macConfigPath in ManualConfigEditorWindow (f…
dsarno Aug 25, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 36 additions & 13 deletions UnityMcpBridge/Editor/Data/McpClients.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Runtime.InteropServices;
using MCPForUnity.Editor.Models;

namespace MCPForUnity.Editor.Data
Expand Down Expand Up @@ -69,32 +70,54 @@ public class McpClients
"Claude",
"claude_desktop_config.json"
),
linuxConfigPath = Path.Combine(
Environment.GetFolderPath(Environment.SpecialFolder.UserProfile),
".config",
"Claude",
"claude_desktop_config.json"
),
// For macOS, Claude Desktop stores config under ~/Library/Application Support/Claude
// For Linux, it remains under ~/.config/Claude
linuxConfigPath = RuntimeInformation.IsOSPlatform(OSPlatform.OSX)
? Path.Combine(
Environment.GetFolderPath(Environment.SpecialFolder.UserProfile),
"Library",
"Application Support",
"Claude",
"claude_desktop_config.json"
)
: Path.Combine(
Environment.GetFolderPath(Environment.SpecialFolder.UserProfile),
".config",
"Claude",
"claude_desktop_config.json"
),
mcpType = McpTypes.ClaudeDesktop,
configStatus = "Not Configured",
},
// 5) VSCode GitHub Copilot
new()
{
name = "VSCode GitHub Copilot",
// Windows path is canonical under %AppData%\Code\User
windowsConfigPath = Path.Combine(
Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData),
"Code",
"User",
"mcp.json"
),
linuxConfigPath = Path.Combine(
Environment.GetFolderPath(Environment.SpecialFolder.UserProfile),
".config",
"Code",
"User",
"mcp.json"
),
// For macOS, VSCode stores user config under ~/Library/Application Support/Code/User
// For Linux, it remains under ~/.config/Code/User
linuxConfigPath = RuntimeInformation.IsOSPlatform(OSPlatform.OSX)
? Path.Combine(
Environment.GetFolderPath(Environment.SpecialFolder.UserProfile),
"Library",
"Application Support",
"Code",
"User",
"mcp.json"
)
: Path.Combine(
Environment.GetFolderPath(Environment.SpecialFolder.UserProfile),
".config",
"Code",
"User",
"mcp.json"
),
mcpType = McpTypes.VSCode,
configStatus = "Not Configured",
},
Expand Down
36 changes: 35 additions & 1 deletion UnityMcpBridge/Editor/Helpers/ConfigJsonBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,41 @@ public static JObject ApplyUnityServerToExistingConfig(JObject root, string uvPa
private static void PopulateUnityNode(JObject unity, string uvPath, string directory, McpClient client, bool isVSCode)
{
unity["command"] = uvPath;
unity["args"] = JArray.FromObject(new[] { "run", "--directory", directory, "server.py" });

// For Cursor (non-VSCode) on macOS, prefer a no-spaces symlink path to avoid arg parsing issues in some runners
string effectiveDir = directory;
#if UNITY_EDITOR_OSX || UNITY_STANDALONE_OSX
bool isCursor = !isVSCode && (client == null || client.mcpType != Models.McpTypes.VSCode);
if (isCursor && !string.IsNullOrEmpty(directory))
{
// Replace canonical path segment with the symlink path if present
const string canonical = "/Library/Application Support/";
const string symlinkSeg = "/Library/AppSupport/";
try
{
// Normalize to full path style
if (directory.Contains(canonical))
{
effectiveDir = directory.Replace(canonical, symlinkSeg);
}
else
{
// If installer returned XDG-style on macOS, map to canonical symlink
string norm = directory.Replace('\\', '/');
int idx = norm.IndexOf("/.local/share/UnityMCP/", System.StringComparison.Ordinal);
if (idx >= 0)
{
string home = System.Environment.GetFolderPath(System.Environment.SpecialFolder.Personal) ?? string.Empty;
string suffix = norm.Substring(idx + "/.local/share/".Length); // UnityMCP/...
effectiveDir = System.IO.Path.Combine(home, "Library", "AppSupport", suffix).Replace('\\', '/');
}
}
}
catch { /* fallback to original directory on any error */ }
}
#endif

unity["args"] = JArray.FromObject(new[] { "run", "--directory", effectiveDir, "server.py" });

if (isVSCode)
{
Expand Down
33 changes: 33 additions & 0 deletions UnityMcpBridge/Editor/Helpers/McpLog.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
using UnityEditor;
using UnityEngine;

namespace MCPForUnity.Editor.Helpers
{
internal static class McpLog
{
private const string Prefix = "<b><color=#2EA3FF>MCP-FOR-UNITY</color></b>:";

private static bool IsDebugEnabled()
{
try { return EditorPrefs.GetBool("MCPForUnity.DebugLogs", false); } catch { return false; }
}

public static void Info(string message, bool always = true)
{
if (!always && !IsDebugEnabled()) return;
Debug.Log($"{Prefix} {message}");
}

public static void Warn(string message)
{
Debug.LogWarning($"<color=#cc7a00>{Prefix} {message}</color>");
}

public static void Error(string message)
{
Debug.LogError($"<color=#cc3333>{Prefix} {message}</color>");
}
}
}


13 changes: 13 additions & 0 deletions UnityMcpBridge/Editor/Helpers/McpLog.cs.meta

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

96 changes: 96 additions & 0 deletions UnityMcpBridge/Editor/Helpers/PackageDetector.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
using UnityEditor;
using UnityEngine;

namespace MCPForUnity.Editor.Helpers
{
/// <summary>
/// Auto-runs legacy/older install detection on package load/update (log-only).
/// Runs once per embedded server version using an EditorPrefs version-scoped key.
/// </summary>
[InitializeOnLoad]
public static class PackageDetector
{
private const string DetectOnceFlagKeyPrefix = "MCPForUnity.LegacyDetectLogged:";

static PackageDetector()
{
try
{
string pkgVer = ReadPackageVersionOrFallback();
string key = DetectOnceFlagKeyPrefix + pkgVer;

// Always force-run if legacy roots exist or canonical install is missing
bool legacyPresent = LegacyRootsExist();
bool canonicalMissing = !System.IO.File.Exists(System.IO.Path.Combine(ServerInstaller.GetServerPath(), "server.py"));

if (!EditorPrefs.GetBool(key, false) || legacyPresent || canonicalMissing)
{
EditorApplication.delayCall += () =>
{
try
{
ServerInstaller.EnsureServerInstalled();
}
catch (System.Exception ex)
{
Debug.LogWarning("MCP for Unity: Auto-detect on load failed: " + ex.Message);
}
finally
{
EditorPrefs.SetBool(key, true);
}
};
}
}
catch { /* ignore */ }
}

private static string ReadEmbeddedVersionOrFallback()
{
try
{
if (ServerPathResolver.TryFindEmbeddedServerSource(out var embeddedSrc))
{
var p = System.IO.Path.Combine(embeddedSrc, "server_version.txt");
if (System.IO.File.Exists(p))
return (System.IO.File.ReadAllText(p)?.Trim() ?? "unknown");
}
}
catch { }
return "unknown";
}

private static string ReadPackageVersionOrFallback()
{
try
{
var info = UnityEditor.PackageManager.PackageInfo.FindForAssembly(typeof(PackageDetector).Assembly);
if (info != null && !string.IsNullOrEmpty(info.version)) return info.version;
}
catch { }
// Fallback to embedded server version if package info unavailable
return ReadEmbeddedVersionOrFallback();
}

private static bool LegacyRootsExist()
{
try
{
string home = System.Environment.GetFolderPath(System.Environment.SpecialFolder.UserProfile) ?? string.Empty;
string[] roots =
{
System.IO.Path.Combine(home, ".config", "UnityMCP", "UnityMcpServer", "src"),
System.IO.Path.Combine(home, ".local", "share", "UnityMCP", "UnityMcpServer", "src")
};
foreach (var r in roots)
{
try { if (System.IO.File.Exists(System.IO.Path.Combine(r, "server.py"))) return true; } catch { }
}
}
catch { }
return false;
}
}
}


2 changes: 2 additions & 0 deletions UnityMcpBridge/Editor/Helpers/PackageDetector.cs.meta

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading