3D・ゲーム開発のMCPサーバー:成否を決めるのはツール設計

run_python だけを公開するMCPサーバーは、すべてを渡して何も助けません。エージェントが実際に使える3Dツール面の条件を整理します。

Cuberta でエージェントが構築した街区全体を上空から見たところ。建物と道路

3Dアプリケーション向けのMCPサーバーは、遅かれ早かれ同じ分岐に行き当たります。ツールを一つだけ——run_python(code)——公開して、アプリケーションのAPI全体を一晩でエージェントに渡すこともできます。あるいは、ロケーションに本当に必要な操作が二十個どれなのかを見極め、それだけを公開することもできます。こちらは数週間かかります。プロトコル側の作業量はどちらも同じですが、その後にエージェントができることは同じになりません。

二百語で分かるMCP

Model Context Protocol は技法ではなく通信の取り決めです。ホスト(目の前にあるAIアプリケーション。エージェント型のCLIやIDE)が接続ごとにクライアントを一つ起動し、各クライアントが一つのサーバーと話します。サーバーは JSON-RPC に応答するただのプログラムで、同じマシン上の標準入出力か、HTTP のどちらかを使います。

サーバーが提供するものは三つです。ツールはモデルが呼び出せる関数で、名前・説明・引数の JSON Schema を持ちます。実際の仕事はこれが行います。リソースはホストが取り込める読み取り専用のデータで、ファイルやスキーマ、マニフェストなどです。プロンプトはユーザーがメニューから選ぶ定型テンプレートです。3Dサーバーでは重みのほとんどをツールが担い、リソースはたまに、プロンプトはほぼ使われません。

Anthropic は2024年11月に MCP を公開し、その一年後に Linux Foundation の Agentic AI Foundation へ寄贈しました。運営委員会には OpenAI、Google、Microsoft、AWS が名を連ねています。ツールの作り手にとってはこれがプロトコルのすべてで、だからこそプロトコルは難しい問題ではありません。

ツール面こそが製品

run_python の代償

コード実行ツールが一つあるだけの構成は、最大限に見えます。アプリケーションにできることが一度にすべて開かれるからです。しかし実際には、エージェントがもともと持っていなかったものを何も与えていません。それを使うには、モデルがアプリケーションのAPIを記憶から再現しなければなりません。モジュールパス、引数の順番、どの軸が上かという取り決め、単位。その記憶は学習時点で凍結されていますが、あなたのディスクにあるビルドは違います。結果としてループはこうなります。スクリプトを書く、トレースバックを読む、名前を直す、次のトレースバックを読む。通り沿いに家を一列並べるだけで二十往復、うち十五往復は自分の失敗の後始末です。しかもこのツールには縁がありません。立方体を足すスクリプトは、まったく同じ権限でシーンを消せます。

同じ仕事を一段上げる

今度は、仕事の形に合わせたツールを渡してみます。

get_scene_summary()
create_road_network(layout, length_m, lanes, sidewalks)
place_buildings_along(road_id, count, storeys, facade)
set_sun(azimuth_deg, elevation_deg)

家十二軒の通りは、三回の呼び出しと一回の読み戻しになります。エージェントにAPIの知識はもう要りません。ツールの一覧がそのまま計画だからです。ターン数はおおよそ一桁減り、速度以上に有り難いことに、失敗するターンは読める場所で失敗するようになります。

これはオブジェクトではなくシーンを生成するという話とまったく同じ論法です。構成はジオメトリとは別の問題であり、ツールは構成についてのものでなければなりません。

どこまで粗いと粗すぎるか

上げすぎるのも別種の失敗です。build_city(prompt) 一つだけならスロットマシンと同じで、レバーは一本、気に入らない箇所を直す手段はありません。ちょうどよい高さの目安はこうです。ツールは、レベルデザイナーが口に出して言うことと一対一で対応するべきです。「この街区を二階建てで埋めて」。ツールを一文で言えないなら、高さの選び方が間違っています。

  • ツールは十五から四十個、四百個ではありません。定義はユーザーが何か打ち込む前からコンテキストに載っており、長すぎるカタログはツール選択の精度を目に見えて下げます。
  • 引数は一ツールあたり八個以下。それを超えると、モデルは当て推量で欄を埋め始めます。
  • 集合が閉じているところは自由記述ではなく列挙型で。facade: brick | render | glass は捏造できませんが、文字列はできます。
  • 単位は引数名に入れる。length_m はバグの一群をまるごと消します。

