Claude Media
MCP Streamable HTTPからGETストリームとセッションが消えた理由

MCP Streamable HTTPからGETストリームとセッションが消えた理由

MCP仕様2026-07-28で、Streamable HTTPのGETストリームとMcp-Session-Idによるセッションが廃止されました。何が変わり、旧クライアントとどう共存するかをまとめます。

Streamable HTTPは、サーバーが独立したプロセスとして複数クライアントを相手にする、MCPのリモート接続用トランスポートです。標準の2方式でカバーできない要件はMCPカスタムトランスポートを設計することも仕様上認められています。2026-07-28の仕様改訂で、このトランスポートから2つの要素が消えました。MCP全体の仕組みと利用面別の違いはMCPとはにまとめています。

1つはサーバー側が長時間の接続を張っておくGETエンドポイント、もう1つはMcp-Session-Idヘッダーによるプロトコルレベルのセッションです。どちらも2025-11-25版までは存在していました。削除は単なる整理ではなく、MCPサーバーを「接続を覚えている常駐プロセス」から「リクエスト単位で完結するWeb API」に近づける設計変更です。

Streamable HTTPの基本形 — 1つのPOSTエンドポイントに全部乗せる

サーバーは単一のHTTPエンドポイント(MCPエンドポイント)を公開し、POSTを受け付けます。クライアントが送るJSON-RPCのリクエストや通知は、それぞれ独立したPOSTです。

サーバーはリクエストごとに、2種類の応答から選びます。単一のJSONオブジェクト(Content-Type: application/json)か、そのリクエストに紐づくSSEストリーム(text/event-stream)です。クライアントは両方を扱えなければなりません。POSTのAcceptヘッダーには、application/jsonとtext/event-streamの両方を並べる決まりです。

通知のPOSTを受け付けたサーバーは、本文なしの202 Acceptedを返します。受け付けられないときは400 Bad RequestなどのHTTPエラーを返します。

セキュリティ面では、DNSリバインディング攻撃を防ぐためOriginヘッダーの検証が必須です。値が不正なら403 Forbiddenを返す義務があります。ローカルで動かす場合は、0.0.0.0ではなく127.0.0.1にのみバインドすることが推奨されています。

すべてのPOSTには、2025-06-18版で加わったMCP-Protocol-Versionヘッダーに加えて、Mcp-Methodが必須です。tools/call・resources/read・prompts/getではMcp-Nameも要ります。この2つの検証条件とHeaderMismatchErrorの発生条件は、MCPでMcp-MethodとMcp-Nameヘッダーが必須になった理由にまとめています。

2026-07-28で何が削除されたか — GETエンドポイントとセッション

削除された4つの仕組みを、2025-11-25版までの姿と並べます。

くらべる

2025-11-25版までと2026-07-28版の違い

接続を覚える

2025-11-25版まで

  • サーバー通知は、GETで開いたSSEストリームで待つ
  • Mcp-Session-Idで接続(セッション)を識別する
  • Last-Event-IDでストリームを再開できる
  • roots/listなどのサーバー発リクエストを、SSEストリーム上で送れる
リクエストで完結

2026-07-28版

  • サーバー通知は、subscriptions/listenへのPOSTで開く
  • セッションがなく、一覧系は接続に関わらず内容が同じ
  • ストリームは再開できず、切れたら新しいリクエストIDで送り直す
  • サーバー発リクエストは廃止し、MRTRのInputRequiredResultに一本化する

呼び出しをまたいで状態を持ちたいサーバーは、サーバー自身が発行するハンドルを通常のツール引数として受け渡す設計に変えます。

Last-Event-IDによる再開がなくなったため、応答用のSSEストリームが途中で切れたリクエストは失われたものとして扱われます。

キャンセルの扱いも変わりました。クライアントがSSE応答ストリームを閉じると、サーバーはそのリクエストのキャンセルとして扱い、できるだけ早く処理を止めて以降のメッセージを送りません。リクエストごとにストリームが分かれているので、切断がどのリクエストを指すのかは曖昧になりません。

サーバーが入力を必要とするときは、独自のリクエストを送らず、inputRequestsを含むInputRequiredResultを返します。この仕組みはMRTR(Multi Round-Trip Requests)と呼ばれます。クライアントは入力を集めたうえで、元のリクエストをinputResponses付きで再送します。

subscriptions/listenが担う変更通知の仕組み

サーバー側の変更をクライアントに知らせる経路は、GETによる常時接続からsubscriptions/listenという1本のリクエストに置き換わりました。クライアントは、欲しい種類を指定して送ります。選べるのはtoolsListChanged・promptsListChanged・resourcesListChanged・resourceSubscriptionsです。

サーバーはPOSTへの応答として開いたSSEストリームを開いたままにします。最初のメッセージはnotifications/subscriptions/acknowledgedで、受理した購読の条件と購読IDが入ります。以降の通知にはio.modelcontextprotocol/subscriptionIdが付くので、1本のストリームに複数の購読が相乗りしても振り分けられます。

notifications/progressやnotifications/messageのようなリクエストに紐づく通知は、このストリームには乗りません。そのリクエスト自身の応答ストリームだけを流れます。

長時間ストリームには、プロキシ越しの運用で2つの注意があります。仕様は、SSEを始めるサーバーにX-Accel-Buffering: noヘッダーを付けることを推奨しています。nginxなどのリバースプロキシが応答をためこんで、通知が遅れるのを防ぐためです。さらに、コロンで始まるSSEコメント行を定期的に流すキープアライブも勧めています。中継プロキシやクライアントのアイドルタイムアウトで接続が切られるのを避けるためです。

後方互換 — 2025-11-25以前のクライアントとどう共存するか

2026-07-28版のみに対応したサーバーが、古いクライアントのトラフィックを受け取ったときの推奨対応は明確です。GETやDELETEには405 Method Not Allowedを返します。Mcp-Session-Idは無視し、セッションIDを発行も反映もしません。Last-Event-IDも無視し、ストリームは再開不可のまま扱います。

クライアント側からサーバーの世代を見分ける手順も定義されています。2024-11-05版のHTTP+SSE(現在は非推奨)に対応するための手順で、流れは次のとおりです。

手順

クライアントがサーバーの世代を見分ける流れ

  1. 1

    通常どおりPOSTを送る

    成功すれば、新しいStreamable HTTPに対応したサーバーです。

  2. 2

    失敗したら応答本文を見る

    400・404・405が返ったとき、本文が新しいプロトコルの既知のJSON-RPCエラーなら、相手は新世代です。メッセージを直すか、サーバーが示す対応バージョンで再試行します。

  3. 3

    既知のエラーでなければGETを送る

    最初のイベントとしてendpointイベントが返れば、相手は2024-11-05版のHTTP+SSEで動いています。以降はその方式に切り替えます。

404の区別には理由があります。2026-07-28版のサーバーは、未実装のRPCメソッドに対して404 Not Foundと-32601(Method not found)のJSON-RPCエラーを返します。レガシーなHTTP+SSEサーバーが返す、既知のJSON-RPCエラーを含まない404と、本文で見分けるわけです。

手元から切り分けるには、MCPエンドポイントにGETを送ります。

curl -i https://example.com/mcp \
  -X GET

405 Method Not Allowedなら、2026-07-28版の推奨どおりGETを受け付けていないサーバーです。

Claude Codeの側から見ると、この世代判定の扱いは接続先の種類で変わります。Claude CodeのMCPクライアントには、MCP TypeScript SDK 1.xベースのv1ランタイムと、SDK 2.0ベースで2026-07-28に対応するv2ランタイムがあります。v2ランタイムが2026-07-28対応かどうかを問い合わせるのは、HTTPサーバーです。claude.aiコネクタは、機能フラグを取得するセッションでだけ問い合わせます。stdioサーバーは問い合わせず、従来のハンドシェイクのままです。

