チュートリアル
Stateless MCP とは?2026 年のステートレスアーキテクチャ、JSON-RPC、Remote Server を解説
2026-07-28 版 MCP はプロトコル層をステートレスに:各 JSON-RPC リクエストが版と capabilities を自前で持ち、Remote Server は普通の HTTP ロードバランサー配下で動ける。ツール引数は依然 JSON — 本番でもローカル検証を。
Model Context Protocol(MCP)は AI クライアントがツール・リソース・プロンプトを発見し、モデルコンテキストへ接続する仕組みです。2026 年最大の設計変更は、MCP を「先に握手し Session ID を付ける双方向ステートフル」から「各リクエストが自己記述・独立ルーティング可能なステートレス JSON-RPC」へ移すことです。Claude Desktop、Cursor、自作 Agent から Remote MCP Server を呼んでいるなら、デプロイ・スケール・ゲートウェイのレート制限に直結します。読み終えたら、プロトコルのステートレスとアプリのステートフルを区別でき、ツール引数 JSON は依然ローカル検証が必要だと分かるはずです。
MCP と Stateless が解く問題
MCP が解くのは「モデルが外部能力を安全かつ発見可能に呼ぶ方法」です。クライアント(Claude、ChatGPT、IDE Agent)はツール一覧・リソース読取・プロンプトテンプレ取得の標準手段を必要とし、サーバー(GitHub、DB、内部 API の MCP アダプタ)は各クライアント向けカスタムプラグインなしで能力を公開する標準手段を必要とします。
初期 MCP はトランスポート層にセッションを残しました。クライアントはまずinitializeを送り、サーバーが capabilities を返し、以降のリクエストもMcp-Session-Idを付け、トラフィックを同一インスタンスか共有 Session Store に固定します。ローカル stdio なら問題ありません。Remote Server を水平スケールし Cloud Run / Lambda で動かし、API ゲートウェイでツール別レート制限する段階では、セッションスティッキネスがボトルネックになります。
2026-07-28 仕様(Release Candidate)はプロトコル層をステートレスにします。任意リクエスト処理に必要なメタデータはリクエスト自身にあり、普通の round-robin ロードバランサー配下の任意インスタンスが受けられます。公式説明:MCP 2026-07-28 仕様アナウンスとStatelessness 章。
ステートフル時代の名残
旧フローでは Streamable HTTP クライアントは通常 handshake を先に行います:
- 送信:
initialize— プロトコル版と client/server capabilities を交換。 - 受信:
initialized通知を受け、サーバーがMcp-Session-Idレスポンスヘッダーを返す。 - その後の
tools/call、resources/readは同じ Session ID が必要。なければゲートウェイやインスタンスメモリにコンテキストがありません。
本番の典型コスト:ロードバランサーで sticky session、レプリカ間 Redis Session、Serverless コールドスタート後の Session 失効。GitHub MCP など人気 Server は Redis 層が必要でした。Google はScaling AI Agent Infrastructureでこの変更を「MCP 公開以来最大の仕様変更」と呼びます — 核心はトランスポート層のセッション管理を外すことです。
| 観点 | ステートフル時代(2025 以前) | ステートレス核心(2026-07-28) |
|---|---|---|
| Handshake | initialize / initialized必須 |
廃止;任意server/discover |
| セッション識別子 | Mcp-Session-Id レスポンスヘッダー |
削除(SEP-2567) |
| Capability 交渉 | 接続確立時に一度交換 | 各リクエストの_metaが運ぶ |
| 水平スケール | スティッキールーティング + 共有 Session Store | 普通の round-robin で足りる |
2026-07-28 ステートレスの核心
仕様の「ステートレス」定義は厳格です。サーバーはしてはならない同一接続上の過去リクエストからプロトコル版・クライアント identity・capabilities を推測すること。各リクエストは_metaにこれらを含めること。複数タスク・スレッド・会話のリクエストは同一トランスポート上で交錯可能。接続や stdio プロセス自体はではないセッション境界。
クライアントは各リクエストのparams._meta(または同等位置)に:
io.modelcontextprotocol/protocolVersion— 必須。例:2026-07-28。io.modelcontextprotocol/clientCapabilities— 必須。空オブジェクトは任意 capability 非対応。io.modelcontextprotocol/clientInfo— ログ・デバッグ用に推奨(サーバーはセキュリティ判断に使わない)。
サーバー capability を先に知りたければ新しいserver/discover RPC を呼べますが、必須ではない — 任意リクエストが任意インスタンスへの最初のリクエストになれます。サーバーはtools/list などの応答にttlMs を付け、クライアントが TTL 内にツール一覧をキャッシュし、発見呼び出しを減らせます。
複数ツール呼び出しにまたがる業務状態(カート、ブラウザセッション、チケット下書き)はトランスポート Session に隠さない。普通の HTTP API のように:ツールが明示的 handle(basket_id、draft_id)を返し、モデルが後続tools/call の引数 JSON で返す。モデルが handle を見える方が、ブラックボックス Session よりデバッグしやすい。
MCP 内の JSON-RPC の動き
MCP メッセージ層は常に JSON-RPC 2.0:各リクエストにjsonrpc、id、method、params;応答はresultまたはerror;通知にはid。Apple Agent 記事の「ツール名 + 引数オブジェクト」と同じ形 — MCP はメソッド名をtools/callに標準化し、params にnameとarguments。
典型的なステートレスtools/callはこう(HTTP ヘッダーは次節):
POST /mcp HTTP/1.1
Content-Type: application/json
MCP-Protocol-Version: 2026-07-28
Mcp-Method: tools/call
Mcp-Name: searchInvoices
{
"jsonrpc": "2.0",
"id": 42,
"method": "tools/call",
"params": {
"name": "searchInvoices",
"arguments": {
"status": "unpaid",
"limit": 10
},
"_meta": {
"io.modelcontextprotocol/protocolVersion": "2026-07-28",
"io.modelcontextprotocol/clientCapabilities": {},
"io.modelcontextprotocol/clientInfo": {
"name": "jsonvue-demo",
"version": "1.0.0"
}
}
}
}
成功時resultには通常content 配列のツール出力(多くはtype: text の JSON 文字列か構造化ブロック)。失敗時 JSON-RPCerrorにcodeとmessage。Streamable HTTP で HTTP ヘッダーと body の method/name が不一致なら、仕様は-32020 系 header mismatch エラーを要求。
JSONVue 読者が見るべきはarguments:外部 Agent は数値を文字列にしたり必須キーを落としがち。MCP のステートレス化はしない業務 JSON の検証 — Structured Output がモデル出力、MCP がツール呼び出しを担当する分担と同じ。サイト内Apple AI Agent と JSONで説明:同一ドメイン関数が App Intent、Foundation Models Tool、MCP を担え、違いはアダプタ層だけ。
Remote Server と Streamable HTTP
Remote MCP Server はクライアントが HTTPS でアクセスする MCP エンドポイントであり、ローカル stdio 子プロセスではありません。Streamable HTTP が現在の Remote デプロイの主トランスポート:単一 POST で RPC 完結。長タスクは開いた通知ストリームを返せますが、状態は接続 Session ではなくそのリクエストにスコープされます。
2026-07-28 以降、Streamable HTTP リクエストは必須body と一致する 3 ヘッダー(SEP-2243)を付け、ゲートウェイ・WAF・レートリミッターが JSON body を parse せずルーティング可能に:
MCP-Protocol-Version—_metaの protocolVersion と一致必須。不一致なら 400。Mcp-Method— JSON-RPC のmethodなど。例:tools/call。Mcp-Name— ツール・プロンプト・リソース名。例:searchInvoices。
デプロイは簡素に:同一 Docker イメージの複数レプリカ + 普通の ALB/nginx round-robin。Cloud Run / Cloud Functions は MCP 専用 Redis Session 不要。Mcp-Name ごとの QPS クォータは body 深検査より安い。GitHub MCP Server など本番サービスはステートレス仕様へ移行中。
stdio ローカル Server も有効。ただし同一 stdio プロセス上で無関係リクエストが交錯可能で、Server はプロセス identity をセッション ID にしてはならない。ローカル開発とクラウド Remote は同一ツール実装を共有し、トランスポートアダプタだけ異なる。
アプリケーションは依然ステートフルでよい
「プロトコルがステートレス」≠「業務がステートレス」。カート、多段承認、ブラウザ自動化の未完成フォームは依然ステートフルでよい — 状態は明示的であってMcp-Session-Idに縛られない。
推奨パターン:
- 最初のツール呼び出しでリソース作成、返却:
{ "draftId": "dr_8k2", ... }。 - ツール説明に:後続ステップは
draftId。 - サーバーは
draftIdで DB/キャッシュ参照。欠落時は JSON-RPC 業務エラー。不可解な Session 404 ではない。
長タスクは Tasks 等の拡張で MRTR(Multi-Request Task Routing):ツールは先にstatus: input_required を返し、クライアントがユーザー追答を後続リクエストの_meta に付けて続行。依然ステートレス上の request/response。応答が複数ラウンドにまたがるだけ。
Structured Output との関係
MCP と Structured Output は別層の問題を解くが、JSON 形状は同じ Agent パイプラインで出会う:
| 層 | 仕組み | 何を拘束するか |
|---|---|---|
| モデル出力 | Structured Output + JSON Schema | 最終回答や抽出結果のフィールドと型 |
| ツール呼び出し | MCP tools/call + ツール inputSchema |
Server へ渡すarguments オブジェクト |
| 業務 API | REST / GraphQL JSON body | Server 内部または下流 HTTP の実ペイロード |
ベストプラクティスはフィールド表を一つを保守し、MCP ツール inputSchema、REST OpenAPI、モデル向け Structured Output Schema を生成。サイト内Gemini API の JSON 出力ガイドがモデル側;Gemini Structured Output チュートリアルにクラウド例。MCP ステートレス化後、ツール一覧はクライアントキャッシュされ得る — Schema 版変更時はツール名かプロトコル版を bump し、古いキャッシュが誤形状をarguments。
本番で JSON をどう見るか
Remote MCP Server 連調では 3 つの JSON を並べるのが最短:クライアントのtools/call 引数、ドメインサービスの HTTP body、モデルへ返すresult.content。形が合わないなら、ほぼアダプタ層の問題。「モデルが賢くない」ではない。
ブラウザで一通り:JSON フォーマットで parse 確認;JSON 検証で末尾カンマ・型エラー;JSON Schemaでツール inputSchema と API body の共通フィールド;JSON Diff「モデル arguments」と「実 HTTP リクエスト body」を比較。固定フィクスチャ 3 件:mcp-args.valid.json、http-body.valid.json、mcp-tool-error.json — CI で同一 Schema。
よくある質問 FAQ
ステートレス MCP に WebSocket 長接続は必要?
Remote は主に Streamable HTTP:単一 POST で RPC。長通知ストリームもリクエスト単位。旧式「handshake して Session 固定」ではない。stdio は長寿命プロセスだが、プロトコル上各リクエストは独立。
Mcp-Session-Id 付き旧クライアントは新 Server に接続できる?
2026-07-28 Server はプロトコル級 Session ID を認識しません。各リクエスト _meta に protocolVersion と clientCapabilities、必須 HTTP ヘッダーへアップグレード。混在時はゲートウェイで MCP-Protocol-Version 振分。
tools/list は毎回必要?
いいえ。Server は ttlMs を返せ、クライアントは TTL 内キャッシュ。ツール/Schema 変更時は TTL 短縮かツール名/版変更で stale 回避。
MCP が Server の代わりに arguments を検証する?
ツールは inputSchema を宣言できるが、Server はサーバー側検証必須。外部 Agent は型を誤りがち。ステートレス化は減らない。構造化 JSON-RPC error は黙って 500 よりモデル再試行に有利。
まとめと次の一歩
Stateless MCP は 2026 年の Remote Server を普通の HTTP 運用へ:JSON-RPC 2.0 がメソッド、_metaがプロトコルコンテキスト、Mcp-Method / Mcp-Name ヘッダーでゲートウェイが読める。initialize と Mcp-Session-Id が退き、任意インスタンス・Serverless 向き・ツール別レート制限が簡単に。
業務状態は arguments の明示 ID で。JSON 契約は依然ローカル検証。次:2026-07-28 仕様で Remote エンドポイントの _meta と HTTP ヘッダー確認;MCP arguments と REST body を同一 Schema に;JSONVue で往復 JSON 検証。