MCP Tool Rules

MCP Tool Rule Library

Practical rule patterns for real MCP servers.

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.

PatternStart withUse when
Hide a tool from the agenthidden + blockThe tool should not be part of the agent's normal tool surface.
Allow read-only toolsvisible + allow + result limitThe tool reads bounded data and should remain useful.
Require review for write-like toolsvisible or dashboard_only + review_requiredA tool may be useful, but should not run silently.
Block send/delete/update actionsblock or hidden + blockThe action can change external state and is not intended for this agent path.
Limit large resultsresult_limits.max_result_bytesSearch, list, thread, or export-style tools may return too much text.
Limit argumentsargument_rulesThe tool should only accept specific IDs, repos, recipients, statuses, or short values.
Bind writes to observed stateobservation_rules + state_bindingA 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:

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:

ExposureUse it when
visibleThe agent may see and request this tool.
dashboard_onlyOperators should inspect it, but the agent should not request it.
hiddenThe tool should not be exposed for normal agent use.
unsupportedThe 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.

ModeMeaning
allowThe call may continue through the checked decision path.
blockThe call stops before downstream execution.
review_requiredThe 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 shapeFirst rule choice
Search, list, metadata readvisible + allow + result limit
Read detail for one known resourcevisible + allow + result limit
Draft, preview, dry-run, prepare changevisible + allow or review_required
Send, publish, merge, push, delete, archive, trashblock, dashboard_only, or review_required
Raw SQL, raw HTTP, shell, admin, batch mutationhidden + 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:

DomainStronger binding fields
Emailmessage_id, thread_id, draft id, label id
GitHubowner, repo, issue_number, pull_number, branch/ref, path
Databasecustomer_id, record_id, tenant id, primary key
Ticketingticket_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:

  • version
  • updated_at
  • etag
  • head_sha
  • state_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 safe
  • sync_* only reads
  • archive_* is reversible
  • create_* is harmless
  • execute_* 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.

json
{
"downstream_tool_name": "email.search_threads",
"exposure": "visible",
"handling_mode": "generic_guarded",
"policy_input_mode": "allow",
"result_limits": {
"max_result_bytes": 32768
}
}

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.

json
{
"downstream_tool_name": "support_db.get_customer_summary",
"exposure": "visible",
"handling_mode": "generic_guarded",
"policy_input_mode": "allow",
"observation_rules": [
{
"source_tool": "support_db.get_customer_summary",
"resource_type": "customer",
"resource_field": "customer_id",
"ttl_seconds": 60,
"facts": [
{ "name": "version", "from_result_field": "version" }
]
}
]
}

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.

json
{
"downstream_tool_name": "support_db.update_customer_status",
"exposure": "visible",
"handling_mode": "generic_guarded",
"policy_input_mode": "review_required",
"state_binding": {
"observation_ref_field": "observation_ref",
"resource_type": "customer",
"resource_field": "customer_id",
"state_hash_field": "state_hash"
}
}

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.

json
{
"downstream_tool_name": "github.push_files",
"exposure": "hidden",
"handling_mode": "generic_guarded",
"policy_input_mode": "block"
}

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.

json
{
"downstream_tool_name": "github.merge_pull_request",
"exposure": "dashboard_only",
"handling_mode": "generic_guarded",
"policy_input_mode": "review_required"
}

More Playbooks

Apply the same rule patterns to concrete server surfaces: