MCPを理解する：生成AIの連携プロトコルの基礎から実装まで

## はじめに

生成AI技術の急速な発展により、ChatGPTやGeminiなどの大規模言語モデル（LLM）が私たちの日常生活やビジネスに革命をもたらしています。
しかし、これらの強力なモデルを効果的に連携させ、より複雑なタスクを実行するための標準的な方法が必要とされています。

そこで登場したのが **MCP（Model Completion Protocol）** です。
MCPは生成AIモデル間の連携を可能にする標準プロトコルであり、異なるAIサービスを簡単に接続して複雑なワークフローを構築できるようにします。

この記事では、MCPの基本概念から実装方法まで、初心者から中級者手前の方々を対象に解説していきます。
技術的な内容は徐々に深くなっていきますので、最後まで読み進めることで、MCPの全体像を把握できるでしょう。

## MCPとは何か？

MCP（Model Completion Protocol）は、生成AIモデル間の連携を標準化するためのプロトコルです。簡単に言えば、異なるAIサービスが共通の言語で会話するための「約束事」のようなものです。

MCPの核となる考え方は以下の通りです：

1. **標準化されたインターフェース**: 異なるAIモデルやサービスが同じ方法で通信できるようにする
2. **モジュール性**: 特定の機能に特化したAIサービスを組み合わせて使用できるようにする
3. **相互運用性**: 異なるベンダーやプラットフォームのAIサービスを連携させる

MCPが解決しようとしている問題は、生成AIの「連携の複雑さ」です。
例えば、あるタスクを実行するために複数のAIサービスを連携させようとすると、それぞれのAPIの仕様を理解し、データの変換や処理を行う必要があります。
MCPはこの複雑さを抽象化し、標準的なインターフェースを提供することで、開発者の負担を軽減します。

## なぜMCPが必要なのか？

生成AIの世界では、特定のタスクに特化したモデルが次々と開発されています。例えば

- テキスト生成に特化したモデル
- コード生成に特化したモデル
- 画像生成に特化したモデル
- データ分析に特化したモデル

これらのモデルは単体でも強力ですが、連携させることでさらに複雑なタスクを実行できるようになります。しかし、これまではそれぞれのモデルやサービスが独自のAPIやインターフェースを持っていたため、連携させるのは容易ではありませんでした。

MCPが提供する標準化されたプロトコルにより、以下のようなメリットが生まれます

1. **開発の効率化**: 標準的なインターフェースを使うことで、開発者は各サービスの詳細な実装を理解する必要がなくなります
2. **柔軟なシステム構築**: 必要に応じて異なるAIサービスを組み合わせることができます
3. **ベンダーロックインの回避**: 特定のプラットフォームに依存せず、最適なサービスを選択できます
4. **イノベーションの促進**: 標準化されたインターフェースにより、新しいAIサービスの開発と統合が容易になります

## MCPの基本構造

MCPの基本構造は、クライアントとサーバーのモデルに基づいています。

### MCPクライアント

MCPクライアントは、ユーザーからの入力を受け取り、適切なMCPサーバーにリクエストを送信する役割を担います。一般的には、以下のような機能を持ちます

- ユーザーからの入力の処理
- 適切なMCPサーバーの選択
- リクエストの送信と応答の処理
- 複数のMCPサーバーとの連携の調整

例えば、ChatGPTのようなLLMがMCPクライアントとして機能し、ユーザーからのリクエストに応じて適切なMCPサーバーにタスクを委任することができます。

### MCPサーバー

MCPサーバーは、特定の機能やタスクを実行するためのAIサービスです。例えば：

- 天気情報を提供するサーバー
- 画像生成を行うサーバー
- データベースクエリを実行するサーバー
- 数学的計算を行うサーバー

各MCPサーバーは、自身が提供する機能（ツール）に関する情報をクライアントに公開します。これにより、クライアントは利用可能なツールを把握し、適切なサーバーにリクエストを送信できるようになります。

### MCPのデータフロー

MCPにおけるデータの流れは以下のようになります

1. ユーザーがMCPクライアント（例：ChatGPT）にリクエストを送信
2. クライアントはリクエストを分析し、必要なタスクを特定
3. クライアントは適切なMCPサーバーにリクエストを送信
4. サーバーはリクエストを処理し、結果をクライアントに返送
5. クライアントは結果を統合し、ユーザーに提示

