# How Unity MCP Architecture Works: A Deep Dive into the C#-TypeScript Bridge

> Explore the Unity MCP architecture, a C#-TypeScript bridge. Discover how the Unity Editor and TypeScript process communicate via JSON-RPC for AI assistant integration and command execution.

- Repository: [いすず/unitymcp](https://github.com/isuzu-shiranui/unitymcp)
- Tags: deep-dive
- Published: 2026-03-04

---

**Unity MCP architecture consists of a bidirectional bridge where the Unity Editor (C#) acts as a TCP client that auto-discovers handler implementations via reflection, while a TypeScript process runs the MCP server and adapts Unity capabilities to the Model-Context-Protocol SDK, enabling AI assistants to execute editor commands, fetch project resources, and process prompts via JSON-RPC.**

The Unity MCP architecture in the `isuzu-shiranui/unitymcp` repository establishes a lightweight, extensible integration pattern that exposes Unity Editor functionality to external AI models. Rather than embedding the MCP server inside Unity, the architecture splits responsibilities: Unity handles network plumbing and main-thread marshaling, while TypeScript implements the actual MCP protocol surface using the official SDK.

## Core Components of the Unity MCP Architecture

The architecture is split into two tightly coupled runtimes that communicate over a persistent TCP connection.

### C# Side: Unity Editor Infrastructure

The Unity side provides the **transport layer**, **service management**, and **reflection-based discovery** mechanisms:

- **McpServer** – A background-thread TCP client that manages the connection to the TypeScript MCP server, handles JSON-RPC message routing, UDP discovery, and automatic reconnection. It maintains dictionaries of `commandHandlers` and `resourceHandlers` for routing incoming requests.
- **McpHandlerDiscovery<T>** – Uses reflection to scan loaded assemblies (excluding Unity/System assemblies) and instantiates every concrete type implementing `IMcpCommandHandler` or `IMcpResourceHandler` via `Activator.CreateInstance`.
- **McpServiceManager** – A simple dependency-injection container that stores the singleton `McpServer` instance and other shared services.
- **McpSettings** – A `ScriptableSingleton` persisted in Unity preferences that stores connection parameters (host, port, auto-start flags, UDP discovery settings).
- **McpEditorInitializer** – An `[InitializeOnLoad]` entry point that wires up `EditorApplication.delayCall` to create the server instance and optionally start it when the editor loads.

### TypeScript Side: MCP Protocol Adapter

The TypeScript side implements the **protocol semantics** using the `@modelcontextprotocol/sdk`:

- **HandlerAdapter** – Bridges C#-style handler contracts to the MCP SDK by registering tools with `server.tool()`, resources with `server.resource()`, and prompts with `server.prompt()`.
- **ICommandHandler / IResourceHandler / IPromptHandler** – Interface contracts defined in `unity-mcp-ts/src/core/interfaces` that TypeScript implementations must satisfy.

## How the Unity MCP Architecture Handles Communication

The data flow follows a strict initialization and runtime pattern designed to keep Unity's main thread responsive while allowing async AI interactions.

### Editor Initialization and Handler Discovery

When Unity starts, the static constructor in `McpEditorInitializer` attaches an `Initialize` method to `EditorApplication.delayCall`. This method constructs a `McpServer` using settings from `McpSettings` and registers it with `McpServiceManager`【/cache/repos/github.com/isuzu-shiranui/unitymcp/main/jp.shiranui-isuzu.unity-mcp/Editor/Core/McpEditorInitializer.cs#L27-L34】.

Immediately after server creation, two instances of `McpHandlerDiscovery<T>` execute:

1. `McpHandlerDiscovery<IMcpCommandHandler>` scans assemblies for command handlers.
2. `McpHandlerDiscovery<IMcpResourceHandler>` scans for resource handlers.

Each discovery walker ignores Unity and System assemblies, then uses `Activator.CreateInstance` to instantiate found types【/cache/repos/github.com/isuzu-shiranui/unitymcp/main/jp.shiranui-isuzu.unity-mcp/Editor/Core/McpHandlerDiscovery.cs#L24-L72】. Discovered handlers are passed to `McpServer.RegisterHandler` (commands) or `RegisterResourceHandler` (resources), which store them in internal dictionaries keyed by command prefix or URI template.

If `McpSettings.autoStartOnLaunch` is enabled, the server begins its connection loop immediately. Additionally, the initializer subscribes to `EditorApplication.playModeStateChanged` to restart the server when play mode changes, provided `autoRestartOnPlayModeChange` is set【/cache/repos/github.com/isuzu-shiranui/unitymcp/main/jp.shiranui-isuzu.unity-mcp/Editor/Core/McpEditorInitializer.cs#L48-L84】.

### TCP Client Loop and Request Routing

The `McpServer` runs its connection logic on a background thread. Upon successful TCP connection to the configured host/port, it sends a **registration** message containing the client ID, Unity version, product name, and project hash【/cache/repos/github.com/isuzu-shiranui/unitymcp/main/jp.shiranui-isuzu.unity-mcp/Editor/Core/McpServer.cs#L94-L106】.

Incoming JSON-RPC messages are deserialized and routed based on type:

- **Commands**: Routed to `ExecuteCommand`, which looks up the handler by prefix in `commandHandlers`, queues execution on the main thread via `mainThreadQueue`, waits up to **5 seconds**, and returns a JSON response.
- **Resources**: Routed to `ProcessResourceRequest`, which invokes `FetchResourceData` to call the matching handler's `FetchResource` method, also main-thread marshaled.

All main-thread work is synchronized through `ExecuteOnMainThread`, ensuring thread-safe access to Unity APIs.

### UDP Discovery Mechanism

When UDP discovery is enabled, `McpServer` opens a `UdpClient` listening on `settings.udpDiscoveryPort`. It parses broadcast packets formatted as `"type":"mcp_server_announce"` from the TypeScript server. Upon receipt, it dynamically updates the `host`/`port` configuration and triggers an immediate reconnection attempt【/cache/repos/github.com/isuzu-shiranui/unitymcp/main/jp.shiranui-isuzu.unity-mcp/Editor/Core/McpServer.cs#L165-L176】.

### TypeScript Handler Adapter Registration

On the TypeScript side, the `HandlerAdapter` class consumes the connection and registers capabilities with the MCP SDK:

- **Commands**: Iterates over `handler.getToolDefinitions()` and registers each with `server.tool()`, forwarding calls back to C# via the TCP bridge.

- **Resources**: Checks if the URI template contains parameters. If so, registers a dynamic **resource template** using `new ResourceTemplate()`; otherwise registers a static string URI. The callback invokes `handler.fetchResource(uri)`.
- **Prompts**: Registers prompt definitions with `server.prompt()`, constructing chat-style message payloads for the model.

The adapter logs registration events to `console.error('[INFO] Registered …')` for debugging visibility.

## Implementing Custom Handlers in Unity MCP

Creating new capabilities requires only implementing the correct C# interface; no manual registration code is necessary.

### Creating a Command Handler

```csharp
using UnityEngine;
using UnityMCP.Editor.Core;
using Newtonsoft.Json.Linq;

public class HelloWorldCommandHandler : IMcpCommandHandler
{
    public string CommandPrefix => "hello";
    public string Description => "Simple hello-world command.";

    public ICommandResult Execute(string action, JObject parameters)
    {
        if (action == "say")
        {
            var name = parameters?["name"]?.ToString() ?? "World";
            return new CommandResult
            {
                Success = true,
                Result = JObject.FromObject(new { message = $"Hello, {name}!" })
            };
        }
        return new CommandResult { Success = false, Error = "Unknown action" };
    }
}

```

When Unity loads, `McpHandlerDiscovery<IMcpCommandHandler>` automatically instantiates and registers this handler. External clients can then invoke `hello.say` via the MCP protocol.

### Creating a Resource Handler

```csharp
using UnityEngine;
using UnityMCP.Editor.Core;
using Newtonsoft.Json.Linq;
using System.Linq;

public class SceneListResourceHandler : IMcpResourceHandler
{
    public string ResourceName => "scenes";
    public string ResourceUri => "unity://scenes";

    public JObject FetchResource(string uri, JObject parameters)
    {
        var scenes = UnityEngine.SceneManagement.SceneManager.GetAllScenes()
                     .Select(s => s.name)
                     .ToArray();

        return JObject.FromObject(new { scenes });
    }
}

```

Resource handlers allow AI models to query the Unity project state (like open scenes or asset lists) without executing commands.

### Consuming from TypeScript

The TypeScript client requires no knowledge of the C# implementation:

```typescript
import { McpClient } from '@modelcontextprotocol/sdk/client/mcp';

async function sayHello(client: McpClient, name: string) {
  const response = await client.callTool('hello.say', { name });
  console.log(response.result?.message); // → "Hello, Alice!"
}

```

## Summary

The Unity MCP architecture decouples the Unity Editor from AI model integration through a clean separation of concerns:

- **Auto-discovery**: The `McpHandlerDiscovery` class eliminates boilerplate by reflecting over assemblies to find `IMcpCommandHandler` and `IMcpResourceHandler` implementations.
- **Thread safety**: All Unity API interactions are marshaled to the main thread via `McpServer.ExecuteOnMainThread`, preventing cross-thread exceptions.
- **Dynamic configuration**: `McpSettings` provides persistent user preferences for network configuration, while UDP discovery allows zero-config setup.
- **Protocol abstraction**: TypeScript handlers implement business logic against standard MCP interfaces, making the system portable across different AI backends.

Key source files defining this architecture include [`Editor/Core/McpServer.cs`](https://github.com/isuzu-shiranui/unitymcp/blob/main/Editor/Core/McpServer.cs) for network logic, [`Editor/Core/McpHandlerDiscovery.cs`](https://github.com/isuzu-shiranui/unitymcp/blob/main/Editor/Core/McpHandlerDiscovery.cs) for reflection-based registration, and [`unity-mcp-ts/src/core/HandlerAdapter.ts`](https://github.com/isuzu-shiranui/unitymcp/blob/main/unity-mcp-ts/src/core/HandlerAdapter.ts) for SDK adaptation.

## Frequently Asked Questions

### What role does McpEditorInitializer play in the Unity MCP architecture?

`McpEditorInitializer` serves as the entry point marked with `[InitializeOnLoad]`, ensuring the MCP server starts automatically when the Unity Editor opens. It creates the `McpServer` singleton, triggers handler discovery, and manages play-mode lifecycle events such as auto-restarting the connection when entering or exiting play mode【/cache/repos/github.com/isuzu-shiranui/unitymcp/main/jp.shiranui-isuzu.unity-mcp/Editor/Core/McpEditorInitializer.cs】.

### How does the architecture handle automatic handler discovery?

The architecture uses generic `McpHandlerDiscovery<T>` classes that scan all loaded assemblies (excluding Unity and System libraries) for concrete implementations of `IMcpCommandHandler` or `IMcpResourceHandler`. It instantiates each found type using `Activator.CreateInstance` and immediately registers the instance with the active `McpServer`, requiring no manual wiring or configuration files【/cache/repos/github.com/isuzu-shiranui/unitymcp/main/jp.shiranui-isuzu.unity-mcp/Editor/Core/McpHandlerDiscovery.cs#L24-L72】.

### What transport protocol does Unity MCP use for communication?

Unity MCP uses **TCP sockets** for primary communication, sending **JSON-RPC 2.0** messages between the C# client and TypeScript server. Additionally, it supports **UDP discovery** on a configurable port (default defined in `McpSettings`) to allow the TypeScript server to broadcast its availability and enable automatic reconnection without manual IP configuration【/cache/repos/github.com/isuzu-shiranui/unitymcp/main/jp.shiranui-isuzu.unity-mcp/Editor/Core/McpServer.cs#L165-L176】.

### How are Unity main-thread operations handled in the architecture?

All handler invocations that require Unity API access are queued to a `mainThreadQueue` managed by `McpServer`. The background TCP thread adds work items via `ExecuteOnMainThread`, then blocks waiting for completion (with a 5-second timeout). This pattern ensures that scene manipulation, asset loading, and other Unity-specific operations occur safely on the main thread while the server remains responsive to network events.