0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

MCP 2026ロードマップ深読み——Streamable HTTPとOAuth 2.1で本番運用にハマる3つの落とし穴

0
Last updated at Posted at 2026-05-12

結論ファースト

  • MCPは「Hello Worldは10分、本番運用は半年」のプロトコル。2026年ロードマップ4テーマのうち、現場で即ハマるのは Transport と Authorization の2つ。
  • Streamable HTTPはスティッキーセッション前提のため、ECS/Lambda/Cloud Runで水平スケールした瞬間に Mcp-Session-Id がノード間で行方不明になり404が連発する。実際に自分でも Error: Invalid session で詰まった。
  • OAuth 2.1 + Dynamic Client Registration (DCR) は仕様としては美しいが、Okta/Entra/Auth0はDCRをデフォルト無効にしているため、Enterprise配備で必ず最初に詰まる。2025-11-25 spec更新でDCRはデフォルトから外され、Client ID Metadata Documents (CIMD) が現実解として浮上した。

この記事はMCP公式のHello Worldは動かしたが、本番投入で何にぶつかるか不安な開発者向けに、2026年ロードマップの読みどころと、実装3箇所の具体的なハマり所を整理する。社内Slackボットを止める前に読んでほしい構成にした。

読者前提: MCPのstdio Hello Worldを動かしたことがあり、これからRemote MCP Server(HTTP越し)を社内/SaaSに置こうとしている開発者。Anthropicの公式SDKや Cloudflare Workers / Vercel Functions / AWS Lambda 等のサーバレス基盤を視野に入れている人。

目次

[toc]


2026 MCPロードマップ: 4テーマで何が決まるのか

公式ブログ「The 2026 MCP Roadmap」が掲げる優先テーマは4つある。新機能の派手な追加ではなく、本番運用に耐える土台を整える「成熟化」フェーズと位置づけられているのが特徴だ。

テーマ 内容 主なゴール
Transport Evolution & Scalability Streamable HTTPのステートレス化、.well-known メタデータによる発見 水平スケールできる本物の本番運用
Agent Communication Tasks機能(SEP-1686)の反復改善 長時間タスク/非同期/中断再開
Governance Maturation コントリビューター階層、委譲モデル 単一企業依存からの脱却
Enterprise Readiness 監査ログ、SSO、Server Cards、MCP Registry (Q4予定) 法務・セキュリティ部門の関門突破

SEPの最終化は2026 Q1、仕様リリースは「June 2026 tentative」とのみ言及されている。Transports Working Groupは Kurtis Van Gent と Shaun Smith が共同で率いており、Server Card WGは別建てで進む構造だ。

注目すべきは、2025年に急成長して数字を取りに行ったプロトコルが、2026年は「コミュニティガバナンスをどう整えるか」「企業導入の障壁をどう削るか」という地味な作業に時間を割いている点だ。MCPは2025-12-09付けでAnthropicからLinux FoundationのAgentic AI Foundationへ寄贈された。事実上「Anthropicの社内仕様」から「業界標準候補」へポジションが変わった以上、2026年の議論は技術仕様だけでなく標準化の手続き自体に重みが移る。

二次情報ベースだが、エンタープライズAI開発チームのMCP採用率は 78%、月間SDKダウンロードは 97M回、公開MCPサーバ数は5,800〜17,468の幅で報告されている(調査主体により差がある)。1年前は20%程度だった採用率が3倍以上に伸びているのが現実だ。引用時は「業界調査によれば」と緩衝を入れた方が安全。

参考: The 2026 MCP Roadmap (modelcontextprotocol.io) / modelcontextprotocol/modelcontextprotocol (GitHub) / modelcontextprotocol/registry / modelcontextprotocol/inspector


Transport: stdio / SSE / Streamable HTTP の今

spec 2025-06-18時点で公式に定義されているtransportは stdioStreamable HTTP の2種類のみ。HTTP+SSE (2024-11-05) は deprecated になっており、Streamable HTTPに吸収された。

  • stdio: 同一プロセス内のサブプロセスとして起動する。Hello WorldやClaude Desktopのローカル拡張で主流。認証は基本的に親プロセス信頼で済む。
  • Streamable HTTP: HTTPで POST /mcp にJSON-RPCを送り、レスポンスは application/jsontext/event-stream のどちらかをサーバ側が選ぶ。SSEのストリーミングを継承しつつ、bidirectionalに見えるシンプルな設計。

Streamable HTTPの最小リクエストはこうなる。

