The two sides of this change are more than 400 edits apart, too far apart to line up, so this is the differ's own diff of it and the words inside a line are not marked.
from line 4
44description: Control when agent and MCP tools execute.
55---
66
7Permission policies control whether server-executed tools (the pre-built agent toolset and MCP toolset) run automatically or wait for your approval. Custom tools are executed by your application and controlled by you, so they are not governed by permission policies.
7Permission policies control whether server-executed tools (the pre-built agent toolset and MCP toolset) run automatically, wait for your approval, or have each call evaluated by the server. Custom tools are executed by your application and controlled by you, so they are not governed by permission policies.
88
99<Note>
1010 Managed Agents API requests require the `managed-agents-2026-04-01` beta header, except memory store endpoints, which use `agent-memory-2026-07-22` instead. The SDK sets the correct beta header automatically. See [Beta headers](https://platform.claude.com/docs/en/api/beta-headers#endpoint-specific-headers).
from line 12
1212
1313## Permission policy types
1414
15| Policy | Behavior |
16| -------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
17| `always_allow` | The tool executes automatically with no confirmation. |
18| `always_ask` | The session pauses and waits for your approval before executing. See [Respond to confirmation requests](https://platform.claude.com/docs/en/managed-agents/permission-policies#respond-to-confirmation-requests) for the event flow. |
15| Policy | Behavior |
16| -------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
17| `always_allow` | The tool executes automatically with no confirmation. |
18| `always_ask` | The session pauses and waits for your approval before executing. See [Respond to confirmation requests](https://platform.claude.com/docs/en/managed-agents/permission-policies#respond-to-confirmation-requests) for the event flow. |
19| `auto` | The server evaluates each call and runs it, denies it, or pauses for your approval. See [Let the server evaluate each call with `auto`](https://platform.claude.com/docs/en/managed-agents/permission-policies#let-the-server-evaluate-each-call-with-auto). |
1920
2021Each toolset kind has its own default: the agent toolset defaults to `always_allow`, and MCP toolsets default to `always_ask`.
2122
from line 665
664665
665666Pass this `tools` configuration in the agent create request (the CLI tab shows the complete command). MCP toolsets support the same per-tool overrides, with `name` set to the tool name reported by the MCP server. See [Configure which MCP tools are available](https://platform.claude.com/docs/en/managed-agents/mcp-connector#configure-which-mcp-tools-are-available).
666667
668## Let the server evaluate each call with `auto`
669
670With the `auto` permission policy, the server evaluates each call before it runs. Because the evaluation considers the tool, the call's input, and the session's content up to that point, the server can treat two calls to the same tool differently. Each call has one of three outcomes:
671
672* **The call runs.** When the server determines that the call is safe, the tool runs as it would under `always_allow`.
673* **The call is denied.** When the server evaluates the call as high-risk, the tool does not run. The agent receives an error tool result with the content `Permission to use {tool_name} has been denied.` and `is_error: true`. The session keeps running, and your client cannot override the denial.
674* **The call pauses for your approval.** When the server reaches no determination, the session pauses as it does under `always_ask`. See [Respond to confirmation requests](https://platform.claude.com/docs/en/managed-agents/permission-policies#respond-to-confirmation-requests).
675
676To turn on `auto`, set `permission_policy` to `{"type": "auto"}`. It goes in the same two places as the other policies: a toolset's [`default_config`](https://platform.claude.com/docs/en/managed-agents/permission-policies#set-a-policy-for-a-toolset) for the whole toolset, or a [`configs` entry](https://platform.claude.com/docs/en/managed-agents/permission-policies#override-an-individual-tool-policy) for one tool. The agent toolset and MCP toolsets both accept it. No toolset uses `auto` by default.
677
678The following example sets `auto` as the default for the agent toolset and for the `github` MCP toolset, and overrides `bash` to `always_ask`:
679
680<CodeGroup defaultLanguage="CLI">
681 ```bash cURL
682 agent=$(curl -fsSL https://api.anthropic.com/v1/agents \
683 -H "x-api-key: $ANTHROPIC_API_KEY" \
684 -H "anthropic-version: 2023-06-01" \
685 -H "anthropic-beta: managed-agents-2026-04-01" \
686 -H "content-type: application/json" \
687 -d '{
688 "name": "Ops Agent",
689 "model": "claude-opus-5",
690 "mcp_servers": [
691 {"type": "url", "name": "github", "url": "https://mcp.example.com/github"}
692 ],
693 "tools": [
694 {
695 "type": "agent_toolset_20260401",
696 "default_config": {
697 "permission_policy": {"type": "auto"}
698 },
699 "configs": [
700 {"name": "bash", "permission_policy": {"type": "always_ask"}}
701 ]
702 },
703 {
704 "type": "mcp_toolset",
705 "mcp_server_name": "github",
706 "default_config": {
707 "permission_policy": {"type": "auto"}
708 }
709 }
710 ]
711 }')
712 ```
713
714 <MultiFileExample language="cli" label="CLI">
715 ```bash CLI
716 ant apply agent.md
717 ```
718
719 <File filename="agent.md">
720 ```markdown
721 ---
722 name: Ops Agent
723 model: claude-opus-5
724 mcp_servers:
725 - type: url
726 name: github
727 url: https://mcp.example.com/github
728 tools:
729 - type: agent_toolset_20260401
730 default_config:
731 permission_policy:
732 type: auto
733 configs:
734 - name: bash
735 permission_policy:
736 type: always_ask
737 - type: mcp_toolset
738 mcp_server_name: github
739 default_config:
740 permission_policy:
741 type: auto
742 ---
743 ```
744 </File>
745 </MultiFileExample>
746
747 ```python Python
748 agent = client.beta.agents.create(
749 name="Ops Agent",
750 model="claude-opus-5",
751 mcp_servers=[
752 {"type": "url", "name": "github", "url": "https://mcp.example.com/github"},
753 ],
754 tools=[
755 {
756 "type": "agent_toolset_20260401",
757 "default_config": {
758 "permission_policy": {"type": "auto"},
759 },
760 "configs": [
761 {"name": "bash", "permission_policy": {"type": "always_ask"}},
762 ],
763 },
764 {
765 "type": "mcp_toolset",
766 "mcp_server_name": "github",
767 "default_config": {
768 "permission_policy": {"type": "auto"},
769 },
770 },
771 ],
772 )
773 ```
774
775 ```typescript TypeScript
776 const agent = await client.beta.agents.create({
777 name: "Ops Agent",
778 model: "claude-opus-5",
779 mcp_servers: [{ type: "url", name: "github", url: "https://mcp.example.com/github" }],
780 tools: [
781 {
782 type: "agent_toolset_20260401",
783 default_config: {
784 permission_policy: { type: "auto" }
785 },
786 configs: [{ name: "bash", permission_policy: { type: "always_ask" } }]
787 },
788 {
789 type: "mcp_toolset",
790 mcp_server_name: "github",
791 default_config: {
792 permission_policy: { type: "auto" }
793 }
794 }
795 ]
796 });
797 ```
798
799 ```csharp C#
800 using Anthropic.Models.Beta.Agents;
801
802 var agent = await client.Beta.Agents.Create(new()
803 {
804 Name = "Ops Agent",
805 Model = BetaManagedAgentsModel.ClaudeOpus5,
806 McpServers =
807 [
808 new()
809 {
810 Type = BetaManagedAgentsUrlMcpServerParamsType.Url,
811 Name = "github",
812 Url = "https://mcp.example.com/github",
813 },
814 ],
815 Tools =
816 [
817 new BetaManagedAgentsAgentToolset20260401Params
818 {
819 Type = BetaManagedAgentsAgentToolset20260401ParamsType.AgentToolset20260401,
820 DefaultConfig = new()
821 {
822 PermissionPolicy = new BetaManagedAgentsAutoPolicy(),
823 },
824 Configs =
825 [
826 new BetaManagedAgentsBashToolConfigParams
827 {
828 PermissionPolicy = new BetaManagedAgentsAlwaysAskPolicy { Type = "always_ask" },
829 },
830 ],
831 },
832 new BetaManagedAgentsMcpToolsetParams
833 {
834 Type = BetaManagedAgentsMcpToolsetParamsType.McpToolset,
835 McpServerName = "github",
836 DefaultConfig = new()
837 {
838 PermissionPolicy = new BetaManagedAgentsAutoPolicy(),
839 },
840 },
841 ],
842 });
843 ```
844
845 ```go Go
846 agent, err := client.Beta.Agents.New(ctx, anthropic.BetaAgentNewParams{
847 Name: "Ops Agent",
848 Model: anthropic.BetaManagedAgentsModelConfigParams{
849 ID: "claude-opus-5",
850 },
851 MCPServers: []anthropic.BetaManagedAgentsURLMCPServerParams{{
852 Type: anthropic.BetaManagedAgentsURLMCPServerParamsTypeURL,
853 Name: "github",
854 URL: "https://mcp.example.com/github",
855 }},
856 Tools: []anthropic.BetaAgentNewParamsToolUnion{
857 {
858 OfAgentToolset20260401: &anthropic.BetaManagedAgentsAgentToolset20260401Params{
859 Type: anthropic.BetaManagedAgentsAgentToolset20260401ParamsTypeAgentToolset20260401,
860 DefaultConfig: anthropic.BetaManagedAgentsAgentToolsetDefaultConfigParams{
861 PermissionPolicy: anthropic.BetaManagedAgentsAgentToolsetDefaultConfigParamsPermissionPolicyUnion{
862 OfAuto: &anthropic.BetaManagedAgentsAutoPolicyParam{},
863 },
864 },
865 Configs: []anthropic.BetaManagedAgentsAgentToolConfigParamsUnion{{
866 OfBash: &anthropic.BetaManagedAgentsBashToolConfigParams{
867 PermissionPolicy: anthropic.BetaManagedAgentsBashToolConfigParamsPermissionPolicyUnion{
868 OfAlwaysAsk: &anthropic.BetaManagedAgentsAlwaysAskPolicyParam{
869 Type: anthropic.BetaManagedAgentsAlwaysAskPolicyTypeAlwaysAsk,
870 },
871 },
872 },
873 }},
874 },
875 },
876 {
877 OfMCPToolset: &anthropic.BetaManagedAgentsMCPToolsetParams{
878 Type: anthropic.BetaManagedAgentsMCPToolsetParamsTypeMCPToolset,
879 MCPServerName: "github",
880 DefaultConfig: anthropic.BetaManagedAgentsMCPToolsetDefaultConfigParams{
881 PermissionPolicy: anthropic.BetaManagedAgentsMCPToolsetDefaultConfigParamsPermissionPolicyUnion{
882 OfAuto: &anthropic.BetaManagedAgentsAutoPolicyParam{},
883 },
884 },
885 },
886 },
887 },
888 })
889 if err != nil {
890 panic(err)
891 }
892 _ = agent
893 ```
894
895 ```java Java
896 import com.anthropic.models.beta.agents.*;
897
898 var agent = client.beta().agents().create(
899 AgentCreateParams.builder()
900 .name("Ops Agent")
901 .model(BetaManagedAgentsModel.CLAUDE_OPUS_5)
902 .addMcpServer(
903 BetaManagedAgentsUrlMcpServerParams.builder()
904 .type(BetaManagedAgentsUrlMcpServerParams.Type.URL)
905 .name("github")
906 .url("https://mcp.example.com/github")
907 .build()
908 )
909 .addTool(
910 BetaManagedAgentsAgentToolset20260401Params.builder()
911 .type(BetaManagedAgentsAgentToolset20260401Params.Type.AGENT_TOOLSET_20260401)
912 .defaultConfig(
913 BetaManagedAgentsAgentToolsetDefaultConfigParams.builder()
914 .permissionPolicy(BetaManagedAgentsAutoPolicy.builder().build())
915 .build()
916 )
917 .addConfig(
918 BetaManagedAgentsBashToolConfigParams.builder()
919 .permissionPolicy(
920 BetaManagedAgentsAlwaysAskPolicy.builder()
921 .type(BetaManagedAgentsAlwaysAskPolicy.Type.ALWAYS_ASK)
922 .build()
923 )
924 .build()
925 )
926 .build()
927 )
928 .addTool(
929 BetaManagedAgentsMcpToolsetParams.builder()
930 .type(BetaManagedAgentsMcpToolsetParams.Type.MCP_TOOLSET)
931 .mcpServerName("github")
932 .defaultConfig(
933 BetaManagedAgentsMcpToolsetDefaultConfigParams.builder()
934 .permissionPolicy(BetaManagedAgentsAutoPolicy.builder().build())
935 .build()
936 )
937 .build()
938 )
939 .build()
940 );
941 ```
942
943 ```php PHP
944 use Anthropic\Beta\Agents\BetaManagedAgentsAgentToolset20260401Params;
945 use Anthropic\Beta\Agents\BetaManagedAgentsAgentToolsetDefaultConfigParams;
946 use Anthropic\Beta\Agents\BetaManagedAgentsAlwaysAskPolicy;
947 use Anthropic\Beta\Agents\BetaManagedAgentsAutoPolicy;
948 use Anthropic\Beta\Agents\BetaManagedAgentsBashToolConfigParams;
949 use Anthropic\Beta\Agents\BetaManagedAgentsMCPToolsetDefaultConfigParams;
950 use Anthropic\Beta\Agents\BetaManagedAgentsMCPToolsetParams;
951 use Anthropic\Beta\Agents\BetaManagedAgentsURLMCPServerParams;
952
953 $agent = $client->beta->agents->create(
954 name: 'Ops Agent',
955 model: 'claude-opus-5',
956 mcpServers: [
957 BetaManagedAgentsURLMCPServerParams::with(
958 type: 'url',
959 name: 'github',
960 url: 'https://mcp.example.com/github',
961 ),
962 ],
963 tools: [
964 BetaManagedAgentsAgentToolset20260401Params::with(
965 type: 'agent_toolset_20260401',
966 defaultConfig: BetaManagedAgentsAgentToolsetDefaultConfigParams::with(
967 permissionPolicy: BetaManagedAgentsAutoPolicy::with(),
968 ),
969 configs: [
970 BetaManagedAgentsBashToolConfigParams::with(
971 permissionPolicy: BetaManagedAgentsAlwaysAskPolicy::with(type: 'always_ask'),
972 ),
973 ],
974 ),
975 BetaManagedAgentsMCPToolsetParams::with(
976 type: 'mcp_toolset',
977 mcpServerName: 'github',
978 defaultConfig: BetaManagedAgentsMCPToolsetDefaultConfigParams::with(
979 permissionPolicy: BetaManagedAgentsAutoPolicy::with(),
980 ),
981 ),
982 ],
983 );
984 ```
985
986 ```ruby Ruby
987 agent = client.beta.agents.create(
988 name: "Ops Agent",
989 model: "claude-opus-5",
990 mcp_servers: [
991 {type: "url", name: "github", url: "https://mcp.example.com/github"}
992 ],
993 tools: [
994 {
995 type: "agent_toolset_20260401",
996 default_config: {
997 permission_policy: {type: "auto"}
998 },
999 configs: [
1000 {name: "bash", permission_policy: {type: "always_ask"}}
1001 ]
1002 },
1003 {
1004 type: "mcp_toolset",
1005 mcp_server_name: "github",
1006 default_config: {
1007 permission_policy: {type: "auto"}
1008 }
1009 }
1010 ]
1011 )
1012 ```
1013</CodeGroup>
1014
1015What you post in `user.message` events counts as your intent, and it can lead the server to allow a call it would otherwise deny. The server does not read intent from a tool result, a fetched webpage, an MCP server's response, or a message between [session threads](https://platform.claude.com/docs/en/managed-agents/multiagent-orchestration#tool-permissions-and-custom-tools). It assesses that content but does not take instructions from it. The server evaluates some calls as high-risk no matter who asks. If you relay untrusted end-user input in `user.message` events, the server reads that input as your intent too, and it can get a call allowed. Configure `always_ask` on the tools you would not let that end user run without review.
1016
1017<Warning>
1018 `auto` is not a human checkpoint. If the server determines that a call is safe, the call runs before anyone sees it, and its effects might not be reversible. If a person must review a tool's calls before they run, configure `always_ask` on that tool.
1019</Warning>
1020
1021## See how each call was evaluated
1022
1023Under any permission policy, each `agent.tool_use` and `agent.mcp_tool_use` event carries `evaluated_permission`, the outcome of the call's permission check: `"allow"`, `"ask"`, or `"deny"`. Most events also carry an `evaluation` object whose `type` names the policy that produced that outcome. Under `auto`, the object also records the server's determination, plus a `reason_code` when the outcome is `ask` or `deny`.
1024
1025For example, when `bash` is under `auto` and the server evaluates a call as high-risk, the denied call appears on the event stream as follows:
1026
1027```json
1028{
1029 "type": "agent.tool_use",
1030 "id": "sevt_01pqr...",
1031 "name": "bash",
1032 "input": {
1033 "command": "rm -rf /workspace/reports"
1034 },
1035 "evaluated_permission": "deny",
1036 "evaluation": {
1037 "type": "auto",
1038 "evaluated_permission": {
1039 "type": "deny",
1040 "reason_code": "high_risk"
1041 }
1042 },
1043 "processed_at": "2026-03-25T14:05:12Z"
1044}
1045```
1046
1047The `evaluation` object takes one of the forms in the following table.
1048
1049| `evaluation` | Top-level `evaluated_permission` | Meaning |
1050| ------------------------------------------------------------------------------------------- | -------------------------------- | ---------------------------------------------------------------------------------------- |
1051| `{"type": "always_allow"}` | `"allow"` | The resolved policy is `always_allow`, so the call ran. |
1052| `{"type": "always_ask"}` | `"ask"` | The resolved policy is `always_ask`, so the call paused for your approval. |
1053| `{"type": "auto", "evaluated_permission": {"type": "allow"}}` | `"allow"` | Under `auto`, the server determined that the call was safe, and it ran. |
1054| `{"type": "auto", "evaluated_permission": {"type": "ask", "reason_code": "indeterminate"}}` | `"ask"` | Under `auto`, the server reached no determination, so the call paused for your approval. |
1055| `{"type": "auto", "evaluated_permission": {"type": "deny", "reason_code": "high_risk"}}` | `"deny"` | Under `auto`, the server evaluated the call as high-risk and denied it. |
1056
1057When `evaluation.type` is `"auto"`, its nested `evaluated_permission.type` repeats the event's top-level `evaluated_permission`, so you can read the outcome from either field. A `reason_code` is a value for your client to branch on and keep in audit records, not text to display to end users.
1058
1059`evaluation` is absent in two cases. When the agent names a tool that is not enabled in the session, the server denies the call without evaluating a policy: the event carries `evaluated_permission: "deny"` and no `evaluation`. Events recorded before `evaluation` was introduced also omit it: read those as `always_allow` when `evaluated_permission` is `"allow"` and as `always_ask` when it is `"ask"`.
1060
1061Write your client to tolerate an `evaluation.type` or `reason_code` it does not recognize. `agent.custom_tool_use` events carry neither field, because permission policies do not govern [custom tools](https://platform.claude.com/docs/en/managed-agents/permission-policies#custom-tools).
1062
6671063## Respond to confirmation requests
6681064
669When the agent invokes a tool with an `always_ask` policy:
1065A tool call evaluates to `ask` under an `always_ask` policy, or under `auto` when the server reaches no determination. When that happens:
6701066
67110671. The session emits an `agent.tool_use` or `agent.mcp_tool_use` event.
67210682. The session pauses with a `session.status_idle` event whose `stop_reason.type` is `requires_action`. The blocking event IDs are in the `stop_reason.event_ids` array. The session waits indefinitely for a response.
67310693. Send a `user.tool_confirmation` event for each blocking event, passing the event ID in the `tool_use_id` parameter. Set `result` to `"allow"` or `"deny"`. Use `deny_message` to explain a denial. You can send several confirmations in a single `events` request.
67410704. Once all blocking events are resolved, the session transitions back to `running`. Allowed tools execute. Denied tools do not run, and the agent receives a tool result saying the call was rejected, including your `deny_message`.
1071
1072If you send a `user.tool_confirmation` for an event whose `evaluated_permission` is not `ask`, the API rejects it with a 400 error. That includes calls the server denied under `auto`: your client cannot override them.
1073
1074To answer interactively instead, use `ant beta:sessions connect`, which shows the waiting call and sends this event when you allow or deny it. See [Connect to a Managed Agents session from your terminal](https://platform.claude.com/docs/en/cli-sdks-libraries/cli/sessions-connect#follow-and-steer-the-session).
6751075
6761076In the following examples, the tool-use event IDs come from the `stop_reason.event_ids` array of the `session.status_idle` event. Learn more about receiving events in the [Session event stream](https://platform.claude.com/docs/en/managed-agents/events-and-streaming#integrating-events) guide, or [subscribe to webhooks](https://platform.claude.com/docs/en/managed-agents/webhooks) to be notified when a session pauses for input.
6771077
6781078