Tool rules

tool_deny and tool_allow match against every tool name in the request. That is one list, and it deliberately does not distinguish where a tool came from, because the wire does not either.

A Claude Code turn’s tools array holds its own tools (Bash, Read, Edit, Task), the flattened tools of every local MCP server (mcp__github__create_pull_request), and any provider-side built-in it has enabled (web_search). To the model they are all just callable functions, so to policy they are all just names.

What a coding agent typically declares

Names are the agent’s to choose and do change between versions — read your own inventory rather than trusting a list in a document. As a starting point:

AgentShape of its tool names
Claude CodeBash, Read, Write, Edit, Glob, Grep, Task, WebFetch, WebSearch, Skill; MCP as mcp__<server>__<tool>
Codex CLIapply_patch, local_shell, web_search; remote MCP as a separate {"type":"mcp"} entry
CursorMCP as mcp_<server>_<tool>

Denying a tool

vulnetix ai-firewall policy guardrail no-shell \
  --rule-type tool_deny --action flag --pattern 'Bash' \
  --priority 100 --enable

At flag this records every session that offers shell execution. At block it refuses those sessions outright. At strip it removes Bash from the array so the model is never offered it, and the session continues without it.

Warning

A tool rule cannot stop a command that already ran.

Bash executes on the developer’s machine. The firewall sees the request that carries the result back, not the execution. What a rule can do is stop the tool being offered on this and every later turn, so the model cannot call it again — and refuse a request whose history shows it was called, so the output never reaches the model.

That is a real control. It is not the control people assume from the name, so it is worth being precise about which one you are buying.

Allowlisting tools

Any enabled tool_allow rule switches the whole tool family into allowlist mode: every tool not matched by an allow rule is refused.

vulnetix ai-firewall policy guardrail read-only-agents \
  --rule-type tool_allow --action block --pattern 'Read' --priority 100 --enable
vulnetix ai-firewall policy guardrail read-only-agents-grep \
  --rule-type tool_allow --action block --pattern 'Grep' --priority 100 --enable

This is strict, and on agent traffic it is stricter than it looks: an agent whose tool list gains one entry in a point release starts failing. Run it at flag first and read what it would have refused.

Blocking a whole MCP server through its tools

A local stdio MCP server has no separate identity on the wire — its tools are already flattened into the array. The prefix is how you reach it:

vulnetix ai-firewall policy guardrail no-jira \
  --rule-type tool_deny --action strip --pattern 'mcp__jira__*' \
  --priority 100 --enable

That is a naming convention, not a protocol guarantee. See MCP servers for what it can and cannot promise.

Narrowing by verb

Tool names are usually verb-shaped, which makes a useful middle ground between “all of this server” and “one specific tool”:

# any destructive MCP tool, from any server
--rule-type tool_deny --action block --pattern '*__delete_*'

Read that as a heuristic. remove_issue and purge_cache do not match it, and delete_draft does. It is a good tripwire and a poor boundary — which is exactly why the shipped blueprint for it is set to flag.