2026 年 7 月 28 日、Model Context Protocol は仕様の新しいリビジョンを公開しました。変更履歴 の冒頭にある 2 つの項目は、すべてのリモートサーバーの動き方を変えます。プロトコルレベルのセッションがなくなり、initialize ハンドシェイクもなくなりました。これからは、サーバーが応答に必要とするものをすべて、各リクエストが自分で運びます。
多くのサーバーにとって、これは移行作業です。身分証明書を読み取るサーバーにとっては、むしろ確認に近いものです。この種のサーバーには、もともとステートレスであるべき十分な理由があったからです。この記事では、ツールサーバーの視点からリビジョンを見ていきます。どの変更は無視してよいか、どの変更は実装しなければならないか、どの変更は早めに取り入れる価値があるか。例は私たちが運用しているサーバーから取っているので、以下で挙げる未対応の点は私たち自身のものでもあります。
これは、MCP サーバーを前面に備えた パスポート・身分証 OCR API の doc.cheap のブログです。製品に関する部分は、その点を踏まえてお読みください。
要点
| 2026-07-28 での変更 | ステートレスなツールサーバーがすること |
|---|---|
Mcp-Session-Id もセッションもなし |
セッションを一度も持っていなければ、何もしない |
initialize ハンドシェイクなし。バージョンとケイパビリティは各リクエストの _meta に |
リクエストごとに読み取り、MCP-Protocol-Version ヘッダーと照合する |
server/discover |
実装する。MUST です |
Mcp-Method と Mcp-Name ヘッダーが必須 |
ボディと一致しているか確認する |
すべての結果に resultType |
"complete" を送る |
list と read の結果に ttlMs と cacheScope |
キャッシュの有効期間とスコープを決める |
| ツールは決定的な順序で | 登録順を安定させる |
| HTTP GET ストリームと再開機能を削除 | GET と DELETE には 405 で応答する |
| Roots、Sampling、Logging が非推奨 | ファイルはツールの引数で受け取り、ログは stderr か OpenTelemetry に出す |
以下では各行を説明し、文書を扱うサーバーにとってそれがなぜより重要なのかを見ていきます。
セッションはなくなった。それは文書サーバーに合っている
変更履歴の最初の項目は、「Streamable HTTP トランスポートからプロトコルレベルのセッションと Mcp-Session-Id ヘッダー」を取り除きます。tools/list のような一覧系のエンドポイントは「接続ごとに変わることはもうなく」、呼び出しをまたいで状態を必要とするサーバーは「サーバーが発行する明示的なハンドルを、通常のツール引数として受け渡す」ことになります。
文書サーバーがそもそもセッションを必要とすることはまれです。セッションが何を保持するか考えてみてください。API キー、読み取りを待っている画像、直前の結果かもしれません。どれも、呼び出しの間にプロセスのメモリに置いておきたくないデータです。そこではバグ一つで次の呼び出し元に渡ってしまいます。
https://mcp.doc.cheap/mcp でホストしている私たちのサーバーは、このリビジョンの前からそのように作られていました。コードには「意図的にステートレス」と書かれています。POST ごとに新しいサーバーと新しいトランスポートを作り、応答したら捨てるので、「メモリ上に生きているセッションはなく、再起動しても何も失われず、ある呼び出し元のキーが別の呼び出し元のリクエストから見えることは決してない」のです。トランスポートはセッション ID ジェネレーターなしで作られます。TypeScript SDK ではそれがステートレスにする方法で、応答はストリームではなく素の JSON です。
リビジョンが説明するハンドルのパターンも、すでにあります。エージェントが保存済みの結果を取り戻したいとき、それを覚えておくためにセッションに頼ることはありません。scan_document はスキャン ID を返し、get_scan と delete_scan のツールはその ID を通常の scan_id 引数として受け取ります。ID がハンドルです。どのサーバーインスタンスでも応答でき、明日再接続したクライアントでも使えます。
あなたのサーバーがセッションごとに何かを保持しているなら、問うべきことは同じです。それを、サーバーが返してクライアントが送り返す ID にできないか。文書を扱う仕事では、答えはたいてい「できる」であり、たいていプライバシー面でも得になります。
ハンドシェイクなし:バージョンは各リクエストとともに届く
2 番目の項目は、MCP をプロトコルレベルでステートレスにします。initialize と notifications/initialized のやり取りは削除され、「すべてのリクエストが、プロトコルバージョンとクライアントのケイパビリティを _meta に入れて運ぶ」ようになりました。HTTP ではバージョンはヘッダーにも入ります。Streamable HTTP のページ は、すべての POST に MCP-Protocol-Version ヘッダーを含めなければならない(MUST)とし、その値が _meta の値と一致しなければならないとしています。一致しない場合、サーバーは HeaderMismatch エラーとともに 400 を返します。
新しい形での文書ツールの呼び出しは次のようになります。ヘッダーと _meta のキーは仕様自身の例に従っています。ツールと引数は私たちのもので、値はプレースホルダーです。
POST /mcp HTTP/1.1
Content-Type: application/json
MCP-Protocol-Version: 2026-07-28
Mcp-Method: tools/call
Mcp-Name: scan_document
{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "scan_document",
"arguments": { "image_base64": "<base64 image>", "retain_hours": 0 },
"_meta": {
"io.modelcontextprotocol/protocolVersion": "2026-07-28",
"io.modelcontextprotocol/clientInfo": { "name": "<client>", "version": "<version>" },
"io.modelcontextprotocol/clientCapabilities": {}
}
}
}
サーバーにとっては、1 回のハンドシェイクの代わりに、リクエストごとに 3 つの確認をすることになります。
- バージョン。 要求されたバージョンをサポートしていなければ、サポートするバージョンを列挙した
UnsupportedProtocolVersionErrorとともに 400 を返します。 - ヘッダーとボディの照合。
Mcp-Methodはすべてのリクエストで必須、Mcp-Nameはtools/call、resources/read、prompts/getで必須です。これらはメソッドとツール名を写したもので、一致しなければHeaderMismatchエラーです。 - ケイパビリティ。 これまで
initializeから覚えていたものを、今は手元のリクエストから読み取ります。
文書サーバーにとって、ヘッダーは見た目以上に重要です。scan_document の呼び出しは画像を丸ごと base64 で運びます。私たちのホストサーバーは最大 36 MiB のリクエストボディを受け付けます。Mcp-Method と Mcp-Name がヘッダーにあれば、ゲートウェイはボディを読まずに、重いツールを軽いツールと分けてルーティングし、数え、レート制限できます。仕様はこうしたゲートウェイに一つ注意を加えています。誰も確認していないヘッダーを信じるのではなく、バージョンヘッダーがヘッダーとボディの検証を必要とするバージョンを示していることを確認し(SHOULD)、そうでなければリクエストを拒否する、というものです。
server/discover は必須
3 番目の項目は server/discover を追加します。「サーバーは、サポートするプロトコルバージョン、ケイパビリティ、アイデンティティを公開するために、この RPC を MUST 実装する」とされています。クライアントは最初にこれを呼んでバージョンを選ぶこともできますし、stdio での互換性の確認に使うこともできます。
これは、ステートレスなサーバーでも省略できない唯一の変更です。私たちのサーバーは今も GET / で小さなディスカバリー文書(名前、バージョン、トランスポート、エンドポイント)を公開していますが、それは普通の Web ページであって、プロトコルのメソッドではありません。2026-07-28 で話したいサーバーは、server/discover に自分で応答します。
結果:resultType、キャッシュ、順序
もう少し小さな 3 つの項目が、結果の形を変えます。
resultType。 すべての結果がこれを持つようになりました。通常の応答には"complete"、複数往復のリクエストの途中の応答には"input_required"です。クライアントは、このフィールドを省略した旧プロトコルのサーバーの結果を"complete"として扱わなければならない(MUST)とされているので、古いサーバーも動き続けますが、新しいサーバーはこれを送ります。ttlMsとcacheScope。tools/list、prompts/list、resources/list、resources/read、resources/templates/listの結果には、ミリ秒単位の鮮度のヒントと、"public"または"private"のスコープが必要です。ツール一覧がデプロイ時にしか変わらず、リソースが同梱のドキュメントであるサーバーなら、長いttlMsと"public"が自然な選択です。呼び出し元のキーに依存するリソースは"private"になります。- 決定的なツールの順序。 サーバーは、クライアントのキャッシュとプロンプトキャッシュのヒットを助けるために、
tools/listのツールを決定的な順序で返すべき(SHOULD)とされています。コードでツールを決まった順序で登録しているなら、そのままにしてください。私たちのサーバーは 6 つのツールを毎回同じ順序で登録しています。
ユーザーに追加で尋ねる:複数往復のリクエスト
以前のリビジョンでは、サーバーが呼び出しの途中でクライアントに自分のリクエストを送ることができました。ユーザーに何かを尋ねる elicitation/create、クライアントのモデルを借りる sampling/createMessage、許可されたフォルダーを知る roots/list です。リビジョンはこれを Multi Round-Trip Requests パターンに置き換えます。サーバーは resultType: "input_required" と inputRequests のリストで応答し、クライアントは元のリクエストを inputResponses 付きで再送します。
文書ツールにとって、これは「写真の左側が切れています。別の写真を送りますか?」のような質問をするのにすっきりした場所です。再送は同じリクエストのやり直しなので、2 回の呼び出しの間にサーバー側で何かを保持する必要はありません。私たちのサーバーのように、サーバー起点のリクエストを一つも使っていなかったサーバーには、ここで移行するものはありません。
非推奨になったもの、代わりに使うもの
Roots、Sampling、Logging は非推奨になりました。少なくとも 12 か月の非推奨期間中は動き続けますが、「新しい実装はこれらのサポートを追加すべきではない」とされています。提案されている代替は、文書サーバーによく合います。
- Roots の代わりに、ファイルをツールの引数か設定で渡す。 私たちのローカルサーバーは、設定で画像ディレクトリが指定されているときだけ、そのディレクトリの中に限ってファイルパスを読み取ります。その外のパスは拒否されます。引数を選ぶのはモデル、柵を決めるのは運用者です。
- Logging の代わりに、stderr か OpenTelemetry にログを出す。 リビジョンは
logging/setLevelも削除しました。ログレベルは今は_metaでリクエストごとに渡され、サーバーは求められていないリクエストについてログメッセージを出してはいけません。トレースコンテキスト(traceparent)も_metaに載せられます。
古いクライアントは呼び出し続ける
すべてのクライアントが同じ日に移行するわけではないので、トランスポートのページには、2026-07-28 だけをサポートするサーバーが古いトラフィックをどう扱うべきかが書かれています。
- MCP エンドポイントへの GET または DELETE:405 Method Not Allowed。
Mcp-Session-Idヘッダー:無視し、決して発行も返送もしない。Last-Event-IDヘッダー:無視する。ストリームはもう再開できないため。
私たちのホストサーバーは、すでにエンドポイントへの GET と DELETE に 405 と Allow: POST, OPTIONS ヘッダーで応答しており、セッション ID も発行しません。古いリビジョンを話すクライアントは、エラーボディからそれを知ります。仕様は、400 のボディが認識できる新しい形式のエラーでない場合に限って initialize にフォールバックするよう、クライアントに求めています。
私たちのサーバーの現状
正確に言うと、ホストサーバーは TypeScript SDK のバージョン 1.30.0 の上に作られており、私たち自身のコードはまだどこにも 2026-07-28 を記していません。上で挙げたうち、すでに当てはまっているのは設計から来る部分です。セッションなし、ハンドルとしての ID、GET と DELETE への 405、設定で囲われたファイル。server/discover、ヘッダーの確認、resultType、キャッシュのフィールドが残りの作業です。パスポート OCR MCP サーバー のページと MCP サーバーガイド が、今日クライアントが接続する先を説明しています。
エージェント向けの文書 API を選んでいるなら、パスポート OCR API の比較 にサービスの一覧があります。MCP の部分については、それぞれに個別に尋ねる価値があります。
あなたのツールサーバーのためのチェックリスト
- リクエストの間に状態は残らない。後の呼び出しが必要とするものは、サーバーが返す ID である。
- 各リクエストのバージョンを
MCP-Protocol-Versionヘッダーと照合し、サポートしないバージョンにはUnsupportedProtocolVersionErrorを返す。 Mcp-MethodとMcp-Nameをボディと照合する。server/discoverがバージョン、ケイパビリティ、アイデンティティを返す。- 結果は
resultTypeを持ち、list と read の結果はttlMsとcacheScopeを持つ。 tools/listは毎回同じ順序を返す。- GET と DELETE には 405 を返し、セッションとイベント ID のヘッダーは無視する。
- ファイルは Roots ではなく、設定された柵の中で引数として受け取る。
- ログはクライアントではなく、stderr か OpenTelemetry に出す。
全文は modelcontextprotocol.io にあり、リリース記事 が背景を説明しています。私たちのサーバーについて詳しくは、パスポート OCR MCP サーバー のページをご覧ください。
あなたへの質問: あなたの MCP サーバーは、今ハンドルに変えなければならないものをセッションに保持していましたか。下のコメント欄で教えてください。