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, returndeny. 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:
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.
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 thestage 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.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 settingfirewall_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.
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:| Verdict | When to reach for it instead of deny |
|---|---|
audit | You want to see the tool fire but not block it yet. |
sanitize | The tool is fine but its arguments may carry secrets/PII — redacts args, never tool results. |
pending_approval | A human should approve each call out-of-band. |
cap_cost | Allow until an agent run’s spend crosses a cents cap. |
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
Dry-run before you depend on it
Dry-run before you depend on it
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.
Shadow mode for a live measurement
Shadow mode for a live measurement
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.Find the tool names from real traffic
Find the tool names from real traffic
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.
Confirm the block in the events log
Confirm the block in the events log
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/*):
| Action | Role |
|---|---|
| Read policies, presets, discovered tools, Simulate | Member |
| Dry-run a policy (Test) | Developer+ |
| Create / edit / delete rules and policies | Developer+ |
| Read the events log and run aggregates | Developer+ |
Related
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.
