MCP の remote server を作り始めると、最初に迷うのは transport 全体ではなく session です。実際、2026-08-16 から 2026-08-23 の GSC でも、このサイトでは mcp session id、mcp-session-id、mcp stateless が同じ記事に着地していました。つまり検索側も「header名の意味」「404で何をするか」「今からなら stateless でよいのか」をひとかたまりで知りたがっています。claude code add remote mcp server や claude mcp add までは進んだのに、その先の MCP-Session-Id、404 再初期化、DELETE 終了、そもそも mcp stateless で足りるか stateful を持つべきかで止まる人は多いです。
2026-07-28 の MCP 仕様では Streamable HTTP から protocol-level session が外れました。新仕様へ寄せるなら MCP 2026-07-28 移行ガイド、2025-03-26 から 2025-11-25 の実装や既存 server との互換を維持するなら本記事を使ってください。特に Claude Code から remote MCP を足した直後に mcp session id や mcp-session-id の扱いで詰まるなら、本記事と Claude Code MCP ガイド を往復しながら見ると、claude mcp add の導入判断と session lifecycle を分けて整理できます。接続追加の入口より session 単位の再初期化や multi-node 配置が知りたい人はこの記事、逆に認証・allowlist・導入手順から見たい人は Claude Code MCP 記事、組織配布や remote MCP の統制まで含めたい人は MCP エンタープライズ運用ガイド の順で読むと混ざりにくいです。
この記事は、MCP の session lifecycle だけを切り出して整理したい人向けです。2026年8月26日時点の最新仕様は 2026-07-28 で、protocol-level session、GET stream endpoint、HTTP DELETE による session 終了はこの revision から外れています。一方で、2025-03-26 から 2025-11-25 の Streamable HTTP revision では MCP-Session-Id、404 再初期化、DELETE 終了が明確に定義されており、既存実装と接続するならまだ読める必要があります。Claude Code 側の追加手順や claude code add remote mcp server の入口を先に整理したいなら Claude Code MCP ガイド、transport 全体の移行論は MCP Streamable HTTP 移行ガイド、認証と配布統制は MCP エンタープライズ運用ガイド、未信頼入力と read/write 分離は MCP prompt injection 対策ガイド を先に読んでください。
迷いやすい検索意図を先に分けると、読む順は次の 3 本で足ります。
mcp-session-id、mcp session id、mcp stateless、404 再初期化なら本記事claude mcp add、remote MCP の追加、claude code mcp stdioの入口判断なら Claude Code MCP ガイド- approval 境界や write tool をどの lane に残すかまで含めて運用を切りたいなら Codex auto review ガイド と MCP prompt injection 対策ガイド
最初の30秒判断表
最初に次の表だけ埋めれば、読む場所をほぼ間違えません。
| いまの状況 | 先に出す答え | 次に見る記事 |
|---|---|---|
mcp session id / mcp-session-id で止まった | 旧revision互換が本当に必要か確認する | 本記事 |
| 新規実装で session をまだ入れていない | まず stateless で始める | 本記事 → MCP 2026-07-28 移行ガイド |
claude mcp add の接続手順で止まった | session ではなく導入手順の問題として切る | Claude Code MCP ガイド |
| 長時間jobや通知まで同時に扱いたい | session と durable state を分ける | MCP Tasks extension 設計ガイド と MCP subscriptions/listen 設計ガイド |
先に結論: session は「使える」ではなく「必要なときだけ使う」
私の結論はかなり単純です。
- デフォルトは stateless でよい
- server から client へ能動的に通知したいときだけ stateful を検討する
- stateful を選ぶなら、404 再初期化と DELETE 終了まで最初から設計する
- multi-node で in-memory session を雑に持たない
2025-03-26 から 2025-11-25 の MCP 仕様では、server は初期化応答で MCP-Session-Id を返してもよいし、返さなくてもよいです。つまり、この世代でも session は必須機能ではありません。2026-07-28 の Streamable HTTP ではさらに protocol-level session 自体が外れたため、新規実装ではまず最新 revision に合わせるべきです。既存 revision と互換を持つ場合だけ、以下の session lifecycle を実装対象として扱います。言い換えると、mcp-session-id の説明が必要な時点で、あなたは最新仕様の総論ではなく legacy compatibility を扱っている 可能性が高いです。
ここを誤解すると、「Streamable HTTP だから session は必須」と思い込んで、不要な状態管理を抱え込みます。まず先に考えるべきなのは、その server が per-client state を本当に持つ必要があるかです。
mcp-session-id / mcp session id で押さえる session lifecycle 5手順
2025-03-26 から 2025-11-25 の MCP transports 仕様では、session 管理のルールはかなり明快です。
- server は
initialize応答でMCP-Session-Idを返してよい - 返した場合、client は以後の HTTP request に同じ header を必ず付ける
- server は session を終了させた後、その session ID に対して
404 Not Foundを返す - client は
MCP-Session-Id付き request に対する404を受けたら、session ID なしでInitializeRequestをやり直す - client は不要になった session を
DELETEで明示終了してよい
重要なのは、404 が「session を捨てて再初期化しろ」という合図だと spec で決まっている点です。ここを 400 や 401 で実装すると、client 側の再接続戦略と噛み合いません。TypeScript SDK の Streamable HTTP transport も、stateful mode では invalid session ID を 404 Not Found、非初期化 request の session ID 欠落を 400 Bad Request と分けています。
この 404 / 400 の意味づけを崩すと、client は「古い session だから作り直せばよい」のか、「単なる不正 request だから直せばよい」のか判断できなくなります。session lifecycle の設計は、status code の設計でもあります。
実務runbook: 404 を受けたらこの順で確認する
MCP-Session-Id 付き request が 404 になったとき、私は次の順で切り分けます。
- 古い session ID を破棄する
- session ID なしで
initializeをやり直す - 再初期化前に残っていた SSE / subscription / task polling を止める
- durable task があるなら session 復旧ではなく別 handle で再取得する
- 同じ事象が繰り返すなら session を持つ設計自体を疑う
特に 3 と 4 を飛ばすと、session は捨てたのに MCP subscriptions/listen 設計ガイド の購読だけ残る、あるいは MCP Tasks extension 設計ガイド の durable task を session と一緒に消したつもりになる、という事故が起きます。
session はいつ不要か
stateless で問題ない server はかなり多いです。私なら、次の条件なら session を持ちません。
- 1 request ごとに完結する
- server から client への unsolicited notification が不要
- 再接続時に replay したい event backlog がない
- client ごとの log level、購読状態、進行中ジョブを保持しない
- load balancer 配下でどの node が受けても困らない
典型例は、read-only の docs 検索、metadata 参照、軽い tool 実行、JSON 応答中心の API 風 server です。こういう server に session を足すと、得られるものより失うものの方が大きいです。
- session store が必要になる
- 404 再初期化を client と揃える必要が出る
- sticky session や共有状態の議論が増える
- session hijacking や cleanup まで考える必要が出る
MCP の C# SDK docs が stateless を強く勧めているのは、このコストがあるからです。session がないと困る理由を言えないなら、それは session を入れない理由です。
stateful が必要になるのは 3 パターン
一方で、stateful を避けられない場面もあります。
1. server から client へ通知したい
たとえば job 完了通知、progress、subscription 更新、client への request 発火などです。session ごとの接続や識別子がないと、どの client へ何を返すか曖昧になります。ただし、2026-07-28 以降に新規実装するなら、「通知が必要 = legacy session」ではありません。list change や resource change は MCP subscriptions/listen 設計ガイド、長時間job は MCP Tasks extension 設計ガイド へ分離した方が、transport と durable state を混ぜずに済みます。
2. per-client state を保持したい
client ごとの購読状態、log level、途中経過、認証済みコンテキスト、stream resumability の cursor などを持つなら、session が自然です。逆に言うと、その state を request ごとの _meta、opaque handle、subscription ID、task ID へ明示的に出せるなら、legacy session を減らせます。
3. SSE の resumability を本気で使う
最新 spec では polling SSE と Last-Event-ID による再開が整理されました。ここで event をどの stream / session に属するものとして replay するかを持つなら、stateful 設計の意味が出ます。
ただし、ここでも雑に「SSE を使うから session 必須」とは言えません。server-to-client 通知を使わず、単一 request の stream response だけで足りるなら、stateless のまま設計できる場合もあります。判断基準は transport の種類ではなく、session をまたいで保持したい状態の有無です。mcp stateless で検索している人が知りたいのも、SSE の有無ではなく、ここです。
実装で一番重要なのは「404 のあとに何を捨てるか」
session 管理の事故は、ID 発行より再初期化で起きます。
client が 404 を受けたら、新しい InitializeRequest を session ID なしで送り直す。これは spec 上かなり明確です。ですが実装では、その前に何を捨てるかを決めないと壊れます。
私なら次を session 単位の揮発状態として扱います。
- SSE 接続ハンドル
- request と response の相関状態
- progress / task の一時的な購読状態
- replay 用 event cursor
- session ごとの log level や subscription state
逆に、session を超えて残したいものは別 storage に切ります。
- durable task の実体
- 認証主体そのもの
- 監査ログ
- ユーザー設定
- 永続的なジョブ実行履歴
ここを分けないと、404 再初期化時に「session を消したのに durable task まで飛ぶ」「古い SSE stream が残って二重配信になる」といった事故が起きます。session は永続化の単位ではなく、会話的な接続状態の単位として扱う方が安定します。
実務的な補足: session store に入れない方がよいもの
実装レビューでは、次が session store に入っていたら止めます。
- tenant 認可の正本
- billing / quota の確定値
- 再実行に必要な durable job state
- 監査ログの唯一の保存先
- write tool の承認結果そのもの
これらは session と一緒に消えてはいけないからです。session store は復旧の起点ではなく、接続の揮発状態だけを持つ場所に寄せた方が壊れにくいです。
DELETE はおまけではない
MCP 仕様では、client は不要になった session を DELETE で明示終了してよいとされています。server は 405 Method Not Allowed を返しても構いませんが、stateful server を作るなら、私は基本的に DELETE を受ける前提で設計します。
理由は単純です。
- ブラウザや desktop client を閉じた後の cleanup がしやすい
- session 数の無限増殖を防ぎやすい
- SSE や subscription を明示的に閉じられる
- 監査上も「切断された」のではなく「終了した」と分かる
放置された session を TTL だけで回収すると、短命 client が多い環境で無駄な state が溜まりやすいです。DELETE を受けるなら、session 終了を明示イベントとして扱えます。
ただし、DELETE を入れてもそれだけで十分ではありません。client が異常終了することは普通にあるので、次も必要です。
- session TTL
- idle timeout
- stale stream cleanup
- 404 再初期化との整合
DELETE は cleanup の唯一手段ではなく、cleanup を早める手段として置くのが現実的です。
multi-node で困るのは session そのものより配置戦略
ローカル実装では動くのに本番で壊れるのは、だいたいここです。
TypeScript SDK docs でも multi-node pattern は 3 つに整理されています。
- stateless mode
- shared storage を使う persistent state mode
- local state + message routing
私なら、判断はこう置きます。
stateless を保てるなら最優先
任意 node が任意 request を処理できるので、一番運用が軽いです。autoscaling と相性がよく、sticky session も不要です。
stateful だが durable にしたいなら shared storage
session metadata、event cursor、subscription state を DB や共有 store に寄せます。session を in-memory だけで持つより安全ですが、read/write latency と整合性の設計が増えます。
local state を使うなら routing まで含めて設計
各 node が local memory を持つなら、同じ session に属する traffic を同じ node へ送る仕組みが要ります。load balancer の sticky session で雑に済ませると、node 再起動や scale out/in で壊れやすいです。
ここで大事なのは、session を使うかどうかの判断は、そのまま deployment 設計の判断でもあるという点です。single-process のサンプルコードをそのまま本番に持ち込まない方がいいです。
session 管理でも security 境界は残る
最新 spec では Origin 検証、localhost bind、認証が引き続き重要です。加えて session を持つなら、session ID 自体の扱いも security 対象になります。
私なら最低限、次を守ります。
- session ID は推測困難な値にする
- session ID を log や URL query に雑に出さない
Origin不一致は 403 で落とす- token と session ID を同一視しない
- 未信頼コンテンツを読む session と write 系 session を分ける
特に 5 は見落とされやすいです。MCP prompt injection 対策でも書いた通り、危険なのは server 単体ではなく 同じ session に何が同席しているか です。未信頼な remote resource を読む session に write tool や shell 実行が見えているなら、session 設計の時点で危ないです。
2026年8月時点で私が採る実装順
今から remote MCP server を作るなら、この順が一番壊れにくいです。
- まず stateless で実装する
POSTJSON 応答だけで成立するか確認する- 本当に必要なら SSE を追加する
- それでも足りないなら session を導入する
- session 導入と同時に 404 再初期化、DELETE、TTL、multi-node 方針を入れる
TypeScript SDK なら、legacy session を持つ実装では sessionIdGenerator を与える、stateless は undefined にする、という切り替えがかなり明確です。つまり技術的には簡単に有効化できます。だからこそ、簡単にオンにできるものほど、先に設計理由を言えるようにしておくべきです。Claude Code から remote MCP を足す側なら Claude Code MCP ガイド、approval reviewer や app tool 承認まで整理したいなら Codex auto review ガイド と分けて読むと、session と reviewer lane を混同しにくくなります。
最後に使う判断表
迷ったら、私は次の 5 問だけで決めます。
| 質問 | Yes なら |
|---|---|
| server から client へ自発通知したいか | stateful を検討 |
| per-client の購読状態や log level を保持したいか | stateful を検討 |
| 任意 node が任意 request を処理してほしいか | stateless を優先 |
| 404 で再初期化しても困らない揮発状態だけか | stateless で十分な可能性が高い |
| DELETE / TTL / shared storage まで面倒を見られるか | できないなら stateful を広げない |
MCP の session 管理は、transport の細部ではありません。状態をどこまで持つか、どこで捨てるか、どの単位で再開させるか という設計そのものです。
最初から全部入りにすると、接続はできても運用できません。逆に、stateless をデフォルトにし、必要な理由が出た時だけ stateful へ進めば、MCP-Session-Id は厄介な足かせではなく、扱いやすい lifecycle 境界になります。