第5章 — トランスポートプロトコルとディスカバリ
LLM Primer IV: MCPで設計するAI認知 のウォークスルー第5回です。第3章と第4章のメッセージはすべてホストとサーバーの間の空中を漂っていましたが、メッセージは漂いません — トランスポートに乗ります。そしてそのトランスポートが、統合の運用特性をほぼすべて静かに決めます。
なぜこの章があるのか
MCPはメッセージ形式 — JSON-RPC 2.0 を双方向チャネル上に — を定義し、そのチャネルを実装する3つのトランスポートを定義します。3つは互換ではありません。それぞれが配備パターンに合い、違う運用負債を運び、違うセキュリティ面を露呈します。同じ領域に重なるもう一つの問いがあります: ホストはそもそもどうやってサーバーを見つけるのか。ホストがサーバーの存在と場所を知るまで、どれほど美しく仕様化されたプロトコルも会話を生みません。
この章は両方を歩きます。トランスポートは、サーバーが同所配置かリモートか、認証かプロセス隔離か、どうスケールするかを決めます。ディスカバリ層は、サーバーが「あるエンジニアだけが使うもの」か「チームが採用できるもの」かを決めます。
.well-known/mcp.json とServer Cardは、設定の問題をルックアップの問題に変える層。
5.1 stdio、SSE、Streamable HTTP
stdio は、ホストがサーバーを子プロセスとして起動する形です。ホストは子のstdinへJSON-RPCを書き、stdoutから応答を読みます。stderrはログを運びます。ポートも、ソケットも、ネットワークもなし。認証はOSのプロセス起動境界が処理します。Claude Desktop、Cursor、公式MCP inspectorは、ローカル・サーバーにstdioを使います。モデルは正直: 自分のマシンの上のツール、同所配置、ホストと同じ信頼ドメイン。ホスト間で共有できず、別マシンでは動かず、ホストあたり1つしか持てない — 同じサーバーを使いたい5つのClientは5つのプロセスを焼きます。
HTTP+SSE はMCPの最初のネットワーク向け答え。双方向ですが、二つの単方向を貼り合わせた二重通信。非推奨。野生にはまだいます。SSEベースのサーバーは当面出会うでしょう。
Streamable HTTP は推奨のネットワーク・トランスポートです。単一のエンドポイント — 通常は /mcp — がJSON-RPCリクエストを受け、同期呼び出しなら単一のレスポンス、複数メッセージがあればServer-Sent Eventsのストリーム(サーバー発の通知を含む)で応えます。セッションは初期化時にセットされる Mcp-Session-Id ヘッダで識別され、後続のリクエストすべてにスレッドされます。セッションが状態の単位で、DELETEで解放するかタイムアウトで回収されます。トランスポートはロードバランサ、リバースプロキシ、エッジキャッシュ、TLSとうまく組みます。水平スケールはセッションIDによるスティッキー・セッション。新しいHTTP工学ではありません — 要点は、MCPが新しい層を発明せずにここに収まるという話です。
この選択は、配備の判断であると同時にセキュリティの判断です。stdioサーバーは過剰権限になりがちです — ユーザーのファイルシステムとネットワーク権限を継承し、リモート呼び出し元がいないので認証もない。ネットワーク・サーバーは開いたインターネットに面し、リクエストごとに認証する必要があり、OAuth 2.1が収束する標準になりつつあります。セキュリティ姿勢と合わないトランスポートを選ぶと、最初から組み込むべきものを後付けする羽目になります。
5.2 サーバー・ディスカバリ: .well-known/mcp.json と Server Cards
すべてのホストにすべてのサーバーのアドレスを手入力で構成させるプロトコルは、エコシステムにはなりません。設定の悪夢になります。MCPのディスカバリ層は、RFC 8615のwell-known URIパターン — robots.txt や .well-known/openid-configuration と同じ仕組み — を借ります。サーバーは自分のベースURLに .well-known/mcp.json を公開します。ホストはそれを取得・解析して、サーバーが自分について主張するもの — MCPエンドポイント、プロトコルバージョン、認証スキーム、ID メタデータ、そしてServer Cardへのポインタ — を学びます。
Server Card はMCPの openapi.json です: マシンも人間も消費できる自己記述的アーティファクト。ホストは接続フローでカードをユーザーに見せられます — 「このサーバーはあなたのLinearワークスペースにアクセスできるとうたう、チケットを読むが削除はしない、Linear自身が運営している、OAuthを使う」 — そしてユーザーは主張が受け入れ可能かを判断できます。署名のないカードは「主張」であって「証明」ではありません。緩和は署名付きの attestation で、署名モデルはsigstore風のOIDCに収束してきました: GitHubのOIDC統合経由で github.com/some-org/mcp-server 配下に署名されたカードは、GitHubのID主張を信頼するホストなら検証できます。ホストは上にポリシーを重ねられます — 署名済みカードのみ信頼、特定発行者の署名済みカードのみ、失効リスト外のみ、など。
フローはWi-Fiネットワークを追加するのに似ています。一度だけ。ホストは構成を保存し、後続のセッションはディスカバリを飛ばします。実務で「何かが変わった」が意味するもの — バージョン変更、スコープ拡張、能力の変化 — はTLS証明書の変更と同じく、同意の更新をトリガーすべきです。これを飛ばすホストは、サーバーが時間をかけて静かに届く範囲を広げるのを許してしまう — それはまさに、どんな長命の統合でも信頼を傷める「静かな能力クリープ」です。
5.3 出荷を決める「地味な部分」
3つの運用上の関心事は、それぞれ独自の扱いに値します。どれも、迂闊な実装が壊れた統合かセキュリティホールを生む場所だからです。
CORS はブラウザベースのホストから到達可能などのMCPサーバーにも効きます。誘惑は Access-Control-Allow-Origin: * をセットして先へ進むこと。これは間違いです。Cookie認証と合わせるとCSRF災害、localStorageのBearerトークンと合わせるとトークン漏洩リスク。Originごとの許可リストを使い、Cookieより Authorization ヘッダを優先して、同一Originだけが防衛線にならないようにします。
Origin検証 はサーバー側で行うCORSです。ブラウザでないクライアントは何も強制しないからです。古典的失敗: 開発者が localhost:8000 でMCPサーバーを動かし、その規約を知るウェブページを訪れ、ページがリクエストを発射する。Originチェックのないサーバーはページの言う通りに動きます。Streamable HTTPサーバーは必ず Origin を検証しましょう。
キャッシュのヘッダが3つ目です。静的なドキュメントは積極的にキャッシュしてよい。データベースの行はサブスクリプションが繋がっている間だけ。編集中の文書は一切。Resourceごとに正しい Cache-Control と ETag を返します。キャッシュとサブスクリプションの相互作用がエンジニアを噛む場所です — 古いコピーを返す中間者がいると、サブスクリプションが生サーバーに届かないので、ホストの resources/updated 通知が発火しません。
DNSリバインディングは近所の話で、ローカル・サーバーに不釣り合いに効きます。0.0.0.0 ではなく 127.0.0.1 にバインドし、Host ヘッダを許可リストに対して検証し、localhostでも認証トークンを必須にする。これらを欠いたローカルMCPサーバーは、デモ1回でセキュリティ・アドバイザリ行きです。
この章を踏まえて
これで本書の第II部が閉じます。プロトコルは手元にあります: 第3章のサーバープリミティブ、第4章のクライアントプリミティブ、そして本章のワイヤとディスカバリ。どんなメッセージがどの方向へ、どのトランスポート上を、どの信頼ドメインの間を、どんなハンドシェイクのあとに流れるかが分かっています。第III部はプリミティブからパターンへ移ります。サーバー1つとホスト1つは有用ですが、MCPのアーキテクチャ的な見返りは構成 — 複数のサーバー、複数のエージェント、複数のモデルが大きな目標へ向けて協調することにあります。
次回 — 第6章: オーケストレーションの基本。 単一のよく装備されたエージェントがマルチ・エージェント設計に勝つ場面と、本番配備の多くが頼る2つの基本形 — 逐次パイプラインとスキャッタ・ギャザー並行。