# How Commands Are Handled in Unity MCP: A Complete Technical Guide

> Explore the seven-stage pipeline for Unity MCP command handling. Learn about dynamic discovery, prefix routing, and TCP socket communication with the Unity Editor.

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

---

**Unity MCP processes every client operation as a command through a seven-stage pipeline involving dynamic handler discovery, prefix-based routing, and TCP socket communication with the Unity Editor.**

Unity MCP (Model Context Protocol) bridges external clients and the Unity Editor via a robust command-handling architecture. Understanding how commands are handled in Unity MCP is essential for developers extending the protocol or debugging integration issues. This guide examines the complete command lifecycle from discovery to execution, referencing the actual TypeScript implementation in the `isuzu-shiranui/unitymcp` repository.

## Command Discovery and Registration

The server initializes its command vocabulary by scanning and registering handler classes dynamically.

### Dynamic Handler Discovery

When the server starts, `HandlerDiscovery` scans the compiled handlers directory (`unity-mcp-ts/src/handlers/`). It dynamically imports each `.js` file and instantiates every exported class.

```typescript
// Conceptual flow from HandlerDiscovery.ts
const handlerFiles = await scanHandlersDirectory();
for (const file of handlerFiles) {
  const module = await import(file);
  const HandlerClass = module.default;
  const instance = new HandlerClass();
  // Registration happens next...
}

```

### CommandRegistry Registration

Each discovered instance is examined against the `ICommandHandler` interface. Valid handlers are added to the central `CommandRegistry`, which maintains a mapping between command prefixes and handler instances.

```typescript
// From CommandRegistry.ts
registerHandler(handler: ICommandHandler): void {
  const prefix = handler.commandPrefix; // e.g., "menu", "console"
  this.handlers.set(prefix, handler);
}

```

The same instance is also handed to `HandlerAdapter` so the adapter can later route calls to the correct handler.

## Request Reception and Routing

Once registered, handlers process incoming TCP requests through a structured routing mechanism.

### TCP Socket Communication via UnityConnection

Clients (such as the Unity Editor plugin) send JSON requests over TCP sockets. `UnityConnection.sendRequest` tags each request with a unique **id**, writes it to the active Unity client, and stores a promise in `pendingRequests` for later resolution.

```typescript
// Client-side usage pattern
import { UnityConnection } from './unity-mcp-ts/src/core/UnityConnection.js';

async function executeMenuItem(menuPath: string) {
  const conn = UnityConnection.getInstance();
  await conn.start();
  
  const response = await conn.sendRequest({
    command: 'menu.execute',
    params: { menuItem: menuPath }
  });
  
  return response;
}

```

### Command Prefix Routing

When the server receives a response or request, `HandlerAdapter` extracts the **command** string (e.g., `menu.execute`). The segment before the first dot (`menu`) serves as the **command prefix**.

`HandlerAdapter` looks up the corresponding handler in `CommandRegistry` and invokes its `execute` method, passing the action (`execute`) and parameters.

## Command Execution Flow

Handlers implement a consistent execution pattern through base class abstractions.

### BaseCommandHandler Abstraction

Most concrete handlers extend `BaseCommandHandler`. The base class first guarantees a live Unity connection via `ensureUnityConnection`, then delegates to the handler-specific `executeCommand` method.

```typescript
// From BaseCommandHandler.ts
async execute(action: string, params: JObject): Promise<JObject> {
  await this.ensureUnityConnection();
  return this.executeCommand(action, params);
}

protected abstract executeCommand(
  action: string, 
  params: JObject
): Promise<JObject>;

```

Handlers typically forward requests to Unity using `sendUnityRequest`, which serializes the command and manages the socket write operation.

### Concrete Handler Implementation

The `MenuItemCommandHandler` demonstrates a typical implementation. It declares its prefix as `menu` and implements `executeCommand` to forward menu execution requests to the Unity Editor.

