Skip to content

Commit f8f8091

Browse files
committed
Improve Unity Editor integration and fix concurrency issues / Unity 에디터 통합 개선 및 동시성 문제 수정
1 parent 8b327cb commit f8f8091

37 files changed

+2765
-1020
lines changed

.github/workflows/python-tests.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ jobs:
2222
version: "latest"
2323

2424
- name: Set up Python
25-
run: uv python install 3.10
25+
run: uv python install 3.11
2626

2727
- name: Install dependencies
2828
run: |

MCPForUnity/Editor/Clients/McpClientConfiguratorBase.cs

Lines changed: 182 additions & 108 deletions
Large diffs are not rendered by default.

MCPForUnity/Editor/Constants/EditorPrefKeys.cs

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -21,21 +21,15 @@ internal static class EditorPrefKeys
2121
internal const string WebSocketUrlOverride = "MCPForUnity.WebSocketUrl";
2222
internal const string GitUrlOverride = "MCPForUnity.GitUrlOverride";
2323

24-
internal const string PackageDeploySourcePath = "MCPForUnity.PackageDeploy.SourcePath";
25-
internal const string PackageDeployLastBackupPath = "MCPForUnity.PackageDeploy.LastBackupPath";
26-
internal const string PackageDeployLastTargetPath = "MCPForUnity.PackageDeploy.LastTargetPath";
27-
internal const string PackageDeployLastSourcePath = "MCPForUnity.PackageDeploy.LastSourcePath";
28-
2924
internal const string ServerSrc = "MCPForUnity.ServerSrc";
3025
internal const string UseEmbeddedServer = "MCPForUnity.UseEmbeddedServer";
3126
internal const string LockCursorConfig = "MCPForUnity.LockCursorConfig";
3227
internal const string AutoRegisterEnabled = "MCPForUnity.AutoRegisterEnabled";
33-
internal const string ToolEnabledPrefix = "MCPForUnity.ToolEnabled.";
34-
internal const string ToolFoldoutStatePrefix = "MCPForUnity.ToolFoldout.";
35-
internal const string EditorWindowActivePanel = "MCPForUnity.EditorWindow.ActivePanel";
3628

3729
internal const string SetupCompleted = "MCPForUnity.SetupCompleted";
3830
internal const string SetupDismissed = "MCPForUnity.SetupDismissed";
31+
32+
internal const string EditorWindowActivePanel = "MCPForUnityEditorWindow.ActivePanel";
3933

4034
internal const string CustomToolRegistrationEnabled = "MCPForUnity.CustomToolRegistrationEnabled";
4135

@@ -45,5 +39,18 @@ internal static class EditorPrefKeys
4539

4640
internal const string TelemetryDisabled = "MCPForUnity.TelemetryDisabled";
4741
internal const string CustomerUuid = "MCPForUnity.CustomerUUID";
42+
43+
// Path Overrides
44+
internal const string PythonPathOverride = "MCPForUnity.PythonPathOverride";
45+
internal const string NodePathOverride = "MCPForUnity.NodePathOverride";
46+
internal const string UvPathOverride = "MCPForUnity.UvPathOverride";
47+
48+
// Deployment & Tool Config
49+
internal const string PackageDeploySourcePath = "MCPForUnity.Deploy.SourcePath";
50+
internal const string PackageDeployLastBackupPath = "MCPForUnity.Deploy.LastBackupPath";
51+
internal const string PackageDeployLastTargetPath = "MCPForUnity.Deploy.LastTargetPath";
52+
internal const string PackageDeployLastSourcePath = "MCPForUnity.Deploy.LastSourcePath";
53+
internal const string ToolFoldoutStatePrefix = "MCPForUnity.Tool.Foldout.";
54+
internal const string ToolEnabledPrefix = "MCPForUnity.Tool.Enabled.";
4855
}
4956
}

MCPForUnity/Editor/Data/.keep

Whitespace-only changes.

MCPForUnity/Editor/Dependencies/DependencyManager.cs

Lines changed: 82 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,24 @@
55
using MCPForUnity.Editor.Dependencies.Models;
66
using MCPForUnity.Editor.Dependencies.PlatformDetectors;
77
using MCPForUnity.Editor.Helpers;
8+
using MCPForUnity.Editor.Services;
89
using UnityEditor;
910
using UnityEngine;
1011

1112
namespace MCPForUnity.Editor.Dependencies
1213
{
14+
/// <summary>
15+
/// Context object containing all necessary paths and settings for dependency checking.
16+
/// This allows the check to run on a background thread without accessing Unity APIs.
17+
/// </summary>
18+
public class DependencyContext
19+
{
20+
public string PackageRootPath { get; set; }
21+
public string PythonOverridePath { get; set; }
22+
public string NodeOverridePath { get; set; }
23+
public string UvOverridePath { get; set; }
24+
}
25+
1326
/// <summary>
1427
/// Main orchestrator for dependency validation and management
1528
/// </summary>
@@ -41,9 +54,31 @@ public static IPlatformDetector GetCurrentPlatformDetector()
4154
}
4255

