Skip to main content
The fastest way to stop an agent from doing something dangerous is to name the tool and deny it. A deny verdict on a tool-name glob is the deny-list primitive of the agent firewall: one rule, one glob, verdict deny, attached to a key — and from then on the gateway refuses that tool on every call, with no change to your agent code. This page covers the deny-list use-case and the one decision it forces: which surface do you block on — the tools you advertise (inbound) or the tool calls the model emits (response). For the full matching vocabulary and verdict semantics, see Rule schema and Verdicts.

1. Block a tool call an ai agent makes

A deny-list rule is the simplest thing a firewall policy can express: match a tool by name, return deny. Use it when a tool should never fire for a given key — shell.exec, *.delete, a community plugin you don’t trust — regardless of arguments. In your workspace console, open a policy (or create one) and add a rule:
{
  "label": "block destructive shell",
  "tool_name_glob": "*.exec",
  "verdict": "deny"
}
The tool_name_glob is a small, case-sensitive glob — shell.* catches a whole family, *.delete catches a verb across servers, * catches everything. No argument clause is needed: a bare glob + deny blocks the tool unconditionally. Add an argument clause only when you want to allow the tool in general but deny one shape of call.
The engine walks a policy’s rules in priority order and the first match wins. Put narrow allow exceptions at a lower priority number (they run first) and your broad deny below them — e.g. allow shell.exec from a trusted builtin.* skill, deny it everywhere else. See Rule priority.

2. Inbound vs response: pick the surface

A deny can land on two different points in the request lifecycle, and the difference matters. Pin the rule with the stage field, or leave it empty to cover both.

inbound

The tools your agent advertises to the model on the request (the tool definitions). A deny here strips the tool before the model can even choose it — the model never sees it as an option.

response

The tool_calls the model emits in its reply. A deny here catches the call the model already decided to make, before it reaches the tool.
Prefer inbound when you want a tool to be invisible — the model can’t call what it was never offered, so you avoid wasted turns where it picks a tool only to be refused. Use response (or leave stage empty) when the tool legitimately appears in some requests and you want to catch the actual emitted call, or when you only control the agent loop and not the advertised tool set.
A rule with no stage applies to all surfaces — the same deny covers a tool whether it’s advertised, emitted, or dispatched through MCP. That’s the belt-and-suspenders default; pin a surface only when a deny should be scoped to one. See Stages.

3. Attach the policy and watch it fire

A policy does nothing until a key resolves to it. Attach in the console by setting firewall_policy_id on the key, or make the policy the workspace default. Resolution is: the key’s attached policy (when it exists and is enabled), else the workspace default. (A disabled attached policy falls back to the default — see Manage policies.) Once attached, a denied call on the inbound surface returns HTTP 400 with error code firewall_blocked and a reason naming the tool — e.g. tool "shell.exec" blocked by firewall. The error is marked skip-retry (re-running the identical call would just block again) and costs no model tokens, since an inbound block fires before the upstream call. A deny dispatched through the MCP gateway surfaces as a tool error instead, so the model sees the rejection and can react.
A deny on the inbound surface removes the tool from what the model is offered. If your agent framework requires a tool it advertised to be callable, blocking it inbound can confuse the loop — in that case block on response instead, so the tool stays advertised but the actual call is refused. Test the difference before you roll out (see §5).

4. Deny is one of several verdicts

Deny is the bluntest tool on the deny-list. When a hard block is too much, the same glob can carry a softer verdict:
VerdictWhen to reach for it instead of deny
auditYou want to see the tool fire but not block it yet.
sanitizeThe tool is fine but its arguments may carry secrets/PII — redacts args, never tool results.
pending_approvalA human should approve each call out-of-band.
cap_costAllow until an agent run’s spend crosses a cents cap.
All of these are documented on Verdicts. A deny-list is just the subset where the verdict is deny. For an allow-list posture (deny everything, permit a named set) flip the policy’s default_verdict to deny and add narrow allow rules — see Tool allow-listing.

5. Roll it out safely

The console Test tab dry-runs a policy against a sample tool call and returns the verdict, the matched rule, and the reason — nothing is dispatched, nothing is persisted. Confirm your glob matches the tool you meant (and only that tool) before attaching a key. See Test rules.
Turn on shadow mode on the policy and every enforcing verdict — including your deny — is downgraded to audit, reason prefixed [shadow] would …. You measure exactly what the deny would block against real traffic, then flip shadow off to enforce.
Not sure of the exact tool name to glob? The Discovered Tools view lists every tool the workspace has seen, flagged covered or gap. Author your deny straight off the names that actually showed up. See Analytics.
Every evaluation writes a firewall event with the verdict, surface, tool, and matched rule. After you enforce, filter the events log by verdict deny to see the rule firing on the calls you expected.

6. Who can do what

All deny-list configuration runs in the console under your session (/api/workspace/firewall/*):
ActionRole
Read policies, presets, discovered tools, SimulateMember
Dry-run a policy (Test)Developer+
Create / edit / delete rules and policiesDeveloper+
Read the events log and run aggregatesDeveloper+
Authoring or changing a deny rule is a Developer+ write, and so is the console Test dry-run. Reading a policy and the read-only Simulate (“what-if”) view are open to every member.

Glob syntax

Exactly how shell.*, *.exec, and *.shell.* match.

Tool allow-listing

The inverse posture: default-deny, permit a named set.

Validate arguments

Deny only one shape of call, not the whole tool.

Dangerous tool calls

The threat a deny-list addresses.

Verdicts

What deny and its softer siblings do on the wire.

Firewall reference

The full rule + matching reference.