このプロセスにより、複数のAIサービスを連携させて複雑なタスクを実行することが可能になります。

## MCPの技術的詳細

ここからは、MCPの技術的な側面について詳しく見ていきましょう。

### MCPのプロトコル仕様

MCPのプロトコル仕様は、JSON形式のリクエストとレスポンスに基づいています。
基本的な構造は以下の通りです。

#### リクエスト

```json
{
  "prompt": "ユーザーからの入力テキスト",
  "tools": [
    {
      "name": "ツール名",
      "description": "ツールの説明",
      "parameters": {
        "type": "object",
        "properties": {
          "param1": {
            "type": "string",
            "description": "パラメータ1の説明"
          },
          "param2": {
            "type": "number",
            "description": "パラメータ2の説明"
          }
        },
        "required": ["param1"]
      }
    }
  ]
}
```

#### レスポンス

```json
{
  "completion": "生成されたテキスト",
  "tool_calls": [
    {
      "name": "ツール名",
      "parameters": {
        "param1": "値1",
        "param2": 42
      }
    }
  ]
}
```

### ツールの定義

MCPにおける「ツール」は、特定の機能やタスクを実行するためのインターフェースです。各ツールは以下の要素で定義されます

- **名前**: ツールを識別するための一意の名前
- **説明**: ツールの機能を説明するテキスト
- **パラメータ**: ツールが受け付けるパラメータの定義
  - パラメータの名前
  - パラメータの型（文字列、数値、ブール値など）
  - パラメータの説明
  - 必須パラメータの指定

ツールの定義は、OpenAPIやJSON Schemaの形式に似ており、クライアントがツールの使用方法を理解するために使用されます。

### MCPの実装例

実際のMCP実装を見てみましょう。
以下は、Pythonを使ったシンプルなMCPサーバーの例です。

```python
from flask import Flask, request, jsonify

app = Flask(__name__)

# 天気情報を提供するツール
weather_tool = {
    "name": "get_weather",
    "description": "指定された都市の天気情報を取得します",
    "parameters": {
        "type": "object",
        "properties": {
            "city": {
                "type": "string",
                "description": "天気を取得したい都市名"
            }
        },
        "required": ["city"]
    }
}

# 利用可能なツールのリスト
available_tools = [weather_tool]

# 天気情報を取得する関数（実際にはAPI呼び出しなどを行う）
def get_weather(city):
    # 実際のアプリケーションでは外部APIを呼び出すなどの処理を行う
    weather_data = {
        "Tokyo": "晴れ、気温25度",
        "Osaka": "曇り、気温22度",
        "Fukuoka": "雨、気温20度"
    }
    return weather_data.get(city, f"{city}の天気情報は利用できません")

@app.route("/tools", methods=["GET"])
def list_tools():
    return jsonify(available_tools)

@app.route("/complete", methods=["POST"])
def complete():
    data = request.json
    prompt = data.get("prompt", "")
    
    # プロンプトを分析して、ツール呼び出しが必要かどうかを判断
    if "天気" in prompt:
        # 都市名を抽出（実際にはもっと高度な処理が必要）
        city = "Tokyo"  # 簡略化のため固定値
        weather_info = get_weather(city)
        
        response = {
            "completion": f"{city}の天気情報: {weather_info}",
            "tool_calls": [
                {
                    "name": "get_weather",
                    "parameters": {
                        "city": city
                    }
                }
            ]
        }
    else:
        response = {
            "completion": "申し訳ありませんが、天気情報以外の質問にはお答えできません。",
            "tool_calls": []
        }
    
    return jsonify(response)

if __name__ == "__main__":
    app.run(debug=True)
```

この例では、天気情報を提供するシンプルなMCPサーバーを実装しています。
実際のアプリケーションではもっと複雑な処理が必要ですが、基本的な構造を理解するのに役立つでしょう。

## MCPの実用例

MCPの実用例をいくつか見てみましょう。

### 例1: 複数のデータソースを統合した情報検索

ユーザーが「東京の明日の天気と、おすすめのレストラン」という質問をした場合

1. MCPクライアント（ChatGPT）が質問を分析
2. 「天気」に関する部分を天気情報MCPサーバーに送信
3. 「レストラン」に関する部分をレストラン推薦MCPサーバーに送信
4. 両方のサーバーからの応答を統合して回答を生成

