Claude Media
Managed Agentsの権限ポリシー設計 — ツールセット単位の制御

Managed Agentsの権限ポリシー設計 — ツールセット単位の制御

Managed Agentsの権限ポリシーはツールセット単位のデフォルトと、個別ツールのオーバーライドを組み合わせて設計します。カスタムツールには権限ポリシーが適用されません。

Managed Agentsの権限ポリシーは、サーバー実行型のツール(エージェントツールセットとMCPツールセット)の動き方を制御します。確認なしで動くか、承認待ちで止まるか、サーバーが呼び出しごとに判定するかを選べます。デフォルトはエージェントツールセットがalways_allow、MCPツールセットがalways_askと対極に設定されています。この非対称を前提に、configs配列による個別オーバーライドを組み合わせるのが設計の基本です。

always_allow・always_ask・autoの3種類がある

権限ポリシーはalways_allow(確認なしで即実行)、always_ask(承認が下りるまでセッションが一時停止)、auto(呼び出しごとにサーバーが評価)の3種類です。ツールセットの種類ごとに既定値が違い、エージェントツールセット(agent_toolset_20260401)はalways_allow、MCPツールセットはalways_askが既定です。どのツールセットも、既定でautoになることはありません。

autoでは、サーバーがツール・呼び出しの入力・そこまでのセッションの内容を見て評価します。同じツールへの2つの呼び出しが別の結果になることもあります。結果は次の3つのいずれかです。

  • 安全と判断した場合: そのまま実行する
  • 高リスクと判断した場合: 拒否する
  • 判定が出なかった場合: 承認待ちでセッションが止まる

拒否されると、Permission to use {tool_name} has been denied.というエラーのツール結果(is_error: true)がモデルに返ります。セッションはそのまま続きます。autoはdefault_configとconfigsのどちらにも指定でき、エージェントツールセットとMCPツールセットの両方で使えます。

MCPツールセットが承認待ちから始まるのは、MCPサーバーに後から追加されたツールが、承認なしにアプリケーション内で動かないようにするためです。

くらべる

権限ポリシーとツールの無効化は別の仕組み

いつ動くかを決める

権限ポリシー

有効なツールの実行タイミングを制御します。always_askにしても、ツールはモデルから見え続け、承認されれば実行されます。

そもそも外す

無効化(enabled: false)

ツールをエージェントから取り除きます。default_config.enabledをfalseにして必要なツールだけtrueにすれば、許可リスト方式にもできます。

ツールセット単位でデフォルトを設定する

権限ポリシーはエージェント作成時のtools設定で指定し、あとからエージェントを更新して変更することもできます。更新が稼働中のセッションにどう効くかは「ポリシー変更は稼働中のセッションに効かない」の節で扱います。

エージェントツールセット全体に一括でポリシーをかける場合はdefault_config.permission_policyを使います。

curl -fsSL https://api.anthropic.com/v1/agents \
  -H "x-api-key: $ANTHROPIC_API_KEY" \
  -H "anthropic-version: 2023-06-01" \
  -H "anthropic-beta: managed-agents-2026-04-01" \
  -H "content-type: application/json" \
  -d '{
    "name": "Coding Assistant",
    "model": "claude-opus-5-5",
    "tools": [
      {
        "type": "agent_toolset_20260401",
        "default_config": {
          "permission_policy": {"type": "always_ask"}
        }
      }
    ]
  }'

default_configは省略可能で、省略した場合はエージェントツールセットの既定であるalways_allowがそのまま使われます。MCPツールセット側で信頼済みのサーバーを自動承認にしたい場合は、mcp_toolsetエントリのdefault_config.permission_policyをalways_allowに設定します。このときmcp_server_nameはmcp_servers配列に登録したサーバーのnameと一致させる必要があります。GitHubのMCPサーバーを自動承認にする例は次の通りです。

