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.

Updated November 4, 2026 View as Markdown

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, SceneTree or EditorInterface must go through MainThread.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 void for 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

CallWhat 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 localhost or 127.0.0.1 with AuthOption.token and 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.