MCPアノテーションはセキュリティ層ではなくUX層

Dev.to / 2026/5/5

💬 オピニオンSignals & Early TrendsIdeas & Deep Analysis

要点

  • この記事では、MCPのツール・アノテーション(readOnly/destructive/idempotentのヒントなど)はセキュリティや権限の強制ではなく、UX向けのヒントだと主張しています。
  • アノテーションはプロトコルによって検証されないため、悪意ある(または誤った)サーバーが破壊的なツールを「readOnly」と偽っても、ホストはアノテーションだけでは見破れません。
  • モデルやホストはアノテーションを確認プロンプト、並び替え、表示などに活用できますが、信頼するかどうかはホスト側の方針(ポリシー)として決める必要がある、と説明されています。
  • SEP-1862とSEP-1913という2つの仕様提案はアノテーション領域を拡張しますが、記事の見立てでは依然としてUX層をより良くするだけで、アノテーションをセキュリティに転換するものではありません。
  • MCP仕様の文言(ツールアノテーションはヒントであり、不信なサーバーから受け取ったアノテーションに基づいてツール利用判断をしてはいけない)を引用して、この点を裏付けています。

モデルコンテキストプロトコルに readOnlyHintdestructiveHintidempotentHint のようなツール注釈が追加されたとき、多くのMCPサーバー作者やホスト実装者が、それらを権限(パーミッション)の仕組みとして読み取ってしまいました。頭の中のモデルは、だいたい次のようなものです。ツールが破壊的だと宣言する、ホストがそれを見て、ホストはユーザーに確認を求めるか、あるいは最初から拒否する。注釈による強制であり、Unixファイルシステムにおけるファイル権限のようなものだ、という考え方です。

しかし、それは違います。ツール注釈は、サーバー作者がツール定義に入力した文字列です。モデルがそれを見て、ホストもそれを見て、それらを確認プロンプトや並べ替え、色分けなどに使うことができます。プロトコルは、その注釈が真実であることを検証しません。たとえば、生産環境のデータベースを削除するようなツールに対して、サーバーが readOnlyHint: true を宣言しても、プロトコルはそれに気づきません。ホストは注釈を信頼するかどうかを選べますが、その信頼は、プロトコルが提供するものではなく、サーバーに関するホスト側のポリシー判断です。

この区別は重要です。注釈システムに、設計者が想定していなかった重みまで背負わせようとしているからです。現在進行中の2つの有効な仕様提案(SEP-1862SEP-1913)は、注釈の表面(annotation surface)を有用な形で拡張します。どちらも、注釈が本質的に何であるかは変えません。UX層をより良くするだけです。セキュリティ層に変えるものではありません。

注釈が実際に何であるか

注釈は、サーバーが宣言するヒントです。サーバー作者がそれらをツール定義に書き込み、サーバーが tools/list でクライアントに送信し、それで一連の管理(custody)の全てが完結します。署名もありませんし、第三者による検証もありません。さらに、モデル側がツール本体として何をするかを分析することもありません。注釈の信頼性は、それを生成したサーバーと同程度です。

MCP仕様は、この点を明確に述べています。スキーマのドキュメントより:「ToolAnnotations のすべてのプロパティはヒントです。ツールの挙動を忠実に記述することが保証されるわけではありません……クライアントは、信頼できないサーバーから受け取った ToolAnnotations に基づいて、ツールの使用判断を決して行うべきではありません」。この文言が仕様にあるのは、注釈は偽造可能であることを作業グループが理解しているからです。

MCPの共同創設者の一人であるJustin Spahr-Summersは、注釈システムの当初レビューの場で、当然の疑問を提起しました。もしクライアントが注釈を信頼できないと分かっているなら、そもそも注釈を持つ意味は何なのか? これは正しい問いですが、仕様は実質的にまだ十分な答えを出していません。実務上の答えとしては、注釈は主に2つのことに役立つ、というものです。第一に、サーバーが信頼できる場合、ホストは注釈の上により良いUXを構築できます(読み取り専用だと宣言するツールは確認プロンプトを省略する、破壊的なツールは別の色で描画する、より安全なものを先に表示するように並べ替える等)。第二に、ホストはツール呼び出しをどれほど精査するかをスコアリングするとき、注釈を多くのシグナルの1つとして使うことができます。

