MCPの正体を理解する:Tool Useのエージェントループから JSON-RPC 2.0 の二層エラーハンドリングまで

MCPの正体を理解する:Tool Useのエージェントループから JSON-RPC 2.0 の二層エラーハンドリングまで

Claude APIのTool Useを起点に、MCPの正体を探ります。LLMはMCPの存在を知らず、クライアントアプリがルーティングを担うこと、そしてJSON-RPC 2.0による二層エラーハンドリングの仕組みまで、一連の疑問を連鎖的に解説します。
2026.07.10

はじめに

Claude API で Tool Use を使ったエージェントを実装しているとき、ふと疑問が湧きました。

「MCP(Model Context Protocol)って結局何なのか?Tool Use と何が違うのか?」

調べていくと、LLM は MCP の存在すら知らないという事実にたどり着き、そこから MCP のアーキテクチャ思想、さらには通信基盤である JSON-RPC 2.0 の仕組みまで、一連の疑問が連鎖的に解けていきました。

この記事では、その探求の過程を共有します。

Tool Use エージェントループの正しいメッセージ構造

まず基本から。Claude API でツール使用を有効にしたエージェントを実装する場合、正しいエージェントループの設計を理解する必要があります。

ループの流れ

Claude が stop_reason: "tool_use" を返したとき、開発者はローカルでツールを実行し、結果を API に返す必要があります。このとき守るべきルールは明確です。

直前の assistant メッセージを含む会話履歴全体と、対応する tool_use_id を持つ tool_result コンテンツブロックを含む新しい user メッセージを送信すること。

cb4027ca-5b75-4d30-a41b-59fdb08ba4b0

{
  "messages": [
    {
      "role": "user",
      "content": "現在の東京の天気を調べて。"
    },
    {
      "role": "assistant",
      "content": [
        {
          "type": "tool_use",
          "id": "toolu_xyz123",
          "name": "get_weather",
          "input": { "city": "Tokyo" }
        }
      ]
    },
    {
      "role": "user",
      "content": [
        {
          "type": "tool_result",
          "tool_use_id": "toolu_xyz123",
          "content": "晴れ、気温 22度"
        }
      ]
    }
  ]
}

なぜ user ロールなのか?

「ツールを呼び出したのは assistant なのに、結果を返すのが user なのはなぜ?」と疑問に思うかもしれません。

Claude API における role は、データの流れる方向を表しています。

ロール 意味
assistant モデルから出てくるデータ(ツール呼び出し命令を含む)
user モデル送り込むデータ(ツール実行結果を含む)

アプリケーションコードはユーザーの「代理人(プロキシ)」として振る舞い、外部世界から得た事実をモデルに伝達する役割を担います。

852c765b-8439-4d4a-a963-6eddfa5583cb

エラー時の扱い

ツール実行がタイムアウトなどで失敗した場合でも、tool_result の送信は省略できません。省略すると API エラー(400 Bad Request)になります。エラー時は is_error: true を設定し、content にエラー詳細を記述します。

{
  "type": "tool_result",
  "tool_use_id": "toolu_01A2B3C4D5",
  "content": "Error: The external API request timed out after 10 seconds.",
  "is_error": true
}

これにより、Claude はエラーの事実を認識し、ユーザーへの説明やリトライの判断を自律的に行えます。

LLM にとって MCP は存在しない

ここからが本題です。上記の Tool Use ルールは、MCP を使った場合でもまったく同じです。

なぜなら、Claude は MCP の存在を一切知らないからです。

クライアントアプリが「幻術師」

MCP のアーキテクチャでは、クライアントアプリ(Claude Desktop、Claude Code、自作のエージェントなど)が中間に立ち、以下の処理を行います。

Phase 1: ツール一覧の統合

クライアントアプリは接続先の MCP サーバー群に「どんなツールを持っていますか?」と問い合わせ、取得したツール定義を標準の tools 配列にまとめて Claude API に送信します。

"tools": [
  { "name": "github_create_issue", "description": "..." },
  { "name": "postgres_query", "description": "..." },
  { "name": "slack_post_message", "description": "..." }
]

