MCPアーキテクチャ — Host/Client/Serverの三層構造を実装者向けに読む
MCPのHost・Client・Serverという参加者の役割分担と、データ層・トランスポート層の2層構造を仕様書ベースで解説します。LSPからの設計継承と2026-07-28のステートレス化がもたらす影響も扱います。
MCPアーキテクチャの3つの参加者
MCP(Model Context Protocol)はクライアント・サーバー型のアーキテクチャを採用しています。参加者は3種類です。
- MCP Host: Claude CodeやClaude Desktopのような、1つ以上のMCPクライアントを管理・調整するAIアプリケーション
- MCP Client: 1つのMCPサーバーへの接続を維持し、Hostのためにコンテキストを取得するコンポーネント
- MCP Server: MCPクライアントにコンテキストを提供するプログラム
HostはMCPサーバー1つにつき1つのMCPクライアントを生成します。Visual Studio CodeがSentry MCPサーバーとローカルのファイルシステムサーバーの両方に接続する場合、VS Codeのランタイムはそれぞれ独立したMCPクライアントオブジェクトを2つ生成します。1つのクライアントは1つのサーバーとの専用接続だけを担当し、複数サーバーをまたいで状態を共有しません。
「MCPサーバー」という語は実行場所を問いません。stdioトランスポートを使うローカルサーバー(ファイルシステムサーバーなど)も、Streamable HTTPを使うリモートサーバー(Sentry MCPサーバーなど)も、どちらも同じく「サーバー」です。ローカルMCPサーバーは典型的に単一クライアントにのみ応答し、リモートMCPサーバーは多数のクライアントに同時に応答します。
MCPアーキテクチャの2層構造 — データ層とトランスポート層
MCPは概念的に2つの層で構成されます。データ層が内側、トランスポート層が外側です。
| 層 | 役割 |
|---|---|
| データ層 | 役割JSON-RPCベースのクライアント・サーバー間通信プロトコル。バージョン・機能の発見、Tool/Resource/Prompt/通知などのコア要素を定義 |
| トランスポート層 | 役割通信の確立・メッセージのフレーミング・認可を含む、データ交換のための通信手段を定義 |
データ層はJSON-RPC 2.0上に構築されています。discover(バージョン・機能・識別情報の発見)、server features(Tool・Resource・Prompt)、client features(elicitation)、utility features(通知・進捗トラッキング)の4種類で構成されます。
トランスポート層が対応する通信手段は2つです。stdioトランスポートはローカルプロセス間の標準入出力を使い、ネットワークオーバーヘッドがありません。Streamable HTTPトランスポートはHTTP POSTとServer-Sent Eventsの組み合わせで、リモート通信とベアラートークン・APIキー・カスタムヘッダーによる標準的なHTTP認証をサポートします。MCPはOAuthによるトークン取得を推奨しています。
トランスポート層が通信の詳細を吸収するため、データ層側は同一のJSON-RPC 2.0メッセージ形式をどのトランスポートでも共通に扱えます。
中核となる3つのプリミティブ — Tools / Resources / Prompts
データ層でクライアント・サーバー間が共有できる情報の種類を「プリミティブ」と呼びます。サーバーが公開できるプリミティブは3つです。
- Tools: AIアプリケーションが呼び出せる実行可能な関数(ファイル操作・API呼び出し・DBクエリなど)
- Resources: コンテキスト情報を提供するデータソース(ファイル内容・DBレコード・APIレスポンスなど)
- Prompts: モデルとのやり取りを構造化する再利用可能なテンプレート
クライアントは tools/list のような */list メソッドでプリミティブを動的に発見し、tools/call で実行します。データベースの例で言えば、サーバーはクエリ用のTool、スキーマ情報を返すResource、Toolの使い方を示すfew-shot例を含むPromptをまとめて公開できます。各プリミティブのリクエスト・レスポンス形式はTools仕様・Resources仕様・Prompts仕様でそれぞれ個別に定義されています。
クライアント側が公開できるプリミティブはElicitation(ユーザーへの追加入力要求)です。ElicitationはMulti Round-Trip Requests(MRTR)パターンで配送されます。かつてクライアント側プリミティブだったSamplingとLoggingは、プロトコルバージョン 2026-07-28 で非推奨になりました。Samplingの新規実装はLLMプロバイダーAPIに直接統合する形に、Loggingは標準エラー出力かOpenTelemetryへのログ出力に置き換えることが推奨されています。
なぜ2026-07-28でステートレス化されたのか
2026-07-28 仕様の最大の変更点は、MCPを完全にステートレスなプロトコルにしたことです。すべてのリクエストは、そのリクエストを処理するために必要な情報を自身の _meta フィールドに含みます。サーバーは以前のリクエストから何かを推測する必要がありません。
具体的には、クライアントはプロトコルバージョン(io.modelcontextprotocol/protocolVersion)とクライアント機能(io.modelcontextprotocol/clientCapabilities)を毎リクエストに含め、識別情報(io.modelcontextprotocol/clientInfo)も基本的に含めます。サーバーは server/discover リクエストを必ず実装し、対応するバージョン・機能・識別情報を返します。server/discover の呼び出し自体は任意です。すべてのリクエストが同じ _meta を持つため、クライアントはdiscoverを省いて直接リクエストを送り、バージョン不一致が起きたらエラーで初めて対処する、という実装も許容されます。
この設計は、接続確立時のハンドシェイク(initialize / notifications/initialized)を前提にしたv1系の設計から離れ、各リクエストが独立して完結する方向への転換です。ロードバランサ配下での水平スケールや、コネクションを維持しない実装がしやすくなる一方、毎リクエストに _meta を付与する分だけペイロードはわずかに増えます。
LSPの設計をMCPはどう継承したか
MCPはLanguage Server Protocol(LSP、プログラミング言語ごとのエディタ支援を標準化するプロトコル)から着想を得ています。LSPが「1つの言語サーバー実装を、あらゆるエディタ・IDEから使えるようにする」という多対多の関係を解決したのと同じように、MCPは「1つのMCPサーバー実装を、あらゆるAIアプリケーションから使えるようにする」という関係を解決しようとしています。
この継承は名称にも表れています。LSPの「Language Server」に対してMCPの「MCP Server」、LSPを話す「エディタ」に対してMCPの「Host」がそれにあたります。ただし違いもあります。LSPはリクエスト・レスポンスの型がほぼ固定(定義ジャンプ・補完・診断など)であるのに対し、MCPはTool・Resource・Promptという3種の汎用プリミティブを介して任意の機能を後から追加できる設計です。LSPが「言語ごとの決まった機能セット」を標準化したのに対し、MCPは「機能セット自体を動的に発見・拡張できる仕組み」を標準化したと言えます。
もう1つの違いは対象範囲です。LSPは1つの言語サーバーが1つのエディタセッションに対して継続的に状態を持つ前提(開いているファイル・カーソル位置など)で設計されています。MCPは逆に、2026-07-28 でステートレス化を選び、LSPが前提にしていた「継続的なセッション状態」を仕様の外に追い出しました。同じ多対多の課題を解決していても、状態管理の哲学は正反対に近い方向へ進化したことになります。
通知はなぜオプトイン購読方式になったか
2026-07-28 では、サーバーからクライアントへのリアルタイム通知の配送方式も変わりました。以前のHTTP GETエンドポイントや resources/subscribe / resources/unsubscribe は廃止され、subscriptions/listen という単一の長時間ストリームに統合されています。
クライアントは toolsListChanged のように受け取りたい通知種別を指定してsubscriptions/listenを呼び出し、サーバーは対応可能な種別だけを確認応答します。以後、対象の変化(Tool一覧の更新など)が起きるたびに、サーバーはそのストリーム上に通知を流します。通知にはリクエストIDに相当する id フィールドが無く、JSON-RPC 2.0の通知セマンティクス(応答を期待しないメッセージ)に従います。
このオプトイン設計により、クライアントは関心のある変化だけを購読でき、サーバーは対応していない通知種別を確認応答から除外できます。進捗通知(notifications/progress)やログメッセージ(notifications/message)のようにリクエストに紐づく通知は、この購読ストリームではなく元のリクエストの応答ストリーム上を流れ続けます。購読ストリームはあくまで「サーバー側の状態変化」を伝えるための経路です。
Host / Client / Serverの呼び分けでつまずきやすい点
3層構造を初めて読む実装者がよく混同するのが、「Client」という語の指す範囲です。日常会話で「MCPクライアントを実装する」と言うとき、多くの場合は「MCPサーバーに接続するアプリケーション全体」を指しています。しかし仕様上の定義では、Clientは1サーバーにつき1つ生成される内部コンポーネントであり、アプリケーション全体を指す語は「Host」です。VS CodeのようなHostが複数のMCPサーバーに接続するとき、Host内部には接続先の数だけClientインスタンスが存在します。
同様に「サーバー」という語も、実行場所(ローカル/リモート)とトランスポート(stdio/Streamable HTTP)を混同しやすい語です。ローカル実行だからstdioとは限らず、開発時に localhost へのStreamable HTTPで動かすローカルサーバーも存在します。仕様上の「ローカル/リモート」という分類は実行場所を指し、トランスポートの選択とは独立した軸だと理解しておくと、SDKのドキュメントで混乱しません。
まとめ
MCPアーキテクチャの骨格は、Host・Client・Serverという3参加者と、データ層・トランスポート層という2層構造で説明できます。実装者がまず押さえるべきは、2026-07-28 でプロトコルがステートレス化され、すべてのリクエストが自己完結するようになった点です。Tool・Resource・Promptという3プリミティブの発見・実行パターンはLSPの設計思想を汎用化したものであり、SDKのAPIを読む前にこの参加者モデルと層構造を頭に入れておくと、各言語SDKのドキュメントが読みやすくなります。プロトコル全体の改訂履歴はMCP仕様のバージョン履歴、Claudeでの実際の使い方はMCPとは何かにまとめています。