{
  "name": "Dev Assistant",
  "model": "claude-opus-5-5",
  "mcp_servers": [
    {"type": "url", "name": "github", "url": "https://mcp.example.com/github"}
  ],
  "tools": [
    {"type": "agent_toolset_20260401"},
    {
      "type": "mcp_toolset",
      "mcp_server_name": "github",
      "default_config": {
        "permission_policy": {"type": "always_allow"}
      }
    }
  ]
}

1つのエージェントに複数のMCPサーバーを繋ぐ場合も、mcp_toolsetがmcp_server_nameで対象を指定するので、サーバーごとに別のポリシーを置けます。社内で運用している信頼済みのサーバーはalways_allow、外部ベンダーのサーバーは既定のalways_askのまま、といった分け方です。ジョブ実行や自動化基盤への書き込みを伴うMCPサーバーの権限設計はAnsible Automation PlatformのMCPサーバーにまとめています。

ポリシー変更は稼働中のセッションに効かない

エージェントの権限ポリシーを更新しても、その時点ですでに走っているセッションには反映されません。稼働中のセッションは、作成された瞬間のツールセット構成をそのまま保持し続けます。ポリシー変更が効くのは、更新より後に新しく作られるセッションだけです。

運用で効いてくるのは、緊急時の止め方です。危険な使われ方をしているツールを見つけて、ポリシーをalways_askに変更したとします。この変更は、すでに走っているセッションを止めません。厳しいポリシーが効くのは新規セッションからなので、既存のセッションには別の手当てが要ります。

その手当てが、セッション自体のtoolsとmcp_serversの更新です。権限ポリシーやドメインリストも、エージェントの新バージョンを作らずにセッション中に書き換えられます。更新はセッション内だけに効き、元のエージェントには伝わりません。セッションがidleのときに限られるため、実行中ならuser.interruptイベントを単独で送り、idleになるのを待ちます。

更新は配列の全置換です。既存のエントリを残したい場合は、セッションをGETで取得し、配列を直してからPOSTで送り返します。

個別ツールだけポリシーを上書きする

ツールセット全体のデフォルトとは別に、configs配列で特定のツールだけポリシーを上書きできます。エージェントツールセットで指定できるnameの一覧は利用可能なツールにまとまっています。次の例は、エージェントツールセット全体をalways_allowにしつつ、bashコマンドの実行だけは確認を必須にする設定です。

tools='[
  {
    "type": "agent_toolset_20260401",
    "default_config": {
      "permission_policy": {"type": "always_allow"}
    },
    "configs": [
      {
        "name": "bash",
        "permission_policy": {"type": "always_ask"}
      }
    ]
  }
]'

MCPツールセットも同じconfigsの仕組みで個別ツールを上書きできます。nameにはサーバーが報告するツール名をそのまま指定し、エントリが受け付けるのはname・enabled・permission_policyだけです。エージェントツールセットのエントリが持つtypeは付けられません。

「全体は自動承認、破壊的な操作だけ確認を挟む」という設計は、取り消しにくい操作を持つツールセットで特に使いやすい形です。読み取り専用のgrepやWeb検索まで一律always_askにすると、承認待ちが頻発してエージェントの自律性が損なわれます。

ツールごとの組み合わせ例

エージェントツールセットの8つのツール(bash・read・write・edit・glob・grep・web_fetch・web_search)を、リスクの性質で分けた組み合わせ例です。公式が定めた推奨ではなく、ここまでの仕組みから組み立てた設計例です。

ツール組み合わせ例考え方
bash組み合わせ例always_ask考え方任意のシェルコマンドを実行でき、削除や外部送信を含むことがある
write / edit組み合わせ例always_ask(本番系では特に)考え方ファイルの書き換えが、人の目を通さずに確定する
read / glob / grep組み合わせ例always_allow考え方読み取り専用なので承認待ちの価値が小さい
web_fetch / web_search組み合わせ例ドメイン制限と併用したalways_allow考え方到達範囲を絞るほうが、承認待ちより運用しやすい

