GitHub MCP Server がステートレス化 — 自作 MCP サーバを 2026-07-28 仕様へ移す棚卸しと検証手順

AI・テック動向

GitHub MCP Server がステートレス化 — 自作 MCP サーバを 2026-07-28 仕様へ移す棚卸しと検証手順

2026年7月23日、GitHub の公式 MCP サーバが、7月28日に確定する新仕様へ先回りで対応した。変更の中身は「セッションを持つのをやめた」というもので、実装では Redis によるセッション保持がまるごと消えている。自作の MCP サーバを持っている人にとっては、他人の移行結果を先に見られる珍しい機会になった。

目次
  1. 7月28日の仕様改訂で消えるもの
  2. 「利用側は無改修」を鵜呑みにしない
  3. 自作サーバの棚卸しから始める
    1. 書き換えの形
  4. 旧クライアントと新クライアントの両方から叩いて確かめる
    1. 移行で見落としやすい箇所
    2. 移行の順番を間違えると戻せなくなる
  5. Roots / Sampling / Logging の扱い
  6. 筆者ならこう進める
    1. よくある疑問
  7. まとめ

7月28日の仕様改訂で消えるもの

MCP の 2026-07-28 改訂は、プロトコル層からセッションの概念を取り除く。接続を確立するための initialize ハンドシェイクも無くなり、クライアントのメタデータ・機能・プロトコルバージョンは、毎回のリクエストの _meta フィールドに載って運ばれる。

項目 これまで 2026-07-28 以降
接続開始 initialize で握手 握手なし。最初のリクエストがそのまま本番
セッションID Mcp-Session-Id ヘッダで維持 プロトコル層から削除
クライアント情報 初期化時に1度だけ送る 毎リクエストの _meta に同梱
サーバの形おすすめ 状態を持つインスタンス+共有ストア ステートレスなインスタンスをLBの後ろに並べるだけ
ロードバランサ スティッキーセッションが必要 設定を外せる

GitHub 側の実装変更は、この仕様変更をそのまま反映している。initialize 時のデータベース書き込みが無くなり、呼び出しごとの読み取りも消えた。リクエストの中身を深く覗いて判断していた処理をやめ、HTTP ヘッダから必要な値を読む形に変えている。tier 1 の SDK はいずれも後方互換を保っているため、利用側の改修は不要というのが GitHub の説明だ。

「利用側は無改修」を鵜呑みにしない

筆者は外部APIの仕様変更を、まず疑ってかかることにしている。過去に、廃止予定の機能を全経路に組み込んだまま運用して、ある日いっせいに動かなくなった経験があるからだ。あのときは代替経路を用意していなかったので、復旧まで手が止まった。

今回の「無改修で動く」は、後方互換を維持している SDK を使っている場合の話になる。自前で HTTP を組み立てているクライアントや、ゲートウェイでヘッダを付け替えている構成は、その外側にいる。Mcp-Session-Id をルーティングのキーに使っていたら、そこは自分で外す必要がある。

自作サーバの棚卸しから始める

移行作業の実体は、コードの書き換えより先に「セッションに何を置いていたか」の洗い出しだ。置いていたものは、だいたい次の3種類に分かれる。

セッションに載せていたもの 移行先 注意点
認証情報(トークン・ユーザーID) 毎リクエストのヘッダ 失効の確認をリクエストごとに行う設計へ
ページングのカーソル位置 リクエスト引数(カーソルを返して受け取る) サーバ側で覚えない。カーソルは不透明な文字列にする
ユーザーごとの設定・作業中の状態 アプリ層の永続ストア プロトコルの都合と業務データを混ぜない

3つ目が曲者で、「接続中だけ覚えておけばいい」と思って置いた値ほど、後から業務ロジックが依存している。筆者が自分のサーバを見直したときも、一時的なつもりの値が2箇所ほど残っていた。

書き換えの形

セッションから読んでいた箇所を、リクエストから読む形に置き換える。Python で書いた例を挙げる。

# 変更前: 初期化時に作ったセッションから読む
def handle_search(session_id, params):
    sess = redis.hgetall(f"mcp:sess:{session_id}")   # 毎回のDB読み取り
    token = sess["token"]
    return search(token, params["q"], cursor=sess.get("cursor"))

# 変更後: リクエストが自己完結している
def handle_search(request, params):
    token = request.headers["Authorization"].removeprefix("Bearer ")
    cursor = params.get("cursor")          # クライアントが持ち回る
    result = search(token, params["q"], cursor=cursor)
    return {"items": result.items, "next_cursor": result.next_cursor}

カーソルをクライアントに返して持ち回らせる形にすると、サーバ側は次の呼び出しがどのインスタンスに届いても同じ答えを返せる。スケールの話に見えて、実際にはローカル開発でも効く。プロセスを再起動しても会話が途切れない。

