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

## はじめに

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

<iframe width="560" height="315" src="https://www.youtube.com/embed/BVwZdBjdevg?si=x2MnJ1PGycaaXFEM" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen></iframe>


## MPCのゲームへの活用

https://gigazine.net/news/20250226-anthropic-claude-play-pokemon/

<blockquote class="twitter-tweet" data-media-max-width="560"><p lang="en" dir="ltr">As AI models become more complex and more capable, is it possible that they’ll have experiences of their own?<br><br>It’s an open question. We recently started a research program to investigate it. <a href="https://t.co/tVrWzsJQKP">pic.twitter.com/tVrWzsJQKP</a></p>&mdash; Anthropic (@AnthropicAI) <a href="https://twitter.com/AnthropicAI/status/1915420604397744497?ref_src=twsrc%5Etfw">April 24, 2025</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>


## 作ったもの

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

## MCP サーバーの基本構造

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

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

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

### 2. サーバーの初期化

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

### 3. ツールの定義

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

```javascript
// キャラクター移動ツール
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. 他のツール例：ミサイル発射

```javascript
// ミサイル発射ツール
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. 情報取得ツール：視界情報

```javascript
// 視界情報取得ツール
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. サーバー起動処理

```javascript
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度方向にミサイル発射

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

```