読み取り系を自動化するほど、write/editの承認待ちが最後の関門として相対的に重みを持ちます。誤った変更や意図しない削除は、承認待ちの一段階で実行前に人の目を通せます。

承認待ちとautoの判定を運用で扱う

always_ask、またはautoで判定が出なかったときは、呼び出しの評価結果がaskになります。この状態のセッションは、返答が届くまで無期限に待ちます。

手順

承認待ちから再開までの流れ

  1. 1

    ツール呼び出しのイベントが出る

    agent.tool_useまたはagent.mcp_tool_useイベントが流れます。

  2. 2

    セッションが止まる

    session.status_idleイベントが届き、stop_reason.typeはrequires_actionです。止めている呼び出しのIDはstop_reason.event_idsの配列に入ります。

  3. 3

    承認か拒否を返す

    止めているイベントごとにuser.tool_confirmationを送ります。tool_use_idにイベントIDを入れ、resultは"allow"か"deny"です。拒否の理由はdeny_messageに書け、複数の確認を1回のeventsリクエストにまとめて送れます。

  4. 4

    セッションが再開する

    すべて解決するとセッションはrunningに戻ります。許可した呼び出しは実行され、拒否した呼び出しはエージェントに拒否の結果としてdeny_messageつきで返ります。

対話的に答えるなら、ant beta:sessions connectが待っている呼び出しを表示し、許可・拒否のイベントも送ってくれます。セッションが入力待ちで止まったときの通知は、Webhookでも受け取れます。

くらべる

拒否の主体で、クライアントの出番が変わる

クライアントが決める

always_askで人が拒否

呼び出しは承認待ちで止まり、許可するか拒否するかはクライアントを通じて人が決めます。

クライアントからは覆せない

autoでサーバーが拒否

evaluated_permissionがdenyの呼び出しは、承認依頼になりません。評価がaskでないイベントにクライアントがuser.tool_confirmationを送っても、APIが400エラーで弾きます。

評価結果はイベントのevaluationで追える

どのポリシーでも、agent.tool_useとagent.mcp_tool_useのイベントにはevaluated_permission("allow"・"ask"・"deny")が付きます。多くのイベントにはevaluationオブジェクトも付き、どのポリシーがその結果を出したかが分かります。autoが高リスクと判定したbashの拒否は、次のようなイベントになります。

{
  "type": "agent.tool_use",
  "name": "bash",
  "input": {"command": "rm -rf /workspace/reports"},
  "evaluated_permission": "deny",
  "evaluation": {
    "type": "auto",
    "evaluated_permission": {"type": "deny", "reason_code": "high_risk"}
  }
}

evaluationの形は5通りです。

evaluation外側のevaluated_permission意味
{"type": "always_allow"}外側のevaluated_permission"allow"意味解決されたポリシーがalways_allowで、そのまま実行
{"type": "always_ask"}外側のevaluated_permission"ask"意味解決されたポリシーがalways_askで、承認待ち
autoでallow外側のevaluated_permission"allow"意味サーバーが安全と判定し、実行
autoでask(reason_code: indeterminate)外側のevaluated_permission"ask"意味サーバーが判定できず、承認待ち
autoでdeny(reason_code: high_risk)外側のevaluated_permission"deny"意味サーバーが高リスクと判定し、拒否

reason_codeは、クライアントが分岐したり監査記録に残したりするための値です。利用者に表示する文言としては想定されていません。

evaluationが付かないケースが2つあります。1つは、セッションで有効になっていないツールの名前をエージェントが呼んだ場合です。サーバーはポリシーを評価せずに拒否し、イベントにはevaluated_permission: "deny"だけが付きます。もう1つは、evaluationの導入前に記録されたイベントです。こちらはevaluated_permissionが"allow"ならalways_allow、"ask"ならalways_askとして読みます。

クライアントは、知らないevaluation.typeやreason_codeが来ても壊れないように書いておく必要があります。agent.custom_tool_useには、どちらのフィールドも付きません。