旧クライアントと新クライアントの両方から叩いて確かめる

移行が終わったかどうかは、コードを読んでも分からない。両方の形式で実際にリクエストを投げて、同じ答えが返るかを見る。

# 旧仕様: セッションIDを付けて呼ぶ(無視されて正常応答が返るのが正解)
curl -s -X POST http://127.0.0.1:8080/mcp \
  -H "Content-Type: application/json" \
  -H "Mcp-Session-Id: legacy-12345" \
  -H "Authorization: Bearer $TOKEN" \
  -d '{"jsonrpc":"2.0","id":1,"method":"tools/list"}' | jq '.result.tools | length'

# 新仕様: 握手なし・_meta 同梱でいきなり本番リクエスト
curl -s -X POST http://127.0.0.1:8080/mcp \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer $TOKEN" \
  -d '{"jsonrpc":"2.0","id":1,"method":"tools/list",
       "params":{"_meta":{"protocolVersion":"2026-07-28",
                          "clientInfo":{"name":"curl-check","version":"1"}}}}' | jq '.result.tools | length'

確認する点は3つある。両方が同じツール数を返すか、旧仕様のリクエストがエラーにならないか、サーバを再起動した直後でも2回目以降の呼び出しが通るか。3つ目は、状態がどこかに残っていないかを見るための確認になる。

移行で見落としやすい箇所

ロードバランサのスティッキー設定は、外し忘れても動いてしまう。動くので気づかない。設定が残っている限り、インスタンスを増やしても偏る。

ゲートウェイのルーティング規則も同じで、Mcp-Session-Id を見る条件が残っていると、ヘッダが来なくなった時点で全部が既定のルートへ流れる。これは負荷が上がるまで表面化しない。

移行の順番を間違えると戻せなくなる

筆者が気をつけているのは、サーバとクライアントを同時に触らないことだ。両方を一度に変えると、動かなくなったときにどちらが原因か分からない。サーバ側を先にステートレス化して、旧クライアントから叩いて通ることを確認してから、クライアント側の改修に入る。

この順番なら、途中で問題が出ても切り戻す先が1つに絞れる。逆順で進めて両方が中途半端になると、旧仕様でも新仕様でも動かない状態ができあがる。

作業を分ける単位も小さくしておきたい。ツールが10個あるサーバなら、副作用のない読み取り系を1つ選んで先に通す。そこで _meta の受け取りとヘッダからの認証情報の取り出しが正しく書けているかが分かるので、残り9個は同じ形を写すだけになる。

移行が終わった後も、しばらくは旧形式のリクエストが届く。ゲートウェイのログで Mcp-Session-Id ヘッダの有無を数えておくと、旧クライアントがどれだけ残っているかが見える。数がゼロに落ちてから、互換のための分岐を消せばいい。先に消すと、まだ移行していない誰かの接続を切ることになる。

Roots / Sampling / Logging の扱い

今回の改訂では、Roots・Sampling・Logging も非推奨になり、12か月の猶予が置かれた。猶予があるうちに代替を決めておくと、期限直前に慌てずに済む。

筆者の方針は単純で、プロトコルに寄せていた機能をアプリ側へ引き取る。作業ディレクトリの範囲(Roots)はツールの引数として明示的に受け取り、ログはサーバ自身の仕組みで出す。プロトコルが面倒を見てくれる領域は縮む方向にあるので、依存を減らしておくほうが後の移行が軽い。

筆者ならこう進める

いきなり本番のサーバを書き換えることはしない。手順としては、まず読み取り専用のツールを1つだけステートレス化して、旧クライアントから叩いて壊れないことを確かめる。そのうえで残りを移す。

この順番にしている理由は、失敗したときに戻せる範囲を小さくしておきたいからだ。Claude Mission Control のように複数のエージェントから同じ MCP サーバを叩く構成だと、1つの変更が全体に波及する。切り戻しの単位を小さくしておくと、原因の特定も早い。

GitHub の実装が先に出たのは、この意味でありがたい。仕様書を読んで想像するより、本番規模で動いている実例が「何を捨てたか」を見るほうが早い。捨てたものが Redis とパケット検査だと分かれば、自分のサーバで同じ役割を担っている箇所を探せばいい。

よくある疑問

7月28日を過ぎたら旧仕様のクライアントは動かなくなるのか。tier 1 の SDK は後方互換を維持しているというのが GitHub の説明で、SDK 経由なら当面は動く見込みになる。自前で HTTP を組んでいる場合は、その保証の外にいる。

セッションが無くなると認証のたびに検証コストが増えないか。増える。増えるぶん、共有ストアへの読み書きが消える。どちらが重いかは認証方式で変わるので、トークン検証をキャッシュする層を自分で持つかどうかを実測で決めればいい。

