【Unity】UnityNaturalMCPで独自のMCPツールをC#で自由に作ってClaude Codeにそれを実行させる方法

UnityNaturalMCPで独自のMCPツールをC#で自由に作ってClaude Codeにそれを実行させる方法です。

Unity6000.2.0f1
UnityNaturalMCP 0.5.0

UnityNaturalMCPとは?

UnityNaturalMCPはUnityエディタを操作するためのMCPサーバです。

github.com

基本的な使い方は以下の記事で解説していますので、必要に応じて参照してください。

light11.hatenadiary.com

このUnityNaturalMCPの特徴として、C#で独自のMCPツールを作成できるという点があります。
そこで本記事では、UnityNaturalMCPでカスタムMCPツールを作ってClaude Codeに独自の処理を実行させる方法をまとめます。

作るもの

UnityNaturalMCPはデフォルトではアセットを作ることができません。
そこで、指定した型のScriptableObjectのアセットを作るツールを作ってみます。

以下のScriptableObjectクラスを作成しておき、このアセットが生成できることをゴールとします。

using UnityEngine;

public class ExampleConfig : ScriptableObject
{
    public int maxLives = 3;
    public float moveSpeed = 5f;
}

ツールを作る

まず指定したScriptableObjectのアセットを作るツールを作成します。

説明はコメントとして記載しました。

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using Cysharp.Threading.Tasks;
using ModelContextProtocol.Server;
using UnityEditor;
using UnityEngine;

[McpServerToolType]
[Description("ScriptableObjectのアセットを作成するためのツール")]
public class ScriptableObjectTools
{
    [McpServerTool]
    [Description("指定型のScriptableObjectのアセットを新規作成")]
    // 非同期メソッドにする場合、戻り値はValueTaskで
    public async ValueTask<Dictionary<string, string>> CreateScriptableObject(string typeName, string assetPath)
    {
        try
        {
            // メインスレッドに切り替え(サブスレッドから呼ばれる可能性もあるが、UnityAPIは対応してないため)
            await UniTask.SwitchToMainThread();
            
            // 型名からScriptableObjectの型を取得
            var type = FindTypeByName(typeName);
            var instance = ScriptableObject.CreateInstance(type);

            // フォルダ作成
            var directory = Path.GetDirectoryName(assetPath);
            if (!string.IsNullOrEmpty(directory) && !Directory.Exists(directory))
                Directory.CreateDirectory(directory);

            // アセット作成
            AssetDatabase.CreateAsset(instance, assetPath);

            // アセットの情報を返す
            var guid = AssetDatabase.AssetPathToGUID(assetPath);
            return new Dictionary<string, string>
            {
                { "guid", guid }, { "path", assetPath }, { "type", typeName }, { "name", instance.name }
            };
        }
        catch (Exception e)
        {
            // UnityNaturalMCPのREADMEより:
            // > MCPツール内でエラーが発生した場合、それはログに表示されません。
            // > try-catchブロックを使用して、エラーをログに記録し、再スローすることを推奨します。
            Debug.LogError(e);
            throw;
        }
    }

    private static Type FindTypeByName(string typeName)
    {
        var type = Type.GetType(typeName);
        if (type != null)
        {
            if (!typeof(ScriptableObject).IsAssignableFrom(type))
                throw new Exception($"Type is not ScriptableObject: {typeName}");
            return type;
        }

        var scriptableObjectTypes = TypeCache.GetTypesDerivedFrom<ScriptableObject>();

        type = scriptableObjectTypes.FirstOrDefault(t => t.FullName == typeName);
        if (type != null)
            return type;

        type = scriptableObjectTypes.FirstOrDefault(t => t.Name == typeName);

        if (type != null)
            return type;

        throw new Exception($"Type not found: {typeName}");
    }
}

ツールビルダーを作る

次にこのツールをMCPサーバに登録するためのスクリプト(ツールビルダー)を作成します。
ボイラープレートです。

using Microsoft.Extensions.DependencyInjection;
using UnityEngine;
using UnityNaturalMCP.Editor;

[CreateAssetMenu(fileName = "ScriptableObjectToolsBuilder",
    menuName = "UnityNaturalMCP/ScriptableObject Tools Builder")]
public class McpScriptableObjectToolsBuilder : McpBuilderScriptableObject
{
    public override void Build(IMcpServerBuilder builder)
    {
        builder.WithTools<ScriptableObjectTools>();
    }
}

基底クラスを見るとわかるように、ツールビルダーはScriptableObjectになっています。
このScriptableObjectのアセットを作成することで、ツールがMCPサーバに登録されます。

CreateAssetMenuアトリビュートに指定したメニュー(今回であればAssets > Create > UnityNaturalMCP > ScriptableObject Tools Builder)を実行し、このビルダーのアセットを作成します。

ここまででツールのクラスとツールビルダーのクラスおよびそのScriptableObjectアセットができました。

作成完了

MCPサーバの更新

ここまでできたら Edit > Project Settings > Unity Natural MCP > RefreshMCPサーバを再起動します。
(手元の環境ではさらにClaudeCodeを一度再起動しないとうまくいきませんでした。

これでMCPサーバにツールが読み込まれたはずです。以下のようにClaude Codeに聞いてみましょう。

UnityNaturalMCPで使えるツールを全部教えて

返答はこんな感じです。CreateScriptableObjectがあるので正常に更新されてそうです。

⏺ UnityNaturalMCPで利用可能なツールは以下の6つです:

  1. RunPlayModeTests - Play Modeのテストを実行
  2. RunEditModeTests - Edit Modeのテストを実行
  3. CreateScriptableObject - 指定型のScriptableObjectアセットを新規作成
  4. GetCurrentConsoleLogs - 現在のコンソールログを取得
  5. ClearConsoleLogs - コンソールログをクリア
  6. RefreshAssets - AssetDatabase.Refresh()を実行(スクリプトコンパイル時にも必要)
  7. GetCompileLogs - コンパイルエラーを取得

  各ツールはフィルタリングやオプション設定が可能で、テスト実行時はassemblyNames、groupNames、tes
  tNamesでの絞り込み、ログ取得時はlogTypes、filter、maxCountなどでの制御ができます。

動作確認

それでは次に以下のようにClaude Codeに指示してみましょう。

ExampleConfigのアセットを作って

すると以下のようなメッセージと共に、アセットを作成してくれることを確認できます。

⏺ ExampleConfigのScriptableObjectアセットを作成します。                                     

⏺ unity-natural-mcp - CreateScriptableObject (MCP)(typeName: "ExampleConfig", assetPath:
                                                  "Assets/ExampleConfig.asset")
  ⎿  {                                                                                         
       "guid": "668cbf529834644f6bfc027587b69711",
       "path": "Assets/ExampleConfig.asset",
       "type": "ExampleConfig",
       "name": "ExampleConfig"
     }

⏺ ExampleConfigアセットを作成しました。                                                     
  - パス: Assets/ExampleConfig.asset
  - GUID: 668cbf529834644f6bfc027587b69711

関連

light11.hatenadiary.com

参考

github.com