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

> Discover how Unity MCP handles resources with its modular pipeline. Learn about handler discovery, registration, and data transformation for efficient Unity connections

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

---

**Unity MCP handles resources through a modular pipeline that discovers handlers in `src/handlers/*.ts`, registers them with `ResourceRegistry`, and exposes them via `HandlerAdapter` to the MCP server, using `BaseResourceHandler` to manage Unity connections and transform data.**

Unity MCP (Model-Context-Protocol) treats resources as read-only data endpoints that allow clients to query live information from a running Unity editor. Understanding how resources are handled in Unity MCP requires examining the TypeScript architecture that bridges the MCP SDK with Unity's internal state.

## The Resource Handling Pipeline

The architecture splits resource management into four distinct phases: **discovery**, **registration**, **connection handling**, and **resource-specific logic**. This separation allows developers to add new resources by creating a single handler class without modifying core infrastructure.

When the server starts, `HandlerDiscovery` scans the `src/handlers` directory, instantiates each class, and checks for the `IResourceHandler` interface. Valid handlers are stored in `ResourceRegistry` and adapted to MCP resources via `HandlerAdapter`. When a client requests a URI like `unity://packages?includeRegistry=true`, the system invokes the handler's `fetchResource` method, which communicates with Unity through `BaseResourceHandler` and returns transformed JSON.

## Handler Discovery and Registration

### Automatic Discovery in src/handlers

The `HandlerDiscovery` class implements a filesystem-based plugin system. It reads all TypeScript files in `src/handlers`, dynamically imports them, and instantiates exported classes:

```typescript
// src/core/HandlerDiscovery.ts (lines 55-84)
const files = await fs.readdir(handlersDir);
for (const file of jsFiles) {
    const module = await import(`../handlers/${file}`);
    for (const exportName in module) {
        const instance = new module[exportName]();
        instance.initialize(this.unityConnection);
        if (this.isResourceHandler(instance)) {
            this.resourceRegistry.registerHandler(instance);
            this.adapter.registerResourceHandler(instance);
        }
    }
}

```

This pattern ensures that adding a new resource requires only creating a file in `src/handlers` that exports a class implementing `IResourceHandler`.

### ResourceRegistry Registration

The `ResourceRegistry` maintains three internal maps: handlers by name, enabled states, and URI templates to resource names. Registration fails if a resource name is empty or already exists:

```typescript
// src/core/ResourceRegistry.ts (lines 11-33)
private handlers: Map<string, IResourceHandler> = new Map();
public registerHandler(handler: IResourceHandler, enabled: boolean = true): boolean {
    const resourceName = handler.resourceName;
    if (!resourceName || this.handlers.has(resourceName)) return false;
    this.handlers.set(resourceName, handler);
    this.enabledState.set(resourceName, enabled);
    if (handler.resourceUriTemplate) this.uriMap.set(handler.resourceUriTemplate, resourceName);
    return true;
}

```

This registry acts as the single source of truth for which resources are available and active.

## BaseResourceHandler and the Template Method Pattern

All concrete resource handlers extend `BaseResourceHandler`, which implements the **Template Method** pattern to enforce consistent connection management and response formatting.

### Connection Management

The `fetchResource` method guarantees a live Unity connection before executing resource-specific logic:

```typescript
// src/core/BaseResourceHandler.ts (lines 49-68)
public async fetchResource(uri: URL, parameters?: JObject) {
    await this.ensureUnityConnection();
    const result = await this.fetchResourceData(uri, parameters);
    return { contents: [{ uri: uri.href, text: JSON.stringify(result), mimeType: 'application/json' }] };
}

```

The `ensureUnityConnection` method checks if the WebSocket or IPC connection to Unity is active, throwing an error if the editor is unreachable.

### Request Dispatch to Unity

Concrete handlers use `sendUnityRequest` to communicate with Unity's internal API:

```typescript
// src/core/BaseResourceHandler.ts (lines 17-26)
protected async sendUnityRequest(command: string, parameters: JObject): Promise<JObject> {
    await this.ensureUnityConnection();
    return this.unityConnection!.sendRequest({ command, type: "resource", params: parameters });
}

```

This method standardizes the request envelope, setting the `type` to `"resource"` and passing parameters to Unity's command dispatcher.

## Concrete Resource Implementations

### PackageResourceHandler (unity://packages)

The `PackageResourceHandler` queries Unity's Package Manager for installed and registry packages. It supports the `includeRegistry` parameter via URI query string or direct parameters:

```typescript
// src/handlers/PackageResourceHandler.ts (lines 31-76)
protected async fetchResourceData(uri: URL, parameters?: JObject) {
    const includeRegistry = parameters?.includeRegistry === true ||
        uri.searchParams.get("includeRegistry") === "true";

    const response = await this.sendUnityRequest("packages.get", { includeRegistry });

    if (!response.success) throw new Error(response.error as string);
    return {
        projectPackages: response.projectPackages.map(pkg => ({
            name: pkg.name, displayName: pkg.displayName, version: pkg.version,
            description: pkg.description, category: pkg.category,
            source: pkg.source, state: pkg.state, author: pkg.author
        })),
        registryPackages: includeRegistry ? response.registryPackages.map(pkg => ({
            name: pkg.name, displayName: pkg.displayName, version: pkg.version,
            description: pkg.description, category: pkg.category,
            source: pkg.source, state: pkg.state, author: pkg.author
        })) : []
    };
}

```