### 例2: コード生成と実行

ユーザーが「Pythonで素数を計算するプログラムを作成して実行して」という要求をした場合

1. MCPクライアントが要求を分析
2. コード生成MCPサーバーにプログラム作成を依頼
3. 生成されたコードをコード実行MCPサーバーに送信
4. 実行結果をユーザーに提示

### 例3: マルチモーダルな対話

ユーザーが画像をアップロードし、「この画像を分析して、似たような風景の場所を教えて」と質問した場合：

1. MCPクライアントが要求を分析
2. 画像分析MCPサーバーに画像の分析を依頼
3. 分析結果を地理情報MCPサーバーに送信して類似の場所を検索
4. 結果をユーザーに提示

これらの例からわかるように、MCPを使用することで、複数のAIサービスを連携させて複雑なタスクを実行することが可能になります。

## MCPの実装方法

ここでは、実際にMCPを実装する方法について説明します。

### MCPサーバーの実装

MCPサーバーを実装するには、以下の手順が必要です：

1. **エンドポイントの設定**: MCPリクエストを受け付けるためのHTTPエンドポイントを設定
2. **ツールの定義**: 提供する機能（ツール）を定義
3. **リクエスト処理**: クライアントからのリクエストを処理し、適切な応答を返す

以下は、Pythonを使ったMCPサーバーの実装例です（Flaskフレームワークを使用）

```python
from flask import Flask, request, jsonify

app = Flask(__name__)

# 計算機能を提供するツール
calculator_tool = {
    "name": "calculate",
    "description": "数学的な計算を実行します",
    "parameters": {
        "type": "object",
        "properties": {
            "expression": {
                "type": "string",
                "description": "計算式（例: 2 + 2）"
            }
        },
        "required": ["expression"]
    }
}

# 利用可能なツールのリスト
available_tools = [calculator_tool]

# 計算を実行する関数
def calculate(expression):
    try:
        # 注意: eval()は実際のアプリケーションでは安全でない場合があります
        result = eval(expression)
        return str(result)
    except Exception as e:
        return f"計算エラー: {str(e)}"

@app.route("/tools", methods=["GET"])
def list_tools():
    return jsonify(available_tools)

@app.route("/complete", methods=["POST"])
def complete():
    data = request.json
    prompt = data.get("prompt", "")
    
    # プロンプトを分析して、計算が必要かどうかを判断
    if "計算" in prompt:
        # 計算式を抽出（実際にはもっと高度な処理が必要）
        expression = prompt.split("計算")[1].strip()
        result = calculate(expression)
        
        response = {
            "completion": f"計算結果: {result}",
            "tool_calls": [
                {
                    "name": "calculate",
                    "parameters": {
                        "expression": expression
                    }
                }
            ]
        }
    else:
        response = {
            "completion": "計算に関する質問を入力してください。",
            "tool_calls": []
        }
    
    return jsonify(response)

if __name__ == "__main__":
    app.run(debug=True, port=5001)
```

### MCPクライアントの実装

MCPクライアントを実装するには、以下の手順が必要です

1. **ユーザー入力の処理**: ユーザーからの入力を受け取り、必要なタスクを特定
2. **MCPサーバーの検出**: 利用可能なMCPサーバーとそのツールを検出
3. **リクエストの送信**: 適切なMCPサーバーにリクエストを送信
4. **応答の処理**: サーバーからの応答を処理し、ユーザーに提示

以下は、Pythonを使ったシンプルなMCPクライアントの実装例です

