How Unity MCP Implements TCP/IP Communication with TypeScript MCP Servers

The Unity-MCP package establishes a persistent TCP connection to a companion TypeScript MCP server, using a lightweight newline-delimited JSON protocol over a socket with automatic reconnection, UDP discovery, and thread-safe dispatch to Unity's main thread.

The unitymcp repository provides a bridge between the Unity Editor and Model Context Protocol (MCP) servers written in TypeScript. Understanding how this C# client manages TCP/IP communication between Unity and TypeScript MCP server implementations is essential for building reliable editor extensions that require live command execution and resource fetching.

UDP Server Discovery and TCP Connection Establishment

The communication workflow begins with optional discovery via UDP broadcast. In jp.shiranui-isuzu.unity-mcp/Editor/Core/McpServer.cs, the client initializes a UDP listener on port 27183 (defined in McpSettings as broadcastPort). When a TypeScript MCP server broadcasts a mcp_server_announce message, the listener extracts the host and port, updates the internal configuration, and immediately invokes TryConnect() to establish the TCP link.

The TryConnect() method (lines 58-70) creates a new TcpClient, initiates an asynchronous connection with a 5-second timeout, and upon success stores the socket reference, raises the Connected event, and transmits a registration packet via SendClientRegistration(). This packet contains the client ID and basic Unity project metadata, identifying the editor instance to the MCP server.

JSON Message Protocol and Request Routing

Once connected, a background thread RunClient continuously polls the socket for incoming data. The ProcessIncomingData() method (lines 85-92) reads the byte stream into a buffer, converts bytes to a UTF-8 string, and forwards the content to ProcessData() for parsing.

The protocol expects newline-delimited JSON objects. Each incoming message must contain a "type" field that determines routing logic:

  • Resource requests ("type": "resource") are delegated to registered IMcpResourceHandler implementations via ProcessResourceRequest
  • Command requests are dispatched to matching IMcpCommandHandler implementations via ExecuteCommand

Both handlers are resolved based on command prefixes and action names extracted from the JSON payload.

Thread Safety and Main Thread Execution

Unity API calls are not thread-safe, so the MCP server must marshal all handler execution to Unity's main thread. In McpServer.cs (lines 87-95 and 124-132), both ProcessResourceRequest and ExecuteCommand wrap their logic in ExecuteOnMainThread delegates.

This ensures that when a TypeScript MCP server requests scene modifications, asset imports, or GameObject manipulations, the actual execution occurs on Unity's main thread while the background TCP thread remains responsive. After processing completes, the server serializes the response object to JSON, appends a newline delimiter, and writes it directly to the TCP stream via stream.Write.

Automatic Reconnection with Exponential Backoff

The TCP client includes robust reconnection logic for handling network instability. If TryConnect() fails or the connection drops, the system triggers exponential back-off using the currentReconnectDelay field (lines 36-44 and 92-99).

The client repeatedly attempts reconnection at increasing intervals until the TCP link is restored. This ensures that temporary network interruptions or server restarts do not require manual intervention in the Unity Editor—the client automatically recovers and re-registers with the MCP server.

Practical Implementation Examples

Establishing the Client Connection

Normally initialized automatically by McpEditorInitializer, you can also manage the server manually:

var server = new McpServer();   // Reads host/port from McpSettings
server.Start();                // Launches UDP listener and TCP client thread

Sending a Custom Command from Unity

Construct a JSON command matching a registered handler prefix:

var command = new JObject
{
    ["type"] = "command",
    ["command"] = "unity.log",
    ["params"] = new JObject { ["message"] = "Hello from Unity!" },
    ["id"] = Guid.NewGuid().ToString()
};

var bytes = Encoding.UTF8.GetBytes(command.ToString(Formatting.None) + "\n");
server.GetTcpClient().GetStream().Write(bytes, 0, bytes.Length);

Receiving Command Responses

Subscribe to execution events to handle responses asynchronously:

server.CommandExecuted += (s, e) =>
{
    Debug.Log($"Command '{e.Prefix}.{e.Action}' finished with result: {e.Result}");
};

Registering a Custom Handler

Implement IMcpCommandHandler to expose Unity functionality to the MCP server:

public class MyLogHandler : IMcpCommandHandler
{
    public string CommandPrefix => "unity";
    public string Description => "Handles Unity-specific commands";

    public JObject Execute(string action, JObject parameters)
    {
        if (action == "log")
        {
            Debug.Log(parameters["message"]?.ToString());
            return new JObject { ["status"] = "success" };
        }
        return new JObject { ["status"] = "error", ["message"] = "Unknown action" };
    }
}

// Register during editor initialization:
server.RegisterHandler(new MyLogHandler());

Summary

  • Discovery: UDP broadcast on port 27183 enables automatic server detection, with TryConnect() establishing the TCP socket
  • Protocol: Newline-delimited JSON messages route to IMcpCommandHandler or IMcpResourceHandler based on the "type" field
  • Thread Safety: All Unity API interactions execute via ExecuteOnMainThread to prevent cross-thread access violations
  • Resilience: Exponential back-off reconnection logic maintains persistent connectivity without manual intervention
  • Key Files: McpServer.cs manages the socket, McpSettings.cs stores configuration, and handlers in Editor/Handlers/ implement the business logic

Frequently Asked Questions

What port does Unity MCP use for TCP communication?

The TCP port is configurable via McpSettings.cs and typically discovered through UDP broadcast on port 27183. If UDP discovery is disabled, the client falls back to manually configured host/port combinations stored in Unity Editor preferences.

How does the MCP server handle Unity API thread safety?

All incoming commands and resource requests are queued to Unity's main thread using ExecuteOnMainThread before invoking handler methods. This ensures that IMcpCommandHandler implementations can safely manipulate GameObjects, assets, and scene data without causing Unity thread errors.

What happens if the TypeScript MCP server disconnects unexpectedly?

The McpServer class implements automatic reconnection with exponential back-off. When the connection drops, the client enters a retry loop that increases the delay between attempts (currentReconnectDelay) until the TCP connection is re-established and the client re-registers automatically.

Can I send custom commands from Unity to the TypeScript server?

Yes. While the typical flow involves the TypeScript server sending commands to Unity, you can write JSON payloads directly to the TCP stream obtained via server.GetTcpClient().GetStream(). Ensure you terminate each JSON object with a newline character to comply with the protocol delimiter expected by the TypeScript server.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →