MCPとAPIの比較: AIツールでの使い分け

Jakub Swistak
公開日 更新日 読了時間:約8分
MCPとHTTPの連携パターンを示すアーキテクチャ比較図

AIエージェントを外部ツールやAPIに接続する方法は、大きく2つあります。抽象化レイヤーとしてModel Context Protocol (MCP)を使う方法と、HTTP経由でAPIを直接呼び出す方法です。どちらも機能します。ただし、柔軟性、複雑さ、性能、移植性について異なるトレードオフがあります。

この記事では、具体的なコード例、レイテンシ分析、選択のための判断基準を使って、この2つの方法を比較します。

2つの方法

直接HTTP連携

AIアプリケーション、またはそのバックエンドが、標準的なHTTPリクエストを使って外部APIを直接呼び出します。開発者は、リクエストの組み立て、認証の処理、レスポンスの解析、結果のLLMへの受け渡しを行うコードを書きます。

┌──────┐     ┌────────┐                        ┌─────────────┐
│ User │────▶│ AI App │──── HTTP request ─────▶│ Weather API │
└──────┘     │        │◀─── JSON response ─────│             │
             │        │                        └─────────────┘
             │        │── result as context ──▶ LLM
             │        │◀── formatted answer ───
             └───┬────┘
                 │
                 ▼
           User gets answer

MCP連携

AIアプリケーションは、外部APIをラップするMCPサーバーに接続します。アプリケーションはMCPプロトコルを使って、利用可能なツールを検出し、名前で呼び出し、結果を受け取ります。外部APIへの実際のHTTP呼び出しはMCPサーバーが処理します。

┌──────┐     ┌───────────────────┐              ┌────────────┐     ┌──────────┐
│ User │────▶│ AI App/MCP Client │── JSON-RPC ─▶│ MCP Server │────▶│ HTTP API │
└──────┘     │                   │◀─ JSON-RPC ──│            │◀────│          │
             │                   │              └────────────┘     └──────────┘
             │                   │── result as context ──▶ LLM
             │                   │◀── formatted answer ───
             └─────────┬─────────┘
                       │
                       ▼
                 User gets answer

主な違いは、直接HTTPではAIアプリケーションがAPI連携コードを所有する点です。MCPではMCPサーバーがそれを所有し、AIアプリケーションはツールを名前で呼び出すだけです。

この図のMCP側は、サーバーを構築しなくても利用できます。Quickchat AIはすべてのAI Agent向けにstreamable-HTTP MCPサーバーをホストしており、エージェントをMCPサーバーにするには、AIアプリにURLを1つ貼り付けるだけです。

コード比較

実用的な例として、GitHubユーザーのリポジトリを取得する場合を比較します。

直接HTTP連携

import httpx

async def get_user_repos(username: str, token: str) -> list[dict]:
    """GitHubユーザーのリポジトリを取得します。"""
    async with httpx.AsyncClient() as client:
        response = await client.get(
            f"https://api.github.com/users/{username}/repos",
            headers={
                "Authorization": f"Bearer {token}",
                "Accept": "application/vnd.github.v3+json",
                "X-GitHub-Api-Version": "2022-11-28"
            },
            params={"sort": "updated", "per_page": 10}
        )
        response.raise_for_status()
        repos = response.json()
        return [
            {
                "name": r["name"],
                "description": r["description"],
                "stars": r["stargazers_count"],
                "language": r["language"],
                "url": r["html_url"]
            }
            for r in repos
        ]

これをLLMと連携するには、さらに以下が必要です。

  • LLMが期待する形式のツール定義、OpenAIのfunction callingスキーマ、Claudeのtool useスキーマなど
  • LLMのツール呼び出しを解析し、get_user_reposを呼び出し、その結果を会話に戻すコード
  • HTTPエラー、レート制限、認証期限切れに対するエラーハンドリング

MCPサーバー

from mcp.server.fastmcp import FastMCP
import httpx

mcp = FastMCP("github-server")

GITHUB_TOKEN = os.environ["GITHUB_TOKEN"]

@mcp.tool()
async def get_user_repos(username: str) -> str:
    """GitHubユーザーについて、最近更新された10件のリポジトリを取得します。

    Args:
        username: 検索対象のGitHubユーザー名
    """
    async with httpx.AsyncClient() as client:
        response = await client.get(
            f"https://api.github.com/users/{username}/repos",
            headers={
                "Authorization": f"Bearer {GITHUB_TOKEN}",
                "Accept": "application/vnd.github.v3+json",
                "X-GitHub-Api-Version": "2022-11-28"
            },
            params={"sort": "updated", "per_page": 10}
        )
        response.raise_for_status()
        repos = response.json()
        lines = []
        for r in repos:
            stars = r["stargazers_count"]
            lang = r["language"] or "unknown"
            lines.append(f"- {r['name']} ({lang}, {stars} stars): {r['description'] or 'No description'}")
        return "\n".join(lines)

if __name__ == "__main__":
    mcp.run(transport="stdio")

MCP版では、API呼び出し、認証、レスポンス整形がサーバー内にカプセル化されます。MCP互換クライアントであれば、GitHub APIについて何も知らなくてもこのツールを使用できます。

AIアプリケーションで変わること

観点直接HTTPMCP
ツール定義LLM固有の形式で記述、OpenAIスキーマなどMCPサーバーから自動生成
認証AIアプリが管理MCPサーバーが管理
レスポンス解析AIアプリがデータを抽出して整形MCPサーバーが整形済みの結果を返す
エラーハンドリングAIアプリがHTTPエラーを処理MCPサーバーがエラーを処理し、構造化されたエラーメッセージを返す
新しいツールの追加AIアプリに新しいコードを書く新しいMCPサーバーに接続する、または既存サーバーにツールを追加する
LLMの切り替え新しいLLM形式に合わせてツール定義を書き直す変更不要

性能比較

MCPは、AIアプリケーションと外部APIの間にレイヤーを追加します。そのレイヤーにはコストがあります。

レイテンシ

stdio transport (ローカルMCPサーバー)の場合、オーバーヘッドは最小です。起動時のプロセス生成 (1回のみ、通常100ms未満)と、メッセージごとのプロセス間通信 (最近のシステムでは1ミリ秒未満)です。実際には、外部API呼び出しが総レイテンシの大部分を占めます。

remote MCP servers (Streamable HTTPまたはSSE)の場合、クライアントとMCPサーバー間のHTTPラウンドトリップが1回追加され、さらにMCPサーバーから外部APIへのHTTPラウンドトリップが発生します。MCPサーバーと外部APIが同じ場所にある場合、このオーバーヘッドは小さいです (1桁ミリ秒)。異なるリージョンにある場合は累積します。ただし、ユーザーが体感するのは多くの場合トランスポートではありません。Notionのホスト型MCPサーバーでヘルプセンターエージェントを構築した際、248件のツール呼び出しの平均は各2.7秒で、そのほぼすべては途中のホップではなく、Notionの検索とページレンダリングに費やされていました。

構成追加レイテンシの目安
ローカルMCPサーバー (stdio)ツール呼び出しごとに< 1ms
リモートMCPサーバー (APIと同一リージョン)ツール呼び出しごとに1-5ms
リモートMCPサーバー (APIと異なるリージョン)ツール呼び出しごとに10-50ms

ほとんどのAIエージェントのユースケースでは、LLM推論に500ms-5sかかるため、MCPのオーバーヘッドは無視できます。

接続管理

直接HTTP: アプリケーションが各外部APIへの接続を管理します。つまり、APIごとに接続プール、リトライロジック、レート制限を処理する必要があります。

MCP: アプリケーションはMCPサーバーごとに1つの接続を管理します。外部APIへの接続はサーバーが管理します。10個のツールが3つのMCPサーバーに分散している場合、10個ではなく3つの接続を管理します。

MCPを使う場合

複数のツール連携

AIアプリケーションが5つ以上の外部サービスに接続する必要がある場合、MCPは連携の負担を減らします。各サービス向けにカスタムAPIクライアントを書いて保守する代わりに、MCPサーバーに接続します。その多くはオープンソースプロジェクトとして利用できます。

AIプラットフォーム間の移植性

自分のツール向けにMCPサーバーを構築すれば、そのサーバーは任意のMCPクライアントで動作します。Claude Desktop、Cursor、Windsurf、カスタムアプリケーション、Quickchat AIのようなプラットフォームなどです。直接HTTPの場合、各プラットフォームの形式に合わせてツール定義を再実装する必要があります。

動的なツール検出