```python
import requests
import json

class MCPClient:
    def __init__(self):
        # 利用可能なMCPサーバーのリスト
        self.servers = [
            {
                "name": "計算サーバー",
                "url": "http://localhost:5001",
                "tools": []
            },
            {
                "name": "天気サーバー",
                "url": "http://localhost:5002",
                "tools": []
            }
        ]
        
        # 各サーバーから利用可能なツールを取得
        self.discover_tools()
    
    def discover_tools(self):
        """各サーバーから利用可能なツールを取得"""
        for server in self.servers:
            try:
                response = requests.get(f"{server['url']}/tools")
                if response.status_code == 200:
                    server["tools"] = response.json()
            except Exception as e:
                print(f"サーバー {server['name']} からツールを取得できませんでした: {str(e)}")
    
    def find_server_for_tool(self, tool_name):
        """指定されたツールを提供するサーバーを検索"""
        for server in self.servers:
            for tool in server["tools"]:
                if tool["name"] == tool_name:
                    return server
        return None
    
    def process_user_input(self, user_input):
        """ユーザー入力を処理し、適切なサーバーにリクエストを送信"""
        # 簡略化のため、キーワードベースでサーバーを選択
        if "計算" in user_input:
            server = self.find_server_for_tool("calculate")
            if server:
                return self.send_request(server, user_input)
        elif "天気" in user_input:
            server = self.find_server_for_tool("get_weather")
            if server:
                return self.send_request(server, user_input)
        
        return "申し訳ありませんが、対応できるサーバーが見つかりませんでした。"
    
    def send_request(self, server, prompt):
        """サーバーにリクエストを送信"""
        try:
            data = {
                "prompt": prompt
            }
            response = requests.post(f"{server['url']}/complete", json=data)
            if response.status_code == 200:
                result = response.json()
                return result["completion"]
            else:
                return f"エラー: サーバーからの応答コード {response.status_code}"
        except Exception as e:
            return f"リクエスト送信エラー: {str(e)}"

# クライアントの使用例
if __name__ == "__main__":
    client = MCPClient()
    
    while True:
        user_input = input("質問を入力してください（終了するには 'exit' と入力）: ")
        if user_input.lower() == "exit":
            break
        
        response = client.process_user_input(user_input)
        print(f"応答: {response}")
```

この例では、2つのMCPサーバー（計算サーバーと天気サーバー）と通信するシンプルなクライアントを実装しています。
実際のアプリケーションではもっと複雑な処理が必要ですが、基本的な構造を理解するのに役立つでしょう。

## MCPの課題と今後の展望

MCPは生成AIの連携を標準化する有望なプロトコルですが、いくつかの課題も存在します。

### 現在の課題

1. **標準化の進展**: MCPはまだ発展途上のプロトコルであり、業界全体での標準化が進んでいません
2. **セキュリティとプライバシー**: 複数のAIサービス間でデータを共有する際のセキュリティとプライバシーの懸念
3. **スケーラビリティ**: 大規模なシステムでの性能とスケーラビリティの課題
4. **互換性**: 異なるベンダーやプラットフォーム間での互換性の確保

### 今後の展望

MCPの今後の展望としては、以下のような発展が期待されます：

1. **業界標準の確立**: 主要なAIプラットフォームやベンダーによるMCPの採用と標準化
2. **エコシステムの拡大**: MCPに対応したAIサービスやツールの増加
3. **高度な機能の追加**: より複雑なタスクや対話をサポートするための機能拡張
4. **セキュリティとプライバシーの強化**: データの保護と安全な共有のためのメカニズムの改善

## まとめ

MCPは生成AIモデル間の連携を標準化するためのプロトコルであり、異なるAIサービスを簡単に接続して複雑なタスクを実行できるようにします。

この記事では、MCPの基本概念から実装方法まで、初心者から中級者手前の方々を対象に解説しました。MCPの主な特徴は以下の通りです

1. **標準化されたインターフェース**: 異なるAIモデルやサービスが同じ方法で通信できるようにする
2. **モジュール性**: 特定の機能に特化したAIサービスを組み合わせて使用できるようにする
3. **相互運用性**: 異なるベンダーやプラットフォームのAIサービスを連携させる

MCPを活用することで、開発者はより柔軟で強力なAIシステムを構築することができます。今後、生成AI技術がさらに発展するにつれて、MCPのような標準プロトコルの重要性はますます高まるでしょう。

## 参考リンク

- [Model Completion Protocol (MCP) 公式ドキュメント](https://github.com/anthropics/anthropic-cookbook/tree/main/mcp)
- [OpenAI Function Calling API](https://platform.openai.com/docs/guides/function-calling)
- [Anthropic Claude Function Calling](https://docs.anthropic.com/claude/docs/function-calling)
- [LangChain Documentation](https://python.langchain.com/docs/get_started/introduction)

---

この記事がMCPの理解の助けになれば幸いです。
質問やフィードバックがあれば、コメントでお知らせください。