v2ランタイムが使われる条件は、2通りあります。機能フラグを取得するセッションではv2.1.232以降です。取得しないセッションでは、v2.1.274以降で、Bedrockなどのクラウド経由、Claude appsゲートウェイ経由、テレメトリーを切った場合などに既定でv2になります。ただし、Claude Codeを組み込むホストプラットフォームがCLAUDE_CODE_PROVIDER_MANAGED_BY_HOSTを設定している場合は、この既定から外れます。

まとめ

v2ランタイムの挙動を決める環境変数

  • MCP_SDK_GENERATION

    v1かv2を指定して、ランタイムそのものを固定します。v2.1.218以降が必要です。

  • MCP_PROTOCOL_NEGOTIATION

    autoにすると、stdioとclaude.aiコネクタにも問い合わせます。legacyなら、どのサーバーにも問い合わせません。v2.1.221以降が必要です。

自作のリモートHTTPサーバーを2026-07-28対応に上げた場合、v2ランタイムなら、Claude Code側の設定を変えなくても新しいトランスポートで通信します。v1ランタイムで動いているセッションは従来のプロトコルのままです。Anthropicは、機能フラグで特定のサーバーを以前のプロトコルのまま、またはこのストリームなしに留めることもできます。Agent SDKからの接続でのトランスポートの選び方はAgent SDK MCP接続ガイドにあります。

古いクライアントとの共存を、自分のサーバー側で維持する選択肢もあります。旧SSEエンドポイントと旧POSTエンドポイントを、新しいMCPエンドポイントと並行してホストし続けます。両者を1つのエンドポイントに統合することも可能ですが、仕様は「不要な複雑さを持ち込む可能性がある」と釘を刺しています。いつ旧エンドポイントを畳むかは、運用者が決める点です。

Claude Codeが変更通知のストリームを保つ条件

v2ランタイムのClaude Codeは、新しい版のサーバーからのlist_changed通知を、開いたままのストリームで受け取ります。ストリームが閉じると再び開きますが、回数に上限があります。

  • 10秒以内にまた閉じる場合: 最大3回まで開き直し、その接続では止めます
  • 10秒より長く開いてから閉じる場合: サーバーレスのホスト先でよくある挙動です。1時間に5回開き直した後は、次の開き直しまで約6時間待ちます

ストリームが開き直るまでの間は、最後に取得したツール・プロンプト・リソースの一覧が使われます。変更を早く反映したいときは、/mcpからサーバーを再接続します。サーバーレス構成でsubscriptions/listenを実装するときは、このストリームの寿命を考えておく必要があります。

手元のclaude mcp addで確かめられること

v2.1.287のclaude mcp add --helpでは、トランスポートにstdio・sse・httpを指定できます。既定はstdioです。

claude mcp add --transport http sentry https://mcp.sentry.dev/mcp

これは--helpの例にそのまま載っているHTTPサーバーの追加コマンドです。JSONで設定ファイルに書く場合は、typeにstreamable-httpと書いてもhttpの別名として扱われ、サーバー側の資料の設定をそのまま写せます。

urlがあるのにtypeがない設定は、stdioサーバーとして読まれるため失敗します。報告されるメッセージは次のとおりです。

MCP server "<name>" has a "url" but no "type"; add "type": "http" (or "sse" / "ws") to this entry

SSEのみを公開している相手に--transport httpで追加した場合は、まずHTTPを試し、受け付けられなければSSEに切り替わります。この自動切り替えにはv2.1.265以降が必要です。

認証の枠組みはトランスポートで別物になる

Streamable HTTPを含むHTTPベースのトランスポートは、MCPが定義するAuthorization(認可)フレームワークに従うべきだとされています。OAuthを軸にしたこのフレームワークは、リモートのMCPエンドポイントに対する認証・認可の標準的なやり方を定めています。OAuth認証の手順そのものはリモートMCPのOAuth認証で扱っています。

