Open2

【Web開発/Web Server】URL末尾のスラッシュの有無について📝

ピン留めされたアイテム
まさぴょん🐱まさぴょん🐱

Cloud Run で Remote MCP を構築する際の注意点について📝

https://zenn.dev/link/comments/e9402adc0bf67d

最初に要点をまとめると ― /mcp でアクセスすると FastAPI(Starlette)が 307 Temporary Redirect を返し、クライアントを /mcp/ にリダイレクトします。
ところが MCP クライアントはサーバー・センチイベント(SSE)やストリーミングの際に 307 を正しく追従できず接続が張れないため「動かない」ように見えます。
/mcp/ を最初から指定するとリダイレクトが発生せず、そのままストリームが張れるので「動く」──違いは Cloud Run 側ではなく アプリケーション・フレームワークの経路マッチングと HTTP 仕様 に起因します。

1. 何が起きているのか

1-1 ルーティングの厳密一致

FastAPI/Starlette は 末尾のスラッシュまで含めてルートを完全一致で照合します。@app.post("/mcp/") と定義すると /mcp/ だけがヒットし、/mcp は見つからないためフレームワークが自動で 307 Redirect を返します。

1-2 307 Temporary Redirect の意味

307 は「リクエストメソッドとボディを変えずに一時的に移動」というステータスで、Location ヘッダーに示された URL(ここでは /mcp/)へ再送を要求します。

/mcp307/mcp/

1-3 ストリーミングと 307 の相性

多くのブラウザは 307 を自動追従しますが、

  • Python の requests や一部 SSE クライアント
  • HTTP/2 でストリームを張りっぱなしにするライブラリ
    は再接続に失敗しがちで、結果としてハングや ECONNRESET が発生します。MCP クライアントも同様で、リダイレクト前提のハンドリングが未実装のため「動かない」ように見えます。

2. Cloud Run 側で起きていること

  • Cloud Run/GFE は 受け取ったパスをそのままコンテナに透過し、リダイレクトを発生させているのはアプリ側です。
  • Google 公式の「Host MCP servers on Cloud Run」ガイドでも、エンドポイント例は必ず /mcp/ とスラッシュ付きで示されています。

3. 解決策とベストプラクティス

方法 メリット 注意点
常にスラッシュ付きで呼び出す (https://…/mcp/) もっとも簡単。MCP クライアント側を直す必要がない ドキュメントや環境変数で明示的に共有する
ルートを両方用意する
@app.post("/mcp/")@app.post("/mcp")
どちらでも動く API が増えるほど面倒/保守コスト
リダイレクト自動生成を無効化
app = FastAPI(redirect_slashes=False)
307 を出さず 404 を返すので挙動が明示的 既存クライアントが /mcp/ 前提だと壊れる
Starlette のミドルウェアで 308 定常リダイレクトに書き換える SEO 的に恒久 URL を決めたい場合 ストリーミングには結局不向き

4. 参考資料

  1. Stack Overflow – FastAPI で /hello が 307 になる理由
  2. Medium – “Ending Slashes in FastAPI Endpoints”
  3. GitHub Issue – redirect_slashes=False で 307 を抑制
  4. MDN – HTTP 307 の仕様
  5. Airbrake Blog – 307 Temporary Redirect 解説
  6. UpDo-Check – 307 エラーの原因と対処
  7. Reddit – Cloud Run + FastAPI で 307 が接続リセットを招く例
  8. Starlette Issue – Trailing slash が 307 を生む実装背景
  9. Google Cloud – Cloud Run Troubleshooting(リクエストはそのまま転送)
  10. Google Cloud – Host MCP servers on Cloud Run(公式例は /mcp/

5. まとめ

  • 原因は Cloud Run ではなく FastAPI/Starlette のリダイレクト機能。
  • ストリーミング API(MCP を含む)は 307 に弱いため、エンドポイントをスラッシュ付きで固定するか、redirect_slashes=False で無効化するのが確実。
  • 設定ファイルやドキュメントでも「必ず /mcp/」を明記し、CI テストでも /mcp に誤ってアクセスしていないか確認すると安心です。