読み戻しは、みんなが飛ばす半分

書き込みしかできないエージェントは手探りで作業しています。ビューポートに目はなく、自分の位置感覚もありません。四回も呼び出せば、シーンについての理解は自分が自分に語った物語になります。エージェント3Dで良いものはすべてこのループを閉じることから生まれ、ループを閉じるのは読み取りツールです。

良いシーンサマリーはサマリーであってダンプではありません。全オブジェクトの全トランスフォームは、巨大であると同時に役に立ちません。エージェントが実際に必要としているのは次のものです。

  • カテゴリ別の個数と、メートル単位の全体バウンディングボックス
  • あとで変更しうるものすべてに付いた安定したid
  • 関係——どの建物がどの道路に属し、どの部屋にどの小道具があるか
  • そして何より問題点。行き止まりになった道路、貫通している二つのメッシュ、通りに背を向けた建物

最後の一項が、読み取りツールと診断ツールを分けます。そして価値が高いのは診断のほうです。壊れていると告げられたものはエージェントが直しますが、自分で気づくことはめったにありません。ビューポートのスクリーンショットも読み取りツールとして扱ってください。「これは通りに見えるか」にはどんな座標表より強く、「この壁は4cmずれているか」にはまったく無力です。両方を用意してください。

冪等性、あるいは三度建てられた道路

エージェントは再試行します。クライアントも再試行します。エディタが忙しいあいだに呼び出しがタイムアウトし、クライアントが送り直し、同じ道路網が二つ、同じ z を奪い合うことになります。

対処は、書き込みをアドレス可能にすることです。何かを作るツールは安定したidを返し、そのidを付けて再度呼べば追加ではなく更新になります。place_building(building_id, ...) を二回呼べば建物は一棟。place_building(...) を二回呼べば二棟です。

MCPにはこのための語彙があります。ツールアノテーション——readOnlyHintdestructiveHintidempotentHintopenWorldHint——は 2025-03-26 版で入り、ホストは何を自動承認し何で止めて尋ねるかをこれで判断します。強制ではなくヒントであり、注釈のないツールは最悪のケース、つまり破壊的で非冪等でインターネットに出ていくもの、と見なされます。読み取りツールに read-only を付ける十分間の作業が、あらゆるループから確認ダイアログを一つ取り除きます。

エラーメッセージもプロンプトである

3DのMCPサーバーが返すエラーの読者はただ一人で、それは人間ではありません。デバッガもソースも持たないまま次の一手を決めようとしているモデルです。その読者に向けて書けば、エラーは手元でいちばん安上がりな教育の場になります。

ツールが返したものエージェントの次の行動
「引数が不正です」まったく同じ呼び出しを再試行し、その後は勘で進む。
40行のPythonトレースバック500トークンを費やして行番号を一つ学ぶ。
「lane_width_m は 2.5 から 6.0 の範囲、受け取った値は 45」妥当な幅で呼び直す。
「r_07 という道路はありません。存在するのは r_01、r_02、r_03。」読み戻しなしでidを訂正する。

つまり、何が不正だったか何なら正しいかを書き、混乱を解消できるツールの名前を挙げ、部分的な成功を正直に報告することです。40本の木のうち34本が置けて6本がポリゴンの外に落ちたなら、どの6本かを言う。部分結果を「成功」として返すことこそ、エージェントが悪い基礎の上に三階を建てる仕組みだからです。

被害範囲

ソースコードを編集するエージェントは git で巻き戻せます。3Dシーンを編集するエージェントが触っているのは、誰かが何時間も手で整えてきた、しかも多くの場合バージョン管理のないドキュメントです。ここでの失敗は悪いコミットではなく、消えた午後です。

