diff --git a/LICENSE b/LICENSE index ebeecf5..e7f878d 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2025 Justin P Barnett +Copyright (c) 2025 CoplayDev Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/README-DEV.md b/README-DEV.md index 954348b..398bdab 100644 --- a/README-DEV.md +++ b/README-DEV.md @@ -48,7 +48,7 @@ Restores original files from backup. Unity package cache is typically located at: ``` -X:\UnityProject\Library\PackageCache\com.justinpbarnett.unity-mcp@1.0.0 +X:\UnityProject\Library\PackageCache\com.coplaydev.unity-mcp@1.0.0 ``` To find it: diff --git a/README.md b/README.md index fd097f1..ec23c4f 100644 --- a/README.md +++ b/README.md @@ -1,11 +1,15 @@ # Unity MCP ✨ +#### Proudly sponsored and maintained by [Coplay](https://www.coplay.dev/?ref=unity-mcp), the AI assistant for Unity. [Read the backstory here.](https://www.coplay.dev/blog/coplay-and-open-source-unity-mcp-join-forces) + +[![Discord](https://img.shields.io/badge/discord-join-red.svg?logo=discord&logoColor=white)](https://discord.gg/y4p8KfzrN4) [![](https://img.shields.io/badge/Unity-000000?style=flat&logo=unity&logoColor=blue 'Unity')](https://unity.com/releases/editor/archive) [![python](https://img.shields.io/badge/Python-3.12-3776AB.svg?style=flat&logo=python&logoColor=white)](https://www.python.org) [![](https://badge.mcpx.dev?status=on 'MCP Enabled')](https://modelcontextprotocol.io/introduction) -![GitHub commit activity](https://img.shields.io/github/commit-activity/w/justinpbarnett/unity-mcp) -![GitHub Issues or Pull Requests](https://img.shields.io/github/issues/justinpbarnett/unity-mcp) +![GitHub commit activity](https://img.shields.io/github/commit-activity/w/CoplayDev/unity-mcp) +![GitHub Issues or Pull Requests](https://img.shields.io/github/issues/CoplayDev/unity-mcp) [![](https://img.shields.io/badge/License-MIT-red.svg 'MIT License')](https://opensource.org/licenses/MIT) +[![](https://img.shields.io/badge/Sponsor-Coplay-red.svg 'Coplay')](https://www.coplay.dev/?ref=unity-mcp) **Create your Unity apps with LLMs!** @@ -13,14 +17,12 @@ Unity MCP acts as a bridge, allowing AI assistants (like Claude, Cursor) to inte ## 💬 Join Our Community -### [Discord](https://discord.gg/vhTUxXaqYr) +### [Discord](https://discord.gg/y4p8KfzrN4) **Get help, share ideas, and collaborate with other Unity MCP developers!** - --- - ## Key Features 🚀 * **🗣️ Natural Language Control:** Instruct your LLM to perform Unity tasks. @@ -35,7 +37,7 @@ Unity MCP acts as a bridge, allowing AI assistants (like Claude, Cursor) to inte * `read_console`: Gets messages from or clears the console. * `manage_script`: Manages C# scripts (create, read, update, delete). - * `manage_editor`: Controls and queries the editor's state and settings. + * `manage_editor`: Controls and queries the editor\'s state and settings. * `manage_scene`: Manages scenes (load, save, create, get hierarchy, etc.). * `manage_asset`: Performs asset operations (import, create, modify, delete, etc.). * `manage_shader`: Performs shader CRUD operations (create, read, modify, delete). @@ -62,7 +64,6 @@ Unity MCP connects your tools using two components: ### Prerequisites - * **Git CLI:** For cloning the server code. [Download Git](https://git-scm.com/downloads) * **Python:** Version 3.12 or newer. [Download Python](https://www.python.org/downloads/) * **Unity Hub & Editor:** Version 2020.3 LTS or newer. [Download Unity](https://unity.com/download) @@ -76,6 +77,7 @@ Unity MCP connects your tools using two components: * [Claude Code](https://github.com/anthropics/claude-code) * [Cursor](https://www.cursor.com/en/downloads) * [Visual Studio Code Copilot](https://code.visualstudio.com/docs/copilot/overview) + * [Windsurf](https://windsurf.com) * *(Others may work with manual config)* *
[Optional] Roslyn for Advanced Script Validation @@ -95,9 +97,8 @@ Unity MCP connects your tools using two components: 3. Ensure .NET compatibility settings are correct 4. Add `USE_ROSLYN` to Scripting Define Symbols 5. Restart Unity - - **Note:** Without Roslyn, script validation falls back to basic structural checks. Roslyn enables full C# compiler diagnostics with precise error reporting.
+ **Note:** Without Roslyn, script validation falls back to basic structural checks. Roslyn enables full C# compiler diagnostics with precise error reporting. ### Step 1: Install the Unity Package (Bridge) @@ -106,11 +107,13 @@ Unity MCP connects your tools using two components: 3. Click `+` -> `Add package from git URL...`. 4. Enter: ``` - https://github.com/justinpbarnett/unity-mcp.git?path=/UnityMcpBridge + https://github.com/CoplayDev/unity-mcp.git?path=/UnityMcpBridge ``` 5. Click `Add`. 6. The MCP Server should automatically be installed onto your machine as a result of this process. +**Note:** If you installed the MCP Server before Coplay's maintenance, you will need to uninstall the old package before re-installing the new one. + ### Step 2: Configure Your MCP Client Connect your MCP Client (Claude, Cursor, etc.) to the Python server you installed in Step 1. @@ -121,13 +124,13 @@ Connect your MCP Client (Claude, Cursor, etc.) to the Python server you installe 1. In Unity, go to `Window > Unity MCP`. 2. Click `Auto Configure` on the IDE you uses. -3. Look for a green status indicator 🟢 and "Connected". *(This attempts to modify the MCP Client's config file automatically)*. +3. Look for a green status indicator 🟢 and "Connected". *(This attempts to modify the MCP Client\'s config file automatically)*. **Option B: Manual Configuration** If Auto-Configure fails or you use a different client: -1. **Find your MCP Client's configuration file.** (Check client documentation). +1. **Find your MCP Client\'s configuration file.** (Check client documentation). * *Claude Example (macOS):* `~/Library/Application Support/Claude/claude_desktop_config.json` * *Claude Example (Windows):* `%APPDATA%\Claude\claude_desktop_config.json` 2. **Edit the file** to add/update the `mcpServers` section, using the *exact* paths from Step 1. @@ -174,6 +177,7 @@ If Auto-Configure fails or you use a different client: } } ``` + (Replace YOUR_USERNAME if using ~/bin) **Linux:** @@ -197,18 +201,18 @@ If Auto-Configure fails or you use a different client: (Replace YOUR_USERNAME) - - **For Claude Code** -If you're using Claude Code, you can register the MCP server using these commands: +If you\'re using Claude Code, you can register the MCP server using these commands: **macOS:** + ```bash claude mcp add UnityMCP -- uv --directory /[PATH_TO]/UnityMCP/UnityMcpServer/src run server.py ``` **Windows:** + ```bash claude mcp add UnityMCP -- "C:/Users/USERNAME/AppData/Roaming/Python/Python313/Scripts/uv.exe" --directory "C:/Users/USERNAME/AppData/Local/Programs/UnityMCP/UnityMcpServer/src" run server.py ``` @@ -225,12 +229,13 @@ claude mcp add UnityMCP -- "C:/Users/USERNAME/AppData/Roaming/Python/Python313/S 3. **Interact!** Unity tools should now be available in your MCP Client. Example Prompt: `Create a 3D player controller`, `Create a yellow and bridge sun`, `Create a cool shader and apply it on a cube`. - + --- ## Future Dev Plans (Besides PR) 📝 ### 🔴 High Priority + - [ ] **Asset Generation Improvements** - Enhanced server request handling and asset pipeline optimization - [ ] **Code Generation Enhancements** - Improved generated code quality and error handling - [ ] **Robust Error Handling** - Comprehensive error messages, recovery mechanisms, and graceful degradation @@ -238,10 +243,12 @@ claude mcp add UnityMCP -- "C:/Users/USERNAME/AppData/Roaming/Python/Python313/S - [ ] **Documentation Expansion** - Complete tutorials for custom tool creation and API reference ### 🟡 Medium Priority + - [ ] **Custom Tool Creation GUI** - Visual interface for users to create and configure their own MCP tools - [ ] **Advanced Logging System** - Logging with filtering, export, and debugging capabilities ### 🟢 Low Priority + - [ ] **Mobile Platform Support** - Extended toolset for mobile development workflows and platform-specific features - [ ] **Easier Tool Setup** - [ ] **Plugin Marketplace** - Community-driven tool sharing and distribution platform @@ -254,6 +261,7 @@ claude mcp add UnityMCP -- "C:/Users/USERNAME/AppData/Roaming/Python/Python313/S ### 🔬 Research & Exploration + - [ ] **AI-Powered Asset Generation** - Integration with AI tools for automatic 3D models, textures, and animations - [ ] **Real-time Collaboration** - Live editing sessions between multiple developers *(Currently in progress)* - [ ] **Analytics Dashboard** - Usage analytics, project insights, and performance metrics @@ -266,7 +274,7 @@ claude mcp add UnityMCP -- "C:/Users/USERNAME/AppData/Roaming/Python/Python313/S ### Development Tools -If you're contributing to Unity MCP or want to test core changes, we have development tools to streamline your workflow: +If you\'re contributing to Unity MCP or want to test core changes, we have development tools to streamline your workflow: - **Development Deployment Scripts**: Quickly deploy and test your changes to Unity MCP Bridge and Python Server - **Automatic Backup System**: Safe testing with easy rollback capabilities @@ -289,8 +297,7 @@ Help make Unity MCP better! 5. **Push** your branch. -6. **Open a Pull Request** against the master branch. - +6. **Open a Pull Request** against the main branch. --- @@ -300,53 +307,37 @@ Help make Unity MCP better! Click to view common issues and fixes... - **Unity Bridge Not Running/Connecting:** - - Ensure Unity Editor is open. - - Check the status window: Window > Unity MCP. - - Restart Unity. - - **MCP Client Not Connecting / Server Not Starting:** - - - **Verify Server Path:** Double-check the --directory path in your MCP Client's JSON config. It must exactly match the location where you cloned the UnityMCP repository in Installation Step 1 (e.g., .../Programs/UnityMCP/UnityMcpServer/src). - - - **Verify uv:** Make sure uv is installed and working (pip show uv). - + - **Verify Server Path:** Double-check the --directory path in your MCP Client\'s JSON config. It must exactly match the location where you cloned the UnityMCP repository in Installation Step 1 (e.g., .../Programs/UnityMCP/UnityMcpServer/src). + - **Verify uv:** Make sure `uv` is installed and working (pip show uv). - **Run Manually:** Try running the server directly from the terminal to see errors: `# Navigate to the src directory first! cd /path/to/your/UnityMCP/UnityMcpServer/src uv run server.py` - - **Permissions (macOS/Linux):** If you installed the server in a system location like /usr/local/bin, ensure the user running the MCP client has permission to execute uv and access files there. Installing in ~/bin might be easier. - - **Auto-Configure Failed:** - - - Use the Manual Configuration steps. Auto-configure might lack permissions to write to the MCP client's config file. - + - Use the Manual Configuration steps. Auto-configure might lack permissions to write to the MCP client\'s config file. -Still stuck? [Open an Issue](https://www.google.com/url?sa=E&q=https%3A%2F%2Fgithub.com%2Fjustinpbarnett%2Funity-mcp%2Fissues) or [Join the Discord](https://discord.gg/vhTUxXaqYr)! - ---- - -## Contact 👋 - -- **justinpbarnett:** [X/Twitter](https://www.google.com/url?sa=E&q=https%3A%2F%2Fx.com%2Fjustinpbarnett) -- **scriptwonder**: [Email](mailto:swu85@ur.rochester.edu), [LinkedIn](https://www.linkedin.com/in/shutong-wu-214043172/) - +Still stuck? [Open an Issue](https://github.com/CoplayDev/unity-mcp/issues) or [Join the Discord](https://discord.gg/y4p8KfzrN4)! --- ## License 📜 -MIT License. See [LICENSE](https://www.google.com/url?sa=E&q=https%3A%2F%2Fgithub.com%2Fjustinpbarnett%2Funity-mcp%2Fblob%2Fmaster%2FLICENSE) file. +MIT License. See [LICENSE](LICENSE) file. --- -## Acknowledgments 🙏 - -Thanks to the contributors and the Unity team. - - ## Star History -[![Star History Chart](https://api.star-history.com/svg?repos=justinpbarnett/unity-mcp&type=Date)](https://www.star-history.com/#justinpbarnett/unity-mcp&Date) +[![Star History Chart](https://api.star-history.com/svg?repos=CoplayDev/unity-mcp&type=Date)](https://www.star-history.com/#CoplayDev/unity-mcp&Date) + +## Sponsor + +