どちらも強制ではありません。どちらも、ホストがすでにそのサーバーを誠実だと判断していることを前提としています。注釈は、ツールの意図をホストがどう表示するかを伝えるものであって、それを許可するかどうかは伝えません。

進行中の2つのSEPs

注釈に関連する2つの提案が、現在MCP仕様のプロセスを通じて進められています。どちらも、GitHubのSam Morrowによって執筆または共同執筆されています。

SEP-1862(Tool Resolution)は、静的注釈に対する実際の問題に対処します。具体的には、action 引数を取り、その値によって挙動が変わる単一のツールは、常に破壊的だと宣言しなければならなくなっています。なぜなら静的注釈は最悪ケースをカバーする必要があるからです。たとえば manage_files ツールが readdelete の両方の操作に対応している場合、読み取り呼び出しであっても、最も危険なモードと同じくらい危険に見えるように宣言せざるを得ません。解決策は新しい tools/resolve メソッドで、LSPの codeAction/resolve パターンに着想を得ています。ツールを呼び出す前に、クライアントがサーバーへ尋ねます。これらの特定の引数を渡したとき、実際の注釈は何なのか? サーバーは、その呼び出しに対する洗練されたメタデータを返します。複数アクションのツールは、UXの正確さを犠牲にすることなく、再び実現可能になります。

SEP-1913(Trust and Sensitivity Annotations)は、OpenAIとの共同執筆により、別の軸で機能します。既存の注釈が「ツールが何をするか」を説明するのに対して、SEP-1913は「ツールを通じて流れるデータが何を意味するか」を説明する注釈を追加します。sensitiveHint(低/中/高)、privateHintmaliciousActivityHintattribution といった新しいフィールドにより、サーバーは返却されるデータに対して信頼性とセンシティビティのメタデータを付与でき、さらにそのメタデータがエージェントセッションを通じて伝播することで、ホストが「privateとマークされたデータを、open-worldとマークされたツールへ送らない」といったポリシーを強制できるようになります。

どちらの提案も、明確なギャップを埋めます。SEP-1862は、静的注釈によって実質的に禁じられていたツール設計パターンのブロックを解除します。SEP-1913は、ツールが何をするかから、それらがどのようなデータを扱うかへと注釈の対象領域を拡張します。これはプロンプトインジェクションやデータ流出(exfiltration)を気にするなら、正しい方向性です。

しかし、どちらの提案も変更しないのが信頼モデルです。SEP-1862の解決された注釈は、依然としてサーバーが宣言するものです。SEP-1913のデータ注釈も、依然としてサーバーが宣言するものです。tools/list で嘘をつくサーバーなら、tools/resolve でも、返却コンテンツの sensitiveHint フィールドでも同様に嘘をつけます。提案は、誠実なサーバーをより表現力豊かにするものです。不誠実なサーバーを検出可能にするものではありません。

今日のMCPサーバー設計にとってこれが意味すること

注釈がUX層であるなら、プロトコルレベルの強制に依存せずとも、UX層が常に正確であり続けるようにサーバーを設計してください。

最初の意思決定はツールの粒度(granularity)です。action 引数を持つ複数アクションのツールは、最悪ケースの静的注釈を強制します。つまり、誠実なホストは過剰に確認プロンプトを出し、うまく調整されたモデルも危険そうに見えるため、そのツールを避けるように誘導されてしまいます。SEP-1862が登場するまでの間は、アクションごとにツールを分けておくと静的注釈を誠実に保てます。1つのツールは読み取り、1つのツールは一覧表示、1つのツールは削除。このそれぞれが実際の形を宣言しており、その注釈は常に真です。これはツール定義をいくつか増やすコストを払う一方で、ホスト側があなたの代わりに悪いUX判断をすることを防げます。

