# MCPのMRTR改ざん耐性設計——requestStateの守り方

> MCP 2026-07-28仕様のMRTRはrequestStateを攻撃者制御入力として扱い、認可に影響する場合はHMACやAEADで改ざん検証することをSEP-2322で要求する。

- Canonical: https://kuucorp.com/blog/mcp-mrtr-requeststate-integrity-design/
- Date: 2026-10-03
- Last modified: 2026-10-03
- Publisher: Kuu株式会社 (https://kuucorp.com)

---
MCPサーバーがツール実行中に「本当に削除しますか」とユーザーへ確認を求める——この一時停止処理が2026-07-28仕様で作り直された。Sampling・Roots・Elicitationという従来のクライアント呼び出し方式は非推奨となり、Multi Round-Trip Requests（MRTR）という新パターンに統一された。問題は、この新パターンの中核にある`requestState`フィールドを、実装者が単なる継続トークン程度に軽く扱ってしまう点にある。

## なぜMCPはSampling/Roots/Elicitationの呼び出し方式を変えたのか

> MCPはサーバーからクライアントへの割り込みリクエストを廃止し、2026-07-28仕様でMRTR（SEP-2322）に統一した。ステートレスな水平スケールを実現するためだ。

2026-07-28仕様はセッション概念（`Mcp-Session-Id`）と`initialize`ハンドシェイクを撤廃し、[MCP](/glossary/mcp/)をステートレスなリクエスト/レスポンス型プロトコルへ転換した。しかし旧来のSampling・Roots・Elicitationは、いずれもサーバーが接続を保持したままクライアントへ割り込みリクエストを送る「サーバー起動」方式だった。接続を保持できないステートレスサーバーではこの方式が成立しない。公式チェンジログはSampling・Roots・Loggingの3機能を非推奨に指定し、新規実装はMRTRパターンへの統一を求めている。従来の[Elicitation実装](/blog/mcp-elicitation-server-user-input-design/)は`elicitation/create`を直接送る前提で解説したが、現行仕様ではこの直接呼び出しがMRTRの枠組みに置き換わっている。

## MRTRの基本フローはどう動くか

> MRTRはクライアントの`tools/call`等に対しサーバーが`resultType: "input_required"`を返し、クライアントが`inputResponses`付きで再送する2往復設計です。

フローは4段階。(1) クライアントが通常のリクエストを送る。(2) サーバーが追加情報を要すると判断し、`InputRequiredResult`で`inputRequests`（Elicitation・Sampling・Rootsのいずれか）と`requestState`を返す。(3) クライアントはユーザーや他の手段から回答を集め、`inputResponses`と`requestState`を添えて同じリクエストを新しいJSON-RPC `id`で再送する。(4) サーバーは`requestState`から文脈を復元し、処理を完了する。対応するのは`tools/call`・`resources/read`・`prompts/get`の3リクエストのみで、他のリクエストへの`InputRequiredResult`は仕様違反となる。[Tasks拡張](/blog/mcp-tasks-extension-long-running-operations-design/)の`input_required`状態と似るが、MRTRは単発リクエスト内の往復であり、長時間タスクのポーリングとは別チャンネルである点に注意したい。

## requestStateはなぜ「攻撃者制御入力」として扱うべきなのか

> requestStateはクライアントが不透明として扱うべき値だが、サーバー視点では悪意あるクライアントが改変しうる攻撃者制御入力として扱う必要がある。

仕様はクライアント側に「`requestState`の内容を検査・解釈・変更してはならない」と課す一方、サーバー側には逆の要求を課す。クライアントを経由して往復する値である以上、悪意あるクライアントや侵害されたクライアントが値を書き換えて再送してくる可能性を排除できない。この非対称性——クライアントには不透明、サーバーには攻撃者制御——を理解していないと、`requestState`に認可判断やリソースアクセスの前提条件をそのまま平文で埋め込む実装に陥る。これは[スコープ付き認証情報設計](/blog/agent-iam-scoped-credentials-design/)で避けるべきとされる「暗黙の信頼境界」と同じ失敗パターンだ。

## requestStateの改ざん防御はどう実装するか

> requestStateが認可・リソースアクセス・業務ロジックに影響する場合、サーバーはHMACやAEADで整合性保護し、検証失敗時は必ず拒否しなければならない。

仕様の要求は明確だ。`requestState`が認可判断・リソースアクセス・業務ロジックに影響を与える場合、サーバーはHMACまたはAEADで整合性保護を実装し、検証に失敗した状態は拒否しなければならない。整合性保護を省略できるのは、改ざんの結果がリクエスト失敗以上の実害を生まない場合に限られる。実装としては、サーバー内部のJSONを平文でBase64エンコードするのではなく、暗号化JWTやAEAD保護済みバイナリとして`requestState`を発行し、復号・検証の失敗を即座にエラー終端させる設計が要る。

## リプレイ防御は何を組み込むべきか

> 改ざん防御だけでは不十分で、整合性保護されたペイロード内に認証プリンシパル・短いTTL・元リクエストの識別子を含め検証すべきだ。

仕様はリプレイ対策として3要素を推奨する。認証済みプリンシパル（異なるユーザーが提示した状態を拒否）、短いTTL（期限切れ状態を拒否）、元リクエストの識別子（メソッド名とパラメータのダイジェストなど。異なるリクエストに対する状態を拒否）の3点だ。ただしこれらはリプレイの時間窓とクロスユーザー再利用を防ぐに留まり、単発利用の保証にはならない。一度しか使えないべき`requestState`（ワンタイム処理等)はサーバー側で別途その制約を強制する必要がある。

## 参考

- [Multi Round-Trip Requests - Model Context Protocol](https://modelcontextprotocol.io/specification/2026-07-28/basic/patterns/mrtr)
- [Key Changes - Model Context Protocol](https://modelcontextprotocol.io/specification/2026-07-28/changelog)
- [The 2026-07-28 Specification](https://blog.modelcontextprotocol.io/posts/2026-07-28/)

## まとめ

MRTRはMCPのステートレス化に不可欠な設計変更だが、`requestState`を単なる継続トークンとして軽視すると、認可バイパスや業務ロジック改ざんの入口になる。サードパーティMCPサーバーを組み込む際は、`requestState`の整合性保護方式（HMAC/AEAD）とリプレイ対策の3要素が実装されているかをベンダー評価の必須項目に加えるべきだ。複数チームでMCPサーバーを運用する体制整備については、[Kuu株式会社のRDE](https://kuucorp.com/services/rde/)が設計レビューから支援する。
