MCP Tool Rules sit in front of a downstream MCP Server. They decide what happens when an agent asks to use a tool:
Can the agent see this tool? Can it call the tool now? Should the call be allowed, reviewed, or blocked? Should the result or arguments be limited? Should a write match something the agent just read?
Use this page when you want practical rule patterns for a real MCP Server. The examples are rule configs using the current policy JSON fields. Keep those field names unchanged in your own files, especially policy_input_mode, exposure, handling_mode, argument_rules, observation_rules, and state_binding.
For the field-level reference and the first local email rule config, see MCP Tool Rules Reference.
One Concrete Example
For an email-like MCP Server, a useful first rule config might say:
search threads visible + allow + result limit read thread visible + allow + result limit create draft visible + review_required or allow send email hidden or visible + block delete/trash hidden + block
That means the agent can still do useful read work, but send/delete-style tools do not silently reach the downstream server. This is the main idea behind MCP Tool Rules: keep the useful tools working, and put tighter rules around tools that can change state, send data, or return too much information.
Quick Rule Patterns
Use these as starting points after you discover the exact tool names from your MCP Server.
| Pattern | Start with | Use when |
|---|---|---|
| Hide a tool from the agent | hidden + block | The tool should not be part of the agent's normal tool surface. |
| Allow read-only tools | visible + allow + result limit | The tool reads bounded data and should remain useful. |
| Require review for write-like tools | visible or dashboard_only + review_required | A tool may be useful, but should not run silently. |
| Block send/delete/update actions | block or hidden + block | The action can change external state and is not intended for this agent path. |
| Limit large results | result_limits.max_result_bytes | Search, list, thread, or export-style tools may return too much text. |
| Limit arguments | argument_rules | The tool should only accept specific IDs, repos, recipients, statuses, or short values. |
| Bind writes to observed state | observation_rules + state_binding | A write should only run against the resource and state the agent just inspected. |
These patterns are not safety guarantees. They only describe what MCP Boundary can check for MCP calls that actually pass through it.
For email tools, treat message_id and thread_id as scope bindings unless the server also exposes a stable state field. The copyable hard state_binding examples in this library use database-style records because those surfaces commonly expose versions, timestamps, or state hashes.
Pick A Server Playbook
After you understand the basic patterns, pick the playbook closest to your MCP Server:
- Local Email Demo MCP Tool Rules - learn the basic read/draft/send-block flow without a real provider.
- Taylor Gmail MCP Tool Rules - apply read, draft, send, label, and thread bindings to a Gmail-like surface.
- Database MCP Tool Rules - use exact record IDs, versions, and state hashes for read-then-write flows.
- GitHub MCP Tool Rules - keep issue reads separate from comments, file writes, pushes, and merges.
What MCP Tool Rules Can Do
A rule config can control the MCP call that passes through MCP Boundary.
Common controls:
- make a discovered tool visible to the agent
- keep a tool dashboard-only or hidden
- allow a call to continue through the checked decision path
- block a call before downstream execution
- mark a call as
review_required - require simple top-level argument rules
- limit large results
- record selected facts from a read result
- require a later write to reference previously observed state
- apply runtime limits for repeated calls
Rules do not make a downstream server intrinsically safe. They control what MCP Boundary can see: the MCP tool call, selected arguments, configured rule file, decision path, downstream execution status, and recorded outcome.
Visibility Rules
Visibility decides whether a tool is part of the normal agent-facing surface.
Common choices:
| Exposure | Use it when |
|---|---|
| visible | The agent may see and request this tool. |
| dashboard_only | Operators should inspect it, but the agent should not request it. |
| hidden | The tool should not be exposed for normal agent use. |
| unsupported | The tool was discovered, but the current runtime should not offer it. |
Visibility is not the same as permission. A visible tool still needs a handling mode and policy input mode. Hidden or dashboard-only tools are useful when a server exposes broad admin, delete, raw, or mutation tools that should not be in the agent's normal vocabulary.
Allow, Block, Review Required
policy_input_mode controls what happens when a requestable tool is called.
| Mode | Meaning |
|---|---|
| allow | The call may continue through the checked decision path. |
| block | The call stops before downstream execution. |
| review_required | The call is not treated as normal allowed work. |
Current limitation: the dashboard does not provide an approve/reject queue. Treat review_required as "do not execute silently" rather than as a clickable approval workflow.
Use allow for reads and carefully bounded writes. Use block for actions you do not want to happen from this agent path. Use review_required when a tool is useful but needs a separate human or application workflow before execution.
Read Vs Write
Classify tools by their strongest possible effect, not by whether the name sounds harmless.
Useful starting point:
| Tool shape | First rule choice |
|---|---|
| Search, list, metadata read | visible + allow + result limit |
| Read detail for one known resource | visible + allow + result limit |
| Draft, preview, dry-run, prepare change | visible + allow or review_required |
| Send, publish, merge, push, delete, archive, trash | block, dashboard_only, or review_required |
| Raw SQL, raw HTTP, shell, admin, batch mutation | hidden + block |
Reads are not automatically safe. A broad read can leak too much data, so add result limits and argument rules when the tool can return large or sensitive results.
Writes are not all equal. Creating a local draft is very different from sending an email. Adding a label is different from permanent deletion. Updating a synthetic demo record is different from writing to a production system.
Scope Binding
Scope binding means the action must target exactly the resource that was read, selected, or confirmed.
Examples:
- only this email message
- only this email thread
- only this issue number
- only this pull request
- only this customer record
- only this repository and path
Good scope bindings use stable identifiers:
| Domain | Stronger binding fields |
|---|---|
| message_id, thread_id, draft id, label id | |
| GitHub | owner, repo, issue_number, pull_number, branch/ref, path |
| Database | customer_id, record_id, tenant id, primary key |
| Ticketing | ticket_id, project id, queue id |
Weak bindings rely on text that can drift or collide:
- subject line only
- display name only
- "the latest email"
- "the issue about billing"
- row number in a table view
- last thing the agent mentioned
In rule configs, simple scope restrictions usually start with argument_rules. For read-then-write flows, use observation_rules and state_binding when the server's tool surface provides stable fields.
Email note: message_id and thread_id are useful scope bindings. They do not by themselves prove the thread has not changed since it was read.
Stale-State Binding
Stale-state binding means a write may proceed only if the relevant state still matches what was previously read.
The problem:
1. The agent reads a record. 2. Time passes. 3. Someone else changes the record. 4. The agent writes based on the old view.
The safer pattern:
Read -> record bounded observation -> write with observation reference -> reject or review if state changed
Good stale-state fields:
versionupdated_atetaghead_shastate_hash- last message id
- message count
- provider history id
Database tools are usually the clearest stale-state demo because they often have versions, update timestamps, or hashes. Email servers can support lighter thread/message binding, but many do not expose a hard version field. GitHub rules often bind writes to head_sha, file sha, branch/ref, issue number, or pull request number.
Do not model Gmail or email state_binding as a hard stale-state check unless the selected downstream MCP Server returns a stable state fact such as a provider history id, last message id, message count, or thread state hash. If it does not, keep email examples framed as scope binding plus blocked or reviewed send/delete actions.
Retry And Re-Check
Do not treat retry as automatically safe.
If a call failed before downstream dispatch, a retry may be harmless. If a call may have reached the downstream server, retry can duplicate a side effect:
- send the same email twice
- post the same comment twice
- create duplicate tickets
- apply the same label or mutation to a changed record
- retry a merge after the branch changed
Before retrying a write, re-check current state and re-run the rule decision against that state. If the previous result is uncertain, verify the provider or system state before attempting the action again.
Why Tool Names Are Not Enough
Tool names are hints, not proof.
Bad assumptions:
get_*always means safesync_*only readsarchive_*is reversiblecreate_*is harmlessexecute_*is acceptable if the description sounds friendly
If a downstream MCP Server hides a destructive internal effect behind a harmless-looking outer tool, classify the outer tool by the strongest effect it can cause. MCP Boundary cannot separately inspect every internal downstream operation unless that operation is exposed as a separate MCP call that passes through the Boundary.
Limits And Non-Claims
MCP Tool Rules are one layer of control. They are not a general security promise.
MCP Boundary evaluates MCP calls that actually pass through MCP Boundary. It does not automatically see:
- direct calls from the agent to the original server if both entries are active
- provider-side automations triggered after the MCP Server runs
- hidden internal downstream tool chaining
- external systems modified outside the MCP call
Do not use rule examples to claim:
- production security
- data-loss prevention
- prompt-injection protection
- hosted multi-tenant isolation
- universal Gmail, GitHub, database, or cloud support
- safe-by-default sending, deletion, merging, or publishing
Use Tested Servers, Evidence, And Limits for the exact evidence standard.
Example Rule Configs
1. Read With A Result Limit
Use this for search/list/read tools that can return too much data.
The agent can see and request email.search_threads. MCP Boundary allows the call through the checked path, but caps the result size. This does not prove the tool is safe or that the returned data is non-sensitive.
2. Prepare But Do Not Publish
Use this when one tool creates a draft, preview, ticket, or local change, while a separate tool performs the external effect.
The agent can prepare work, but send/publish actions are not normal automatic work. This does not guarantee the draft is harmless; it only separates preparation from the external effect.
create draft visible + allow send draft dashboard_only + block direct send hidden + block
This is useful for email, publishing, repository changes, and support workflows.
3. Read Then Write The Same Resource
Use this when the write must refer to the exact resource the agent inspected.
The read rule records bounded facts from support_db.get_customer_summary. The agent can request the read, and MCP Boundary can record selected facts for a short time. This does not guarantee the whole database row is safe to write; it only creates a bounded observation for later checks.
The write rule requires the later call to reference that observation. In this example, the write is still review_required, so it is not normal automatic work. If you change a state-bound write to allow, test both matching and mismatched state paths first.
4. Hide Broad Mutation Tools
Use this for tools that can mutate many targets or accept freeform commands.
The agent cannot see github.push_files as a normal tool, and MCP Boundary blocks the call before downstream execution if it is requested through this path. This does not remove other direct routes to the original MCP Server; make sure the agent is configured to use MCP Boundary instead of the original server directly.
Do the same for raw SQL, batch modify, repository deletion, permanent delete, shell-like tools, and broad admin actions.
5. Review Before Irreversible Effects
Use this when a tool is not safe as a normal automatic action but you still want to document that it exists.
The dashboard can show github.merge_pull_request, but the call is not treated as normal allowed work. In the current release, this is a stop signal, not a dashboard approval button.
More Playbooks
Apply the same rule patterns to concrete server surfaces: