# UnityConnection Component in TypeScript MCP: Complete Networking Layer Guide

> Master the UnityConnection component in TypeScript MCP. This TCP server guide details client registration, request/response handling, and UDP auto-discovery for seamless Unity and TypeScript communication.

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

---

**The UnityConnection component is a singleton TCP server that manages bidirectional communication between TypeScript MCP handlers and Unity Editor instances, handling client registration, request/response correlation, and UDP auto-discovery.**

The `UnityConnection` class serves as the backbone of the networking stack in the `isuzu-shiranui/unitymcp` repository. Located in [`unity-mcp-ts/src/core/UnityConnection.ts`](https://github.com/isuzu-shiranui/unitymcp/blob/main/unity-mcp-ts/src/core/UnityConnection.ts), this component abstracts low-level socket operations to provide a reliable, promise-based API for higher-level MCP handlers.

## What Is the UnityConnection Component?

The UnityConnection is a **singleton** class that implements the server-side networking layer of the Model Context Protocol (MCP) implementation for Unity. It maintains a TCP server that listens for connections from one or more Unity Editor instances, manages the lifecycle of those connections, and correlates asynchronous requests with their corresponding responses.

Unlike standard HTTP-based MCP transports, this component uses **persistent TCP sockets** with newline-delimited JSON (NDJSON) messaging to enable real-time, bidirectional communication between the TypeScript MCP server and the Unity C# runtime.

## Key Features and Architecture

### Singleton Pattern Implementation

The component enforces a single instance across the application using a static getter:

```typescript
private static instance: UnityConnection | null = null;

public static getInstance(): UnityConnection {
  if (!UnityConnection.instance) {
    UnityConnection.instance = new UnityConnection();
  }
  return UnityConnection.instance;
}

```

This ensures that all MCP handlers—whether commands, resources, or prompts—share the same connection state and client registry.

### TCP Server and Client Management

The `start()` method in [`unity-mcp-ts/src/core/UnityConnection.ts`](https://github.com/isuzu-shiranui/unitymcp/blob/main/unity-mcp-ts/src/core/UnityConnection.ts) creates a TCP server using Node.js `net.createServer`. When a Unity client connects, the server:

1. Generates a temporary client ID for the socket
2. Adds the client to an internal `Map` of connected clients
3. Sets up data listeners for incoming messages
4. Automatically designates the first connected client as the **active client**

The `setActiveClient()` method allows runtime switching between multiple Unity instances, enabling workflows where you might target different editor windows or build targets.

### Request/Response Correlation

The component implements a **promise-based request system** with automatic ID correlation:

```typescript
public async sendRequest(request: any): Promise<any> {
  const id = ++this.requestIdCounter;
  const message = { ...request, id };
  
  return new Promise((resolve, reject) => {
    this.pendingRequests.set(id, { resolve, reject, timeout });
    this.activeClient?.write(JSON.stringify(message) + '\n');
  });
}

```

Each outgoing request receives a monotonically incrementing `id`. The component stores `resolve` and `reject` callbacks in a `pendingRequests` map. When a response arrives with a matching `id`, the promise is resolved. If no response arrives within **30 seconds**, the promise rejects with a timeout error.

### UDP Auto-Discovery

To eliminate manual configuration, the component supports UDP broadcast discovery. When `start()` is called, `sendInitialBroadcast()` creates a temporary UDP socket and broadcasts a JSON packet containing the server's host, port, and version:

```typescript
private sendInitialBroadcast(): void {
  const message = JSON.stringify({
    type: 'mcp_server_announce',
    host: this.host,
    port: this.port,
    version: '1.0.0'
  });
  
  // Broadcast to 255.255.255.255 on discovery port
}

```

Unity clients listening on the discovery port can automatically detect and connect to the MCP server without requiring users to input IP addresses or port numbers manually.

## Implementation Details

### Client Registration Protocol

When a Unity client first connects, it must send a registration message. The `handleRegistration()` method in [`unity-mcp-ts/src/core/UnityConnection.ts`](https://github.com/isuzu-shiranui/unitymcp/blob/main/unity-mcp-ts/src/core/UnityConnection.ts) processes this:

```typescript
private handleRegistration(client: Client, message: any): void {
  const oldId = client.id;
  const newId = message.clientId;
  
  // Update the client ID from temporary to persistent
  client.id = newId;
  this.clients.delete(oldId);
  this.clients.set(newId, client);
  
  this.emit('clientRegistered', { clientId: newId });
}

```

This registration step allows the Unity client to specify its own identifier (typically derived from the project name or process ID), replacing the temporary socket ID assigned by the server.

### Event-Driven Architecture

The component extends Node.js `EventEmitter` and emits specific events that other parts of the system can listen to:

- `clientConnected` – Emitted when a new TCP socket connects
- `clientDisconnected` – Emitted when a socket closes or errors
- `clientRegistered` – Emitted after successful registration handshake
- `serverStarted` – Emitted when the TCP server begins listening
- `serverStopped` – Emitted after graceful shutdown
- `message` – Emitted for every incoming message (used for logging/debugging)

Handlers in [`unity-mcp-ts/src/core/BaseCommandHandler.ts`](https://github.com/isuzu-shiranui/unitymcp/blob/main/unity-mcp-ts/src/core/BaseCommandHandler.ts) and related files rely on these events to detect when Unity becomes available or unavailable.

### Graceful Shutdown

The `stop()` method ensures clean termination:

```typescript
public stop(): void {
  // Reject all pending requests with an error
  for (const [id, pending] of this.pendingRequests) {
    pending.reject(new Error('Server shutting down'));
  }
  this.pendingRequests.clear();
  
  // Destroy all client sockets
  for (const client of this.clients.values()) {
    client.socket.destroy();
  }
  this.clients.clear();
  
  // Close the server
  this.server?.close();
  this.emit('serverStopped');
}

```

This prevents hanging promises and ensures that Unity clients receive immediate connection termination rather than waiting for TCP timeouts.

## Code Examples

### Getting the Singleton Instance

```typescript
import { UnityConnection } from './core/UnityConnection.js';

const connection = UnityConnection.getInstance();

```

### Starting the TCP Server

```typescript
await connection.configure('127.0.0.1', 27182);
await connection.start();

```

### Sending a Request from a Custom Handler

```typescript
const request = {
  command: 'unity.editor.openScene',
  type: 'command',
  params: { path: 'Assets/Scenes/Main.unity' }
};

try {
  const response = await connection.sendRequest(request);
  console.log('Unity responded with', response);
} catch (err) {
  console.error('Request failed:', err);
}

```

### Listening for Incoming Messages

```typescript
connection.on('message', ({ clientId, message }) => {
  console.log(`Message from ${clientId}:`, message);
});

```

### Switching the Active Client

```typescript
const clients = connection.getConnectedClients();
if (clients.length > 1) {
  const newActive = clients[1].id;
  connection.setActiveClient(newActive);
}

```

### Stopping the Server

```typescript
connection.stop();

```

## Summary

- The **UnityConnection** component is a singleton TCP server that bridges TypeScript MCP handlers with Unity Editor instances via persistent sockets.
- It manages **client lifecycle** through registration events, supports multiple simultaneous Unity clients, and maintains an **active client** for request routing.
- **Request/response correlation** uses monotonic IDs and Promise-based resolution with automatic 30-second timeouts.
- **UDP auto-discovery** eliminates manual configuration by broadcasting server availability to the local network.
- The component emits events for all connection state changes, enabling reactive handler logic in `BaseCommandHandler`, `BaseResourceHandler`, and `BasePromptHandler` classes.

## Frequently Asked Questions

### How does UnityConnection handle multiple Unity Editor instances?

The component maintains a `Map` of all connected clients in [`unity-mcp-ts/src/core/UnityConnection.ts`](https://github.com/isuzu-shiranui/unitymcp/blob/main/unity-mcp-ts/src/core/UnityConnection.ts). While multiple clients can remain connected simultaneously, the server designates one as the **active client** (by default, the first to connect). You can switch the active target at runtime using `setActiveClient(clientId)`, allowing you to send commands to specific Unity instances without disconnecting others.

### What happens if a request to Unity times out?

Every request sent via `sendRequest()` includes a 30-second timeout mechanism. If the Unity client does not respond with a matching request ID within this window, the stored Promise is rejected with a timeout error. This prevents the TypeScript MCP server from hanging indefinitely when Unity is busy, crashed, or disconnected. The timeout duration is hardcoded in the `sendRequest` implementation in [`unity-mcp-ts/src/core/UnityConnection.ts`](https://github.com/isuzu-shiranui/unitymcp/blob/main/unity-mcp-ts/src/core/UnityConnection.ts).

### Can I use UnityConnection without UDP auto-discovery?

Yes. While the component automatically broadcasts a UDP packet on startup via `sendInitialBroadcast()`, this is purely for convenience. You can disable or ignore the discovery mechanism by simply not implementing the listener on the Unity side. The TCP server will still accept direct connections at the configured host and port (default `127.0.0.1:27182`). The registration handshake over TCP is mandatory, but UDP discovery is optional.

### How does the registration handshake work between TypeScript and Unity?

When a Unity client first connects via TCP, the server assigns it a temporary socket ID. The client must then send a JSON registration message containing its preferred `clientId` (typically derived from the project name). The `handleRegistration()` method in [`unity-mcp-ts/src/core/UnityConnection.ts`](https://github.com/isuzu-shiranui/unitymcp/blob/main/unity-mcp-ts/src/core/UnityConnection.ts) swaps the temporary ID for the persistent one, updates the internal client map, and emits a `clientRegistered` event. This handshake allows Unity to maintain a stable identity across reconnections.