web_fetchとweb_searchはドメイン制限と組み合わせる

web_searchとweb_fetchには、権限ポリシーとは別の制御軸としてallowed_domains(到達を許可するホストのみに限定)とblocked_domains(到達を禁止するホストを指定)を設定できます。どちらもconfigs配列の該当エントリに指定し、web_searchとweb_fetchで別々のリストを持てます。1つのドメインを指定すると、そのホストとすべてのサブドメインが対象になります。

{
  "type": "agent_toolset_20260401",
  "configs": [
    {
      "type": "web_search",
      "name": "web_search",
      "allowed_domains": ["docs.example.com", "arxiv.org"]
    },
    {
      "type": "web_fetch",
      "name": "web_fetch",
      "blocked_domains": ["ads.example.com"],
      "max_content_tokens": 50000
    }
  ]
}

許可リストに無いURLへweb_fetchが到達しようとすると、agent.tool_resultイベントでis_error: trueとurl_not_allowedエラーコードを含む結果が返ります。web_searchの場合はエラーにはならず、リストが許可しない結果が検索結果から単に除外されます。

リストの書き方には、作成・更新時に400のinvalid_request_errorで弾かれる決まりがあります。

  • 1つのエントリにallowed_domainsとblocked_domainsは同時に指定できない
  • 各リストは1〜64ドメインで、空配列は不可(制限をかけないなら項目を省くかnullにする)
  • 同じリスト内でドメインを重複させられない
  • 日本語などのドメインはxn--で始まるPunycode形式で書く
  • スキームもポート番号も付けないホスト名で書く(example.comであってhttps://example.comではない)
  • IPアドレス、ワイルドカード、comのようなTLD単独、localhostや.internalで終わるホストは不可
  • web_fetchのドメインにはパスを付けられない(web_searchはパス付きの指定が可能)
  • www.example.comとexample.comは別のドメインとして数え、www.付きで書くとexample.comは対象外になる

制限の効き方にも注意が必要です。環境のnetworking設定が制御するのはサンドボックス自身の通信で、web_searchとweb_fetchはAnthropicのサーバー側で動くため影響を受けません。Claude Consoleの組織レベルのWeb検索・Web取得の設定も、Managed Agentsのセッションには適用されません。到達先を絞る手段は、ツールごとのドメインリストです。マルチエージェントのセッションでは呼び出し元の制限が重ねて適用されるので、ロスターのエージェントは到達範囲を狭められても広げられません。

カスタムツールは権限ポリシーの対象外

設計で見落としやすいのが、カスタムツールには権限ポリシーが一切適用されない点です。カスタムツールはアプリケーション側が実行するツールで、Managed Agentsのサーバー実行環境の外にあります。エージェントがカスタムツールを呼び出すとagent.custom_tool_useイベントが届き、実行するかどうかを判断してuser.custom_tool_resultを返すのはアプリケーション自身の責任です。

つまり「このツールは危ないからalways_askにしておこう」という発想が通用するのは、あらかじめ用意されたエージェントツールセットとMCPツールセットだけです。カスタムツールの実行可否は、権限ポリシーの設定ではなくアプリケーションコード側のロジックとして実装します。カスタムツールの作り方自体はAgent SDKカスタムツールの作り方で扱っています。

まとめ

エージェントツールセットは自動実行、MCPツールセットは承認待ちから出発するので、書き込み系だけをalways_askに寄せるかautoに任せるかを先に決めておくと設計が速くなります。エージェント側のポリシー変更は新しいセッションにしか効かないので、稼働中のセッションはセッションのtools更新で直します。カスタムツールはポリシーの外にあるため、その承認はアプリケーション側で実装します。認証情報側の設計はAgent SDKのManaged Agentsの設計思想、SDKからMCPサーバーへ接続する手順はAgent SDK MCP接続ガイドを参照してください。

この記事を共有:XはてブLinkedIn