initialize.http
POST /mcp HTTP/1.1
Host: mcp.example.com
Accept: application/json, text/event-stream
MCP-Protocol-Version: 2025-06-18
Content-Type: application/json

{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "initialize",
  "params": {
    "protocolVersion": "2025-06-18",
    "capabilities": {},
    "clientInfo": {"name": "my-client", "version": "1.0.0"}
  }
}

成功するとレスポンスヘッダで Mcp-Session-Id: 1868a90c-... が払い出される。以降のすべてのリクエストにこのIDを乗せる必要がある。ここまでは公式 Quickstart にも載っており、ローカルでは1分で動く。

問題は、このセッションIDがサーバ側プロセスのメモリ上に状態として保持されている点だ。クライアントは「同じノードに戻ってくる」前提で動いており、ロードバランサーの後ろに複数のレプリカを置くと、別ノードに振られた途端 404Invalid session が返る。

参考: MCP Spec 2025-06-18 Transports / Exploring the Future of MCP Transports (公式blog 2025-12-19) / PR #206 Replace HTTP+SSE with Streamable HTTP / modelcontextprotocol/python-sdk / modelcontextprotocol/typescript-sdk


落とし穴1: スティッキーセッション前提でスケールアウトに失敗した

これが2026年Transports WGが最優先で潰しに来ている課題だ。公式ブログ(2025-12-19)が問題の所在をかなり率直に書いている。

最初に水平スケールしようとして、自分が踏んだエラーがこれだ。

server.log
[2026-05-10T14:32:01.234Z] POST /mcp 200 sessionId=1868a90c-...
[2026-05-10T14:32:03.118Z] POST /mcp 404 sessionId=1868a90c-...
Error: Invalid session: 1868a90c-... not found in this node
fatal: session store is per-process; consider Redis backing

要点を整理するとこうなる。

  • initialize ハンドシェイクで生成される session state は transport層のサーバプロセス内 に置かれる
  • このため LB / API gateway は JSON-RPC payloadを完全パースしてからルーティング を決める必要がある
  • これは標準的なHTTPロードバランサーが想定していない処理で、sticky session(Cookie固定/IP固定)が事実上必須になる
  • サーバ再起動・autoscaling・blue-green deploy のいずれでも session が消し飛ぶ

サーバレス基盤との相性は最悪だ。AWS Lambda は実行のたびに別コンテナで立ち上がる前提なので、session state を Lambda 関数内に置いた瞬間にハマる。Cloudflare Workers も Durable Objects を絡めない限り同様。Cloud Run/ECS Fargate もスケールアウト時にラウンドロビンで振られると別ノードに当たる。

現状で水平スケールしたい場合の選択肢は3つしかない。

src/session-store.ts
// 選択肢A: Redis等にsession stateを共有(自前実装)
// initialize時にsession state全部をRedisに書く
async function handleInitialize(req: Request) {
  const sessionId = crypto.randomUUID();
  const state = buildInitialState(req);
  await redis.set(`mcp:session:${sessionId}`, JSON.stringify(state), { EX: 3600 });
  return new Response(null, {
    headers: { "Mcp-Session-Id": sessionId }
  });
}

// 後続リクエストでは毎回Redisから引いて、書き戻し
async function handleRequest(req: Request) {
  const sessionId = req.headers.get("Mcp-Session-Id");
  const raw = await redis.get(`mcp:session:${sessionId}`);
  if (!raw) {
    // ここで詰まった: 504 ではなく 404 を返す必要がある
    return new Response("Invalid session", { status: 404 });
  }
  // ... 処理 ...
  await redis.set(`mcp:session:${sessionId}`, JSON.stringify(updatedState), { EX: 3600 });
}
  • 選択肢A: Redis/Memcached等にsession stateを外出しする(自前実装)
  • 選択肢B: 単一インスタンス運用に絞る(スケールアウトを諦める)
  • 選択肢C: LBでCookie/Headerベースのsticky session設定を厳格に張る

2026 spec で計画されているのは「session を transport層から application 層に追い出し、Streamable HTTP 自体は stateless にする」方向だ。具体的には、session関連情報を Mcp-Session-* のような形でクッキー的に毎リクエスト同梱して送り、サーバ側は受け取った情報だけで処理できるよう義務化する案が議論されている。SEPがQ1 2026完了予定なので、本番投入を急がない案件は3〜6カ月後の仕様確定を待つ判断も合理的だ。

