How Handler Discovery Works in Unity MCP for C#: Automatic Registration Explained

Unity MCP automatically discovers and registers command and resource handlers at editor startup by scanning loaded assemblies for types implementing IMcpCommandHandler or IMcpResourceHandler, then instantiating them via Activator.CreateInstance without requiring manual registration code.

Unity MCP (Meta-Command-Protocol) eliminates boilerplate registration by employing a reflection-based discovery pipeline. When the Unity editor loads, the system automatically locates and wires up C# handlers according to the isuzu-shiranui/unitymcp source code, enabling plug-and-play extensibility for editor automation.

The Generic Discovery Engine

The discovery process centers on McpHandlerDiscovery<T>, a generic class defined in Editor/Core/McpHandlerDiscovery.cs that uses reflection to locate concrete implementations of handler interfaces. The class constructor accepts an Action<T> registration callback that executes for every valid handler discovered:

// From Editor/Core/McpHandlerDiscovery.cs (lines 13-21)
public McpHandlerDiscovery(Action<T> registerAction)
{
    _registerAction = registerAction ?? throw new ArgumentNullException(nameof(registerAction));
}

The DiscoverAndRegister() method orchestrates the scanning process, returning an integer count of registered handlers for diagnostic purposes.

Assembly Scanning and Type Filtering

During discovery, the system iterates over all assemblies in the current AppDomain while excluding system and Unity-specific namespaces to optimize performance. As implemented in Editor/Core/McpHandlerDiscovery.cs (lines 34-44), the scanner skips assemblies whose names start with System., Unity., or UnityEditor..

For each remaining assembly, the algorithm filters types using three criteria (lines 50-55):

  1. Interface implementation – typeof(T).IsAssignableFrom(t) ensures the type implements the target interface (e.g., IMcpCommandHandler)
  2. Concrete class requirement – !t.IsAbstract verifies the type is instantiable
  3. Non-interface check – !t.IsInterface excludes the interface definition itself

Instantiation and Registration Pipeline

Once the scanner identifies valid handler types, it instantiates each using Activator.CreateInstance and immediately invokes the registration callback. The implementation in Editor/Core/McpHandlerDiscovery.cs (lines 61-64) follows this pattern:

var instance = (T)Activator.CreateInstance(handlerType);
_registerAction(instance);

For command handlers, the registration callback passes the instance to McpServer.RegisterHandler, which stores it in a dictionary keyed by CommandPrefix. Resource handlers follow an identical pattern via RegisterResourceHandler, using ResourceName as the dictionary key.

Editor Initialization Trigger

Discovery triggers automatically when the Unity editor loads through the McpEditorInitializer class in Editor/Core/McpEditorInitializer.cs. The static constructor schedules initialization using EditorApplication.delayCall:

// Editor/Core/McpEditorInitializer.cs
static McpEditorInitializer()
{
    EditorApplication.delayCall += Initialize;
}

The Initialize() method executes two separate discovery passes:

// Register command handlers
var commandDiscovery = new McpHandlerDiscovery<IMcpCommandHandler>(
    handler => server.RegisterHandler(handler));
var commandCount = commandDiscovery.DiscoverAndRegister();

// Register resource handlers  
var resourceDiscovery = new McpHandlerDiscovery<IMcpResourceHandler>(
    handler => server.RegisterResourceHandler(handler));
var resourceCount = resourceDiscovery.DiscoverAndRegister();

This dual-pass approach ensures both command and resource handlers are available before the MCP server begins accepting requests.

Handler Interface Contracts

Unity MCP defines two distinct handler contracts that enable the discovery system to identify capable classes:

IMcpCommandHandler (defined in Editor/Core/IMcpCommandHandler.cs) requires:

  • string CommandPrefix – unique identifier for routing
  • string Description – human-readable documentation
  • JObject Execute(string action, JObject parameters) – execution logic

