How to Create Custom Resource Handlers in Unity MCP: A Complete Implementation Guide
Create custom resource handlers in Unity MCP by implementing the IMcpResourceHandler interface and placing your class in the Editor/ folder; the McpHandlerDiscovery<T> system automatically registers it on Unity editor startup.
Unity MCP (Message Communication Protocol) from the isuzu-shiranui/unitymcp repository provides a discovery-based architecture for extending the MCP server with custom data sources. When you create custom resource handlers in Unity MCP, you enable external clients to query Unity-specific information—such as scene states, asset metadata, or project statistics—through a standardized JSON-RPC interface. This guide covers the automatic registration pipeline, the required interface implementation, and production-ready code examples.
Understanding the Resource Handler Architecture
A resource handler is any class that implements the IMcpResourceHandler interface defined in Editor/Core/IMcpResourceHandler.cs. Unlike manual registration systems, Unity MCP uses reflection-based discovery to find and instantiate these handlers automatically when the editor loads.
The lifecycle follows this sequence:
IMcpResourceHandlerdefines the contract:ResourceName,Description,ResourceUri, and theFetchResourcemethod.McpHandlerDiscovery<IMcpResourceHandler>scans loaded assemblies for non-abstract implementations of the interface.McpEditorInitializertriggers discovery on editor startup and invokes the registration callback for each found handler.McpServer.RegisterResourceHandlerstores the handler in an internal dictionary and applies saved enable/disable states fromMcpSettings.McpServer.FetchResourceDataroutes incoming client requests to the matching handler'sFetchResourcemethod, executing on the Unity main thread.
Implementing the IMcpResourceHandler Interface
To create custom resource handlers in Unity MCP, your class must fulfill four requirements defined in the interface:
ResourceName(string): The unique identifier used in client requests (format:resourceName.action). Must be unique across the project.Description(string): Human-readable explanation of what the handler provides.ResourceUri(string, optional): A URL-style address (e.g.,unity://myresource) for clients that prefer URI-based addressing.FetchResource(JObject parameters): The method that returns aJObjectcontaining the requested data.
Thread Safety and Unity API Access
The FetchResource method always executes on the Unity main thread because McpServer queues the call via ExecuteOnMainThread. This means your implementation can safely invoke Unity Editor APIs, access SceneManager, or query AssetDatabase without manual thread marshaling.
Complete Custom Resource Handler Example
The following implementation returns a JSON array of all currently open scenes. Place this file in Assets/Editor/OpenScenesResourceHandler.cs or any Editor/ folder assembly.
using UnityEngine;
using UnityEngine.SceneManagement;
using Newtonsoft.Json.Linq;
using UnityMCP.Editor.Resources;
namespace MyCompany.UnityMCP
{
internal sealed class OpenScenesResourceHandler : IMcpResourceHandler
{
public string ResourceName => "openscenes";
public string Description => "Provides a list of currently opened Unity scenes";
public string ResourceUri => "unity://openscenes";
public JObject FetchResource(JObject parameters)
{
var scenesArray = new JArray();
foreach (var scene in SceneManager.GetAllScenes())
{
scenesArray.Add(new JObject
{
["name"] = scene.name,
["path"] = scene.path,
["isLoaded"] = scene.isLoaded,
["isDirty"] = scene.isDirty
});
}
return new JObject
{
["success"] = true,
["scenes"] = scenesArray,
["count"] = scenesArray.Count
};
}
}
}
Once Unity recompiles the scripts, McpHandlerDiscovery<IMcpResourceHandler> automatically finds this class, instantiates it, and registers it with the server via McpServer.RegisterResourceHandler (line 1057 in Editor/Core/McpServer.cs). No additional registration code is required.
Calling Your Handler from an MCP Client
External clients interact with your handler using the resourceName.command pattern. The server parses the prefix, looks up the registered handler, and forwards the parameters to FetchResource.
TypeScript Client Example
// Assumes an established McpClient instance named 'client'
client.send({
type: "resource",
command: "openscenes.fetch",
id: "request-001",
params: {}
}).then(response => {
if (response.status === "success") {
console.log(`Found ${response.result.count} scenes:`);
response.result.scenes.forEach(scene => {
console.log(`- ${scene.name} (${scene.path})`);
});
} else {
console.error("Resource fetch failed:", response.message);
}
});
URI-Based Requests
If your client prefers addressing resources by URI, you can use the ResourceUri value in the command field:
client.send({
type: "resource",
command: "unity://openscenes",
id: "request-002",
params: {}
});
Key Configuration and Constraints
When you create custom resource handlers in Unity MCP, keep these technical constraints in mind:
- Unique Naming: The
ResourceNameproperty must be globally unique. If two handlers register with the same name, the last one discovered will overwrite the previous registration inMcpServer's internal dictionary. - Persistence: The enabled/disabled state of each handler is stored in
McpSettings. WhenMcpEditorInitializerruns discovery, it applies these saved states automatically viaRegisterResourceHandler. - Assembly Location: Handlers must reside in compiled assemblies accessible to the Unity Editor (typically under
Assets/Editor/or within Editor-specific Assembly Definition files). - Error Handling: Return a
JObjectwith"success": falseand an error message field rather than throwing exceptions, as uncaught exceptions inFetchResourcemay disrupt the server pipeline.
Summary
- Implement
IMcpResourceHandlerfromEditor/Core/IMcpResourceHandler.csto define your handler contract. - Place handler classes in the
Editor/folder;McpHandlerDiscovery<T>automatically registers them on startup. - Use
ResourceNameas the unique identifier for client requests following the patternresourceName.action. - Access Unity APIs freely in
FetchResourcebecause execution occurs on the main thread via the server'sExecuteOnMainThreadqueue. - Reference built-in examples such as
PackagesResourceHandler.csandAssembliesResourceHandler.csinEditor/Handlers/for implementation patterns.
Frequently Asked Questions
How does Unity MCP discover custom resource handlers automatically?
The McpHandlerDiscovery<T> class in Editor/Core/McpHandlerDiscovery.cs uses reflection to scan all loaded assemblies during McpEditorInitializer startup. It instantiates every non-abstract class implementing IMcpResourceHandler and invokes the registration callback provided by McpServer, requiring no manual configuration or explicit registration calls from the developer.
Can I use Unity Editor APIs inside the FetchResource method?
Yes. The McpServer.FetchResourceData method queues handler calls via ExecuteOnMainThread, ensuring FetchResource runs on the Unity main thread. This allows safe usage of SceneManager, AssetDatabase, Selection, and other Unity Editor APIs that are normally restricted to the main thread.
Where should I place custom handler files in my Unity project?
Place custom resource handler scripts in any folder named Editor (e.g., Assets/Editor/ or Assets/MyTools/Editor/) or within an Assembly Definition file marked as Editor-only. This ensures the code compiles against the Unity Editor assemblies and is available for discovery by McpHandlerDiscovery<IMcpResourceHandler> when the editor initializes.
How do I ensure my resource handler name is unique?
Set the ResourceName property to a specific, namespaced value (e.g., "mycompany.scenestats" instead of "scenes"). The McpServer.RegisterResourceHandler method stores handlers in a dictionary keyed by ResourceName, so duplicate names cause the last registered handler to overwrite previous entries without warning. Check existing handlers in Editor/Handlers/ to avoid collisions with built-in resources like "packages" or "assemblies".
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:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →