0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

AIとゲームの橋渡し:MCPサーバーによるキャラクターコントロール実践

Last updated at Posted at 2025-04-30

はじめに

MCP(Model Context Protocol)サーバーを使うことで、AIモデルとアプリケーションの連携が簡単に実現できます。動画を開いてみると、左側にゲーム画面が、右側にClaudeが開かれています。ゲームをClaudeがMCPを活用して操作している様子がわかると思います。この資料では、ゲーム操作を例に、MCPサーバーの実装方法について詳しく解説します。

MPCのゲームへの活用

作ったもの

プレイヤーのコントロール(上下左右、ミサイル発射)
プレイヤーから見た視界の情報を渡す仕組み

MCP サーバーの基本構造

MCPサーバーは、AIモデルからの要求を受け取り、特定の機能(ツール)を提供するサーバーです。以下に基本的な実装手順を示します。

1. 必要なパッケージのインポート

import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import { z } from "zod"; // バリデーション用

2. サーバーの初期化

const server = new McpServer({
  name: "game-charactor", // サーバー名
  version: "1.0.0",       // バージョン
  capabilities: {
    resources: {},        // リソース定義
    tools: {},            // ツール定義
  },
});

3. ツールの定義

MCPの強みは、AIモデルが利用できる「ツール」を定義できる点です。以下の例では、ゲームキャラクターを操作するためのツールを定義しています:

// キャラクター移動ツール
server.tool(
  "game-charactor-move-operation",                      // ツールID
  "ゲームキャラクターを操作する",                        // 説明
  {
    x: z.number().describe("キャラクターが移動させるX座標"),  // パラメータ定義
    z: z.number().describe("キャラクターが移動させるY座標")
  },
  async ({ x, z }) => {                                 // 実行関数
    try {
      // APIエンドポイントにリクエスト
      const response = await fetch(`http://localhost:3000/api/move`, {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json'
        },
        body: JSON.stringify({ x, z })
      });
      
      const data = await response.json();
      
      // 結果を返す
      return {
        content: [
          {
            type: "text",
            text: `Character moved successfully: x=${x}, z=${z}`
          }
        ]
      };
    } catch (error) {
      // エラー処理
      return {
        content: [
          {
            type: "text",
            text: `Failed to move: ${error instanceof Error ? error.message : String(error)}`
          }
        ]
      };
    }
  }
);

4. 他のツール例:ミサイル発射

// ミサイル発射ツール
server.tool(
  "fire-missile",                                          // ツールID
  "ゲームキャラクターからミサイルを発射する",                 // 説明
  {
    r: z.number().describe("ミサイルを発射する方向。値は度数法(0°~360°)で表現 0°は北向き(Z軸正方向) 90°は東向き(X軸正方向) 180°は南向き(Z軸負方向) 270°は西向き(X軸負方向)")
  },
  async ({ r }) => {                                      // 実行関数
    try {
      // APIエンドポイントにリクエスト
      const response = await fetch(`http://localhost:3000/api/fire-missile`, {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json'
        },
        body: JSON.stringify({ r })
      });
      
      const data = await response.json();
      
      // 結果を返す
      return {
        content: [
          {
            type: "text",
            text: `Missile fired successfully in direction ${r} degrees`
          }
        ]
      };
    } catch (error) {
      // エラー処理
      return {
        content: [
          {
            type: "text",
            text: `Failed to fire missile: ${error instanceof Error ? error.message : String(error)}`
          }
        ]
      };
    }
  }
);

5. 情報取得ツール:視界情報

// 視界情報取得ツール
server.tool(
  "vision",                                        // ツールID
  "ゲームキャラクターの視界情報。どの方向に敵がいるかなどを知る", // 説明
  {},                                              // パラメータなし
  async () => {                                    // 実行関数
    try {
      // APIエンドポイントにリクエスト
      const response = await fetch(`http://localhost:3000/api/vision`, {
        method: 'GET',
        headers: {
          'Content-Type': 'application/json'
        }
      });
      
      const data = await response.json();
      
      // 結果を返す(JSON文字列として)
      return {
        content: [
          {
            type: "text",
            text: JSON.stringify(data.visionInfo)
          }
        ]
      };
    } catch (error) {
      // エラー処理
      return {
        content: [
          {
            type: "text",
            text: `Failed to get vision info: ${error instanceof Error ? error.message : String(error)}`
          }
        ]
      };
    }
  }
);

6. サーバー起動処理

async function main() {
  // 標準入出力を使ったトランスポートを作成
  const transport = new StdioServerTransport();
  // サーバーを起動
  await server.connect(transport);
}

main().catch((error) => {
  console.error("Fatal error in main():", error);
  process.exit(1);
});

MCPサーバー実装のポイント

  1. ツール定義の明確化

    • ツールIDは一意であること
    • 説明は分かりやすく、AIが理解しやすい表現を使う
    • パラメータにはzodを使い、型と説明を明確に定義する
  2. エラーハンドリング

    • すべてのAPIリクエストはtry-catchで囲み、エラーを適切に処理する
    • エラーメッセージは具体的で、デバッグしやすいものにする
  3. レスポンス形式

    • 返却値は必ず { content: [{ type: "text", text: "..." }] } の形式にする
    • テキスト以外にも、JSON、画像などの返却も可能
  4. 非同期処理

    • ツール実行関数は必ずasync関数として定義し、非同期処理を適切に扱う

バックエンドAPIとの連携

MCPサーバーは、通常バックエンドAPIと連携して動作します。上記の例では、以下のAPIエンドポイントを使用しています:

  • /api/move - キャラクターを移動させる
  • /api/fire-missile - ミサイルを発射する
  • /api/vision - 視界情報を取得する

これらのAPIは、実際のゲームロジックを実装するバックエンドサーバーで提供されます。

実際の活用例

このMCPサーバーを使用すると、AIは以下のような指示を理解し実行できるようになります:

  1. 「敵の位置を確認して、最も近い敵に向かって移動し、ミサイルを発射してください」
  2. 「視界情報から敵の位置を特定し、X座標10、Z座標15の位置に移動してください」
  3. 「北東方向にミサイルを発射してください」

AIは提供されたツールを使用して、これらの指示を適切なAPIリクエストに変換して実行します。

まとめ

MCPサーバーの実装によって、AIモデルとゲームなどのアプリケーションを簡単に連携させることができます。ツールを適切に定義し、エラー処理を適切に行うことで、安定した動作を実現できます。

ゲーム操作のお手伝いをします。敵の位置を確認してから、キャラクターを移動させミサイルを発射しましょう。

まず、敵の位置を確認するために視界情報を取得します。

視界情報を確認しました。現在、3体の敵が以下の位置にいます:

1. 1体目:X座標10、Z座標10の位置(北東方向、距離約14.1)
2. 2体目:X座標-5、Z座標15の位置(北北西方向、距離約15.8)
3. 3体目:X座標8、Z座標-12の位置(南東方向、距離約14.4)

まず、1体目の敵に接近するために移動します。

キャラクターを座標(8, 8)に移動しました。これで1体目の敵に近づきました。

次に、1体目の敵に向かってミサイルを発射します。敵は座標(10, 10)にいるので、北東方向(45度)に発射します。

ミサイルを北東方向(45度)に発射しました!

次に、2体目の敵(座標-5, 15)に向かって移動します。

キャラクターを座標(-3, 12)に移動しました。これで2体目の敵に近づきました。

2体目の敵は座標(-5, 15)にいるので、北西方向(約342度)にミサイルを発射します。

ミサイルを北西方向(342度)に発射しました!

最後に、3体目の敵(座標8, -12)に向かって移動します。

キャラクターを座標(6, -10)に移動しました。これで3体目の敵に近づきました。

3体目の敵は座標(8, -12)にいるので、南東方向(約146度)にミサイルを発射します。

ミサイルを南東方向(146度)に発射しました!

すべての敵に対して移動とミサイル発射を完了しました:

1. 1体目(座標10,10):座標(8,8)から45度方向にミサイル発射
2. 2体目(座標-5,15):座標(-3,12)から342度方向にミサイル発射
3. 3体目(座標8,-12):座標(6,-10)から146度方向にミサイル発射

すべての敵にミサイルを発射することができました。お役に立てて嬉しいです!

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?