# 自訂工具 — Godot · AI Game Developer Wiki

用 C# 撰寫你自己的 Godot MCP 工具，在主執行緒上呼叫 Godot API，並從執行中的 Godot 遊戲對外提供工具、提示詞與資源。

本頁面由英文機器翻譯而成。[閱讀英文原文](https://ai-game.dev/docs/wiki/godot/custom-tools)。

你可以在專案內用純 C# 將自己的 MCP 工具加進 Godot MCP。自訂工具就是一個 AI 代理可以呼叫的方法，並附上描述告訴模型它的用途。本頁涵蓋編輯器工具、主執行緒規則，以及讓代理能與執行中遊戲溝通的選用執行階段。

## 撰寫編輯器工具

工具家族是一個標上 `[AiToolType]` 的 `partial class`。每個工具都是標上 `[AiTool("tool-name")]` 的方法，並在方法及每個參數上加上 `[Description]`，讓模型知道何時該呼叫、以及如何呼叫。

```csharp
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`，或請代理執行 `script-build`）。Godot 會重新載入組件，外掛會重新連線，新工具就會出現在代理的工具清單與停靠面板的 Tools 視窗中。

### 讓工具保持可靠的規則

- **Godot 物件只能在主執行緒操作。** 工具方法是在主執行緒之外被呼叫的。任何對 `Node`、`Resource`、`SceneTree` 或 `EditorInterface` 的呼叫都必須透過 `MainThread.Instance.Run(...)` 進行。從背景執行緒存取它們可能導致編輯器當機。
- **回傳資料，而非格式化文字。** 回傳帶有屬性的類別（會序列化給模型），或對只有副作用的工具回傳 `void`。凡是代理需要解析的內容，都避免自己拼接字串。
- **標記選用參數。** 使用可為 null 的型別並給予預設值，例如 `string? filter = null`，模型就會把該參數視為選用。
- **把一切描述清楚。** 模型讀的就是這些描述。說明工具做什麼、何時使用，以及每個參數代表什麼。
- **僅限編輯器的程式碼要放在 `#if TOOLS` 之後。** 使用編輯器 API 的程式碼絕不能編譯進匯出的遊戲中。

### 提示與目標

`[AiTool]` 可接受選用提示，例如 `ReadOnlyHint = true` 與 `IdempotentHint = true`，用來告訴用戶端該工具不會改變任何東西，或可安全地重複執行。`Target` 決定工具註冊的位置：`ToolTarget.Editor`（僅編輯器）、`ToolTarget.Runtime`（僅遊戲），或預設的兩者皆可。

### 讓代理來撰寫工具

系統工具 `godot-skill-create` 會在你的專案中寫入新的 C# 工具檔案；下次建置後該工具即可被呼叫。在撰寫新工具之前，先確認 RQL 是否已能完成這件事：大多數的編輯器資料存取（節點、資源、檔案、專案設定）只要一次 `rql-query` 或 `rql-mutate` 就能搞定。參見 [Tools](https://ai-game.dev/zh-hant/docs/wiki/godot/tools#rql)。

## 執行中遊戲裡的工具

Godot MCP 也能在執行中或已匯出的遊戲內運作，無論是 debug 或 release 版本。這讓代理能讀取並驅動即時的遊戲狀態，例如一款由 LLM 提供機器人走步的西洋棋遊戲。有兩點是刻意設計的：

- **它絕不會自行連線。** 由你的程式碼決定是否以及何時呼叫 `Connect()`。
- **預設不公開任何東西。** 每個工具、提示詞與資源都由你自己註冊。外掛的編輯器工具不會編譯進遊戲組建中。

在 `SceneTree` 存在後啟動它，例如從 autoload 的 `_Ready()` 中：

```csharp
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`）標記僅限遊戲的工具類別，這樣編輯器就不會註冊它們，即使編輯器已連線，代理仍能連到遊戲。

### 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()`：

```xml
<PropertyGroup>
  <GodotMcpCodeExecInGame>true</GodotMcpCodeExecInGame>
  <DefineConstants>$(DefineConstants);GODOT_MCP_CODE_EXEC_IN_GAME</DefineConstants>
</PropertyGroup>
```

此功能僅支援桌面 CoreCLR 組建，不支援 NativeAOT 或 iOS。

**警告**

遊戲內的 `script-execute` 等同於任意程式碼執行，而執行階段錯誤擷取會轉送完整訊息與堆疊追蹤，其中可能包含路徑、使用者名稱或機密資訊。兩者都只應在開發組建中使用，並在具備真實權杖的 loopback 主機上啟用，絕不要在公開發行版本中保持啟用。

## 遊戲組建的安全檢查清單

- 優先使用 `localhost` 或 `127.0.0.1` 上的 Custom 模式，並搭配 `AuthOption.token` 與真實權杖。
- 只註冊你需要的工具；攻擊面就正好是你註冊的那些工具。
- 除非你已針對此用途設計並做好防護，否則不要在發行組建中把連線暴露在公開網路介面上。

完整的工具清單請見 [Tools](https://ai-game.dev/zh-hant/docs/wiki/godot/tools)；打包好的工具集請見 [Extensions](https://ai-game.dev/zh-hant/docs/wiki/godot/extensions)。

---

Source (HTML): https://ai-game.dev/zh-hant/docs/wiki/godot/custom-tools

Machine-translated (zh-Hant) from the English page: https://ai-game.dev/docs/wiki/godot/custom-tools