Claude にとっては、これらが MCP サーバーから来たものか、ローカルに書かれた関数かは区別がつきません。

Phase 2: Claude は標準の Tool Use を呼ぶだけ

{
  "type": "tool_use",
  "name": "postgres_query",
  "input": { "query": "SELECT * FROM users WHERE active = true" }
}

Claude は「どうやって実行されるか」を知りません。構造化された JSON の意図を出力して停止するだけです。

Phase 3: クライアントアプリがルーティングを決定

クライアントアプリが tool_usename を見て判断します。

  • ローカル関数なら → 直接実行
  • MCP サーバーのツールなら → JSON-RPC で該当サーバーに転送

Phase 4: 結果を tool_result で返す

MCP サーバーから受け取った結果を、標準の tool_result メッセージブロックに包んで Claude に返します。

mcp-tool-use-json-rpc-architecture-deep-dive-mcp-architecture

MCP = AI 時代の HTTP、LLM のためのマイクロサービス

では、LLM が MCP を知らないなら、なぜ Anthropic は MCP を作ったのか?

答えはデカップリングです。HTTP がウェブブラウザとウェブサーバーを分離したように、MCP は AI クライアントとツール・データソースを分離します。

HTTP との構造的類似性

観点 HTTP MCP
クライアントは何を知らなくていい? サーバーの実装言語・DB種別 ツールの実装言語・認証フロー
サーバーは何を知らなくていい? クライアントのOS・デバイス どのLLMが呼んでいるか
共通の契約 HTTP メソッド・ステータスコード JSON-RPC 2.0・3つのプリミティブ

マイクロサービスとのアナロジー

従来のシステム設計では、巨大なアプリを マイクロサービス(認証サービス、決済サービス、配送サービスなど)に分割し、メインアプリはネットワーク呼び出しで必要な機能を使います。

MCP はまったく同じことを AI の世界で行っています。ただし、サービスを呼び出す「ボス」がハードコードされたアプリケーションではなく、LLM である点が異なります。

MCP はマイクロサービスに似ている。マイクロサービスがアプリケーションのためのものなら、MCP は LLM のためのもの。

6652d830-f78c-4aa3-a591-183a917aa141

MCP 以前の問題

MCP がなかった時代、5つの異なる AI コーディングアシスタント(Cursor、Claude Desktop、Continue.dev、Aider、社内エージェントなど)が GitHub 連携を実装したい場合、5回とも同じ車輪を再発明する必要がありました。しかもそれぞれの実装は互換性がありません。

MCP があれば、ある開発者が優れた GitHub MCP サーバーを1つ作れば、すべての AI クライアントアプリが即座に利用可能になります。

エコシステムの現実

ただし、「100人の開発者が同じアプリに対して100個の MCP サーバーを作る」ことを MCP は止められません。npm に文字列パディングのパッケージが50個あるのと同じです。

重要なのは、努力が注がれる場所が変わったことです。各アプリ開発者が同じ基本ツールを非公開で書き直す」のではなく、 「コミュニティが最高の公開 MCP サーバーを競い合う」 形になりました。

JSON-RPC 2.0:通信プロトコルのスキーマ強制

MCP の通信基盤を支えているのが JSON-RPC 2.0 です。

JSON と JSON-RPC 2.0 の違い

JSON はデータフォーマット、JSON-RPC 2.0 は厳格な契約です。 JSON が「アルファベット」なら、JSON-RPC 2.0 はそのアルファベットで書かれた「法的契約書」のようなものです。

JSON は構文のみを規定し、意味についてのルールはありません。

{ "coffee": "iced", "temperature": 2, "is_good": true }

一方、JSON-RPC 2.0 はリモートプロシージャコール(RPC)のための厳密な構造を強制します。

リクエスト契約

{
  "jsonrpc": "2.0",
  "method": "tools/call",
  "params": { "name": "fetch_file", "path": "./src/main.ts" },
  "id": "request-abc-123"
}

3つの必須キー:jsonrpc(バージョン)、method(実行する関数名)、id(リクエスト識別子)。params(引数)はオプショナルだが、MCP では通常含まれる。

レスポンス契約