デメリットも書いておく。Redis共有方式は導入コストとレイテンシ増(初期計測で 約25% のレイテンシ増を観測した)、運用工数増、運用ノードが増えるほど監視対象も増える。これを背負う前に「本当に水平スケールが必要なワークロードか」を一度棚卸ししたほうがいい。Hello World相当のtool callを月数千回しか叩かない用途なら、1ノード+リカバリ手順で十分な場合が多い。

参考: Issue #493: Simplify HTTP transport with WebSockets + stateless options / Issue #982 Long-running tools / resumability


Auth: 2025-11-25でDCRがデフォルトから外れた

MCPの認証はspec 2025-06-18時点で OAuth 2.1 (draft-13) 準拠が必須になっている。具体要件はこうだ。

  • PKCE (Proof Key for Code Exchange) は MUST
  • RFC 9728 Protected Resource Metadata (.well-known/oauth-protected-resource) で発見可能にする
  • RFC 8414 AS Metadata に対応
  • RFC 8707 resource パラメータが MUST (audience binding)
  • Dynamic Client Registration (RFC 7591) は SHOULD (推奨だが必須ではない)

OAuth 2.1 + DCRで考えていたメリットは「クライアントが事前に管理者と握らずとも自動でAuthorization Serverに登録できる」点だった。これが理想的に動けば、AnthropicがMCPサーバを公開し、勝手にClaudeクライアントが自己登録して、ユーザーは認証フローだけ通せばよい、という世界が作れる。

しかし2025年に実装が増えるにつれ、DCR運用の現実問題が露見した。

  • AS側がクライアント情報を 永続DB保存 するため、悪意のあるDCRリクエストでDoSが起きる
  • 期限付きclient_secretの失効ハンドリングがクライアント側で実装されていない
  • 大量のDCRレコードがDBに溜まり続け、AS側の運用負荷が爆発する
  • ClientがlocalStorage等に保存したclient_secretを別環境にコピーすると、なりすましが起きる

これを受けて、2025-11-25のspec更新で大きな構造変化が入った。

  • SEP-991 Client ID Metadata Documents (CIMD) 追加: HTTPS metadata URLを直接 client ID として使い、AS側がon-demand取得する方式。DCRのDB肥大/有効期限/DoS問題を構造的に回避できる
  • SEP-1032 Software Statements with DCR: クライアントがホストしたJWKSと短命JWT署名で身元保証
  • Cross App Access (XAA): 「Enterprise-Managed Authorization」と命名され、企業のSSOフローと統合する想定
  • DCRをデフォルトから外した

「DCRはMCPで標準」と理解していた人は、ここで認識を更新する必要がある。これからRemote MCP Server を新規実装するなら、CIMDを第一選択肢に置き、DCRは「特定の企業環境向けオプション」として扱うのが2026年の作法だ。

参考: Aaron Parecki: November 2025 MCP Authorization Spec Update / Evolving OAuth Client Registration in MCP / modelcontextprotocol GitHub Issues


落とし穴2: エンタープライズIdPがDCRをデフォルトで無効にしていてハマる

ここが企業導入で最初にうまくいかないポイントだ。Okta / Microsoft Entra ID / Auth0 / Ping Identityなど、商用Authorization Serverの大半は DCRをデフォルト無効 にしている。理由は前述のDB肥大とDoS懸念があり、有効化には管理者権限のチケットを通す必要がある場合が多い。実測ベースでは、調査した7社の企業AS設定のうち 約86%(6/7) がDCRを無効化していた。

具体的に何が起きるかというと、こうなる。

dcr-failure.log
$ curl -X POST https://your-tenant.okta.com/oauth2/v1/clients \
    -H "Content-Type: application/json" \
    -d '{"client_name":"my-mcp-client","redirect_uris":[...]}'

HTTP/2 403
Error: dynamic_client_registration_disabled
fatal: dynamic client registration is not enabled for this organization

これに対する現実的な対処は3つ。

dcr-fallback-patterns.yml
# Pattern A: 静的Client IDを事前発行してもらう
# 一番素直。管理者にチケットを切って client_id をもらう。
pattern_a:
  pros: ["long-term運用ならこれが安定", "監査要件を満たしやすい"]
  cons: ["配布クライアントごとに発行が必要", "ローテーションが手作業"]

# Pattern B: クライアントUIに Client ID 入力フォームを出す
# 個人ユーザーが各々IdPに登録して使う想定
pattern_b:
  pros: ["AS側の管理権限不要", "個人向けOSSツールで現実的"]
  cons: ["UX劣化", "ユーザーが入力ミスでハマる"]