対照的に、stdioトランスポートの実装はこのフレームワークに従うべきではないとされ、環境変数などその場の実行環境から認証情報を取得することが想定されています。同じMCPでも、トランスポートが変わると、認証情報を扱う場所そのものが変わります。クライアントとサーバーが独自の認証方式を合意することも、仕様上は妨げられていません。

この改訂では、認可レスポンスのissパラメータ(RFC 9207)についても規定が加わりました。認可サーバーはissを含めるべきで、MCPクライアントは、認可コードを引き換える前に、issが記録済みの発行者と一致するかを検証しなければなりません。issが含まれているときは、クライアントに照合の義務があります。含まれていない場合の扱いは、Claude Codeの挙動とあわせて後述します。

Claude Codeのv2ランタイムは、v2.1.221以降でこの検証を実装しています。一致しなければ、/mcpのサーバーメニューに次の形のエラーを出してサインインを失敗させます。

Issuer mismatch in authorization response (RFC 9207): expected "https://auth.example.com", received "https://other.example.com"

expectedはサーバーのOAuthメタデータの発行者、receivedはリダイレクトで返ってきたissの値です。リダイレクトにissがなければ検証は通ります。ただし、メタデータでauthorization_response_iss_parameter_supportedを有効にしている場合は、issがないとサインインが失敗します。

v1ランタイムはこの検証を行いません。自作のOAuth実装でこのエラーが出るなら、対処はサーバー側です。認可サーバーが返すissを、メタデータで公開している発行者と同じ値にそろえます。一時的な回避としてMCP_SDK_GENERATION=v1で起動する方法もあります。ただし、mix-up攻撃(認可サーバーの取り違え)への防御が外れるため、サーバー側の修正が向いています。

Streamable HTTPの版数タイムライン

Streamable HTTPという名前自体は2025-03-26版から使われていますが、中身は複数回にわたって手が入っています。

あゆみ

Streamable HTTPの変遷

  1. 2024-11-05HTTP+SSE

    GETでSSEを開き、POSTでメッセージを送る方式です。2025-03-26版から非推奨とされています。

  2. 2025-03-26Streamable HTTPとして導入

    単一のPOSTエンドポイントに統合し、Mcp-Session-IdによるセッションとLast-Event-IDによる再開を規定しました。

  3. 2025-06-18プロトコルバージョンのヘッダー

    後続リクエストでMCP-Protocol-Versionヘッダーを送る要件を加えました。

  4. 2025-11-25Origin検証とSSEポーリング

    不正なOriginへの403応答を明確にしました。サーバーが任意にSSE接続を切るポーリングも認め、再開はGET経由と整理しました。

  5. 2026-07-28セッションとGETを廃止

    セッション・GETエンドポイント・ストリーム再開をすべて削除しました。

2025-11-25版でも「サーバーが切ってクライアントが再開する」前提のポーリングが加わっているので、この撤回は直前の版の方向とも逆向きです。

GETエンドポイントの廃止でMCPサーバーはコネクション管理から解放される

セッションIDやストリームの再開ロジックを実装から取り除くと、サーバー側の設計はシンプルになります。どのリクエストも「届いたら処理して返す」だけで完結し、特定のクライアントとの接続状態をどこかに保持しておく必要がありません。

これは、一般的なWebバックエンドが、ロードバランサーの背後で複数インスタンスを気軽にスケールできるステートレスな構成へ寄っていった流れと同じ方向です。MCPサーバーをコンテナで動かし、オートスケールやローリングデプロイの対象にしたい事業者にとって、特定のインスタンスに固定されるセッションは扱いにくい制約でした。

代償は、状態を持つ処理の書き方に出ます。連続した操作が必要なツールは、状態をサーバーに置けないぶん、ハンドルの設計をツール側で引き受けることになります。

まとめ

自作のリモートMCPサーバーを上げる前に、呼び出しをまたぐ状態をハンドル引数へ移せるかを確かめておくと、移行で詰まりにくくなります。サーバーレスのホスト先では、subscriptions/listenのストリームが再接続の上限内で保てるかも合わせて見ておく点です。

この記事を共有:XはてブLinkedIn
MCP をもっと見る →