using UnityEngine;
using UnityEditor;
using System;
using System.IO;
using System.Net;
using System.Text;
using System.Threading;
namespace unity-mcp
{
/// <summary>
/// HTTP server running in Unity Editor to receive MCP commands
/// Enables AI assistants to control Unity Editor via REST API
/// </summary>
[InitializeOnLoad]
public class MCPEditorServer
{
private static HttpListener listener;
private static Thread serverThread;
private static bool isRunning = false;
private static bool isStarting = false;
private static MCPConfig config;
static MCPEditorServer()
{
config = MCPConfig.GetOrCreate();
EditorApplication.update += Initialize;
}
private static void Initialize()
{
EditorApplication.update -= Initialize;
if (!isRunning && config.autoStart)
{
StartServer();
}
}
/// <summary>
/// Get the HTTP listener instance
/// </summary>
public static HttpListener GetListener()
{
return listener;
}
/// <summary>
/// Check if server is currently starting
/// </summary>
public static bool IsStarting()
{
return isStarting;
}
[MenuItem("Tools/Unity MCP/Start Server")]
public static void StartServer()
{
if (isRunning || isStarting) return;
isStarting = true;
try
{
if (config == null)
{
config = MCPConfig.GetOrCreate();
}
listener = new HttpListener();
string prefix = config.allowRemoteConnections
? $"http://+:{config.port}/"
: $"http://localhost:{config.port}/";
listener.Prefixes.Add(prefix);
listener.Start();
isRunning = true;
isStarting = false;
serverThread = new Thread(HandleRequests);
serverThread.Start();
Debug.Log($"[Unity MCP] Server started on port {config.port}");
if (config.verboseLogging)
{
Debug.Log($"[Unity MCP] Remote connections: {config.allowRemoteConnections}");
Debug.Log($"[Unity MCP] Request timeout: {config.requestTimeout}s");
}
}
catch (Exception e)
{
isStarting = false;
Debug.LogError($"[Unity MCP] Failed to start server: {e.Message}");
}
}
[MenuItem("Tools/Unity MCP/Stop Server")]
public static void StopServer()
{
if (!isRunning) return;
isRunning = false;
listener?.Stop();
listener?.Close();
serverThread?.Abort();
Debug.Log("[Unity MCP] Server stopped");
}
private static void HandleRequests()
{
while (isRunning)
{
try
{
var context = listener.GetContext();
ThreadPool.QueueUserWorkItem(_ => ProcessRequest(context));
}
catch (Exception e)
{
if (isRunning)
{
Debug.LogError($"[Unity MCP] Request handling error: {e.Message}");
}
}
}
}
private static void ProcessRequest(HttpListenerContext context)
{
try
{
var request = context.Request;
var response = context.Response;
// Enable CORS
response.AddHeader("Access-Control-Allow-Origin", "*");
response.AddHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS");
response.AddHeader("Access-Control-Allow-Headers", "Content-Type");
if (request.HttpMethod == "OPTIONS")
{
response.StatusCode = 200;
response.Close();
return;
}
string requestBody = "";
if (request.HasEntityBody)
{
using (var reader = new StreamReader(request.InputStream, request.ContentEncoding))
{
requestBody = reader.ReadToEnd();
}
}
string responseString = "";
response.StatusCode = 200;
// Route to appropriate handler
string path = request.Url.AbsolutePath;
if (path.StartsWith("/editor/"))
{
responseString = EditorCommandHandler.HandleCommand(path, requestBody);
}
else if (path.StartsWith("/playmode/"))
{
responseString = PlayModeHandler.HandleCommand(path, requestBody);
}
else if (path.StartsWith("/scene/"))
{
responseString = SceneHandler.HandleCommand(path, requestBody);
}
else if (path.StartsWith("/console/") || path.StartsWith("/asset/") || path.StartsWith("/project/"))
{
responseString = AssetHandler.HandleCommand(path, requestBody, request.Url.Query);
}
else if (path.StartsWith("/advanced/"))
{
responseString = AdvancedToolsHandler.HandleCommand(path, requestBody);
}
else if (path == "/health")
{
responseString = "{\"status\":\"ok\",\"version\":\"1.0.0\"}";
}
else
{
response.StatusCode = 404;
responseString = "{\"error\":\"Endpoint not found\"}";
}
byte[] buffer = Encoding.UTF8.GetBytes(responseString);
response.ContentType = "application/json";
response.ContentLength64 = buffer.Length;
response.OutputStream.Write(buffer, 0, buffer.Length);
response.Close();
}
catch (Exception e)
{
Debug.LogError($"[Unity MCP] Request processing error: {e.Message}");
}
}
}
}