This handler transforms Unity's internal package representation into a clean JSON schema suitable for LLM consumption.

### AssemblyResourceHandler (unity://assemblies)

The `AssemblyResourceHandler` retrieves loaded assemblies from Unity's AppDomain, supporting filters for system, Unity, and project assemblies:

```typescript
// src/handlers/AssemblyResourceHandler.ts (lines 36-62)
protected async fetchResourceData(uri: URL, parameters?: JObject) {
    const includeSystem = parameters?.includeSystemAssemblies === true ||
        uri.searchParams.get("includeSystemAssemblies") === "true";
    const includeUnity = parameters?.includeUnityAssemblies !== false &&
        uri.searchParams.get("includeUnityAssemblies") !== "false";
    const includeProject = parameters?.includeProjectAssemblies !== false &&
        uri.searchParams.get("includeProjectAssemblies") !== "false";

    const response = await this.sendUnityRequest("assemblies.get", {
        includeSystemAssemblies: includeSystem,
        includeUnityAssemblies: includeUnity,
        includeProjectAssemblies: includeProject
    });

    if (!response.success) throw new Error(response.error as string);
    return { assemblies: response.assemblies || [], count: response.count || 0 };
}

```

Both handlers demonstrate the pattern: parse parameters, call `sendUnityRequest` with a Unity command, validate success, and return structured data.

## Exposing Resources to the MCP Server

The `HandlerAdapter` class bridges the internal handler system with the official MCP SDK. It registers handlers as MCP resources, supporting both static URIs and URI templates with parameters:

```typescript
// src/core/HandlerAdapter.ts (lines 35-71)
if (handler.resourceUriTemplate.includes('{')) {
    const template = new ResourceTemplate(handler.resourceUriTemplate, {list: undefined});
    this.server.resource(handler.resourceName, template, async (uri, parameters) => {
        return await handler.fetchResource(uri, parameters);
    });
} else {
    this.server.resource(handler.resourceName, handler.resourceUriTemplate, async (uri) => {
        return await handler.fetchResource(uri);
    });
}

```

This adapter determines whether to use `ResourceTemplate` for parameterized URIs or simple string registration for static resources. Once registered, the MCP server handles the network protocol, leaving the Unity MCP handlers to focus solely on data retrieval and transformation.

## Summary

- **Unity MCP resources** are read-only data endpoints that query live Unity editor state through a structured pipeline.
- **Handler discovery** automatically loads classes from `src/handlers/*.ts` that implement `IResourceHandler`, registering them with `ResourceRegistry`.
- **BaseResourceHandler** enforces connection management via `ensureUnityConnection()` and standardizes Unity communication through `sendUnityRequest()`.
- **Concrete handlers** like `PackageResourceHandler` and `AssemblyResourceHandler` parse URI parameters, execute Unity commands (`packages.get`, `assemblies.get`), and transform responses into clean JSON.
- **HandlerAdapter** bridges internal handlers to the MCP SDK, supporting both static URIs and templated URIs with parameters.

## Frequently Asked Questions

### How does Unity MCP discover new resource handlers?

Unity MCP uses the `HandlerDiscovery` class to scan the `src/handlers` directory at startup. It dynamically imports each TypeScript file, instantiates exported classes, and checks if they implement the `IResourceHandler` interface. Valid handlers are automatically registered with `ResourceRegistry` and exposed through `HandlerAdapter` without requiring manual configuration.

### What is the difference between a resource URI and a resource URI template in Unity MCP?

A **resource URI** is a static string like `unity://packages` that identifies a single endpoint. A **resource URI template** contains parameterized segments (e.g., `unity://objects/{id}`) that allow dynamic values. The `HandlerAdapter` detects templates by checking for `{` characters and registers them with the MCP SDK's `ResourceTemplate` class, enabling parameterized queries.

### How does Unity MCP maintain connection stability when fetching resources?

All resource handlers extend `BaseResourceHandler`, which implements the **Template Method** pattern. Before executing any resource-specific logic, the `fetchResource` method calls `ensureUnityConnection()` to verify the WebSocket or IPC link to Unity is active. If the connection is lost, the method throws an error before attempting to send requests, preventing partial failures and ensuring consistent error handling across all resources.

### Can I create a custom resource handler for Unity MCP?

Yes, creating a custom resource requires implementing a class that extends `BaseResourceHandler` and implements `IResourceHandler`. You must define `resourceName`, `description`, and `resourceUriTemplate` (or `resourceUri`), then override `fetchResourceData` to parse parameters and return data. Place the file in `src/handlers/`, and the `HandlerDiscovery` system will automatically register it on the next server startup.