# カスタムツール — Unreal Engine · AI Game Developer Wiki

任意のC++プラグインから独自のAIツール、RQLモジュール、プロンプト、リソースをUnreal MCPに追加し、実行中のゲームでゲームプレイツールを公開できます。

このページは英語から機械翻訳されています。[英語の原文を読む](https://ai-game.dev/docs/wiki/unreal/custom-tools)。

Unreal MCPでは、自分のゲームプロジェクトのプラグインを含め、任意のUnrealプラグインがAIエージェント向けの機能を追加できます。Unreal MCPをフォークする必要はありません。小さな公開インターフェースを実装してUnrealの**モジュラーフィーチャー**として登録するだけで、モジュールの読み込み時にプラグインがそれを認識します。

このページはC++開発者向けです。エンジンのカバレッジを増やしたいだけの場合は、まず既成の[拡張機能](https://ai-game.dev/ja/docs/wiki/unreal/extensions)を確認してください。

## 適切な種類のコントリビューションを選ぶ

| エージェントに求めていること… | 提供するもの | インターフェース |
| --- | --- | --- |
| エンジン機能や独自型のエディタデータを読み取り・変更する | **RQLモジュール**（エディタ作業に推奨） | `IUnrealMcpRqlModule` |
| データアクセス以外のアクションを実行する、または実行中のゲーム内で操作する | **ツール** | `IUnrealMcpToolProvider` |
| 再利用可能なプロンプトテンプレートを取得する | **プロンプト** | `IUnrealMcpPromptProvider` |
| URIで固定コンテンツを読み取る | **リソース** | `IUnrealMcpResourceProvider` |

ファーストパーティの拡張機能はすべてRQLモジュールなので、エージェントはエディタの他の部分と同じ`rql-query`と`rql-mutate`ツールを通じてそれらにアクセスします。

## オプション1: RQLモジュール

エディタモジュールの`Build.cs`で`UnrealMcpRql`モジュールに依存し、`.uplugin`の`Plugins`配列で`UnrealMCP`プラグインを宣言します。その後、モジュールを実装します:

```cpp
#include "IUnrealMcpRqlModule.h"

class FMyRqlModule : public IUnrealMcpRqlModule
{
public:
    virtual FString GetRqlModuleName() const override { return TEXT("Niagara"); }
    virtual FString GetExtensionId() const override { return TEXT("com.example.niagara-ai"); }
    virtual FString GetExtensionVersion() const override { return UnrealMcpRql::PluginVersion(TEXT("MyNiagaraAI")); }
    virtual void ConfigureRql(FUnrealMcpRqlModuleContext& Context) override
    {
        Context.AddAssetSource(TEXT("niagaraSystems"), TEXT("Niagara system assets"), UNiagaraSystem::StaticClass());
        Context.AddApiSource(TEXT("niagara"), TEXT("Niagara operations"), UMyNiagaraOperations::StaticClass(),
            TEXT("NiagaraOperations"));
        Context.AddGuide(TEXT("Niagara"), TEXT("... markdown with example queries ..."));
    }
};

IMPLEMENT_MODULE(TUnrealMcpRqlEditorModule<FMyRqlModule>, MyNiagaraAI)
```

コンテキストで追加できるもの:

- **ソース**（クエリの開始点）: `AddObjectSource`、`AddObjectListSource`、`AddAssetSource`、`AddClassDefaultsSource`。
- **オペレーション**（`call`で呼び出し）: `AddApiClass`または`AddApiSource`は、クラスのすべての`UFUNCTION`を呼び出し可能にします。それらを`UFUNCTION(BlueprintCallable, meta = (BlueprintInternalUseOnly = "true"))`として宣言してください。各関数の上のドキュメントコメントが、エージェントが読む説明になります。
- **メンバー**: リフレクションから隠れたプロパティには`ExposeProperties`、読み取り専用の計算メンバーには`AddJsonMember`、`AddObjectMember`、`AddObjectListMember`。
- **ガイド**: `AddGuide`は`unreal-rql`スキルにセクションを追加します。

ミューテーションは1つのエディタトランザクションで実行されるため、オブジェクトは`RF_Transactional`で作成し、変更するものには`Modify()`を呼び出してください。エディタのExtensionsセクションにモジュールが表示され、無効化できます。ビルド可能なリファレンスは、[Unreal-MCPリポジトリ](https://github.com/IvanMurzak/Unreal-MCP)の`samples/UnrealAITemplate`プラグインです。

## オプション2: カスタムツール

### ステップ1: 依存関係を追加する

モジュールの`Build.cs`に:

```csharp
PublicDependencyModuleNames.AddRange(new string[] { "Core" });

PrivateDependencyModuleNames.AddRange(new string[]
{
    "CoreUObject", "Engine", "Projects",
    "Json",            // the registry header includes Dom/JsonObject.h
    "UnrealMcpEditor", // the extension contract and tool registry
});
```

`.uplugin`にプラグイン依存を追加して、読み込み順が解決されるようにします:

```json
{
  "Plugins": [ { "Name": "UnrealMCP", "Enabled": true } ]
}
```

### ステップ2: プロバイダーを実装する

```cpp
#include "IUnrealMcpToolProvider.h"
#include "UnrealMcpToolRegistry.h"

class FMyExtensionProvider : public IUnrealMcpToolProvider
{
public:
    virtual FString GetExtensionId() const override      { return TEXT("com.foo.my-extension"); }
    virtual FText   GetDisplayName() const override      { return NSLOCTEXT("Foo", "Name", "My Extension"); }
    virtual FString GetExtensionVersion() const override { return TEXT("1.0.0"); }

    virtual void RegisterTools(FUnrealMcpToolRegistry& Registry) override
    {
        Registry.Tool(TEXT("hello-extension"))
            .Title(TEXT("Hello Extension"))
            .Description(TEXT("Returns a friendly greeting."))
            .ParamString(TEXT("name"), TEXT("Who to greet. Defaults to 'world'."))
            .ReadOnlyHint(true).DestructiveHint(false).IdempotentHint(true).OpenWorldHint(false)
            .Handle([](const FUnrealMcpToolCall& Call) -> FUnrealMcpToolResult
            {
                const FString Name = Call.Has(TEXT("name")) ? Call.GetString(TEXT("name")) : TEXT("world");
                return FUnrealMcpToolResult::Success(FString::Printf(TEXT("Hello, %s!"), *Name));
            });
    }
};
```

ビルダーは`.Title`、`.Description`、パラメータヘルパー`.ParamString`、`.ParamInt`、`.ParamNumber`、`.ParamBool`、`.ParamVector`（必須にする場合は`EUnrealMcpParamRequirement::Required`を渡す）、4つのMCPヒント、そして`.Handle`を提供します。ハンドラーはゲームスレッドで実行されるため、エディタや`UObject`のAPIを直接呼び出せます。

重要なルール:

- ツールIDはケバブケースです。小文字と数字を単一のハイフンで区切ります。
- すべてのツールにタイトルと4つのヒントをすべて設定してください。削除や上書きを行うものは破壊的としてマークしてください。
- 自分で`.ExtensionId(...)`を呼び出さないでください。`GetExtensionId()`の値が自動的に設定されます。

### ステップ3: モジュラーフィーチャーとして登録する

```cpp
virtual void StartupModule() override
{
    Provider = MakeUnique<FMyExtensionProvider>();
    IModularFeatures::Get().RegisterModularFeature(
        IUnrealMcpToolProvider::GetModularFeatureName(), Provider.Get());
}

virtual void ShutdownModule() override
{
    if (Provider.IsValid())
    {
        IModularFeatures::Get().UnregisterModularFeature(
            IUnrealMcpToolProvider::GetModularFeatureName(), Provider.Get());
        Provider.Reset();
    }
}
```

プロバイダーは登録されている間は生かしておき、シャットダウン時には必ず登録解除してください。

## 登録の動作

- **検出とホットリロード。** プロバイダーはエディタ起動時に検出されます。後からモジュールを読み込みまたはアンロードするとレジストリが再構築され、AIクライアントはその変更を自動的に認識します。
- **決定的な順序。** プロバイダーは拡張IDの昇順でマージされ、1つのプロバイダー内のツールは宣言順を保ちます。
- **分離。** 無効なツール（不正なID、壊れたスキーマ、ハンドラーなし）や重複したツール名は破棄され、拡張のエントリに記録されます。他のツールや他の拡張機能は影響を受けません。ハンドラー内のクラッシュは依然としてエディタのクラッシュになるため、入力を検証して`FUnrealMcpToolResult::Error(...)`を返してください。
- **可視性と切り替え。** ツールには、組み込みのものと同じくMCP Toolsウィンドウに**Visible**チェックボックスが表示されます。無効化された拡張は何も提供しません。

## プロンプトとリソース

プロンプトとリソースは同じパターンを使用し、`IUnrealMcpPromptProvider` と `FUnrealMcpPromptRegistry`、`IUnrealMcpResourceProvider` と `FUnrealMcpResourceRegistry` を組み合わせます。プロンプトは同じ `Param*` ヘルパーでパラメータを宣言し、ロールタグ付きのメッセージを返します。リソースは URI で識別され、テキストまたは MIME タイプ付きの base64 blob のいずれかを返します。現在サポートされているのは固定 URI のみで、テンプレート化された URI には対応していません。組み込みの `level-design-brief` プロンプトと `unreal://project/levels` リソースは動作する参照例です。

## エージェントでツールを生成する

プラグインをソースからインストールしている場合、`unreal-skill-create` システムツールがプラグインのエディタモジュールに新しい C++ ツールファイルを書き込みます。ツールはエディタを再ビルド（Live Coding またはプロジェクトの再ビルド）した後にのみ存在します。

## ゲーム内（ランタイム）ツール

Unreal MCP は実行中のゲーム（Play In Editor、Standalone、またはパッケージ化された Development ビルド）にも接続できるため、AI エージェントがそれを操作できます。ランタイム接続ではエンジンツールは提供されず、ゲームが登録したツールのみが利用できます。

1. ゲームモジュールを `UnrealMcpRuntime`（`UnrealMcpEditor` ではない）に依存させ、上記とまったく同じ方法でツールを記述します。
2. **Project Settings, Plugins, Unreal MCP (Runtime)** を有効にします。このスイッチはデフォルトでオフで、`DefaultGame.ini` に保存されます。
3. 明示的に接続します。ゲームが自動的に接続することはありません。

C++ から：

```cpp
#include "UnrealMcpRuntimeSubsystem.h"

if (UUnrealMcpRuntimeSubsystem* Mcp = UUnrealMcpRuntimeSubsystem::Get(this))
{
    Mcp->RegisterToolProvider(MyToolProvider);
    Mcp->Connect(TEXT("http://localhost:8080"), TEXT("my-token"));
}
```

Blueprint からは、**Get Unreal MCP Runtime Subsystem** を使用し、その後 **Connect**、**Disconnect**、**Is Connected** を呼び出します。コンソールからは：

```text
UnrealMcp.Connect <host> [token]
UnrealMcp.Disconnect
```

`Connect()` に組み込まれた安全規則：

- Shipping ビルドは、`bUnrealMcpAllowShipping` フラグを含めてコンパイルしない限り接続を拒否します。
- `bAllowRemoteHost = true` を渡さない限り、ループバックホストのみが許可されます。
- ランタイムモードはデスクトッププラットフォーム（Windows、macOS、Linux）でのみ動作します。

リポジトリ内の `samples/UnrealAIRuntimeSample` プラグインは、実行中のゲームでワールドのタイムディレーションを読み取り、設定する `game-time-dilation` ツールを追加します。ランタイムツールが不要な場合は、[Installation](https://ai-game.dev/ja/docs/wiki/unreal/installation#editor-only) で説明されているように、パッケージ化されたビルドからプラグインを除外してください。

---

Source (HTML): https://ai-game.dev/ja/docs/wiki/unreal/custom-tools

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