アンドゥ、境界、そして手が届かないツール

  • 一回の呼び出しにつきアンドゥ一段。木を四十本置いてアンドゥスタックに四十件残るなら、そのアンドゥは飾りです。
  • 境界はプロンプトではなくサーバーに。「このポリゴンの内側だけに建てて」はプロンプトに書けばお願いですが、ツール内部の境界チェックにすれば保証になります。建築禁止として印を付けた領域は後者に属します。
  • 破壊的な動詞にはスコープを。delete_selection は問題ありません。delete_all は存在しないか、明示的な確認の向こう側に置くべきです。MCPの elicitation を使えば、サーバーは呼び出しの途中でユーザーに尋ねられます。

誰も見積もらない注入面

ツールの出力は信頼できない入力です。コミュニティのアセットライブラリを検索するサーバーは、見知らぬ人が書いたタイトルとタグを返し、その文章はあなたの指示のすぐ隣、エージェントのコンテキストに着地します。ツールポイズニング——ツールの返り値に指示を紛れ込ませる手口——は記録された攻撃分類であり、アセットのメタデータは理想的な運び手です。次にどのツールを呼ぶかという判断を、ネットワークから来た文章から遠ざけてください。

Cuberta はこの取引の狭いほうを選んでいます。自前のMCPサーバーを持つ無料のデスクトップエディタで、Copy connect command を押してターミナルに貼り付ければ、あなたのエージェントがつながります。作られるものはすべて選択・移動・削除・取り消しができる実体のあるオブジェクトで、建てて良いと印を付けた範囲の内側にとどまります。

いま存在するもの、カテゴリ別

3D周辺のMCPは、おおむね四つの形に分かれます。

  • DCCブリッジ。Blender、Maya、Houdini、Cinema 4D、テクスチャ系アプリの内部でアドオンがソケットを持ち、外側の小さなプロセスがMCPの呼び出しをそこへ中継します。最も知られているのは Blender MCP です。ほぼすべてがコード実行ツールを備えており、これは run_python 問題の自然な生息地です。その得失は別の記事の題材です。
  • アセットライブラリと生成のサーバー。Sketchfab、Poly Haven、Meshy、Tripo、Hyper3D Rodin。検索・プレビュー・ダウンロード・インポート。作るのがいちばん簡単な部類です。読み取り中心で完全にオープンワールドなので、アノテーションと注入対策の衛生管理はここが最も重要になります。
  • エンジンブリッジ。Unity、Unreal、Godot、Roblox Studio のいずれにも存在します。多くはコミュニティ製で、広く使われているUnity向けのものは Unity Technologies とは無関係です。一方 Unreal Engine 5.8 には Epic 製の実験的な公式MCPプラグインが同梱され、アクター、シーン、マテリアルインスタンス向けのツールセットが用意されています。ここで繰り返し起きる危険は非同期性です。スクリプトを書き換え、エディタの再コンパイルが終わる前に戻るツールは、当てにできない成功を報告します。
  • エージェント前提で作られたエディタ。最初からエージェントを想定して設計され、MCP面が既存APIの被せ物ではなく主たるインターフェースになっているアプリケーションです。Cuberta はこの作りです。粒度を自分で選べる唯一のカテゴリでもあります。

自分で書くなら

APIからではなく、会話の書き起こしから始めてください。ユーザーが自分の言葉であなたのアプリケーションに実際に言いそうな文を十個書き出す。その文があなたのツールで、すでにあるAPIはその下の実装詳細です。そのうえで、

  • 読み戻しツールを最初に出し、自分で使ってください。自分のシーンサマリーを自分で理解できないなら、モデルにも理解できません。
  • ツールは結果で名付けます。batch_transform_instances ではなく place_buildings_along です。
  • システムプロンプトも例も与えていないエージェントでテストします。最初の一回で間違えたものは、モデルの問題ではなくツールの問題です。

ツール面は設計文書です。あなたのアプリケーションがシーンを何でできていると考えているか、人はどの粒度でそれを考えるか、どの間違いなら安く済むかが、そこに書かれています。エージェントはたまたま、その文書を極めて字義通りに読む読者だった——だからそれを丁寧に書くことが仕事の大半で、その下のプロトコルは本当にいちばん簡単な部分なのです。