Skip to main content
Glama
McpEditorServerLauncher.cs10.3 kB
using System; using UnityEditor; using UnityEngine; namespace LocalMcp.UnityServer { /// <summary> /// Automatically launches the MCP Server when Unity Editor starts. /// </summary> [InitializeOnLoad] public static class McpEditorServerLauncher { private static UnityMcpServer wsServer; private static UnityMcpHttpServer httpServer; private static int actualWsPort; private static int actualHttpPort; static McpEditorServerLauncher() { EditorApplication.delayCall += LaunchServer; EditorApplication.quitting += StopServer; // Restart server after assembly reload (compilation) UnityEditor.Compilation.CompilationPipeline.assemblyCompilationFinished += OnAssemblyCompilationFinished; } private static void OnAssemblyCompilationFinished(string assemblyPath, UnityEditor.Compilation.CompilerMessage[] messages) { // Check if it's our MCP server assembly if (assemblyPath.Contains("LocalMcp.UnityServer.Editor")) { Debug.Log("[MCP] MCP Server assembly recompiled, restarting server..."); EditorApplication.delayCall += () => { StopServer(); System.Threading.Thread.Sleep(500); // Brief delay to ensure cleanup LaunchServer(); }; } } private static void LaunchServer() { // Check if server is already running if (wsServer != null || httpServer != null) { return; } // UnityMainThreadDispatcher is automatically initialized via [InitializeOnLoadMethod] // No need to check Instance - it's a static class that auto-initializes // Initialize GlobalLogCapture (required for log history) // Singleton pattern ensures Instance is never null var logCapture = GlobalLogCapture.Instance; // Load configuration from .unity-mcp-config.json var config = McpServerConfig.Load(); // Allocate available ports with fallback try { (actualWsPort, actualHttpPort) = McpPortManager.AllocatePairedPorts( config.ports.websocket, config.ports.http ); } catch (Exception e) { Debug.LogError($"[MCP] Failed to allocate ports: {e.Message}"); return; } // Start WebSocket server (for direct WebSocket connections) wsServer = new UnityMcpServer(); wsServer.StartServer(actualWsPort); // Start HTTP server (for MCP protocol bridge) httpServer = new UnityMcpHttpServer(); httpServer.StartServer(actualHttpPort); // Save runtime configuration for mcp-bridge to discover SaveRuntimeConfig(config.projectName); Debug.Log("[MCP] Servers auto-started on Unity Editor launch"); Debug.Log($"[MCP] WebSocket: ws://localhost:{actualWsPort}"); Debug.Log($"[MCP] HTTP API: http://localhost:{actualHttpPort}"); } private static void SaveRuntimeConfig(string projectName) { var runtimeConfig = new McpRuntimeConfig { projectName = projectName, websocketPort = actualWsPort, httpPort = actualHttpPort, processId = System.Diagnostics.Process.GetCurrentProcess().Id, startTime = DateTime.Now.ToString("o"), unityVersion = Application.unityVersion }; McpRuntimeConfig.Save(runtimeConfig); } private static void StopServer() { if (wsServer != null) { wsServer.Cleanup(); wsServer = null; } if (httpServer != null) { httpServer.Cleanup(); httpServer = null; } // Delete runtime config file McpRuntimeConfig.Delete(); // Cleanup GlobalLogCapture GlobalLogCapture.Instance?.Cleanup(); } [MenuItem("MCP/Server/Start", false, 0)] private static void MenuStartServer() { if (wsServer == null && httpServer == null) { LaunchServer(); } else { Debug.LogWarning("[MCP] Server is already running"); } } [MenuItem("MCP/Server/Stop", false, 1)] private static void MenuStopServer() { if (wsServer != null || httpServer != null) { StopServer(); Debug.Log("[MCP] Server stopped manually"); } else { Debug.LogWarning("[MCP] Server is not running"); } } [MenuItem("MCP/Server/Status", false, 2)] private static void MenuServerStatus() { if (wsServer != null) { int connectionCount = wsServer.GetActiveConnectionCount(); Debug.Log($"[MCP] ✅ Server is RUNNING | Active connections: {connectionCount} | Ports: WS:{actualWsPort}, HTTP:{actualHttpPort}"); } else { Debug.Log("[MCP] ⚠️ Server is NOT RUNNING | Use 'MCP > Start Server' to start it"); } } [MenuItem("MCP/Package Version", false, 100)] private static void MenuPackageVersion() { string version = GetPackageVersion(); string message; if (!string.IsNullOrEmpty(version)) { message = $"Unity MCP Server\n\nCurrent Version: {version}\n\n" + "Repository: github.com/dsgarage/CC2UniMCP"; } else { message = "Unity MCP Server\n\nVersion information not available.\n\n" + "Repository: github.com/dsgarage/CC2UniMCP"; } EditorUtility.DisplayDialog("Package Version", message, "OK"); Debug.Log($"[MCP] Package Version: {version ?? "Unknown"}"); } [MenuItem("MCP/Update Package", false, 101)] private static void MenuUpdatePackage() { string currentVersion = GetPackageVersion(); string versionInfo = !string.IsNullOrEmpty(currentVersion) ? $"Current version: {currentVersion}\n\n" : ""; bool confirmed = EditorUtility.DisplayDialog( "Update Unity MCP Server", versionInfo + "This will update the Unity MCP Server package to the latest version from GitHub.\n\n" + "The update process will:\n" + "1. Fetch the latest version from the repository\n" + "2. Update the package via Package Manager\n" + "3. Restart the MCP Server automatically\n\n" + "Do you want to continue?", "Update", "Cancel" ); if (!confirmed) { Debug.Log("[MCP] Package update cancelled by user"); return; } Debug.Log("[MCP] Starting package update..."); Debug.Log($"[MCP] Current version: {currentVersion ?? "Unknown"}"); // Use PackageManager Client API to update the package // Explicitly specify #main to ensure we get the latest release branch UnityEditor.PackageManager.Client.Add("git@github.com:dsgarage/CC2UniMCP.git#main"); Debug.Log("[MCP] Package update requested. Unity will refresh when complete."); Debug.Log("[MCP] Check Package Manager window for update progress."); } /// <summary> /// Gets the current package version from package.json /// </summary> private static string GetPackageVersion() { try { // Use PackageInfo to get the correct package path var listRequest = UnityEditor.PackageManager.Client.List(true, false); // Wait for request to complete (synchronous for simplicity in menu) while (!listRequest.IsCompleted) { System.Threading.Thread.Sleep(10); } if (listRequest.Status == UnityEditor.PackageManager.StatusCode.Success) { foreach (var package in listRequest.Result) { if (package.name == "com.local.mcp.unityserver") { // Return version from PackageInfo return package.version; } } } // Fallback: try direct file path in multiple locations string[] possiblePaths = new[] { "Packages/com.local.mcp.unityserver/package.json", System.IO.Path.Combine(Application.dataPath, "../Packages/com.local.mcp.unityserver/package.json"), System.IO.Path.Combine(Application.dataPath, "../Library/PackageCache/com.local.mcp.unityserver/package.json") }; foreach (string path in possiblePaths) { if (System.IO.File.Exists(path)) { string json = System.IO.File.ReadAllText(path); var match = System.Text.RegularExpressions.Regex.Match(json, @"""version"":\s*""([^""]+)"""); if (match.Success) { return match.Groups[1].Value; } } } } catch (System.Exception e) { Debug.LogWarning($"[MCP] Failed to read package version: {e.Message}"); } return null; } } }

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/dsgarage/UniMCP4CC'

If you have feedback or need assistance with the MCP directory API, please join our Discord server