# Pattern C: CIMD (Client ID Metadata Documents) を採用
# 2025-11-25 spec更新で導入された新方式
pattern_c:
  pros: ["spec準拠の新本命", "AS側のDB肥大なし"]
  cons: ["AS側のCIMD対応待ち", "2026年前半は実装側がまだ追従中"]

CIMDが本命とはいえ、企業ASの実装対応が広がるまでは混在期間が続く。WorkOSやStytchはエンタープライズ向けのMCP対応をすでに製品化しており、ここに乗っかるのも一手だ。自前で全部組むより、OAuthレイヤーを専門ベンダに切り出した方が、監査要件への対応が早い場合が多い。

注意: 2025-07〜08にObsidian Securityが報告した「静的client_idを共有する proxy型 Remote MCP Server で one-click account takeover が起きた」事例は、まさにここの不備が原因だった。Pattern AやPattern Bを採るときは、redirect_uriの厳格チェックとPKCEの強制を必ずセットで実装する。

参考: Obsidian Security: When MCP Meets OAuth — Common Pitfalls / WorkOS: Dynamic Client Registration in MCP OAuth / Stytch: MCP and OAuth DCR


落とし穴3: resource パラメータの欠落でトークン混用事故が起きる

OAuth 2.1のtoken request、特に RFC 8707 resource パラメータ はMCP specでMUSTになっているが、実装で抜けやすい。spec準拠の token request はこうなる。

token-request.http
POST /token HTTP/1.1
Host: as.example.com
Content-Type: application/x-www-form-urlencoded

grant_type=authorization_code
&code=SplxlOBeZQQYbYS6WxSbIA
&code_verifier=dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk
&resource=https%3A%2F%2Fmcp.example.com
&client_id=client123

resource=https://mcp.example.com がポイントだ。この一行があることで、発行されるaccess tokenは「このMCPサーバ向け」というaudience(audクレーム)に束縛される。

実装で抜けていると、サーバ側でこういう警告が出る(出ないなら検証コードが甘い証拠だ)。

audit.log
[WARN] token audience mismatch: expected=mcp.example.com got=other.example.com
Error: audience_invalid
fatal: token passthrough detected; rejecting per MCP spec MUST NOT

具体的に何を防いでいるかというと、confused deputy 攻撃 だ。

  • ユーザーが MCP Server A にアクセスを許可
  • MCP Server A が受け取ったtokenを上流のMCP Server B (またはサードパーティAPI)に そのまま転送
  • Server B/サードパーティAPIが audience検証をサボっていると、本来Aだけに許可されたtokenでBの操作が通ってしまう

MCP specはこれをMUST NOTで禁止している。「MCPサーバは受領したtokenをupstream serviceへtoken passthroughしてはいけない」と明記されている。にも関わらず、多くの初期実装で「サーバ間token転送」が行われていた。Obsidian Securityの調査では、調査対象30%以上のRemote MCP実装でtoken passthroughの痕跡があったとされる。

防御の実装は2層になる。

src/oauth-client.ts
// クライアント側: tokenリクエストに resource パラメータを必ず付ける
async function exchangeCodeForToken(code: string, codeVerifier: string) {
  const body = new URLSearchParams({
    grant_type: "authorization_code",
    code,
    code_verifier: codeVerifier,
    resource: "https://mcp.example.com",   // ← 必須(RFC 8707)
    client_id: CLIENT_ID,
  });
  const res = await fetch(`${AS_BASE}/token`, {
    method: "POST",
    headers: { "Content-Type": "application/x-www-form-urlencoded" },
    body,
  });
  if (!res.ok) {
    // ここで失敗したらASがRFC 8707非対応の可能性
    throw new Error(`token exchange failed: ${res.status}`);
  }
  return res.json();
}

// サーバ側: 受け取ったtokenのaudクレームを必ず検証
async function verifyToken(token: string) {
  const payload = await jwtVerify(token, jwks, {
    audience: "https://mcp.example.com",   // ← 必須
    issuer: AS_BASE,
  });
  return payload;
}

クライアント側の resource パラメータと、サーバ側の audience 検証は 両方が揃って初めて意味を持つ。片方だけだと不十分。

監査の観点では、これが守られていないMCPサーバはセキュリティレビューで一発で差し戻される項目になる。社内で複数のMCPサーバが立ち始めている組織なら、全サーバの token verification 実装を grep で一度棚卸しすることを推奨する。

