# How to Create Custom Command Handlers in Unity MCP: A Complete Guide

> Learn to create custom command handlers in Unity MCP using TypeScript and C#. Implement advanced command logic for your Unity game server and editor with this complete guide.

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

---

**You can create custom command handlers in Unity MCP by extending `BaseCommandHandler` in TypeScript for the server side and implementing `IMcpCommandHandler` in C# for the Unity Editor side, then placing them in the respective `handlers` folders for automatic discovery.**

The Unity MCP project by `isuzu-shiranui/unitymcp` bridges the gap between AI assistants and the Unity Editor through a Model Context Protocol (MCP) implementation. Creating custom command handlers allows you to expose new Unity Editor functionality to external AI tools, enabling automated scene manipulation, asset management, and workflow optimization.

## Understanding the Unity MCP Command Architecture

Unity MCP operates as a bidirectional bridge with two distinct components that handle command processing.

### The TypeScript Server Side (unity-mcp-ts)

The MCP server, located in `unity-mcp-ts/`, exposes a JSON-RPC-like API that receives requests from AI clients. When a request arrives containing a command string like `"menu.execute"`, the server:

1. Parses the command to extract the prefix (`"menu"`) and action (`"execute"`)
2. Looks up a registered handler implementing `ICommandHandler` with a matching `commandPrefix`
3. Invokes the handler's `execute` method, which typically forwards the request to Unity via `sendUnityRequest`

