Lesson 3 of 6
Agent-side controls: permissions, sandboxing, MCP policy and hooks
9 min
Listen to this lesson
The second layer lives in the agent's own software, on the developer's machine. This lesson uses Claude Code because Anthropic documents its controls in detail, then states the same principles in vendor-neutral terms so you can apply them to any agent. Everything here was checked against Anthropic's documentation in October 2026; Claude Code changes often, so recheck before you roll out.
Permission modes
| Mode | Behavior (Anthropic docs) | Use on SAP work |
|---|---|---|
| default (labeled Manual) | Prompts on first use of each tool; read-only commands run | Normal interactive work |
| acceptEdits | Auto-accepts file edits and common filesystem commands in the working directories | Local files only; doesn't change MCP tool prompts |
| plan | Reads and explores; doesn't edit source files until you approve a plan; where auto mode is available, classifier-approved commands can also run | Analysis of findings before any change |
| auto | A classifier reviews actions instead of the user; explicit ask and deny rules still apply | Only if your organization allows it; can be turned off |
| dontAsk | Denies anything that would prompt; pre-approved tools still run | Non-interactive runs with a tight allow list |
| bypassPermissions | Skips prompts | Never on SAP-connected machines; Anthropic says isolated containers or VMs only |
Claude Code permission modes and how Contoso uses them.
Organizations can stop the riskiest modes: setting permissions.disableBypassPermissionsMode or permissions.disableAutoMode to "disable", ideally in managed settings where users can't override it.
Which mode a session starts in
The starting mode changed in 2026, and it matters for SAP work. Anthropic's documentation says that from Claude Code v2.1.283, auto is the built-in starting mode for interactive terminal and VS Code sessions. Two details decide where you pin something else. A project's .claude/settings.json can set defaultMode for terminal sessions, but it can't set auto or bypassPermissions, and sessions the VS Code extension starts don't read project settings for the starting mode at all; the extension reads its own claudeCode.initialPermissionMode setting, then permissions.defaultMode from managed or user settings. So a mode pinned only in the repository protects terminal users and silently misses VS Code users.
| Goal | Where Contoso sets it | Covers |
|---|---|---|
| Start every session in Manual | permissions.defaultMode: "default" in managed settings | Terminal and VS Code sessions on managed laptops |
| Nobody can switch to auto | permissions.disableAutoMode: "disable" in managed settings (Contoso's pilot policy) | Every surface; sessions then start in Manual |
| No bypass, ever | permissions.disableBypassPermissionsMode: "disable" in managed settings | Every surface; deny rules still apply in any mode |
| Repository default for analysis work | defaultMode: "plan" in the project's .claude/settings.json | Terminal sessions only; VS Code users need their own setting |
Pinning the permission mode for SAP work (Claude Code behavior checked against Anthropic's documentation, October 2026).
Permission rules
Rules come in three lists, deny, ask and allow, and Claude Code evaluates them in that order; the first match wins, and a broad deny can't be carved out by a narrower allow. A bare tool name in deny removes the tool from the agent's context entirely. MCP tools are named mcp__<server>__<tool>, so if the ADT MCP server is configured under the name adt, its tools appear as mcp__adt__abap_activate_objects and so on.
| List | Contoso rule | Why |
|---|---|---|
| deny | mcp__adt__abap_atc_exemption_request | ATC exemptions are a human decision |
| deny | Read(./.env), Read(~/.ssh/**) | Keep secrets out of context |
| deny | Bash(curl *), Bash(wget *) | No ad-hoc network calls; paired with sandbox network rules |
| deny | mcp__adt__abap_feed_query | Dumps, error logs and system messages can show other users' runtime errors and business data |
| ask | mcp__adt__abap_transport_create_request, mcp__adt__abap_object_run_action | A person confirms new requests and custom actions |
| allow | mcp__adt__abap_repository_search_object, mcp__adt__abap_object_check, mcp__adt__abap_run_unit_tests, mcp__adt__abap_run_atc, mcp__adt__abap_atc_get_result, mcp__adt__abap_transport_get_unified_diff | Read, check and test without prompts |
Example permission rules for SAP's ADT MCP server tools (Contoso design; tool names from SAP's MCP tool list).
Managed settings and MCP policy
Managed settings sit at the top of Claude Code's settings precedence: no user, project or command-line setting can override them, and a deny at any level can't be allowed elsewhere. allowManagedPermissionRulesOnly makes managed settings the only source of permission rules. For MCP servers, administrators can deploy managed-mcp.json for a fixed set, or use allowedMcpServers with allowManagedMcpServersOnly: true for an approved catalog. Entries match by serverUrl or serverCommand; Anthropic warns that serverName entries aren't a security control because users choose names. Contoso's catalog allows the ADT MCP server by URL for both IDEs it supports: http://localhost:2236/* for ADT for VS Code, the default in the pilot setup, and http://localhost:2234/* for ADT for Eclipse. Both are SAP's default ports, so a developer who has to change the port asks for a catalog update first. The catalog also allows the pinned commands of the CAP, UI5 and Fiori servers from sap-aid-205.
Sandboxing and hooks
Permission rules match commands as written; Anthropic notes that a deny rule doesn't stop a program run by path or inside another shell. For enforcement at the operating system level, Claude Code's sandbox isolates Bash commands' filesystem and network access. Hooks add custom logic: a PreToolUse hook receives JSON with fields such as session_id, tool_name and tool_input, and exit code 2 blocks the call, with stderr shown to the agent as the reason. Hooks don't override deny rules, and a hook that times out doesn't block by default, so use permissions for hard allow or deny and hooks for checks and logging. Administrators can set allowManagedHooksOnly so that only managed hooks run, and ConfigChange hooks can audit or block settings changes during a session.
Contoso deploys one managed hook for the ADT tools (matcher mcp__adt__.*). It appends every call's session id, tool name and input to a local log that is shipped to the central log store (lesson 4), and it blocks calls whose input names an ABAP project or destination other than the CMD agent project, as a second line behind the ADT access restrictions.
| Principle (any agent) | Claude Code mechanism | SAP-side counterpart |
|---|---|---|
| Least privilege by default | Manual mode; deny-first rules; bypass disabled | Agent role without release, debug change or user admin |
| Central policy users can't loosen | Managed settings, allowManagedPermissionRulesOnly | Roles maintained by security, not by developers |
| Approved tools only | managed-mcp.json or allowedMcpServers by URL or command | ADT MCP access restrictions on projects and packages |
| Human approval for risky actions | ask rules; prompts in Manual mode | Human release of transports; ATC exemptions by quality experts |
| Isolation | Sandbox for Bash; containers or VMs for unattended runs | Development system and client only |
| Observable | Hooks and OpenTelemetry | Security Audit Log, version history, transport logs |
- Use Manual or plan mode for SAP work; disable bypass and, if policy requires, auto mode in managed settings.
- Rules evaluate deny, then ask, then allow; ADT MCP tools are addressed as mcp__server__tool.
- Approve MCP servers by URL or command, not by name; managed settings can't be overridden.
- CLAUDE.md guides; permissions, sandbox, hooks and SAP authorizations enforce.
Check your understanding · not graded
Lesson check
1. In which order does Claude Code evaluate permission rules?
2. How would you write a rule for the ADT MCP tool abap_run_atc on a server configured as "adt"?
3. What happens when a PreToolUse hook exits with code 2?
4. Why don't serverName entries make a reliable MCP allowlist?