到達できる範囲
正直な境界。
どのツールが存在するかはロールが決める
サーバーは自分自身として、アクティブにしているコネクションに対して動作する。別のサービスアカウントはなく、自分以上のアクセス権もない。ロールが導入されて以降は、自分のロール以上のアクセス権もない。クライアントに渡されるツールの一覧は、アクティブなワークスペースで保持している権限から組み立てられるので、Viewer のクライアントには sendEmail、createRule、sendWithTemplate がそもそも並ばない。
それは呼び出しを拒否するよりも強い。一覧にないツールは、モデルが考慮するツールではなく、コンテキストを食わず、誰かの代わりに試みてからあとで詫びる対象にもならない。また、クライアントが空に見えるのは、たいていこのサーバーに機能がないからではなく、自分が持っていない権限のせいだということでもある。whoAmI はまさにそれを伝えるために存在する。
登録と呼び出しという 2 つの関門があり、実際に守っているのは後者だけである。一覧はセッションが開いたときに一度だけ組み立てられ、setActiveConnection はそのセッションを、自分にできることがより少ないメールボックスへ移せる。したがって一覧は構造上古くなり、プロトコルにはセッションの途中でツールを取り下げる手段がない。そのため、権限で保護されたツールはすべて、実行前に現在のコネクションに対して自分のロールを解決し直す。登録は礼儀であり、境界は呼び出しである。
拒否は両方の側面を示す。たとえば Refused (missing_permission): your role in this mailbox is Viewer, which does not include “Send email” のように。そのためエージェントは、作業相手の人にそれを説明して試行をやめられる。不透明なエラーを、誰かが諦めるまで再試行し続けることにはならない。セッションが開いている間に管理者がロールを変更した場合も、次の呼び出しでまったく同じように現れる。
アドレスはもう 1 つの軸であり、ここまでの話の影響をまったく受けない。ロールは何をしてよいかを定め、付与されたアドレスはどのメールボックスに対してそれをしてよいかを定める。メッセージが出ていくには、その両方が揃っている必要がある。
トークン自体は今もスコープを持たない
変わっていないのは付与のほうである。アプリが受け取るトークンは、承認の際に自分で選んだ一部ではなく、自分のロールが許すすべてに到達する。つまり、クライアントを承認することは、そのワークスペースで自分にできるすべてを承認することである。何かが付与される前に、何が要求しているのかは表示され、あとから Account → Connected apps で削除すれば、そのアプリが保持するすべてのトークンとその背後にある承認も消える。しかし「このアプリには読み取りだけ」という選び方は作られていない。
したがって MCP クライアントの上限は、自分自身の上限である。アプリにできることを狭めるには、接続した人のロールを狭めるしかなく、そうするとその人がアプリの中でできることも狭まる。これが今日の正直な姿であり、付与ごとのスコープを作る価値がいまだにある理由でもある。
語彙はすでに共有されている。ロールの権限と API キーのスコープは 1 つのアルファベットから引かれており、だからこそキーの権限は両者の積集合として計算できる。付与ごとの MCP スコープが実装されるときも、同じ言葉で表現される。