IMcpResourceHandler (defined in Editor/Core/IMcpResourceHandler.cs) requires:

  • string ResourceName – unique resource identifier
  • string Description – documentation string
  • string ResourceUri – URI scheme for the resource
  • JObject FetchResource(JObject parameters) – data retrieval logic

Implementing Custom Handlers

Developers implement these interfaces without writing registration code. The discovery system automatically picks up any concrete class in the project assemblies.

Example: Command Handler

The following handler responds to ping commands:

using Newtonsoft.Json.Linq;
using UnityMCP.Editor.Core;

public sealed class PingCommandHandler : IMcpCommandHandler
{
    public string CommandPrefix => "ping";
    public string Description => "Simple health-check command";

    public JObject Execute(string action, JObject parameters)
    {
        return new JObject
        {
            ["success"] = true,
            ["message"] = "pong"
        };
    }
}

When the editor starts, McpHandlerDiscovery<IMcpCommandHandler> instantiates this class and registers it with the server automatically.

Example: Resource Handler

Resource handlers expose project data via the MCP protocol:

using Newtonsoft.Json.Linq;
using UnityMCP.Editor.Resources;

public sealed class ProjectInfoResourceHandler : IMcpResourceHandler
{
    public string ResourceName => "projectInfo";
    public string Description => "Provides basic Unity project metadata";
    public string ResourceUri => "mcp://resource/projectInfo";

    public JObject FetchResource(JObject parameters)
    {
        return new JObject
        {
            ["unityVersion"] = UnityEngine.Application.unityVersion,
            ["platform"] = UnityEngine.Application.platform.ToString(),
            ["productName"] = UnityEngine.Application.productName
        };
    }
}

Error Handling and Diagnostics

The discovery pipeline includes defensive error handling to prevent individual handler failures from crashing the initialization process. As shown in Editor/Core/McpHandlerDiscovery.cs (lines 66-75), the system catches exceptions at both the assembly level and the individual type level, logging detailed error messages to the Unity console while continuing to process remaining handlers.

The DiscoverAndRegister() method returns the total count of successfully registered handlers (lines 78-86), enabling diagnostic logging that reports how many commands and resources are available after initialization.

Summary

  • Reflection-based scanning: McpHandlerDiscovery<T> scans all non-system assemblies for interface implementations
  • Automatic instantiation: Valid handlers are instantiated via Activator.CreateInstance without manual registration
  • Editor-triggered startup: McpEditorInitializer triggers discovery via EditorApplication.delayCall when the Unity editor loads
  • Dual handler types: Separate discovery passes register both IMcpCommandHandler and IMcpResourceHandler implementations
  • Fault isolation: Per-type and per-assembly try-catch blocks ensure one bad handler doesn't break the entire system

Frequently Asked Questions

How does Unity MCP know which assemblies to scan for handlers?

The discovery system iterates over AppDomain.CurrentDomain.GetAssemblies() but filters out assemblies starting with System., Unity., or UnityEditor. to avoid scanning framework code. This optimization is implemented in Editor/Core/McpHandlerDiscovery.cs lines 34-44.

Can abstract base classes implement handler interfaces without being registered?

Yes. The discovery algorithm explicitly checks !t.IsAbstract before instantiation, ensuring only concrete classes are registered. Abstract implementations are filtered out during the type selection phase in Editor/Core/McpHandlerDiscovery.cs lines 50-55.

What happens if a handler constructor throws an exception?

The discovery pipeline wraps each instantiation attempt in a try-catch block. If Activator.CreateInstance fails for a specific type, the error is logged to the Unity console and the system continues processing remaining handlers, as shown in lines 66-75 of McpHandlerDiscovery.cs.

Do handlers require specific namespaces or folder locations to be discovered?

No. The discovery system scans all loaded assemblies regardless of namespace or file location. Any concrete class implementing IMcpCommandHandler or IMcpResourceHandler anywhere in the project will be automatically registered, provided it resides in a non-excluded assembly.

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 →