自定义工具
用 C# 编写你自己的 Godot MCP 工具,在主线程执行 Godot API 调用,并从运行中的 Godot 游戏里暴露工具、提示和资源。
你可以在项目内用纯 C# 为 Godot MCP 添加自己的 MCP 工具。自定义工具就是一个 AI agent 可以调用的方法,并带有描述,告诉模型它做什么。本页介绍编辑器工具、主线程规则,以及让 agent 与运行中的游戏通信的可选运行时。
编写编辑器工具
一个工具族就是一个标记了 [AiToolType] 的 partial class。每个工具就是一个标记了 [AiTool("tool-name")] 的方法,方法本身和每个参数上都要有 [Description],这样模型才知道何时以及如何调用它。
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.";
});
}
}构建 C# 项目(编辑器的 Build 按钮、godot-cli build,或让 agent 运行 script-build)。Godot 会重新加载程序集,插件会重新连接,新工具就会出现在 agent 的工具列表和停靠面板的 Tools 窗口中。
让工具保持可靠的规则
- Godot 对象只能在主线程访问。 工具方法是在主线程之外被调用的。对
Node、Resource、SceneTree或EditorInterface的任何调用都必须通过MainThread.Instance.Run(...)。从后台线程访问它们可能导致编辑器崩溃。 - 返回数据,而不是格式化文本。 返回一个带属性的类(它会为模型序列化),或者对只有副作用的工具返回
void。凡是 agent 需要解析的内容,都不要用手工拼接的字符串。 - 标记可选参数。 使用带默认值的可空类型,例如
string? filter = null,模型就会把该参数视为可选。 - 为一切写描述。 模型读的就是这些描述。说明工具做什么、何时使用,以及每个参数的含义。
- 仅限编辑器的代码放在
#if TOOLS之后。 使用编辑器 API 的代码绝不能编译进导出的游戏。
提示与目标
[AiTool] 接受可选提示,例如 ReadOnlyHint = true 和 IdempotentHint = true,它们告诉客户端该工具不改变任何东西,或者可以安全地重复调用。Target 决定工具注册到哪里:ToolTarget.Editor(仅编辑器)、ToolTarget.Runtime(仅游戏)或默认值,两者都注册。
让 agent 来编写工具
系统工具 godot-skill-create 会把新的 C# 工具文件写入你的项目;该工具在下次构建后即可调用。在编写新工具之前,先确认 RQL 是否已经能完成这件事:大多数编辑器数据访问(节点、资源、文件、项目设置)只需一次 rql-query 或 rql-mutate。参见 工具。
运行中游戏里的工具
Godot MCP 也可以运行在运行中或已导出的游戏内,无论是调试版还是发布版。这使 agent 能够读取并驱动实时游戏状态,例如一个由 LLM 提供机器人走法的国际象棋游戏。有两点是刻意设计的:
- 它绝不会自行连接。 由你的代码决定是否以及何时调用
Connect()。 - 默认不暴露任何东西。 每个工具、提示和资源都由你自己注册。插件的编辑器工具不会被编译进游戏构建。
在 SceneTree 存在之后再启动它,例如在某个 autoload 的 _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();
}
}用 [AiToolType(Target = ToolTarget.Runtime)](来自 com.IvanMurzak.McpPlugin.Common)标记仅游戏用的工具类,这样编辑器就不会注册它们,即使编辑器已连接,agent 也能访问到游戏。
Builder 选项
| 调用 | 作用 |
|---|---|
WithConfig(...) | 在代码中设置 Host、Token、ConnectionMode 和 AuthOption。 |
WithToolsFromAssembly(...) / WithTools(...) | 从程序集注册 [AiToolType] 类,或注册指定类型。 |
WithPromptsFromAssembly(...) / WithPrompts(...) | 注册 [AiPromptType] 提示类。 |
WithResourcesFromAssembly(...) / WithResources(...) | 注册 [AiResourceType] 资源类。 |
WithRuntimeErrorCapture() | 捕获游戏内错误,并注册 runtime-errors-get / runtime-errors-clear。默认关闭。 |
WithScriptExecute() | 在游戏中注册 script-execute。默认关闭;需要在 .csproj 中选择启用。 |
ConnectWhenRunFromEditor() | 当从编辑器用 Play 启动游戏时也进行连接。默认关闭。 |
WithoutMainThreadDispatcher() | 跳过自动的主线程调度器(仅在你安装了自己的调度器时使用)。 |
Host 和 token 也可以来自 GODOT_MCP_* 环境变量或 .env 文件,它们的优先级高于代码。游戏永远不会读取编辑器保存的设置。
提示与资源
除了工具之外,游戏还可以暴露 MCP prompts(具名指令模板,[AiPromptType] 搭配 [AiPrompt] 方法)和 resources(通过 URI 获取的只读内容,[AiResourceType] 搭配 [AiResource] 方法)。这两种类型都是可选的,注册方式与工具相同。
在游戏内运行 C#
要让 agent 在游戏中运行 C#,需要在游戏的 .csproj 中选择启用,并调用 WithScriptExecute():
<PropertyGroup>
<GodotMcpCodeExecInGame>true</GodotMcpCodeExecInGame>
<DefineConstants>$(DefineConstants);GODOT_MCP_CODE_EXEC_IN_GAME</DefineConstants>
</PropertyGroup>此功能仅适用于桌面平台的 CoreCLR 构建,不适用于 NativeAOT 或 iOS。
游戏构建的安全检查清单
- 优先在
localhost或127.0.0.1上使用 Custom 模式,并配合AuthOption.token和真实 token。 - 只注册你需要的工具;攻击面正是你所注册的那些工具。
- 在发布构建中,不要把连接暴露在公网网络接口上,除非你已为此做了专门的设计与安全加固。