Creating Custom C# Tools
Relevant source files
The following files were used as context for generating this wiki page:- Assets/Editor/CustomCommandSamples/HelloWorld/HelloWorldTool.cs
- Packages/src/Editor/Api/McpTools/Core/AbstractUnityTool.cs
- Packages/src/Editor/Api/McpTools/Core/McpToolAttribute.cs
- Packages/src/Editor/Api/McpTools/Core/UnityToolRegistry.cs
- Packages/src/README.md
- Packages/src/Editor/UI/McpEditorWindow.cs
- Packages/src/TypeScriptServer~/src/unity-tool-manager.ts
- Packages/src/Cli~/scripts/generate-bundled-skills.ts
uLoopMCP provides a type-safe extension model for creating project-specific MCP tools in C#. These custom tools allow AI agents to perform specialized tasks within the Unity Editor, tailored to a project's unique needs. The system is designed for efficiency, featuring automatic discovery and registration, which enables developers to implement and integrate new tools with minimal boilerplate.
Custom tools are automatically discovered at startup and exposed to LLM clients. This allows for a powerful workflow where an AI can be instructed to use project-specific automation, such as custom checks, automated refactors, or scene manipulations. These tools are fully integrated into the uLoopMCP ecosystem, including security settings and CLI discovery through the Skills system.
Sources: Packages/src/README.md:310-313
Architecture and Core Components
The custom tool system is built around three key C# classes that work together to enable discovery, registration, and execution.
Sources: Packages/src/Editor/Api/McpTools/Core/AbstractUnityTool.cs, Packages/src/Editor/Api/McpTools/Core/McpToolAttribute.cs, Packages/src/Editor/Api/McpTools/Core/UnityToolRegistry.cs
The following diagram illustrates the relationship between the core components and a custom tool implementation.
AbstractUnityTool<TSchema, TResponse>
This abstract base class provides a type-safe foundation for all custom tools. It handles the deserialization of JSON parameters into a strongly-typed schema class (TSchema) and expects a strongly-typed response class (TResponse).
ToolName: An abstract property that must be overridden to define the unique name of the tool.ParameterSchema: A virtual property that automatically generates the tool's parameter schema from theTSchematype.ExecuteAsync(TSchema, CancellationToken): The core abstract method where the tool's logic is implemented. It receives type-safe parameters and a cancellation token. This method is guaranteed to be executed on Unity's main thread.
Sources: Packages/src/Editor/Api/McpTools/Core/AbstractUnityTool.cs:15-32
McpToolAttribute
This attribute is used to mark a class as a discoverable MCP tool. The UnityToolRegistry scans assemblies for classes decorated with this attribute.
| Property | Type | Description |
|---|---|---|
Description | string | A description of the tool's purpose, which is exposed to the LLM client. |
DisplayDevelopmentOnly | bool | If true, the tool is only exposed when the MCP server is in development mode. Defaults to false. |
Sources: Packages/src/Editor/Api/McpTools/Core/McpToolAttribute.cs:8-19
UnityToolRegistry
This singleton class is responsible for discovering, registering, and executing all MCP tools, including custom ones.
- On initialization, it calls
RegisterToolsWithAttributes(), which scans all loaded assemblies for types that implementIUnityTooland are decorated with[McpTool]. - It instantiates each discovered tool and stores it in a dictionary, keyed by
ToolName. - When a tool execution request is received, it finds the corresponding tool and calls its
ExecuteAsyncmethod after performing a security check.
Sources: Packages/src/Editor/Api/McpTools/Core/UnityToolRegistry.cs:20-25, 43-73, 150-163
Implementation Guide
Creating a custom tool involves three main steps: defining the parameter schema, defining the response structure, and implementing the tool logic.
The following flowchart shows the steps to create a custom tool.
Sources: Packages/src/README.md:337-389
Step 1: Create the Parameter Schema Class
Define a class that inherits from BaseToolSchema. Each public property in this class represents a parameter for your tool. Use the [Description] attribute to document what each parameter does for the AI.
// From Assets/Editor/CustomCommandSamples/HelloWorld/HelloWorldTool.cs
public class HelloWorldSchema : BaseToolSchema
{
[Description("The name to include in the greeting message.")]
public string Name { get; set; } = "World";
}
Sources: Assets/Editor/CustomCommandSamples/HelloWorld/HelloWorldTool.cs:33-39
Step 2: Create the Response Class
Define a class that inherits from BaseToolResponse. Public properties in this class will be serialized to JSON and sent back to the client. A parameterless constructor is required for serialization.
// From Assets/Editor/CustomCommandSamples/HelloWorld/HelloWorldTool.cs
public class HelloWorldResponse : BaseToolResponse
{
public string Greeting { get; set; }
public HelloWorldResponse(string greeting)
{
Greeting = greeting;
}
public HelloWorldResponse() { }
}
Sources: Assets/Editor/CustomCommandSamples/HelloWorld/HelloWorldTool.cs:41-53
Step 3: Create the Tool Class
Create the main tool class by inheriting from AbstractUnityTool<TSchema, TResponse>, using your schema and response classes as generic arguments.
- Decorate the class with the
[McpTool(Description = "...")]attribute. - Override
ToolNameto provide a unique identifier. - Implement
ExecuteAsyncto define the tool's logic. This method will receive a type-safe instance of your schema class.
// From Assets/Editor/CustomCommandSamples/HelloWorld/HelloWorldTool.cs
[McpTool(Description = "A simple tool that returns a greeting message.")]
public class HelloWorldTool : AbstractUnityTool<HelloWorldSchema, HelloWorldResponse>
{
public override string ToolName => "hello-world";
protected override Task<HelloWorldResponse> ExecuteAsync(HelloWorldSchema parameters, CancellationToken cancellationToken)
{
// Access parameters in a type-safe way
string greeting = $"Hello, {parameters.Name}! This is a custom uLoopMCP tool.";
// All tool logic runs on the Unity main thread, so Unity APIs are safe to call.
Debug.Log(greeting);
return Task.FromResult(new HelloWorldResponse(greeting));
}
}
Sources: Assets/Editor/CustomCommandSamples/HelloWorld/HelloWorldTool.cs:11-31
Tool Registration and Execution
Registration Flow
The UnityToolRegistry automatically discovers and registers custom tools when the Unity Editor starts or after a script compilation.
The sequence diagram below shows the tool registration process.
Execution Flow
When an LLM client invokes a custom tool, the request flows from the client, through the TypeScript server, to the Unity C# backend where it is executed by the UnityToolRegistry.
The following diagram illustrates the end-to-end execution flow of a custom tool.
Security
For security reasons, custom tools (referred to as "Third Party Tools") are disabled by default. To enable them, you must check the "Allow Third Party Tools" option in the uLoopMCP Editor window under "Security Settings".
When a tool is executed, the UnityToolRegistry calls McpSecurityChecker.IsToolAllowed(toolName) to verify that the tool is permitted to run. If the setting is disabled, the execution will be blocked and an McpSecurityException will be thrown.
Sources: Packages/src/README.md:323-326, Packages/src/Editor/UI/McpEditorWindow.cs:256-260, Packages/src/Editor/Api/McpTools/Core/UnityToolRegistry.cs:156-160
Making Tools Discoverable with Skills
To make your custom tool easily discoverable and usable by LLM tools like Claude Code, you can create a SKILL.md file in the same directory as your tool's C# source file. The uloop CLI can then scan for these files and install them as "Skills".
The SKILL.md file uses YAML frontmatter to define the skill's name and description.
Example SKILL.md:
---
name: uloop-hello-world
description: A sample skill that prints a greeting. Use it to test if custom skills are working.
---
# uloop hello-world
This is the documentation for the hello-world skill.
The CLI build script (generate-bundled-skills.ts) scans for SKILL.md files in Assets/**/Editor/, Packages/*/Editor/, and Library/PackageCache/*/Editor/ to bundle them for installation.
Sources: Packages/src/README.md:391-412, Packages/src/Cli~/scripts/generate-bundled-skills.ts:16-21, 102-106
Summary
The uLoopMCP extension system provides a robust and developer-friendly way to extend the capabilities of AI agents within Unity. By leveraging C# attributes and a type-safe abstract base class, developers can quickly create, register, and deploy custom tools. The integration with security settings and the Skills discovery mechanism ensures that these tools are both safe and easily accessible, bridging the gap between project-specific needs and AI-driven development.