MCPはtools/listによる実行時のツール検出をサポートします。AIアプリケーションはサーバーに接続し、ハードコードされた設定なしで利用可能なツールを把握できます。これは、ツールが頻繁に変わる場合や、ユーザーが構成できる場合に有用です。

関心の分離

異なるチームが異なるツールを所有している場合、MCPは明確な境界を提供します。Salesforce連携を所有するチームがSalesforce MCPサーバーを構築して保守します。AIアプリケーションチームは、SalesforceのAPIを理解する必要なくそれに接続します。Salesforce APIの更新はMCPサーバー内で処理され、AIアプリケーションに手を加える必要はありません。

直接HTTPを使う場合

1つまたは2つの連携

AIエージェントが1つのAPI、たとえばデータベース検索だけを呼び出せばよい場合、MCPサーバーを実行するオーバーヘッドは不要です。直接HTTP呼び出しの方が単純で、可動部分も少なくなります。

リクエストを手書きする必要もありません。plain-English API Action builderは、文書化されたREST APIを読み取り、メソッド、URL、パラメータ、説明を生成し、有効化する前に実際のレスポンスをテストできるようにします。

リクエストを最大限制御したい場合

MCPサーバーはHTTPの詳細を抽象化します。リクエスト構築を正確に制御する必要がある場合、特定のヘッダー、クエリパラメータ、リクエスト署名、非標準の認証などでは、直接HTTPにより抽象化レイヤーと衝突することなく制御できます。

レイテンシに敏感な処理

1ミリ秒単位が重要な場合、たとえばツール呼び出しを厳しい時間予算内に完了する必要があるリアルタイム音声エージェントでは、MCPレイヤーを取り除くことで1ホップを削減できます。

AI以外のHTTP呼び出し

HTTP呼び出しがAIエージェントによってトリガーされない場合、たとえばデータを同期するバックエンドのcronジョブでは、MCPは関係ありません。MCPはAIとツールの通信のために特化して設計されています。通常のバックエンドサービスは通常のHTTPクライアントを使うべきです。

ハイブリッドアプローチ

本番システムの多くは両方を使います。パターンは次のとおりです。

  • MCPは、AIエージェントが会話中に呼び出すツール連携に使用します (CRM検索、チケット作成、ナレッジベース検索)
  • 直接HTTPは、内部バックエンド処理、Webhook、システム間通信に使用します

Quickchat AIの内部もこのように動作しています。このプラットフォームは、HTTP Request Actions (パラメータテンプレートを使った直接API呼び出し)とRemote MCP Actions (外部MCPサーバーへの接続)の両方をサポートしています。各連携に適した方法を選択します。

連携タイプ推奨アプローチ
既知のパラメータを使う単純なAPI呼び出しHTTP Request Action
複数の関連ツールを含む複雑な連携Remote MCP Action
既存のMCPサーバーを持つサードパーティサービスRemote MCP Action
カスタム認証を使う内部APIHTTP Request Action
ユーザーが構成できるツールRemote MCP Action

実務上これがどのように機能するか、OpenAIのGPT ActionsとMCPの違いを含む詳細な比較については、GPT Actions vs MCPを参照してください。

判断基準

次のフローチャートで選択します。

  1. AIエージェントがそのツールを呼び出しますか。 いいえの場合 (バックエンド処理である場合)は、直接HTTPを使います。
  2. 外部ツールはいくつ必要ですか。 1-2個なら直接HTTPの方が単純です。3個以上ならMCPを検討します。
  3. そのサービス向けの事前構築済みMCPサーバーはありますか。 はいの場合、それを使うことで開発時間を節約できます。
  4. 連携を複数のAIプラットフォームで動作させる必要がありますか。 はいの場合、MCPは移植性を提供します。
  5. レイテンシは重要ですか (ツール呼び出しの予算が100ms未満)。 はいの場合、MCPのオーバーヘッドをベンチマークし、それに基づいて判断します。
  6. 異なるチームが異なる連携を所有していますか。 はいの場合、MCPの連携ごとにサーバーを持つモデルは所有境界の管理に役立ちます。

実際には、外部サービスとやり取りするAIエージェントを構築する場合、MCPが標準的な選択肢になりつつあります。事前構築済みサーバーのエコシステムは十分に大きくなっており、多くの場合、サーバーコードをまったく書かずに開始できます。

関連記事