unity-mcp/UnityMcpBridge/Editor/Helpers/McpPathResolver.cs

124 lines
5.1 KiB
C#
Raw Normal View History

feat: Unity Asset Store compliance with post-installation dependency setup (#281) * feat: implement Unity Asset Store compliance with post-installation dependency setup - Remove bundled Python dependencies from Unity package - Add comprehensive 6-step setup wizard with auto-trigger on first import - Implement cross-platform dependency detection (Windows, macOS, Linux) - Add integrated MCP client configuration within setup process - Create production-ready menu structure with clean UI/UX - Ensure complete end-to-end setup requiring no additional configuration - Add comprehensive error handling and recovery mechanisms This implementation ensures Asset Store compliance while maintaining full functionality through guided user setup. Users are left 100% ready to use MCP after completing the setup wizard. * refactor: improve Asset Store compliance implementation with production-ready setup - Remove automatic installation attempts on package import - Always show setup wizard on package install/reinstall - Integrate MCP client configuration as part of setup wizard process - Ensure MCP client config window remains accessible via menu - Remove testing components for production readiness - Replace automatic installation with manual guidance only - Add complete 4-step setup flow: Welcome → Dependencies → Installation Guide → Client Configuration → Complete - Improve user experience with clear instructions and accessible client management * feat: add comprehensive dependency requirement warnings - Add critical warnings throughout setup wizard that package cannot function without dependencies - Update package.json description to clearly state manual dependency installation requirement - Prevent setup completion if dependencies are missing - Enhance skip setup warning to emphasize package will be non-functional - Add error messages explaining consequences of missing dependencies - Update menu item to indicate setup wizard is required - Ensure users understand package is completely non-functional without proper dependency installation * refactor: simplify setup wizard for production BREAKING: Reduced setup wizard from 5 steps to 3 streamlined steps: - Step 1: Setup (welcome + dependency check + installation guide) - Step 2: Configure (client configuration with direct access to full settings) - Step 3: Complete (final status and quick access to resources) Simplifications: - Consolidated UI components with DRY helper methods (DrawSectionTitle, DrawSuccessStatus, DrawErrorStatus) - Simplified dependency status display with clean icons and essential info - Removed complex state management - using simple EditorPrefs instead - Removed unused InstallationOrchestrator and SetupState classes - Streamlined client configuration to direct users to full settings window - Simplified navigation with back/skip/next buttons - Reduced code complexity while maintaining solid principles Results: - 40% less code while maintaining all functionality - Cleaner, more intuitive user flow - Faster setup process with fewer clicks - Production-ready simplicity - Easier maintenance and debugging * fix: add missing using statement for DependencyCheckResult Add missing 'using MCPForUnity.Editor.Dependencies.Models;' to resolve DependencyCheckResult type reference in SetupWizard.cs * refactor: optimize dependency checks and remove dead code * fix: remove unused DrawInstallationProgressStep method Removes leftover method that references deleted _isInstalling and _installationStatus fields, fixing compilation errors. * feat: improve setup wizard UX and add real client configuration 1. Remove dependency mentions from package.json description 2. Only show dependency warnings when dependencies are actually missing 3. Add actual MCP client configuration functionality within the wizard: - Client selection dropdown - Individual client configuration - Claude Code registration/unregistration - Batch configuration for all clients - Manual setup instructions - Real configuration file writing Users can now complete full setup including client configuration without leaving the wizard. * refactor: improve menu text and client restart tip - Remove '(Required)' from Setup Wizard menu item for cleaner appearance - Update tip to reflect that most AI clients auto-detect configuration changes * refactor: simplify client restart tip message * fix: add missing using statement for MCPForUnityEditorWindow Add 'using MCPForUnity.Editor.Windows;' to resolve unresolved symbol error for MCPForUnityEditorWindow in SetupWizard.cs * Format code * Remove unused folders * Same for validators * Same for Setup... * feat: add setup wizard persistence to avoid showing on subsequent imports * fix: update Python version check to support Python 4+ across all platform detectors * refactor: extract common platform detection logic into PlatformDetectorBase class * feat: add configuration helpers for MCP client setup with sophisticated path resolution * fix: add missing override keyword to DetectPython method in platform detectors * fix: update menu item labels for consistent capitalization and naming * fix: standardize "MCP For Unity" capitalization in window titles and dialogs * refactor: update package ID from justinpbarnett to coplaydev across codebase * refactor: remove unused validation and configuration helper methods * refactor: remove unused warnOnLegacyPackageId parameter from TryFindEmbeddedServerSource --------- Co-authored-by: Claude <claude@anthropic.com> Co-authored-by: Marcus Sanatan <msanatan@gmail.com>
2025-10-04 04:43:40 +08:00
using System;
using System.IO;
using UnityEngine;
using UnityEditor;
using MCPForUnity.Editor.Helpers;
namespace MCPForUnity.Editor.Helpers
{
/// <summary>
/// Shared helper for resolving Python server directory paths with support for
/// development mode, embedded servers, and installed packages
/// </summary>
public static class McpPathResolver
{
private const string USE_EMBEDDED_SERVER_KEY = "MCPForUnity.UseEmbeddedServer";
/// <summary>
/// Resolves the Python server directory path with comprehensive logic
/// including development mode support and fallback mechanisms
/// </summary>
public static string FindPackagePythonDirectory(bool debugLogsEnabled = false)
{
string pythonDir = McpConfigFileHelper.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;
}
/// <summary>
/// Checks if the current Unity project is in development mode
/// (i.e., the package is referenced as a local file path in manifest.json)
/// </summary>
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;
}
}
/// <summary>
/// Gets the appropriate PATH prepend for the current platform when running external processes
/// </summary>
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;
}
}
}