Repository navigation
feat(agents): select an agent's own tools at deploy, and claude-code's - #437
Merged
earakely-scale merged 7 commits intoNov 2, 2026
Conversation
A task can now say which of an agent's own tools it may use: deploy_agent takes builtin_tools, {"disable": "*"},
{"disable": [names]} or {"only": [names]}. It travels on agent-config/v1, as configuration does. The protocol's
BuiltinTools types the field over a Literal of the agent's tools, so the card's schema names them, and its enabled()
says what a selection leaves on. deploy_agent refuses, before any request, an agent whose agent-config has no
builtin_tools or a selection naming a tool its schema doesn't.
claude-code names the pinned CLI's 24 tools and turns a selection into --tools with the tools left on, plus
--strict-mcp-config, so its model is offered only those and the task env's MCP servers. The bench needs
{"disable": "*"} for its GUI-only rule.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ploy_agent's check needs no A2AAgent The claude-code image installs the newest released agentenv-framework-protocol, which has no BuiltinTools yet, so the agent declares the same fields and checks itself until its floor can be raised. The builtin_tools check takes the agent-config extension from its caller, since deploy_agent imports A2AAgent only inside execute. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…to turn off keeps the rest at their defaults In the agent's container the CLI's default tools depend on the model (the fake one gets no Task tools) and gain the three MCP resource tools when MCP servers are attached, so the card names every tool the CLI has, and the test checks the CLI offers nothing it doesn't name. A disable list now goes to --disallowedTools, so the rest keep the CLI's defaults instead of every named tool being turned on; "*" and only stay a --tools list. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…every turn Chaos testing restarted the claude-code container between two turns: the second turn offered all the CLI's own tools again, since the selection lived only in the agent's memory. prompt_agent now sends the selection deploy_agent recorded on the agent's card with each turn's config, so a restarted agent has it before the turn runs. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
An agent whose agent-config takes builtin_tools could advertise it and never enforce it, and validation would pass.
The new verify_a2a_builtin_tools step deploys a second agent with {"disable": "*"} and no envs, so any tool call it
makes is one of its own: asked to run a shell command it must make none (or, reporting no count, say it has no tool),
an unknown tool must be refused, and agent-config must read the selection back. The validation agent itself is never
limited, since the other checks need its tools. An agent without the field is recorded as not supporting it.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…eld to the protocol and the pinned CLI - ClaudeCodeTool and ClaudeCodeTools move into claude_bridge, so the CLI command takes the typed selection instead of a dict a2a_server dumped and the bridge read back by key. - A test holds ClaudeCodeTools to the protocol's BuiltinTools[ClaudeCodeTool] schema, so the copy can't drift. - TOOLS_CLI_VERSION records the CLI the tool names were taken from; a test fails when the Dockerfile's CLAUDE_CODE_VERSION moves without it. - BuiltinTools loses enabled(), which nothing called. Also from the validator e2e on a VM: the builtin_tools check now reads a selection back without the fields an agent leaves unset (the protocol's readback returns them as null), and the episode rules count the new step among the agent validator's. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
earakely-scale
deleted the
edgararakelyan/fd-4351-m26-claude-code-limited-to-the-computer-envs-mcp-tools
branch
November 2, 2026 06:07
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
A task can now choose which of an agent's own tools it may use, at deploy:
{"id": "agent", "type": "deploy_agent", "env_ids": ["desktop"], "builtin_tools": {"disable": "*"}}{"disable": "*"}turns off every built-in tool,{"disable": ["WebFetch"]}just those, and{"only": ["Read"]}keeps just those. The bound envs' MCP tools, and agentenv's own when a prompt asks for them, are not the agent's own tools and are never affected. The bench needs{"disable": "*"}for its GUI-only rule.agent-config/v1:BuiltinToolstypes the field over aLiteralof the agent's tools, so the card's agent-config schema names them.deploy_agenttakesbuiltin_toolsand checks its shape when the step is built.builtin_tools, or if the selection names a tool the card's schema doesn't (for example "'Glob' is not one of [...]").prompt_agentsends it again with every turn's config, so an agent whose container restarted since its deploy doesn't get its own tools back. Chaos testing caught this: after a restart between two turns, the second turn offered all the CLI's tools.Agent, which--toolsalso accepts."*"andonlybecome a--toolslist (--tools ""for none). A disable list becomes--disallowedTools, so the other tools keep the CLI's defaults rather than all being turned on.--strict-mcp-config, so MCP servers from the agent's own settings files go too.BuiltinToolsyet, so claude-code carries a copy of the type (ClaudeCodeToolsinclaude_bridge.py) until its protocol floor can be raised. A test holds the copy to the protocol type's schema.TOOLS_CLI_VERSIONrecords the CLI the tool names came from, and a test fails when the Dockerfile'sCLAUDE_CODE_VERSIONmoves without it.verify_a2a_builtin_tools). Otherwise an agent could advertisebuiltin_toolswithout enforcing it and still pass validation.{"disable": "*"}and no envs, so any tool call it makes is one of its own. Asked to run a shell command, it must make none, or, if it reports no count, reply that it has no tool.Tests
BuiltinToolson an agent's card: its names in the schema, exactly one ofdisableandonly, and an unknown name answered with a 400."*", an only list, an empty only list and a disable list;builtin_tools;deploy_agentrecorded; an agent deployed without one is sent none.run_bundle_claude_code_test.py): the shipped claude-code against the fake Anthropic endpoint. Each case first runs with no selection to record the CLI's defaults in that environment."*", it offers only the echo env's MCP tool, and the call to it still works.{"disable": ["WebFetch"]}, it offers the defaults minus WebFetch.{"only": ["Read", "TaskList"]}, it offers just those two, including a tool that's off by default.Part of FD-4351 (M2.6). Design doc: CUA Env: claude-code limited to MCP tools (M2.6).
🤖 Generated with Claude Code


Confidence Score: 5/5
The PR appears safe to merge; no blocking findings remain.Summary
Adds
builtin_toolsselection at deploy and keeps it in each turn’s config. Claude Code turns the selection into CLI flags, while the validator checks that agents honor it.Diagram
%%{init: {'theme': 'neutral'}}%% flowchart LR A["deploy_agent: builtin_tools"] --> B["Check agent card schema"] B --> C["Send config and record selection"] C --> D["prompt_agent resends selection each turn"] D --> E["Claude Code applies CLI tool flags"]Reviews (6) · Last reviewed commit: "test: drop an unused import from the bui..." · Reviewed by Greptile