Skip to content

Commit 46b926b

Browse files
committed
Refactor: Optimize Stdio transport with UVX fallback and Python environment variables
Stdio 통신 최적화 (Wrapper 우선, UVX Fallback, Python 환경변수 적용)
1 parent a6af630 commit 46b926b

31 files changed

+2078
-848
lines changed

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: 81 additions & 3 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 = "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);
@@ -128,6 +202,10 @@ private static void GenerateRecommendations(DependencyCheckResult result, IPlatf
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: 37 additions & 2 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))
@@ -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))

MCPForUnity/Editor/Dependencies/PlatformDetectors/MacOSPlatformDetector.cs

Lines changed: 52 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ public class MacOSPlatformDetector : PlatformDetectorBase
1616

1717
public override bool CanDetect => RuntimeInformation.IsOSPlatform(OSPlatform.OSX);
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,33 +25,50 @@ public override DependencyStatus DetectPython()
2525

2626
try
2727
{
28-
// 1. Try 'which' command with augmented PATH (prioritizing Homebrew)
29-
if (TryFindInPath("python3", out string pathResult) ||
30-
TryFindInPath("python", out pathResult))
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))
3135
{
32-
if (TryValidatePython(pathResult, out string version, out string fullPath))
36+
if (TryValidatePython(overridePath, out string ovVersion, out string ovPath))
3337
{
3438
status.IsAvailable = true;
35-
status.Version = version;
36-
status.Path = fullPath;
37-
status.Details = $"Found Python {version} at {fullPath}";
39+
status.Version = ovVersion;
40+
status.Path = ovPath;
41+
status.Details = $"Using custom Python path: {ovPath}";
3842
return status;
3943
}
4044
}
41-
42-
// 2. Fallback: Try running python directly from PATH
43-
if (TryValidatePython("python3", out string v, out string p) ||
44-
TryValidatePython("python", out v, out p))
45+
// Try running python directly first
46+
if (TryValidatePython("python3", out string version, out string fullPath) ||
47+
TryValidatePython("python", out version, out fullPath))
4548
{
4649
status.IsAvailable = true;
47-
status.Version = v;
48-
status.Path = p;
49-
status.Details = $"Found Python {v} in PATH";
50+
status.Version = version;
51+
status.Path = fullPath;
52+
status.Details = $"Found Python {version} in PATH";
5053
return status;
5154
}
5255

53-
status.ErrorMessage = "Python not found in PATH or standard locations";
54-
status.Details = "Install Python 3.10+ via Homebrew ('brew install python3') and ensure it's in your PATH.";
56+
// Fallback: try 'which' command
57+
if (TryFindInPath("python3", out string pathResult) ||
58+
TryFindInPath("python", out pathResult))
59+
{
60+
if (TryValidatePython(pathResult, out version, out fullPath))
61+
{
62+
status.IsAvailable = true;
63+
status.Version = version;
64+
status.Path = fullPath;
65+
status.Details = $"Found Python {version} in PATH";
66+
return status;
67+
}
68+
}
69+
70+
status.ErrorMessage = "Python not found in PATH";
71+
status.Details = "Install Python 3.10+ and ensure it's added to PATH.";
5572
}
5673
catch (Exception ex)
5774
{
@@ -88,7 +105,7 @@ public override string GetInstallationRecommendations()
88105
Note: If using Homebrew, make sure /opt/homebrew/bin is in your PATH.";
89106
}
90107

91-
public override DependencyStatus DetectUv()
108+
public override DependencyStatus DetectUv(string overridePath = null)
92109
{
93110
var status = new DependencyStatus("uv Package Manager", isRequired: true)
94111
{
@@ -97,6 +114,23 @@ public override DependencyStatus DetectUv()
97114

98115
try
99116
{
117+
// 0. Check Override
118+
if (overridePath == null)
119+
{
120+
try { overridePath = UnityEditor.EditorPrefs.GetString(MCPForUnity.Editor.Constants.EditorPrefKeys.UvPathOverride, ""); } catch {}
121+
}
122+
123+
if (!string.IsNullOrEmpty(overridePath) && File.Exists(overridePath))
124+
{
125+
if (TryValidateUv(overridePath, out string ovVersion, out string ovPath))
126+
{
127+
status.IsAvailable = true;
128+
status.Version = ovVersion;
129+
status.Path = ovPath;
130+
status.Details = $"Using custom uv path: {ovPath}";
131+
return status;
132+
}
133+
}
100134
// Try running uv/uvx directly with augmented PATH
101135
if (TryValidateUv("uv", out string version, out string fullPath) ||
102136
TryValidateUv("uvx", out version, out fullPath))

0 commit comments

Comments
 (0)