define_subagent exposes permission flags (enable_mcp_tools, enable_write_tools, enable_subagent_tools) but they are not enforced at runtime. Subagents always inherit the parent's full MCP toolset regardless of flags, and write tools are always denied even when the flag is true.
Steps to reproduce
- Configure an agent with a custom MCP stdio server exposing a
get_secret_word tool (returns "vodka")
- Define two subagent types via
define_subagent:
mcp_yes: enable_mcp_tools=true
mcp_no: enable_mcp_tools=false
- Invoke each with prompt: "Call get_secret_word and report the result"
- Both subagents successfully call the MCP tool and return
"vodka"
Results
Tested with gemini-3.1-pro-preview-customtools, reproduced 3 times consistently.
| Subagent |
enable_mcp_tools |
enable_write_tools |
MCP call |
Write call |
| parent |
n/a |
n/a |
✅ "vodka" |
n/a |
mcp_yes |
true |
false |
✅ "vodka" |
n/a |
mcp_no |
false |
false |
✅ "vodka" |
n/a |
writer |
false |
true |
n/a |
❌ denied |
enable_mcp_tools=false is not enforced — mcp_no called mcp_secret_get_secret_word identically to mcp_yes
enable_write_tools=true is not enforced — writer subagent's edit_file was denied. The parent's policies=[policy.allow_all()] does not propagate to subagents.
Impact
Agents cannot create least-privilege subagents. Any subagent gets the parent's full MCP toolset, bypassing the intended isolation. A subagent meant for read-only research gets access to IDE write tools, external APIs, etc. This is a security boundary violation.
Investigation: how the flags were discovered
The flags are present in the Go harness binary (found via strings localharness):
EnableMCPTools json:"enable_mcp_tools,omitempty"
jsonschema_description:"Set true to enable the subagent to call MCP tools."
enable_write_tools json:"enable_write_tools,omitempty"
jsonschema_description:"Set true to equip the subagent with tools to create and edit files, and run commands."
enable_subagent_tools json:"enable_subagent_tools,omitempty"
jsonschema_description:"Set true to equip the subagent with tools to define and invoke its own subagents"
The define_subagent tool accepts these flags without error — they're part of the JSON schema. The harness just doesn't enforce them.
The invoke_subagent tool takes a Subagents array, each with TypeName, Role, Prompt, and optional Workspace (inherit/branch/share). The Workspace flag controls filesystem isolation but has no bearing on tool access.
Built-in subagent types (research, self, Coder, CodeReviewer, PlanReviewer, InvestigationReviewer, Planner, owl) are also present in the binary. The SDK example (examples/getting_started/subagents.py) enables subagents but doesn't demonstrate or document the permission flags.
Reproduction code
MCP server (secret_mcp_server.py):
from fastmcp import FastMCP
mcp = FastMCP("secret")
@mcp.tool()
def get_secret_word() -> str:
\"\"\"Returns the secret word. Call this to prove you have MCP access.\"\"\"
return "vodka"
if __name__ == "__main__":
mcp.run(transport="stdio")
Test script (key parts of subagent_isolation.py):
config = LocalAgentConfig(
model="gemini-3.1-pro-preview-customtools",
capabilities=types.CapabilitiesConfig(enable_subagents=True),
policies=[policy.allow_all()],
mcp_servers=[
types.McpStdioServer(name="secret", command=python, args=[mcp_server]),
],
)
async with Agent(config) as agent:
# Turn 0: verify MCP works from parent
r = await agent.chat("Call get_secret_word MCP tool and tell me the result.")
# Returns "vodka" ✓
# Turn 1: define subagents with different flags
r = await agent.chat(
"Define 3 subagent types using define_subagent:\\n"
"1. name='mcp_yes', enable_mcp_tools=true, enable_write_tools=false\\n"
"2. name='mcp_no', enable_mcp_tools=false, enable_write_tools=false\\n"
"3. name='writer', enable_mcp_tools=false, enable_write_tools=true"
)
# Turns 2-4: invoke each subagent separately
# mcp_yes: gets "vodka" ✓ (expected)
# mcp_no: gets "vodka" ✓ (BUG — should be denied)
# writer: edit_file denied (BUG — should be allowed)
Full scripts: spike/subagent_isolation.py, spike/secret_mcp_server.py
Environment
- SDK: google-antigravity (latest from PyPI as of 2026-06-15)
- Model: gemini-3.1-pro-preview-customtools
- Platform: macOS 26, Python 3.14
- fastmcp 3.4.2 (for test MCP server)
define_subagentexposes permission flags (enable_mcp_tools,enable_write_tools,enable_subagent_tools) but they are not enforced at runtime. Subagents always inherit the parent's full MCP toolset regardless of flags, and write tools are always denied even when the flag istrue.Steps to reproduce
get_secret_wordtool (returns"vodka")define_subagent:mcp_yes:enable_mcp_tools=truemcp_no:enable_mcp_tools=false"vodka"Results
Tested with
gemini-3.1-pro-preview-customtools, reproduced 3 times consistently.enable_mcp_toolsenable_write_tools"vodka"mcp_yestruefalse"vodka"mcp_nofalsefalse"vodka"writerfalsetrueenable_mcp_tools=falseis not enforced —mcp_nocalledmcp_secret_get_secret_wordidentically tomcp_yesenable_write_tools=trueis not enforced —writersubagent'sedit_filewas denied. The parent'spolicies=[policy.allow_all()]does not propagate to subagents.Impact
Agents cannot create least-privilege subagents. Any subagent gets the parent's full MCP toolset, bypassing the intended isolation. A subagent meant for read-only research gets access to IDE write tools, external APIs, etc. This is a security boundary violation.
Investigation: how the flags were discovered
The flags are present in the Go harness binary (found via
strings localharness):The
define_subagenttool accepts these flags without error — they're part of the JSON schema. The harness just doesn't enforce them.The
invoke_subagenttool takes aSubagentsarray, each withTypeName,Role,Prompt, and optionalWorkspace(inherit/branch/share). TheWorkspaceflag controls filesystem isolation but has no bearing on tool access.Built-in subagent types (
research,self,Coder,CodeReviewer,PlanReviewer,InvestigationReviewer,Planner,owl) are also present in the binary. The SDK example (examples/getting_started/subagents.py) enables subagents but doesn't demonstrate or document the permission flags.Reproduction code
MCP server (
secret_mcp_server.py):Test script (key parts of
subagent_isolation.py):Full scripts: spike/subagent_isolation.py, spike/secret_mcp_server.py
Environment