2つ目の意思決定は、既存の注釈フィールドをどう使うかです。ブールのグリッド(readOnlyHintdestructiveHintidempotentHintopenWorldHint)は、順序付けされた階層(tier)というより独立したフラグですが、実際のところツールは3つのグループにまとまります。読み取り専用ツール(readOnlyHint: true)。変更するが復旧可能なツール(readOnlyHint: false, destructiveHint: false)。破壊的ツール(readOnlyHint: false, destructiveHint: true)。これらを内部的に階層として扱うと、プロトコルがその構造を強制しないとしても、ホストのポリシーを単純化できます。また、新しいツールを追加するときに、そのツールがどの階層に属するかが明確になるため、大規模化の際にも重要になります。

3つ目の判断は、信頼ギャップに対して何をするかです。率直な答えは、このプロトコルはそれをあなたの代わりに埋められないので、別の場所で埋める必要があるということです。サンドボックス化された実行、インフラ層でのエグレス(送信先)コントロール、そしてサードパーティのスキャナ(SnykのAgent Scanはその一例です)は、プロトコルの外側にあり、ツールが何を主張しているかに関係なく、実際にツールが何をするのかを検証したり制約したりします。もしあなたのMCPサーバが、それらの層のいずれかが存在する状況で動いているなら、それらに頼るべきです。ツールへの注釈は正直であるべきですが、安全境界は別の場所にあります。

やってはいけないのは、注釈の正しさを安全境界だとみなすことです。注釈を丁寧に書くサーバ作成者と、嘘をつくサーバ作成者は、プロトコルの観点では同じに見えます。設計が「ホストが注釈だけで両者を見分けられる」ことを前提にしているなら、そこにギャップがあります。

実際のセキュリティ層はMCPの外側にある

注釈はUX(ユーザー体験)層だと受け入れると、安全が実際にどこにあるのかという問いは、答えやすくなります。セキュリティは3つの場所にあり、いずれもプロトコルの中にはありません。

1つ目は、どのサーバを信頼するかに関するホスト側のポリシーです。ホストは、どのMCPサーバからツールを受け入れるか、それらのサーバがどのスコープで動くか、そしてユーザーが何を承認したかを決めます。ここで、真の許可/拒否の判断が行われます。注釈は、ホストがより明確なプロンプトやより良いデフォルトを作るのに役立ちますが、ツール呼び出しを受け入れるか拒否するのはホストです。

2つ目は、インフラ層での強制(エンフォースメント)です。サンドボックス化された実行、ネットワークのエグレス規則、ファイルシステム権限、コンテナ境界。これらは、ツールの注釈が何と言っているかを気にしません。読み取り専用だと主張していてもサンドボックスの外へ書き込もうとするツールは、注釈ではなくサンドボックスによって止められます。プロダクションで実際の作業を行うMCPサーバのためのこの層こそが、削除、情報の持ち出し(exfiltration)、および横方向への移動(lateral movement)を実際に防ぐ場所です。

3つ目は、サードパーティによる検証です。サーバが主張する内容とは独立して、MCPサーバのコードや挙動を調べるスキャナです。SnykのAgent Scanはこのカテゴリの一例で、エコシステムが成熟するにつれてさらに増えていくでしょう。これらのツールは、サーバを信頼せず、定義上「検証」することであり「信頼」することではないため、プロトコルが埋められない領域を占めます。

これらのいずれも、注釈を無価値にするわけではありません。注釈は、正直なサーバが意図を伝えることを可能にし、ホストがその意図に合うインターフェースを構築するのを助け、適切なタイミングでユーザーに適切な量の摩擦を与えます。SEP-1862は、複数アクションのツールに対してこのシグナルをより鋭くします。SEP-1913は、それをツールを通じて流れるデータにも拡張します。どちらも提供する価値があります。