using System; using System.IO; using UnityEngine; using UnityEditor; using MCPForUnity.Editor.Helpers; namespace MCPForUnity.Editor.Helpers { /// /// Shared helper for resolving MCP server directory paths with support for /// development mode, embedded servers, and installed packages /// public static class McpPathResolver { private const string USE_EMBEDDED_SERVER_KEY = "MCPForUnity.UseEmbeddedServer"; /// /// Resolves the MCP server directory path with comprehensive logic /// including development mode support and fallback mechanisms /// public static string FindPackagePythonDirectory(bool debugLogsEnabled = false) { string pythonDir = McpConfigurationHelper.ResolveServerSource(); try { // Only check dev paths if we're using a file-based package (development mode) bool isDevelopmentMode = IsDevelopmentMode(); if (isDevelopmentMode) { string currentPackagePath = Path.GetDirectoryName(Application.dataPath); string[] devPaths = { Path.Combine(currentPackagePath, "unity-mcp", "UnityMcpServer", "src"), Path.Combine(Path.GetDirectoryName(currentPackagePath), "unity-mcp", "UnityMcpServer", "src"), }; foreach (string devPath in devPaths) { if (Directory.Exists(devPath) && File.Exists(Path.Combine(devPath, "server.py"))) { if (debugLogsEnabled) { Debug.Log($"Currently in development mode. Package: {devPath}"); } return devPath; } } } // Resolve via shared helper (handles local registry and older fallback) only if dev override on if (EditorPrefs.GetBool(USE_EMBEDDED_SERVER_KEY, false)) { if (ServerPathResolver.TryFindEmbeddedServerSource(out string embedded)) { return embedded; } } // Log only if the resolved path does not actually contain server.py if (debugLogsEnabled) { bool hasServer = false; try { hasServer = File.Exists(Path.Combine(pythonDir, "server.py")); } catch { } if (!hasServer) { Debug.LogWarning("Could not find Python directory with server.py; falling back to installed path"); } } } catch (Exception e) { Debug.LogError($"Error finding package path: {e.Message}"); } return pythonDir; } /// /// Checks if the current Unity project is in development mode /// (i.e., the package is referenced as a local file path in manifest.json) /// private static bool IsDevelopmentMode() { try { // Only treat as development if manifest explicitly references a local file path for the package string manifestPath = Path.Combine(Application.dataPath, "..", "Packages", "manifest.json"); if (!File.Exists(manifestPath)) return false; string manifestContent = File.ReadAllText(manifestPath); // Look specifically for our package dependency set to a file: URL // This avoids auto-enabling dev mode just because a repo exists elsewhere on disk if (manifestContent.IndexOf("\"com.coplaydev.unity-mcp\"", StringComparison.OrdinalIgnoreCase) >= 0) { int idx = manifestContent.IndexOf("com.coplaydev.unity-mcp", StringComparison.OrdinalIgnoreCase); // Crude but effective: check for "file:" in the same line/value if (manifestContent.IndexOf("file:", idx, StringComparison.OrdinalIgnoreCase) >= 0 && manifestContent.IndexOf("\n", idx, StringComparison.OrdinalIgnoreCase) > manifestContent.IndexOf("file:", idx, StringComparison.OrdinalIgnoreCase)) { return true; } } return false; } catch { return false; } } /// /// Gets the appropriate PATH prepend for the current platform when running external processes /// public static string GetPathPrepend() { if (Application.platform == RuntimePlatform.OSXEditor) return "/opt/homebrew/bin:/usr/local/bin:/usr/bin:/bin"; else if (Application.platform == RuntimePlatform.LinuxEditor) return "/usr/local/bin:/usr/bin:/bin"; return null; } } }