🌐

MCP サーバーを remote で公開したいが、古い SSE ベースの記事やサンプルを見ているうちに、何を新実装すべきか分からなくなる。/sse/messages を分けるべきなのか、session は必要なのか、404 になった session をどう扱うのか、OAuth はどこまで必須なのか。このあたりで止まりやすい人向けの記事です。

結論から言うと、今から remote MCP を出すなら、前提を Streamable HTTP に切り替えた方がよいです。 2025-03-26 版の MCP 仕様では、旧 HTTP+SSE transport から Streamable HTTP transport へ置き換えられました。単なる名前変更ではありません。endpoint 設計、client との接続の張り方、session の扱い、認証の考え方、DNS rebinding 対策まで変わっています。

この記事では、MCP の changelogtransport specificationClaude Code の MCP docs を踏まえて、SSE 時代の設計からどこを直すべきか を実務目線で整理します。Claude Code から MCP をつなぐ実務手順を先に見たい場合は Claude Code MCP ガイド、remote MCP の承認境界や tool poisoning まで含めて詰めたい場合は MCP prompt injection 対策ガイド を併読すると、transport と安全運用の責務を分けて考えやすいです。MCP の組織配布や監査まで含めた話は MCP エンタープライズ運用ガイド、Claude Code 側の allowlist や managed-mcp.json まで見たい場合は Claude Code managed settings 設計ガイド を先に読むとつながります。

先に結論: 旧HTTP+SSEの知識のまま実装するとズレる

私なら、移行判断を次の 4 点で整理します。

  1. endpoint を単一化する
    Streamable HTTP では、MCP endpoint は基本的に 1 本です。POSTGET の両方を受けます。
  2. response は JSON か SSE の両対応にする
    POST に対して、即時なら JSON、ストリームが必要なら SSE を返す実装が必要です。
  3. session を設計で決める
    stateful にするなら MCP-Session-Id を返し、以後のリクエストで引き回します。単純な read-only server なら stateless も現実的です。
  4. remote 公開ならセキュリティを transport 層で持つ
    仕様上も Origin header 検証、localhost bind、認証が強く推奨されています。

ここを押さえずに「SSE endpoint を 1 本立てればよい」と考えると、client 互換も運用も中途半端になります。

何が変わったのか: HTTP+SSE から Streamable HTTP へ

MCP の 2025-03-26 版 changelog では、主要変更の 1 つとして HTTP+SSE transport が Streamable HTTP transport に置き換えられた と明記されています。つまり、remote MCP の標準実装はもう「SSE endpoint と別 POST endpoint を並べる前提」ではありません。

新しい transport で重要なのは、HTTP を request/response だけでなく、必要に応じて SSE も返せる単一 transport として扱う 点です。

整理すると、発想はこう変わります。

  • 旧HTTP+SSE:
    • GET /sse のような購読 endpoint
    • POST /messages のような別 endpoint
    • client 側が「どの URL にどう送るか」を transport 前提で強く知っている
  • Streamable HTTP:
    • https://example.com/mcp のような 単一 endpoint
    • POST で JSON-RPC message を送る
    • server は JSON で即答してもよいし、text/event-stream で流してもよい
    • GET は server-to-client notification や stream 再接続に使える

この変更で嬉しいのは、reverse proxy や SaaS の API gateway に乗せやすくなることです。一方で、server 実装者は「SSE を返す場合」「JSON で終わる場合」「接続を閉じて再接続させる場合」を以前より明示的に設計しないといけません。

実装で最初に直すべきは endpoint 設計

旧HTTP+SSE 実装から移るとき、最初に見るべきは handler の切り方です。

仕様上、Streamable HTTP server は 単一の MCP endpoint が POSTGET を両方サポート します。たとえば https://api.example.com/mcp のような形です。

POST の役割:

  • client から JSON-RPC request / notification / response を送る
  • JSON-RPC request に対しては
    • application/json で単発 response を返すか
    • text/event-stream で複数 message を返す

GET の役割:

  • server から client へ通知や request を流す SSE stream を開く
  • 切断後の resume に使う

ここで大事なのは、POST = 書き込み APIGET = 読み取り API という REST 的な発想で分けないこと です。これはあくまで transport です。中身は JSON-RPC message であり、HTTP method は通信路の都合で決まっています。

もし既存実装が /sse/messages を前提にしているなら、今後の標準 client に合わせるには mcp endpoint へ寄せる方が安全です。後方互換が必要なら、旧 endpoint をしばらく残しつつ、新 endpoint でも initialize を受けられるようにするのが現実的です。

JSON と SSE をどう使い分けるか

Streamable HTTP で実装が雑になりやすいのがここです。

仕様では、client が POST する際に Accept header で application/jsontext/event-stream の両方を受けられる前提を示します。server は request の性質に応じて返し方を選べます。

私なら基準をこう置きます。

  • JSON で返すケース
    • 処理が短い
    • response が 1 回で終わる
    • progress 通知や server-side request が不要
  • SSE で返すケース
    • 長時間ツール実行がある
    • progress を出したい
    • 途中で追加の JSON-RPC notification / request を返したい

read-only な軽い resource server なら、最初は JSON 中心でも構いません。逆に、長い検索、外部 API 呼び出し、server からの追加イベントが必要な server を JSON 固定で作ると、あとで transport を作り直すことになります。

MCP Inspector や各 SDK の最近の examples でも、Streamable HTTP は「direct response も SSE streaming も両方扱える transport」として実装されています。つまり、SSE 専用 server を作るのではなく、HTTP transport の中に streaming を持つ 発想に変えるべきです。

