Skip to main content
Glama
UnityMcpServer.cs5.75 kB
using System; using System.Collections.Generic; using System.Net; using System.Net.Sockets; using System.Text; using System.Threading; using UnityEngine; namespace LocalMcp.UnityServer { /// <summary> /// WebSocket server that runs inside Unity Editor and accepts MCP (Model Context Protocol) connections. /// Listens on ws://localhost:5050 by default. /// </summary> public class UnityMcpServer { private TcpListener tcpListener; private Thread listenerThread; private bool isRunning = false; private int port = 5050; private List<McpSession> activeSessions = new List<McpSession>(); /// <summary> /// Singleton instance of the MCP server. /// </summary> public static UnityMcpServer Instance { get; private set; } /// <summary> /// Gets whether the server is currently running. /// </summary> public bool IsRunning => isRunning; public UnityMcpServer() { Instance = this; } /// <summary> /// Starts the WebSocket server on the specified port. /// </summary> /// <param name="serverPort">Port number to listen on (default: 5050)</param> public void StartServer(int serverPort = 5050) { if (isRunning) { Debug.LogWarning("[MCP] Server is already running"); return; } port = serverPort; isRunning = true; listenerThread = new Thread(ServerLoop); listenerThread.IsBackground = true; listenerThread.Start(); Debug.Log($"[MCP] Server started on ws://localhost:{port}"); } /// <summary> /// Stops the WebSocket server and closes all active connections. /// </summary> public void StopServer() { if (!isRunning) { return; } isRunning = false; // Close all active sessions lock (activeSessions) { foreach (var session in activeSessions) { session.Close(); } activeSessions.Clear(); } // Stop the TCP listener if (tcpListener != null) { tcpListener.Stop(); tcpListener = null; } // Wait for listener thread to finish if (listenerThread != null && listenerThread.IsAlive) { listenerThread.Join(1000); listenerThread = null; } Debug.Log("[MCP] Server stopped"); } private void ServerLoop() { try { tcpListener = new TcpListener(IPAddress.Loopback, port); tcpListener.Start(); Debug.Log($"[MCP] Server listening on port {port}"); while (isRunning) { if (tcpListener.Pending()) { TcpClient client = tcpListener.AcceptTcpClient(); Debug.Log("[MCP] Client connected"); // Handle the client in a new session McpSession session = new McpSession(client); lock (activeSessions) { activeSessions.Add(session); } Thread sessionThread = new Thread(session.HandleClient); sessionThread.IsBackground = true; sessionThread.Start(); } else { Thread.Sleep(100); } } } catch (ThreadAbortException) { // Silently handle thread abort during domain reload // This is expected when Unity recompiles scripts Thread.ResetAbort(); } catch (Exception e) { // Only log unexpected errors if (isRunning) { Debug.LogError($"[MCP] Server error: {e.Message}"); } } } /// <summary> /// Removes a session from the active sessions list. /// </summary> /// <param name="session">The session to remove</param> internal void RemoveSession(McpSession session) { lock (activeSessions) { activeSessions.Remove(session); } Debug.Log($"[MCP] Session removed. Active sessions: {activeSessions.Count}"); } /// <summary> /// Gets the number of active connections. /// </summary> public int GetActiveConnectionCount() { lock (activeSessions) { return activeSessions.Count; } } /// <summary> /// Broadcasts a message to all connected clients. /// </summary> /// <param name="message">The message to broadcast</param> public void BroadcastMessage(string message) { lock (activeSessions) { foreach (var session in activeSessions) { session.SendMessage(message); } } } /// <summary> /// Cleanup method to be called when shutting down. /// </summary> public void Cleanup() { StopServer(); } } }

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