```typescript
// Excerpt from MenuItemCommandHandler.ts
class MenuItemCommandHandler extends BaseCommandHandler {
  get commandPrefix(): string { return 'menu'; }
  
  protected async executeCommand(
    action: string, 
    params: JObject
  ): Promise<JObject> {
    if (action === 'execute') {
      await this.ensureUnityConnection();
      const response = await this.sendUnityRequest(
        `${this.commandPrefix}.execute`,
        { menuItem: params.menuItem }
      );
      return response;
    }
    return { success: false, error: 'Unknown action' };
  }
}

```

## Implementing Custom Command Handlers

Developers can extend Unity MCP by creating new handler classes. The system automatically discovers and registers them without modifying core router code.

Here is a complete custom handler that adds a `ping` health-check command:

```typescript
// Save as: unity-mcp-ts/src/handlers/PingCommandHandler.ts
import { BaseCommandHandler } from '../core/BaseCommandHandler.js';
import { JObject } from '../types/index.js';

export class PingCommandHandler extends BaseCommandHandler {
  public get commandPrefix(): string { return 'ping'; }
  public get description(): string { return 'Simple health-check command'; }

  public getToolDefinitions() { return null; }

  protected async executeCommand(
    action: string, 
    _params: JObject
  ): Promise<JObject> {
    if (action.toLowerCase() !== 'ping') {
      return { success: false, error: `Unsupported action ${action}` };
    }
    // Directly answer without contacting Unity
    return { success: true, reply: 'pong' };
  }
}

```

Because `HandlerDiscovery` loads every compiled handler automatically, the new `ping` command becomes available as `ping.pong` immediately upon server restart.

## Summary

- **Dynamic Discovery**: `HandlerDiscovery` scans the handlers directory at startup, instantiating every exported class it finds.
- **Prefix Registration**: Valid handlers implementing `ICommandHandler` register their command prefix (e.g., `menu`, `console`) with `CommandRegistry`.
- **Socket Communication**: `UnityConnection` manages TCP sockets, tagging requests with unique IDs and tracking pending promises.
- **Prefix Routing**: `HandlerAdapter` extracts the command prefix from incoming requests (e.g., `menu` from `menu.execute`) and routes to the appropriate handler.
- **Base Abstraction**: `BaseCommandHandler` ensures Unity connectivity before delegating to handler-specific `executeCommand` implementations.
- **Extensibility**: New commands require only creating a handler class extending `BaseCommandHandler`; no core router modifications are necessary.

## Frequently Asked Questions

### What is the role of the command prefix in Unity MCP?

The command prefix is the segment before the first dot in a command string (e.g., `menu` in `menu.execute`). It acts as a namespace that `HandlerAdapter` uses to look up the correct `ICommandHandler` instance in `CommandRegistry`. Each handler declares its prefix via the `commandPrefix` getter, enabling the router to dispatch requests without hardcoding handler references.

### How does Unity MCP handle requests when Unity Editor is not connected?

`BaseCommandHandler` includes an `ensureUnityConnection` method that verifies an active TCP connection to the Unity Editor before executing commands. If the connection is lost or unavailable, the method throws an error or returns a failure response, preventing commands from being dropped silently. Handlers that do not require Unity interaction (like the example `PingCommandHandler`) can bypass this check by implementing custom logic directly in `executeCommand`.

### Can I add new commands without modifying the core server code?

Yes. Unity MCP uses dynamic discovery via `HandlerDiscovery` to load handlers from the `src/handlers/` directory at startup. To add a new command, create a class extending `BaseCommandHandler`, implement the `commandPrefix` getter and `executeCommand` method, and export the class from a new file in the handlers directory. The server automatically registers the new prefix and routes matching commands to your handler without requiring changes to `CommandRegistry` or `HandlerAdapter`.

### What is the difference between HandlerAdapter and CommandRegistry?

`CommandRegistry` serves as a static storage mechanism that maps command prefixes to handler instances, providing methods like `registerHandler` and `getHandler`. `HandlerAdapter` acts as the active router that intercepts incoming requests, extracts the command prefix, queries `CommandRegistry` for the appropriate handler, and invokes the handler's `execute` method. While `CommandRegistry` maintains the lookup table, `HandlerAdapter` performs the runtime dispatch logic.