Custom tools
Write your own Godot MCP tools in C#, run Godot API calls on the main thread, and expose tools, prompts and resources from a running Godot game.
You can add your own MCP tools to Godot MCP in plain C#, inside your project. A custom tool is a method the AI agent can call, with a description that tells the model what it does. This page covers editor tools, the main-thread rule, and the opt-in runtime that lets an agent talk to a running game.
Write an editor tool
A tool family is a partial class marked [AiToolType]. Each tool is a method marked [AiTool("tool-name")], with a [Description] on the method and on every parameter so the model knows when and how to call it.
using System.ComponentModel;
using com.IvanMurzak.McpPlugin; // [AiToolType], [AiTool]
using com.IvanMurzak.ReflectorNet.Utils; // MainThread
[AiToolType]
public partial class Tool_MyFeature
{
[AiTool("my-custom-task", Title = "Do a custom task")]
[Description("Explain to the LLM what this does and when to call it.")]
public string CustomTask
(
[Description("Explain to the LLM what this parameter is.")]
string inputData
)
{
// Work that does not touch the Godot API can run here, on a background thread.
return MainThread.Instance.Run(() =>
{
// Touch EditorInterface, Node or Resource here, on the main thread.
return "[Success] Operation completed.";
});
}
}Build the C# project (the editor's Build button, godot-cli build, or ask the agent to run script-build). Godot reloads the assembly, the addon reconnects, and the new tool appears in the agent's tool list and in the dock's Tools window.
Rules that keep tools reliable
- Main thread only for Godot objects. Tool methods are called off the main thread. Any call on
Node,Resource,SceneTreeorEditorInterfacemust go throughMainThread.Instance.Run(...). Touching them from the background thread can crash the editor. - Return data, not formatted text. Return a class with properties (it is serialized for the model), or
voidfor side-effect-only tools. Avoid hand-built strings for anything the agent needs to parse. - Mark optional parameters. Use a nullable type with a default, for example
string? filter = null, and the model treats the parameter as optional. - Describe everything. The descriptions are what the model reads. Say what the tool does, when to use it and what each parameter means.
- Editor-only code goes behind
#if TOOLS. Code that uses editor APIs must not compile into an exported game.
Hints and targets
[AiTool] takes optional hints such as ReadOnlyHint = true and IdempotentHint = true, which tell clients the tool does not change anything or can safely be repeated. A Target decides where a tool is registered: ToolTarget.Editor (editor only), ToolTarget.Runtime (game only) or the default, both.
Let the agent write the tool
The system tool godot-skill-create writes a new C# tool file into your project; the tool becomes callable after the next build. Before writing a new tool, check whether RQL already covers the job: most editor data access (nodes, resources, files, project settings) is one rql-query or rql-mutate away. See Tools.
Tools in a running game
Godot MCP can also run inside a running or exported game, debug or release. This lets an agent read and drive live game state, for example a chess game whose bot moves come from an LLM. Two things are deliberate:
- It never connects on its own. Your code decides if and when to call
Connect(). - It exposes nothing by default. You register every tool, prompt and resource yourself. The addon's editor tools are not compiled into a game build.
Start it once a SceneTree exists, for example from an autoload's _Ready():
using System.Reflection;
using com.IvanMurzak.Godot.MCP.Connection;
using com.IvanMurzak.Godot.MCP.Runtime;
using McpServerConsts = com.IvanMurzak.McpPlugin.Common.Consts.MCP.Server;
using Godot;
public partial class GameMcp : Node
{
private GodotMcpRuntimeHandle? _mcp;
public override async void _Ready()
{
_mcp = GodotMcpRuntime.Initialize(builder =>
{
builder.WithConfig(config =>
{
config.ConnectionMode = GodotMcpConnectionMode.Custom;
config.Host = "http://localhost:8080";
config.AuthOption = McpServerConsts.AuthOption.token;
config.Token = "your-secret-token";
});
builder.WithToolsFromAssembly(Assembly.GetExecutingAssembly());
}).Build();
await _mcp.Connect();
}
public override async void _ExitTree()
{
if (_mcp is not null)
await _mcp.Disconnect();
}
}Mark game-only tool classes with [AiToolType(Target = ToolTarget.Runtime)] (from com.IvanMurzak.McpPlugin.Common), so the editor does not register them and the agent reaches the game even while the editor is connected.
Builder options
| Call | What it does |
|---|---|
WithConfig(...) | Set Host, Token, ConnectionMode and AuthOption in code. |
WithToolsFromAssembly(...) / WithTools(...) | Register [AiToolType] classes from an assembly, or specific types. |
WithPromptsFromAssembly(...) / WithPrompts(...) | Register [AiPromptType] prompt classes. |
WithResourcesFromAssembly(...) / WithResources(...) | Register [AiResourceType] resource classes. |
WithRuntimeErrorCapture() | Capture in-game errors and register runtime-errors-get / runtime-errors-clear. Off by default. |
WithScriptExecute() | Register script-execute in the game. Off by default; needs a .csproj opt-in. |
ConnectWhenRunFromEditor() | Also connect when the game is started with Play from the editor. Off by default. |
WithoutMainThreadDispatcher() | Skip the automatic main-thread dispatcher (only if you install your own). |
Host and token can also come from GODOT_MCP_* environment variables or a .env file, which win over code. A game never reads the editor's saved settings.
Prompts and resources
Besides tools, a game can expose MCP prompts (named instruction templates, [AiPromptType] with [AiPrompt] methods) and resources (read-only content fetched by URI, [AiResourceType] with [AiResource] methods). Each kind is optional and registered the same way as tools.
Running C# inside the game
To let the agent run C# in the game, opt in in the game's .csproj and call WithScriptExecute():
<PropertyGroup>
<GodotMcpCodeExecInGame>true</GodotMcpCodeExecInGame>
<DefineConstants>$(DefineConstants);GODOT_MCP_CODE_EXEC_IN_GAME</DefineConstants>
</PropertyGroup>This works on desktop CoreCLR builds only, not NativeAOT or iOS.
Security checklist for game builds
- Prefer Custom mode on
localhostor127.0.0.1withAuthOption.tokenand a real token. - Register only the tools you need; the attack surface is exactly the tools you register.
- Do not expose the connection on a public network interface in a release build unless you designed and secured it for that.
For the full tool list, see Tools; for packaged tool sets, see Extensions.