+ + Coplay Logo + +

diff --git a/UnityMcpBridge/Editor/Helpers/PackageInstaller.cs b/UnityMcpBridge/Editor/Helpers/PackageInstaller.cs index 75cdb3b..ae420a2 100644 --- a/UnityMcpBridge/Editor/Helpers/PackageInstaller.cs +++ b/UnityMcpBridge/Editor/Helpers/PackageInstaller.cs @@ -25,18 +25,18 @@ namespace UnityMcpBridge.Editor.Helpers { try { - Debug.Log("Unity MCP: Installing Python server..."); + Debug.Log("UNITY-MCP: Installing Python server..."); ServerInstaller.EnsureServerInstalled(); // Mark as installed EditorPrefs.SetBool(InstallationFlagKey, true); - Debug.Log("Unity MCP: Python server installation completed successfully."); + Debug.Log("UNITY-MCP: Python server installation completed successfully."); } catch (System.Exception ex) { - Debug.LogError($"Unity MCP: Failed to install Python server: {ex.Message}"); - Debug.LogWarning("Unity MCP: You may need to manually install the Python server. Check the Unity MCP Editor Window for instructions."); + Debug.LogError($"UNITY-MCP: Failed to install Python server: {ex.Message}"); + Debug.LogWarning("UNITY-MCP: You may need to manually install the Python server. Check the Unity MCP Editor Window for instructions."); } } } diff --git a/UnityMcpBridge/Editor/Helpers/PortManager.cs b/UnityMcpBridge/Editor/Helpers/PortManager.cs index 9caeccc..376f916 100644 --- a/UnityMcpBridge/Editor/Helpers/PortManager.cs +++ b/UnityMcpBridge/Editor/Helpers/PortManager.cs @@ -1,5 +1,6 @@ using System; using System.IO; +using UnityEditor; using System.Net; using System.Net.Sockets; using System.Security.Cryptography; @@ -15,6 +16,12 @@ namespace UnityMcpBridge.Editor.Helpers /// public static class PortManager { + private static bool IsDebugEnabled() + { + try { return EditorPrefs.GetBool("UnityMCP.DebugLogs", false); } + catch { return false; } + } + private const int DefaultPort = 6400; private const int MaxPortAttempts = 100; private const string RegistryFileName = "unity-mcp-port.json"; @@ -41,7 +48,7 @@ namespace UnityMcpBridge.Editor.Helpers string.Equals(storedConfig.project_path ?? string.Empty, Application.dataPath ?? string.Empty, StringComparison.OrdinalIgnoreCase) && IsPortAvailable(storedConfig.unity_port)) { - Debug.Log($"Using stored port {storedConfig.unity_port} for current project"); + if (IsDebugEnabled()) Debug.Log($"UNITY-MCP: Using stored port {storedConfig.unity_port} for current project"); return storedConfig.unity_port; } @@ -50,7 +57,7 @@ namespace UnityMcpBridge.Editor.Helpers { if (WaitForPortRelease(storedConfig.unity_port, 1500)) { - Debug.Log($"Stored port {storedConfig.unity_port} became available after short wait"); + if (IsDebugEnabled()) Debug.Log($"UNITY-MCP: Stored port {storedConfig.unity_port} became available after short wait"); return storedConfig.unity_port; } // Prefer sticking to the same port; let the caller handle bind retries/fallbacks @@ -71,7 +78,7 @@ namespace UnityMcpBridge.Editor.Helpers { int newPort = FindAvailablePort(); SavePort(newPort); - Debug.Log($"Discovered and saved new port: {newPort}"); + if (IsDebugEnabled()) Debug.Log($"UNITY-MCP: Discovered and saved new port: {newPort}"); return newPort; } @@ -84,18 +91,18 @@ namespace UnityMcpBridge.Editor.Helpers // Always try default port first if (IsPortAvailable(DefaultPort)) { - Debug.Log($"Using default port {DefaultPort}"); + if (IsDebugEnabled()) Debug.Log($"UNITY-MCP: Using default port {DefaultPort}"); return DefaultPort; } - Debug.Log($"Default port {DefaultPort} is in use, searching for alternative..."); + if (IsDebugEnabled()) Debug.Log($"UNITY-MCP: Default port {DefaultPort} is in use, searching for alternative..."); // Search for alternatives for (int port = DefaultPort + 1; port < DefaultPort + MaxPortAttempts; port++) { if (IsPortAvailable(port)) { - Debug.Log($"Found available port {port}"); + if (IsDebugEnabled()) Debug.Log($"UNITY-MCP: Found available port {port}"); return port; } } @@ -204,7 +211,7 @@ namespace UnityMcpBridge.Editor.Helpers string legacy = Path.Combine(GetRegistryDirectory(), RegistryFileName); File.WriteAllText(legacy, json); - Debug.Log($"Saved port {port} to storage"); + if (IsDebugEnabled()) Debug.Log($"UNITY-MCP: Saved port {port} to storage"); } catch (Exception ex) { diff --git a/UnityMcpBridge/Editor/Helpers/ServerInstaller.cs b/UnityMcpBridge/Editor/Helpers/ServerInstaller.cs index ed92786..03b753f 100644 --- a/UnityMcpBridge/Editor/Helpers/ServerInstaller.cs +++ b/UnityMcpBridge/Editor/Helpers/ServerInstaller.cs @@ -281,7 +281,7 @@ namespace UnityMcpBridge.Editor.Helpers return false; } - Debug.Log("Unity MCP: Python environment repaired successfully."); + Debug.Log("UNITY-MCP: Python environment repaired successfully."); return true; } catch (Exception ex) @@ -305,47 +305,100 @@ namespace UnityMcpBridge.Editor.Helpers catch { } string home = Environment.GetFolderPath(Environment.SpecialFolder.UserProfile) ?? string.Empty; - string[] candidates = + + // Platform-specific candidate lists + string[] candidates; + if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) { - "/opt/homebrew/bin/uv", - "/usr/local/bin/uv", - "/usr/bin/uv", - "/opt/local/bin/uv", - Path.Combine(home, ".local", "bin", "uv"), - "/opt/homebrew/opt/uv/bin/uv", - // Framework Python installs - "/Library/Frameworks/Python.framework/Versions/3.13/bin/uv", - "/Library/Frameworks/Python.framework/Versions/3.12/bin/uv", - // Fallback to PATH resolution by name - "uv" - }; + candidates = new[] + { + // Common per-user installs + Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData) ?? string.Empty, @"Programs\Python\Python313\Scripts\uv.exe"), + Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData) ?? string.Empty, @"Programs\Python\Python312\Scripts\uv.exe"), + Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData) ?? string.Empty, @"Programs\Python\Python311\Scripts\uv.exe"), + Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData) ?? string.Empty, @"Programs\Python\Python310\Scripts\uv.exe"), + Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) ?? string.Empty, @"Python\Python313\Scripts\uv.exe"), + Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) ?? string.Empty, @"Python\Python312\Scripts\uv.exe"), + Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) ?? string.Empty, @"Python\Python311\Scripts\uv.exe"), + Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) ?? string.Empty, @"Python\Python310\Scripts\uv.exe"), + // Program Files style installs (if a native installer was used) + Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles) ?? string.Empty, @"uv\uv.exe"), + // Try simple name resolution later via PATH + "uv.exe", + "uv" + }; + } + else + { + candidates = new[] + { + "/opt/homebrew/bin/uv", + "/usr/local/bin/uv", + "/usr/bin/uv", + "/opt/local/bin/uv", + Path.Combine(home, ".local", "bin", "uv"), + "/opt/homebrew/opt/uv/bin/uv", + // Framework Python installs + "/Library/Frameworks/Python.framework/Versions/3.13/bin/uv", + "/Library/Frameworks/Python.framework/Versions/3.12/bin/uv", + // Fallback to PATH resolution by name + "uv" + }; + } + foreach (string c in candidates) { try { - if (ValidateUvBinary(c)) return c; + if (File.Exists(c) && ValidateUvBinary(c)) return c; } catch { /* ignore */ } } - // Try which uv (explicit path) + // Use platform-appropriate which/where to resolve from PATH try { - var whichPsi = new System.Diagnostics.ProcessStartInfo + if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) { - FileName = "/usr/bin/which", - Arguments = "uv", - UseShellExecute = false, - RedirectStandardOutput = true, - RedirectStandardError = true, - CreateNoWindow = true - }; - using var wp = System.Diagnostics.Process.Start(whichPsi); - string output = wp.StandardOutput.ReadToEnd().Trim(); - wp.WaitForExit(3000); - if (wp.ExitCode == 0 && !string.IsNullOrEmpty(output) && File.Exists(output)) + var wherePsi = new System.Diagnostics.ProcessStartInfo + { + FileName = "where", + Arguments = "uv.exe", + UseShellExecute = false, + RedirectStandardOutput = true, + RedirectStandardError = true, + CreateNoWindow = true + }; + using var wp = System.Diagnostics.Process.Start(wherePsi); + string output = wp.StandardOutput.ReadToEnd().Trim(); + wp.WaitForExit(3000); + if (wp.ExitCode == 0 && !string.IsNullOrEmpty(output)) + { + foreach (var line in output.Split(new[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries)) + { + string path = line.Trim(); + if (File.Exists(path) && ValidateUvBinary(path)) return path; + } + } + } + else { - if (ValidateUvBinary(output)) return output; + var whichPsi = new System.Diagnostics.ProcessStartInfo + { + FileName = "/usr/bin/which", + Arguments = "uv", + UseShellExecute = false, + RedirectStandardOutput = true, + RedirectStandardError = true, + CreateNoWindow = true + }; + using var wp = System.Diagnostics.Process.Start(whichPsi); + string output = wp.StandardOutput.ReadToEnd().Trim(); + wp.WaitForExit(3000); + if (wp.ExitCode == 0 && !string.IsNullOrEmpty(output) && File.Exists(output)) + { + if (ValidateUvBinary(output)) return output; + } } } catch { } @@ -359,8 +412,11 @@ namespace UnityMcpBridge.Editor.Helpers { try { - string candidate = Path.Combine(part, "uv"); - if (File.Exists(candidate) && ValidateUvBinary(candidate)) return candidate; + // Check both uv and uv.exe + string candidateUv = Path.Combine(part, "uv"); + string candidateUvExe = Path.Combine(part, "uv.exe"); + if (File.Exists(candidateUv) && ValidateUvBinary(candidateUv)) return candidateUv; + if (File.Exists(candidateUvExe) && ValidateUvBinary(candidateUvExe)) return candidateUvExe; } catch { } } diff --git a/UnityMcpBridge/Editor/Windows/UnityMcpEditorWindow.cs b/UnityMcpBridge/Editor/Windows/UnityMcpEditorWindow.cs index 408a63b..f85aa6f 100644 --- a/UnityMcpBridge/Editor/Windows/UnityMcpEditorWindow.cs +++ b/UnityMcpBridge/Editor/Windows/UnityMcpEditorWindow.cs @@ -1990,37 +1990,91 @@ namespace UnityMcpBridge.Editor.Windows { try { - // Common absolute paths - string home = Environment.GetFolderPath(Environment.SpecialFolder.UserProfile) ?? string.Empty; - string[] candidates = + // Windows-specific Python detection + if (Application.platform == RuntimePlatform.WindowsEditor) { - "/opt/homebrew/bin/python3", - "/usr/local/bin/python3", - "/usr/bin/python3", - "/opt/local/bin/python3", - Path.Combine(home, ".local", "bin", "python3"), - "/Library/Frameworks/Python.framework/Versions/3.13/bin/python3", - "/Library/Frameworks/Python.framework/Versions/3.12/bin/python3", - }; - foreach (string c in candidates) - { - if (File.Exists(c)) return true; - } + // Common Windows Python installation paths + string[] windowsCandidates = + { + @"C:\Python313\python.exe", + @"C:\Python312\python.exe", + @"C:\Python311\python.exe", + @"C:\Python310\python.exe", + @"C:\Python39\python.exe", + Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), @"Programs\Python\Python313\python.exe"), + Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), @"Programs\Python\Python312\python.exe"), + Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), @"Programs\Python\Python311\python.exe"), + Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), @"Programs\Python\Python310\python.exe"), + Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), @"Programs\Python\Python39\python.exe"), + Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles), @"Python313\python.exe"), + Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles), @"Python312\python.exe"), + Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles), @"Python311\python.exe"), + Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles), @"Python310\python.exe"), + Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles), @"Python39\python.exe"), + }; + + foreach (string c in windowsCandidates) + { + if (File.Exists(c)) return true; + } - // Try 'which python3' - var psi = new ProcessStartInfo + // Try 'where python' command (Windows equivalent of 'which') + var psi = new ProcessStartInfo + { + FileName = "where", + Arguments = "python", + UseShellExecute = false, + RedirectStandardOutput = true, + RedirectStandardError = true, + CreateNoWindow = true + }; + using var p = Process.Start(psi); + string outp = p.StandardOutput.ReadToEnd().Trim(); + p.WaitForExit(2000); + if (p.ExitCode == 0 && !string.IsNullOrEmpty(outp)) + { + string[] lines = outp.Split('\n'); + foreach (string line in lines) + { + string trimmed = line.Trim(); + if (File.Exists(trimmed)) return true; + } + } + } + else { - FileName = "/usr/bin/which", - Arguments = "python3", - UseShellExecute = false, - RedirectStandardOutput = true, - RedirectStandardError = true, - CreateNoWindow = true - }; - using var p = Process.Start(psi); - string outp = p.StandardOutput.ReadToEnd().Trim(); - p.WaitForExit(2000); - if (p.ExitCode == 0 && !string.IsNullOrEmpty(outp) && File.Exists(outp)) return true; + // macOS/Linux detection (existing code) + string home = Environment.GetFolderPath(Environment.SpecialFolder.UserProfile) ?? string.Empty; + string[] candidates = + { + "/opt/homebrew/bin/python3", + "/usr/local/bin/python3", + "/usr/bin/python3", + "/opt/local/bin/python3", + Path.Combine(home, ".local", "bin", "python3"), + "/Library/Frameworks/Python.framework/Versions/3.13/bin/python3", + "/Library/Frameworks/Python.framework/Versions/3.12/bin/python3", + }; + foreach (string c in candidates) + { + if (File.Exists(c)) return true; + } + + // Try 'which python3' + var psi = new ProcessStartInfo + { + FileName = "/usr/bin/which", + Arguments = "python3", + UseShellExecute = false, + RedirectStandardOutput = true, + RedirectStandardError = true, + CreateNoWindow = true + }; + using var p = Process.Start(psi); + string outp = p.StandardOutput.ReadToEnd().Trim(); + p.WaitForExit(2000); + if (p.ExitCode == 0 && !string.IsNullOrEmpty(outp) && File.Exists(outp)) return true; + } } catch { } return false; diff --git a/UnityMcpBridge/package.json b/UnityMcpBridge/package.json index d1ee008..8471710 100644 --- a/UnityMcpBridge/package.json +++ b/UnityMcpBridge/package.json @@ -1,4 +1,5 @@ { +<<<<<<< HEAD "name": "com.justinpbarnett.unity-mcp", "version": "2.0.0", "displayName": "Unity MCP Bridge", @@ -6,5 +7,30 @@ "unity": "2020.3", "dependencies": { "com.unity.nuget.newtonsoft-json": "3.0.2" +======= + "name": "com.coplaydev.unity-mcp", + "version": "1.0.0", + "displayName": "Unity MCP Bridge", + "description": "A bridge that manages and communicates with the sister application, Unity MCP Server, which allows for communications with MCP Clients like Claude Desktop or Cursor.", + "unity": "2020.3", + "documentationUrl": "https://github.com/CoplayDev/unity-mcp", + "licensesUrl": "https://github.com/CoplayDev/unity-mcp/blob/main/LICENSE", + "dependencies": { + "com.unity.nuget.newtonsoft-json": "3.0.2" + }, + "keywords": [ + "unity", + "ai", + "llm", + "mcp", + "model-context-protocol", + "mcp-server", + "mcp-client" + ], + "author": { + "name": "CoplayDev", + "email": "support@coplay.dev", + "url": "https://coplay.dev" +>>>>>>> upstream/main } } diff --git a/UnityMcpServer/src/.python-version b/UnityMcpServer/src/.python-version new file mode 100644 index 0000000..e4fba21 --- /dev/null +++ b/UnityMcpServer/src/.python-version @@ -0,0 +1 @@ +3.12 diff --git a/deploy-dev.bat b/deploy-dev.bat index 4cc61de..6a83fcf 100644 --- a/deploy-dev.bat +++ b/deploy-dev.bat @@ -19,7 +19,7 @@ echo. :: Package cache location echo Unity Package Cache Location: -echo Example: X:\UnityProject\Library\PackageCache\com.justinpbarnett.unity-mcp@1.0.0 +echo Example: X:\UnityProject\Library\PackageCache\com.coplaydev.unity-mcp@1.0.0 set /p "PACKAGE_CACHE_PATH=Enter Unity package cache path: " if "%PACKAGE_CACHE_PATH%"=="" ( diff --git a/logo.png b/logo.png new file mode 100644 index 0000000..9472a36 Binary files /dev/null and b/logo.png differ diff --git a/restore-dev.bat b/restore-dev.bat index a8e327a..69d9312 100644 --- a/restore-dev.bat +++ b/restore-dev.bat @@ -16,7 +16,7 @@ echo. :: Package cache location echo Unity Package Cache Location: -echo Example: X:\UnityProject\Library\PackageCache\com.justinpbarnett.unity-mcp@1.0.0 +echo Example: X:\UnityProject\Library\PackageCache\com.coplaydev.unity-mcp@1.0.0 set /p "PACKAGE_CACHE_PATH=Enter Unity package cache path: " if "%PACKAGE_CACHE_PATH%"=="" (