session は必須ではないが、stateful か stateless かを曖昧にしない

Streamable HTTP では MCP-Session-Id header が導入されています。server が initialize response で session ID を返した場合、client はその後の request で同じ ID を送る必要があります。

ここで迷いやすいのは、「session を実装しないといけないのか」です。答えは 必須ではないが、どちらで行くかを先に決めるべき です。

加えて、session を持つなら lifecycle も transport とセットで決める 必要があります。古い session ID に対して server が 404 を返したときに client をどう再初期化させるか、終了時に DELETE をどこで受けるかを曖昧にすると、「接続できるが復旧しない」 server になりやすいです。

stateless が向くケース

  • read-only ツール中心
  • tool 実行ごとに独立して完結する
  • 再接続や進行中状態の保持がいらない
  • API gateway 配下で水平分散しやすくしたい

stateful が向くケース

  • 長い SSE stream を扱う
  • message resume をやりたい
  • server からの notification を継続的に送りたい
  • 実行中ジョブや接続状態を memory / store に持ちたい

私の感覚では、社内 read-only MCP や docs / search 系は stateless 寄り、agent control plane や長時間ジョブは stateful 寄り です。ここを曖昧にすると、ロードバランサや再接続時に破綻します。

remote MCP で事故りやすいのは transport より認証

もう 1 つの大きな変化が認証です。2025-03-26 版の MCP 仕様では authorization framework が入り、OAuth 2.1 ベースの考え方が前提に置かれました。Claude Code の remote MCP docs でも、HTTP transport の server に対して /mcp から OAuth 認証を進める流れが整理されています。

ここで重要なのは、remote MCP を「社内 API にBearer tokenを1本刺せば終わり」と考えないこと です。

最低限見るべき論点は次です。

  • human user が対話しながら使うのか
  • background job が使うのか
  • authorization server discovery をどう出すのか
  • dynamic client registration 前提でよいのか
  • 固定 callback port が必要か

たとえば Claude Code では、OAuth callback port を固定しないと事前登録型の redirect URI に合わない場合があります。逆に、server 側が Dynamic Client Registration を持たないなら、client 側に client_id を明示させる運用が必要です。

このあたりは transport の違いというより、remote 化した瞬間に発生する運用の仕事 です。組織配布や allowlist 運用まで含めて見るなら MCP エンタープライズ運用ガイドAIコーディングツールの社内ガイドライン を分けて読んだ方が整理しやすいです。

Security で最初に見るべきは Origin 検証

仕様を読まずに実装すると落としやすいのがここです。

Streamable HTTP transport の security warning では、server 実装者に対して次が求められています。

  • Origin header を検証する
  • ローカル運用なら 0.0.0.0 ではなく localhost bind を優先する
  • 適切な認証を入れる

特に Origin 検証は、remote server だけでなく ローカルでブラウザや inspector を併用する時にも見落としやすい です。DNS rebinding を意識しないままローカル MCP を広く bind すると、便利な開発サーバーではなく危ない穴になります。

私は remote 化の前に、次のチェックを固定します。

  1. Origin 不一致を 403 にできるか
  2. localhost 以外 bind の必要性を説明できるか
  3. access token を query string に載せていないか
  4. read-only で始められるか
  5. 失敗ログと拒否ログを残せるか

MCP の security は prompt injection だけではありません。transport 境界そのものの防御 を先に作るべきです。

後方互換は「古いclientをいつまで残すか」で決める

既存利用者がいる server では、いきなり旧HTTP+SSE endpoint を消せないことがあります。MCP 仕様にも、backwards compatibility の考え方は明記されています。

私なら移行を 3 段階でやります。

1. 新 endpoint を先に追加する

  • https://example.com/mcp を追加
  • 新 client はここへ寄せる
  • initialize が Streamable HTTP で通ることを確認する

2. 旧 endpoint は read-only 互換期間にする

  • /sse と旧 POST endpoint は残す
  • 新機能は追加しない
  • deprecation date を内部に明示する

3. session / auth / logging を新 endpoint に集約する

  • 監査対象を新 endpoint に寄せる
  • token / callback / session 問題は新 transport でだけ直す
  • 旧 endpoint は撤去計画を切る

ここで「両方ずっと残す」は避けた方がよいです。server 実装も運用手順も二重化して、結局どちらも中途半端になります。

私ならこう設計する: 最小の移行チェックリスト

最後に、実務で使うならこの順番が扱いやすいです。

  1. 単一 MCP endpoint を作る
  2. POST で JSON と SSE の両返却を受けられるようにする
  3. GET で stream 再接続を扱えるようにする
  4. stateful / stateless を決める
  5. Origin 検証と認証を先に入れる
  6. OAuth discovery と callback 方針を固める
  7. 旧HTTP+SSE endpoint の撤去期限を決める

MCP Streamable HTTP は、単なる transport の新名称ではありません。remote MCP を API としてちゃんと運用できる形へ寄せるための整理 です。

SSE 時代の理解のまま進めると、「つながるけど運用できない」 server を作りやすいです。逆に、単一 endpoint、session 方針、OAuth、Origin 検証まで最初に決めれば、Claude Code や今後の MCP client から扱いやすい remote server になります。

まずは transport を置き換えるのではなく、server の責務を整理する ところから始めるのが正解です.

WRITTEN BY nidoneko

Full-stack engineer with 8+ years of experience in TypeScript, React, Node.js, and cloud-native development across healthcare, finance, HR, and IoT domains.

View Profile →