ローカルで stdio 接続しているだけなら関係ないか。プロトコル層の変更なので、握手が消える点は同じく効く。影響は小さいが、SDK を上げたときに挙動が変わる可能性はある。手元の MCP サーバを1つ叩いて確かめておくと安心できる。

いつ移行するのが安全か。仕様が確定する7月28日を待つ判断もありうる。GitHub の実装は正式リリース前の対応なので、細部が動く可能性は残っている。急ぎでなければ、確定後に条文と実装を見比べてから着手するほうが手戻りが少ない。

まとめ

ステートレス化の作業は、コードの書き換えより棚卸しが本体になる。セッションに置いていた値を認証情報・カーソル・業務データの3つに仕分けて、それぞれヘッダ・リクエスト引数・アプリ層の永続ストアへ割り振る。仕分けが終われば、書き換え自体は各ハンドラ数行で済む。

今日やるなら、自作サーバのコードで session という語を全文検索するところから始めるのがいい。ヒットした箇所が、そのまま移行対象の一覧になる。

一次ソース: GitHub MCP Server supports the next MCP specification(GitHub Changelog)

Claude Opus 5 は価格据え置きで載せ替わった — 請求額を決める「1タスクの総トークン」を測り直す手順Claude Opus 5 は価格据え置きで載せ替わった — 請求額を決める「1タスクの総トークン」を測り直す手順前のページ

Dependabot が既定3日のクールダウンを導入 — 「切る前に読む」設定と自動マージの組み合わせ方次のページDependabot が既定3日のクールダウンを導入 — 「切る前に読む」設定と自動マージの組み合わせ方

ピックアップ記事

  1. 高精度OCRデスクトップアプリの作り方 — PaddleOCR-VLとPyIns…

  2. New Eden Intelligence Hub の作り方 — EVE Onl…

  3. 競艇予想AIの作り方 — LightGBMで「当たる順位」を学習させる実装ガイド…

  4. Claude Mission Control の作り方 — Tauri+Pyth…

関連記事

  1. Python 3.15 RC 目前と Pyrefly 1.0 — 毎キーストロークで走る型チェッカを mypy と比べる
  2. Claude Code v2.1.214 で allow ルールの dir/** が「効かなくなる」— 棚卸しスクリプトと書き換えの判断基準
  3. Claude Sonnet 5 が Claude Code の既定モデルに — 1Mコンテキストと月コスト激減を実額で検証
  4. Claude Fable 5 のプラン変更を一次ソースで確認した — 50%枠は他モデルと共通

    AI・テック動向

    Claude Fable 5 のプラン変更を一次ソースで確認した — 50%枠は他モデルと共通

    7月20日から Fable 5 の提供形態が変わった。報道の多くが X…

  5. Claude 音声モードが Opus / Sonnet 対応 — 音声が「入力手段」から「実行手段」に変わった

    AI・テック動向

    Claude 音声モードが Opus / Sonnet 対応 — 音声が「入力手段」から「実行手段」…

    Haiku 固定をやめ、コネクタを音声から呼べるようになった。日本語を…

  6. GPT-5.6 Sol/Terra/Luna が Copilot に — 従量課金で3層を使い分ける

注目

AIで、ここまで作れる

AIで作った2D RPGを、ブラウザでそのまま遊べます。その「作り方=最後まで完成させる進め方」も実例つきで公開中。

▶ ゲームを遊ぶやり方を読む

PR

お名前.com 独自ドメイン取得(PR)

独自ドメイン:お名前.com(本サイトで使用・PR)

  1. MCP 2026-07-28 仕様RC — 史上最大の改訂。ステートレス化・MCP Apps・Tasks で自作サーバは何が変わるか

    AI・テック動向

    MCP 2026-07-28 仕様RC — 史上最大の改訂。ステートレス化・MC…
  2. VS Code 1.128 のマルチチャット — 1セッションで2方針を並走する

    AI・テック動向

    VS Code 1.128 のマルチチャット — 1セッションで2方針を並走する…
  3. アーティファクトがライブになった代わりに、配れなくなった — MCP コネクタ対応の実際

    AI・テック動向

    アーティファクトがライブになった代わりに、配れなくなった — MCP コネクタ対…
  4. 都市開発シミュを作る③|需要・成長・経済の決定論シミュレーション(MVP完成)【Aurum City制作】

    アプリの作り方

    都市開発シミュを作る③|需要・成長・経済の決定論シミュレーション(MVP完成)【…
  5. 「Opus級」の実像 — Grok 4.5 はベンチ4位、それでも $2/$6 が効く用途

    AI・テック動向

    「Opus級」の実像 — Grok 4.5 はベンチ4位、それでも $2/$6 …
PAGE TOP

TAG CLOUD

ドラッグで回転・クリックでそのタグの記事一覧へ