{
  "jsonrpc": "2.0",
  "result": { "content": "console.log('hello world');" },
  "id": "request-abc-123"
}

エラー契約

{
  "jsonrpc": "2.0",
  "error": { "code": -32602, "message": "File not found at specified path" },
  "id": "request-abc-123"
}

スキーマ違反時の自動拒否

JSON-RPC 2.0 はスキーマ違反を自動で検出・拒否します。

違反の種類 エラーコード 発生条件
Parse error -32700 JSON 構文エラー(閉じ括弧忘れなど)
Invalid Request -32600 必須キー欠落(jsonrpcmethod がない)
Method not found -32601 存在しないメソッドの呼び出し
Invalid params -32602 パラメータの型・構造が不正

なぜ LLM にとって重要か

LLM はツールパラメータを動的に生成するため、ツール名のハルシネーションやパラメータの欠落が起こりえます。JSON-RPC 2.0 のスキーマ強制があることで、MCP サーバーはクラッシュせず、標準化されたエラーコードを返します。クライアントアプリはそのエラーを Claude にフィードバックし、Claude が自己修正して再リクエストする、という堅牢なループが実現します。

HTTP ステータスコードと JSON-RPC エラーコードの二層構造

JSON-RPC 2.0 は HTTP のステータスコード(400, 500 など)を置き換えるのではなく、共存します。

二層のセキュリティモデル

装甲トラックに例えると分かりやすいです。

  • HTTP ステータスコード → トラックそのものを管理(配送が物理的に成功したか?)
  • JSON-RPC エラーコード → トラック内の金庫を管理(中身の検査に合格したか?)

dcfe0a98-c739-4469-b7c8-749e0eb6c666

パターン1:ネットワーク成功 + ツール実行成功

HTTP/1.1 200 OK

{
  "jsonrpc": "2.0",
  "result": { "status": "Slack message sent successfully!" },
  "id": "mcp-msg-99"
}

パターン2:ネットワーク成功 + ツール実行失敗

HTTP は 200 OK を返すのに、内部的にはエラー。ネットワークの配送は成功したが、中身の検査で不合格だったケースです。

HTTP/1.1 200 OK

{
  "jsonrpc": "2.0",
  "error": { "code": -32602, "message": "Invalid params: 'path' must be an absolute string." },
  "id": "claude-bad-request-1"
}

パターン3:ネットワーク自体が失敗

MCP サーバーがクラッシュした場合、JSON-RPC のレスポンスすら返せません。

HTTP/1.1 504 Gateway Timeout

mcp-tool-use-json-rpc-architecture-deep-dive-dual-layer-error

レイヤー 何を意味するか
HTTP(4xx, 5xx) パイプが壊れている サーバー到達不能、タイムアウト
JSON-RPC(-32xxx) パイプは正常だが、流したデータが検査不合格 メソッド不在、パラメータ不正

まとめ

この探求を通じて得られた理解を整理します。

概念 本質
Tool Use のエージェントループ assistant: tool_useuser: tool_result の厳密な交互パターン。会話履歴の完全保持が必須
MCP と LLM の関係 LLM は MCP を知らない。クライアントアプリがルーティングを判断する
MCP の価値 AI 時代の HTTP。プラットフォーム・言語を問わないデカップリング標準
JSON-RPC 2.0 通信プロトコルのスキーマ強制層。HTTP ステータスコードとは別レイヤーで共存

実務的な判断基準としては、MCP を「LLM のためのマイクロサービス」と捉えるのが最も実用的です。従来のマイクロサービスがアプリケーションのためのものなら、MCP は LLM のためのもの。HTTP の上に JSON-RPC 2.0 という契約を重ね、3つのプリミティブ(Prompts, Resources, Tools)で構成される。この理解があれば、MCP の設計判断で迷うことは少なくなるはずです。


Claudeならクラスメソッドにお任せください

クラスメソッドは、Anthropic社とリセラー契約を締結しています。各種製品ガイドから、業種別の活用法、フェーズごとのお悩み解決などサービス支援ページにまとめております。まずはご覧いただき、お気軽にご相談ください。

サービス詳細を見る

この記事をシェアする

関連記事