RBAC
Decide which agents access which tools
Tool Access by Role
Set the rules before the agents connect, and every agent's tools/list and calls follow its role;
change them mid-run, and the next call sees the change, so an agent has to find another way.
The gateway keeps rules that turn tools off or on for a role, and applies them to every tool it
serves. They come with the gateway topology, on the card as
urn:agentenv:disable-tool/v1 and urn:agentenv:enable-tool/v1, so email and contacts know
nothing of roles.
The Caller's Role
A caller names its role in the AgentEnv-Role header, over MCP and /step alike, and a request
without the header is default. The gateway takes the header as given: a role decides what an agent
is offered, not who may connect.
Disable and Enable Tools
POST /tools/disable and POST /tools/enable take a role and its tools, a list of names or
"*" for all of them, and answer with that role's rules:
curl -sS -X POST http://localhost:61854/tools/disable -H 'content-type: application/json' \
-d '{"role": "reviewer", "tools": ["send"]}'{"role": "reviewer", "disabled": ["send"], "allowed": []}A body without a role, or with tools that is neither a list of names nor "*", gets a 400. Tool
names aren't checked, so a rule can name a tool the instance doesn't serve yet.
What a Role Sees
A tool that is off for a role is left out of that role's tools/list over MCP and list_tools over
/step. If the agent calls it anyway, the call never reaches the server: /step answers 403, and MCP
returns the same message as a tool error with isError: true.
curl -sS -X POST http://localhost:61854/step \
-H 'AgentEnv-Role: reviewer' \
-d '{"action": "call_tool", "tool_name": "send", "arguments": {"to": "sam.lee@example.com", "subject": "Q3 plan", "body": "Draft attached."}}'{"error": "Tool 'send' is disabled for role 'reviewer'"}The rules cover the gateway's own tools too, such as get_time. The gateway doesn't tell an agent
that its tools changed: its next list shows the change, and every call is checked when it arrives.
How Rules Combine
For each call, the gateway looks for four rules in order, and the first one it finds decides. A tool that none of them names is on.
| Order | Rule |
|---|---|
| 1 | The role's rule for the tool |
| 2 | The role's rule for * |
| 3 | Role *'s rule for the tool |
| 4 | Role *'s rule for * |
Enabling doesn't remove a rule, it overwrites it. Enabling a tool after disabling it leaves an
allowed rule, which comes before any rule of role *.
Wildcards overwrite more. Tools "*" replace all of the role's rules with one, role "*" also writes
its rule into every role that has rules, and "*" for both replaces every rule of every role.
Read the Rules
GET /state lists each role's rules next to the servers and their tools. The rules live in the
gateway's memory, and no request deletes one: sending "*" for both with enable leaves a single
rule that turns every tool on.
{
"roles": {
"*": {"disabled": ["send"], "allowed": []},
"reviewer": {"disabled": [], "allowed": ["send"]}
}
}From a Task
The modify_env_tool_access step sends one of these requests to a deployed env. It takes env_id, action
(disable or enable), role and tools, all required; tools is always a list, and ["*"]
means all tools.
{"id": "reviewer-no-send", "type": "modify_env_tool_access", "env_id": "office", "action": "disable", "role": "reviewer", "tools": ["send"], "depends_on": [{"task_step_id": "office"}]}The step finds the endpoint on the instance's card and fails before sending anything if the card
doesn't list the action. It records the role's rules afterwards in metadata["tool_access_changes"].
One Role per Agent
deploy_agent's role gives an agent its role,
through the agent's urn:agentenv:agent-config/v1 when that lists role among its fields. The SDK
hands it to run() as request.config.role, and the agent's own code sends it in AgentEnv-Role
on its calls to the gateway:
[
{"id": "assistant", "type": "deploy_agent", "env_ids": ["office"], "agent_name": "assistant", "role": "assistant", "depends_on": [{"task_step_id": "office"}]},
{"id": "reviewer", "type": "deploy_agent", "env_ids": ["office"], "agent_name": "reviewer", "role": "reviewer", "depends_on": [{"task_step_id": "office"}]}
]With reviewer-no-send after them, both agents share one instance, and only assistant can send.
The verify_a2a_role step checks that an agent accepts a role and reads it back, not that it sends
the header. The CLI that build_mcp_cli builds sends the value of AGENT_ENV_ROLE, or cli when
that is unset.
Change Access Mid-Run
A trigger's permission action sets the same rules when its condition fires, so a role can gain or
lose a tool partway through a run. Triggers covers the conditions and
the register_env_triggers step.
{"type": "permission", "action": "disable", "role": "assistant", "tools": ["send"]}Without the Gateway
In the server topology nothing sits in front of your server, so
there are no rules unless it implements the two extensions itself. modify_env_tool_access calls
whatever the card lists, so the same step drives either;
Env Topology Extensions compares the
two cards.
Last updated on