The `HandlerDiscovery` class in [`unity-mcp-ts/src/core/HandlerDiscovery.ts`](https://github.com/isuzu-shiranui/unitymcp/blob/main/unity-mcp-ts/src/core/HandlerDiscovery.ts) automates registration by scanning the `src/handlers/` directory, instantiating each handler, injecting the shared `UnityConnection`, and registering it with `CommandRegistry`【/cache/repos/github.com/isuzu-shiranui/unitymcp/main/unity-mcp-ts/src/core/HandlerDiscovery.ts#L80-L112】.

### The C# Unity Editor Side

For commands requiring Unity Editor interaction, you need a C# counterpart in `jp.shiranui-isuzu.unity-mcp/Editor/`. These handlers implement `IMcpCommandHandler` and receive requests forwarded from the TypeScript server.

The `McpEditorInitializer` in [`Editor/Core/McpEditorInitializer.cs`](https://github.com/isuzu-shiranui/unitymcp/blob/main/Editor/Core/McpEditorInitializer.cs) uses `McpHandlerDiscovery<IMcpCommandHandler>` to automatically discover and register C# handlers at startup【/cache/repos/github.com/isuzu-shiranui/unitymcp/main/jp.shiranui-isuzu.unity-mcp/Editor/Core/McpEditorInitializer.cs#L34-L38】.

## Creating a TypeScript Command Handler

To create a server-side command handler, extend `BaseCommandHandler` from [`unity-mcp-ts/src/core/BaseCommandHandler.ts`](https://github.com/isuzu-shiranui/unitymcp/blob/main/unity-mcp-ts/src/core/BaseCommandHandler.ts).

### Extending BaseCommandHandler

Create a new TypeScript file in `unity-mcp-ts/src/handlers/`. The `BaseCommandHandler` class provides essential infrastructure including `ensureUnityConnection()` to verify Unity availability and `sendUnityRequest(command, params)` to forward requests to the Unity Editor【/cache/repos/github.com/isuzu-shiranui/unitymcp/main/unity-mcp-ts/src/core/BaseCommandHandler.ts#L40-L104】.

### Implementing Required Methods

You must implement three abstract members:

- `commandPrefix`: The string identifier for your command namespace (e.g., `"mycmd"` for requests like `"mycmd.action"`)
- `description`: Human-readable description of what the handler does
- `executeCommand(action, parameters)`: The core logic that processes the action and returns a `JObject`

### Optional Tool Definitions

Override `getToolDefinitions()` to expose parameter schemas for UI tools. This allows AI assistants to understand what parameters your commands accept.

### Example: Ping Command Handler

```typescript
// src/handlers/PingCommandHandler.ts
import { JObject } from "../types/index.js";
import { BaseCommandHandler } from "../core/BaseCommandHandler.js";
import { IMcpToolDefinition } from "../core/interfaces/ICommandHandler.js";

/**
 * Simple "ping" command – replies with the server timestamp.
 */
export class PingCommandHandler extends BaseCommandHandler {
    public get commandPrefix(): string {
        return "ping";
    }

    public get description(): string {
        return "Returns a timestamp confirming the server is alive";
    }

    public getToolDefinitions(): Map<string, IMcpToolDefinition> {
        const tools = new Map<string, IMcpToolDefinition>();
        tools.set("ping_now", {
            description: "Get the current server timestamp",
            parameterSchema: {},
            annotations: {
                title: "Ping",
                readOnlyHint: true,
                destructiveHint: false,
                idempotentHint: true,
                openWorldHint: false,
            },
        });
        return tools;
    }

    protected async executeCommand(_: string, __: JObject): Promise<JObject> {
        // No need to talk to Unity – just return a JSON payload
        return {
            success: true,
            timestamp: new Date().toISOString(),
        };
    }
}

```

This handler responds to `"ping.execute"` or `"ping.ping_now"` without contacting Unity, demonstrating how to create standalone server-side commands.

## Creating the C# Counterpart Handler

When your command requires Unity Editor functionality, implement `IMcpCommandHandler` in C#.

### Implementing IMcpCommandHandler

Create a new class in `jp.shiranui-isuzu.unity-mcp/Editor/Handlers/`:

```csharp
// Editor/Handlers/HelloWorldCommandHandler.cs
using Newtonsoft.Json.Linq;
using UnityEditor;
using UnityEngine;
using UnityMCP.Editor.Core;

namespace UnityMCP.Editor.Handlers
{
    internal sealed class HelloWorldCommandHandler : IMcpCommandHandler
    {
        public string CommandPrefix => "hello";

        public string Description => "Logs a hello-world message in the Unity console";

        public JObject Execute(string action, JObject parameters)
        {
            if (action.ToLower() != "say")
                return new JObject
                {
                    ["success"] = false,
                    ["error"] = $"Unsupported action '{action}'. Expected 'say'."
                };

            // Perform Unity-side work
            Debug.Log("[MCP] Hello, world!");
            return new JObject { ["success"] = true };
        }
    }
}

```

The C# handler receives requests forwarded by the TypeScript `sendUnityRequest` method. It validates the action, performs Unity Editor operations, and returns JSON results.

## Automatic Discovery and Registration

Unity MCP eliminates manual registration through automatic discovery mechanisms on both sides.

On the TypeScript server, `HandlerDiscovery` scans `src/handlers/` at startup, imports each module, instantiates handler classes, injects the `UnityConnection` dependency, and registers them with `CommandRegistry`. This happens in the `initializeHandlers()` method【/cache/repos/github.com/isuzu-shiranui/unitymcp/main/unity-mcp-ts/src/core/HandlerDiscovery.ts#L80-L112】.

On the Unity Editor side, `McpEditorInitializer` creates a `McpHandlerDiscovery<IMcpCommandHandler>` instance and calls `DiscoverAndRegister()` to find all C# implementations of `IMcpCommandHandler` in the `Editor/Handlers/` directory【/cache/repos/github.com/isuzu-shiranui/unitymcp/main/jp.shiranui-isuzu.unity-mcp/Editor/Core/McpEditorInitializer.cs#L34-L38】.

Simply placing your files in these directories ensures registration on the next server restart or Unity Editor reload.

## Testing Your Custom Command

Once implemented, test your handlers using JSON-RPC requests.

For the TypeScript-only ping handler:

```json
{
  "command": "ping.execute",
  "params": {}
}

```

Expected response:

```json
{
  "success": true,
  "timestamp": "2026-03-04T12:34:56.789Z"
}

```

For the C# hello handler:

```json
{
  "command": "hello.say",
  "params": {}
}

```

This logs `"[MCP] Hello, world!"` in the Unity Console and returns:

```json
{ "success": true }

```

## Summary

- **Extend `BaseCommandHandler`** in TypeScript to create server-side command logic in `unity-mcp-ts/src/handlers/`.
- **Implement `IMcpCommandHandler`** in C# for Unity Editor-side operations in `Editor/Handlers/`.

- **Use `sendUnityRequest`** from TypeScript to forward requests to the C# implementation when Unity interaction is required.

- **Leverage automatic discovery** via `HandlerDiscovery` (TypeScript) and `McpHandlerDiscovery` (C#) — no manual registration required.
- **Define tool schemas** by overriding `getToolDefinitions()` to enable AI assistant parameter discovery.

## Frequently Asked Questions

### What is the difference between BaseCommandHandler and IMcpCommandHandler?

`BaseCommandHandler` is the TypeScript abstract class used in the MCP server (`unity-mcp-ts`) to process incoming JSON-RPC requests and optionally forward them to Unity. `IMcpCommandHandler` is the C# interface implemented in the Unity Editor to receive those forwarded requests and execute Unity-specific operations. You use `BaseCommandHandler` for server-side logic and `IMcpCommandHandler` for Unity-side logic.

### Do I need to register custom handlers manually in Unity MCP?

No. Unity MCP uses automatic discovery mechanisms on both sides. On the TypeScript server, `HandlerDiscovery` scans the `src/handlers/` directory and registers any class extending `BaseCommandHandler`. On the Unity side, `McpHandlerDiscovery` scans `Editor/Handlers/` for implementations of `IMcpCommandHandler`. Simply place your files in these directories and restart the server or reload the Unity Editor.

### Can I create a command handler that doesn't communicate with Unity?

Yes. If your command only requires server-side processing (such as returning status information or performing calculations), you can extend `BaseCommandHandler` and implement `executeCommand` without calling `sendUnityRequest` or `ensureUnityConnection`. The `PingCommandHandler` example demonstrates this pattern by returning a timestamp directly from the TypeScript server without contacting the Unity Editor.

### Where should I place my custom handler files?

Place TypeScript handlers in `unity-mcp-ts/src/handlers/` and ensure they export a class extending `BaseCommandHandler`. Place C# handlers in `jp.shiranui-isuzu.unity-mcp/Editor/Handlers/` (or any `Editor/Handlers/` path in your Unity project) and ensure the class implements `IMcpCommandHandler`. Both locations are scanned automatically by their respective discovery systems.