4356
/// <summary>
44-
/// Perform a comprehensive dependency check
57+
/// Perform a comprehensive dependency check (Synchronous - Main Thread Only)
4558
/// </summary>
4659
public static DependencyCheckResult CheckAllDependencies()
60+
{
61+
// Gather context on main thread
62+
var context = new DependencyContext
63+
{
64+
PackageRootPath = AssetPathUtility.GetMcpPackageRootPath(), // Changed to match local API
65+
PythonOverridePath = MCPServiceLocator.Paths.GetPythonPath(),
66+
NodeOverridePath = MCPServiceLocator.Paths.GetNodePath(),
67+
UvOverridePath = MCPServiceLocator.Paths.GetUvxPath()
68+
};
69+
70+
return CheckAllDependenciesInternal(context);
71+
}
72+
73+
/// <summary>
74+
/// Perform a comprehensive dependency check (Thread-Safe)
75+
/// </summary>
76+
public static DependencyCheckResult CheckAllDependenciesAsync(DependencyContext context)
77+
{
78+
return CheckAllDependenciesInternal(context);
79+
}
80+
81+
private static DependencyCheckResult CheckAllDependenciesInternal(DependencyContext context)
4782
{
4883
var result = new DependencyCheckResult();
4984

@@ -53,13 +88,52 @@ public static DependencyCheckResult CheckAllDependencies()
5388
McpLog.Info($"Checking dependencies on {detector.PlatformName}...", always: false);
5489

5590
// Check Python
56-
var pythonStatus = detector.DetectPython();
91+
var pythonStatus = detector.DetectPython(context.PythonOverridePath);
5792
result.Dependencies.Add(pythonStatus);
5893

5994
// Check uv
60-
var uvStatus = detector.DetectUv();
95+
var uvStatus = detector.DetectUv(context.UvOverridePath);
6196
result.Dependencies.Add(uvStatus);
6297

98+
// Check Node.js
99+
// Note: If detector doesn't support DetectNode yet, we might need to update detectors too.
100+
// Assuming detectors are being updated or have default interface implementation.
101+
var nodeStatus = detector.DetectNode(context.NodeOverridePath);
102+
result.Dependencies.Add(nodeStatus);
103+
104+
// Check Server Environment
105+
// We assume ServerEnvironmentSetup.IsEnvironmentReady exists.
106+
// If not, we'll need to update that too.
107+
// Note: IsEnvironmentReady might access Unity API. If so, this "Async" flavor is risky.
108+
// But CheckAllDependencies() is called on main thread in our UI usage.
109+
110+
// For now, we use a try-catch block specifically for server check to avoid blocking the whole result
111+
try
112+
{
113+
// We use the path gathered on the main thread to ensure thread safety
114+
bool isServerReady = MCPForUnity.Editor.Setup.ServerEnvironmentSetup.IsEnvironmentReady(context.PackageRootPath);
115+
116+
result.Dependencies.Add(new DependencyStatus("Server Environment", true)
117+
{
118+
Version = isServerReady ? "Installed" : "Missing",
119+
IsAvailable = isServerReady,
120+
Details = isServerReady ? "Virtual Environment Ready" : "Run 'Install Server Environment'",
121+
ErrorMessage = isServerReady ? null : "Virtual environment not set up"
122+
});
123+
}
124+
catch (Exception ex)
125+
{
126+
McpLog.Warn($"Server environment check failed: {ex.Message}");
127+
result.Dependencies.Add(new DependencyStatus("Server Environment", true)
128+
{
129+
Version = "Error",
130+
IsAvailable = false,
131+
Details = "Check failed",
132+
ErrorMessage = ex.Message
133+
});
134+
}
135+
136+
63137
// Generate summary and recommendations
64138
result.GenerateSummary();
65139
GenerateRecommendations(result, detector);
@@ -122,12 +196,16 @@ private static void GenerateRecommendations(DependencyCheckResult result, IPlatf
122196
{
123197
if (dep.Name == "Python")
124198
{
125-
result.RecommendedActions.Add($"Install Python 3.10+ from: {detector.GetPythonInstallUrl()}");
199+
result.RecommendedActions.Add($"Install python 3.11+ from: {detector.GetPythonInstallUrl()}");
126200
}
127201
else if (dep.Name == "uv Package Manager")
128202
{
129203
result.RecommendedActions.Add($"Install uv package manager from: {detector.GetUvInstallUrl()}");
130204
}
205+
else if (dep.Name == "Node.js")
206+
{
207+
result.RecommendedActions.Add("Install Node.js (LTS) from: https://nodejs.org/");
208+
}
131209
else if (dep.Name == "MCP Server")
132210
{
133211
result.RecommendedActions.Add("MCP Server will be installed automatically when needed.");

MCPForUnity/Editor/Dependencies/PlatformDetectors/IPlatformDetector.cs

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,12 +20,17 @@ public interface IPlatformDetector
2020
/// <summary>
2121
/// Detect Python installation on this platform
2222
/// </summary>
23-
DependencyStatus DetectPython();
23+
DependencyStatus DetectPython(string overridePath = null);
2424

2525
/// <summary>
2626
/// Detect uv package manager on this platform
2727
/// </summary>
28-
DependencyStatus DetectUv();
28+
DependencyStatus DetectUv(string overridePath = null);
29+
30+
/// <summary>
31+
/// Detect Node.js on this platform
32+
/// </summary>
33+
DependencyStatus DetectNode(string overridePath = null);
2934

3035
/// <summary>
3136
/// Get platform-specific installation recommendations

MCPForUnity/Editor/Dependencies/PlatformDetectors/LinuxPlatformDetector.cs

Lines changed: 39 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ public class LinuxPlatformDetector : PlatformDetectorBase
1616

1717
public override bool CanDetect => RuntimeInformation.IsOSPlatform(OSPlatform.Linux);
1818

19-
public override DependencyStatus DetectPython()
19+
public override DependencyStatus DetectPython(string overridePath = null)
2020
{
2121
var status = new DependencyStatus("Python", isRequired: true)
2222
{
@@ -25,6 +25,23 @@ public override DependencyStatus DetectPython()
2525

2626
try
2727
{
28+
// 1. Check Override
29+
if (overridePath == null)
30+
{
31+
try { overridePath = UnityEditor.EditorPrefs.GetString(MCPForUnity.Editor.Constants.EditorPrefKeys.PythonPathOverride, ""); } catch {}
32+
}
33+
34+
if (!string.IsNullOrEmpty(overridePath) && File.Exists(overridePath))
35+
{
36+
if (TryValidatePython(overridePath, out string ovVersion, out string ovPath))
37+
{
38+
status.IsAvailable = true;
39+
status.Version = ovVersion;
40+
status.Path = ovPath;
41+
status.Details = $"Using custom Python path: {ovPath}";
42+
return status;
43+
}
44+
}
2845
// Try running python directly first
2946
if (TryValidatePython("python3", out string version, out string fullPath) ||
3047
TryValidatePython("python", out version, out fullPath))
@@ -51,7 +68,7 @@ public override DependencyStatus DetectPython()
5168
}
5269

5370
status.ErrorMessage = "Python not found in PATH";
54-
status.Details = "Install Python 3.10+ and ensure it's added to PATH.";
71+
status.Details = "Install python 3.11+ and ensure it's added to PATH.";
5572
}
5673
catch (Exception ex)
5774
{
@@ -90,7 +107,7 @@ public override string GetInstallationRecommendations()
90107
Note: Make sure ~/.local/bin is in your PATH for user-local installations.";
91108
}
92109

93-
public override DependencyStatus DetectUv()
110+
public override DependencyStatus DetectUv(string overridePath = null)
94111
{
95112
var status = new DependencyStatus("uv Package Manager", isRequired: true)
96113
{
@@ -99,6 +116,24 @@ public override DependencyStatus DetectUv()
99116

100117
try
101118
{
119+
// 0. Check Override
120+
if (overridePath == null)
121+
{
122+
try { overridePath = UnityEditor.EditorPrefs.GetString(MCPForUnity.Editor.Constants.EditorPrefKeys.UvPathOverride, ""); } catch {}
123+
}
124+
125+
if (!string.IsNullOrEmpty(overridePath) && File.Exists(overridePath))
126+
{
127+
if (TryValidateUv(overridePath, out string ovVersion, out string ovPath))
128+
{
129+
status.IsAvailable = true;
130+
status.Version = ovVersion;
131+
status.Path = ovPath;
132+
status.Details = $"Using custom uv path: {ovPath}";
133+
return status;
134+
}
135+
}
136+
102137
// Try running uv/uvx directly with augmented PATH
103138
if (TryValidateUv("uv", out string version, out string fullPath) ||
104139
TryValidateUv("uvx", out version, out fullPath))
@@ -177,7 +212,7 @@ private bool TryValidatePython(string pythonPath, out string version, out string
177212
version = output.Substring(7); // Remove "Python " prefix
178213
fullPath = pythonPath;
179214

180-
// Validate minimum version (Python 4+ or Python 3.10+)
215+
// Validate minimum version (Python 4+ or python 3.11+)
181216
if (TryParseVersion(version, out var major, out var minor))
182217
{
183218
return major > 3 || (major >= 3 && minor >= 10);

0 commit comments

Comments
 (0)