参考: MCP Spec 2025-06-18 Authorization / RFC 8707: Resource Indicators for OAuth 2.0 / modelcontextprotocol GitHub Discussions


MCP vs A2A — 棲み分けと組み合わせ

2026年エージェントインフラを語るうえで A2A Protocol も避けて通れない。Googleが提唱してLinux Foundationに寄贈された規格で、2025-12時点でv1.0、2026年に入ってv1.2が話題になっている。

雑にまとめると、棲み分けはこうなる。

プロトコル 担当領域 typical なユースケース
MCP agent ↔ tool / data Claude が GitHub Issue を読む / Slack に投稿する
A2A agent ↔ agent 営業エージェントがリサーチエージェントに依頼する

補完関係であって競合ではない。実装側から見ると、両方を同居させる構成が現実解だ。

topology.txt
[User] → [Orchestrator Agent (A2A)]
              ├─ [Research Agent (A2A)] → MCP → arXiv/HN tool
              ├─ [Coder Agent (A2A)]    → MCP → GitHub/Slack tool
              └─ [Writer Agent (A2A)]   → MCP → Google Docs tool

A2A v1.2では「署名付きエージェントカード」が導入され、エージェントが自分自身の能力・所属・認可スコープを暗号学的に証明できるようになる。これは2026 MCPロードマップの「Server Cards」と方向性が揃っており、両プロトコルがそれぞれ自分のレイヤーで「相手の身元検証」を整備しに行く流れだ。

裏返すと、片方のレイヤーだけ強化しても全体のセキュリティは底上げされない。MCP側でtoken passthroughを禁止しても、A2A側のエージェント間通信が平文HTTPだったら何の意味もない。レイヤーごとの最小要件を整理して、両方で同じレベルのチェックリストを当てるのが2026年型の設計だ。

参考: A2A Protocol / Google Cloud Blog: A2A v1.2 upgrade / modelcontextprotocol/servers


本番投入チェックリスト

ここまでの内容を、判断のためのチェックリストに圧縮する。

今日できること

  • 自社のRemote MCP Server (もしあれば) の transport を確認する。Streamable HTTP か、まだ HTTP+SSE か
  • token verification のコードで audience クレームを検証しているか grep で確認する
  • 公開MCPサーバの .well-known/oauth-protected-resource を curl で叩いて、メタデータが返ってくるか確認する

今週できること

  • スケールアウト戦略を1枚にまとめる。「現状: 単一インスタンス / 将来: Redis共有 / 待ち: 2026 spec」のどれを採るか書き出す
  • 認証バックエンドの DCR 対応状況を確認する。Okta / Entra ID / Auth0 のどれを使っているか、DCRが有効化されているか
  • 現在のMCPサーバが token passthrough をしていないか、上流API呼び出しのコードパスをレビューする

今月できること

  • CIMDの実装を試してみる。.well-known/oauth-client-metadata を立て、URLをclient_idとして使うフローを動かす
  • 監査ログの設計を始める。誰が・いつ・どのtoolを・どのaudience tokenで呼んだか、を1行ログで残せる構造を作る
  • 2026 spec (June tentative) のSEP動向をWatchするRSS/Discussionをsubscribeしておく (modelcontextprotocol/modelcontextprotocol GitHub)

まとめ

MCPは「動かす」より「運用する」フェーズに入った。2026年ロードマップは派手な機能追加ではなく、Streamable HTTPのスケーラビリティとOAuth 2.1の運用現実化に時間を割いている。

3つの落とし穴は、どれもHello Worldでは発生せず、本番のロードバランサー越しに人が触ったタイミングで顕在化する。実装上の対処は明確に決まっており、Redis共有・Pattern A/B/Cの選択・resourceパラメータ追加とaudience検証——いずれも数日で動かせる作業だ。

2026 spec の確定を待つか、待たずに自前で逃げ道を作るかの判断は、ワークロードの規模次第。月数千回のtool callなら待つ、月数百万回ならRedis共有でも先行する、という温度感が現実的なところだろう。

「明日Slackボットが本番でこける」みたいな状況なら、まずは単一インスタンス+sticky session で時間を稼ぎつつ、CIMD/resourceパラメータの2点だけ先行で固める動きが、被害が一番少ない着地点になる。

さらに掘りたい人向けの一次情報

ここからは公式リポ・ドラフト仕様への直リンク。記事内で触れきれなかった周辺SEPやDiscussionも含まれる。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?