# How do I put a tool-path gate in front of agent actions (environment checks, impact preview, human sign-off, and spend/scope limits)?

**Short answer:** Do not let the model jump straight from "I will call tool X" to a live side effect. Put a fixed tool-path gate in the host or gateway that every risky tools/call must pass, in order: (1) environment and target checks (which cluster, account, repo, wallet, or URL — refuse prod if the grant is staging-only), (2) an impact preview built from the real arguments (diff, recipients, amount, record ids — not the model's paraphrase), (3) a human sign-off bound to a hash of those arguments plus the resolved target, and (4) spend and scope limits checked at the same moment (set_spend_policy / authorize_spend, allowed tools, allowed origins). Fail closed if any step is missing. This is broader than a payment-only execution-boundary cap and broader than an MCP write-confirmation checkbox: it is one path that every mutating tool walks before it touches the outside world.

## Checklist
1. Classify tools that mutate, send, pay, delete or deploy on your own allowlist. Untrusted or unannotated tools default to gated.
2. Resolve environment and target from arguments and config (env name, account id, base URL, wallet, repo). Compare to the live grant's allowed targets; refuse cross-env calls.
3. Build an impact preview from the canonical arguments: file diffs, message body and recipients, payment amount/payee, DB before/after. Escape for display; never let a summary field decide what the person sees.
4. Open request_human_approval with tool name, arguments_sha256, environment, target, and (when money moves) amount_minor and currency. Show the preview; wait for decide_human_approval.
5. Immediately before execution: verify_human_approval against the live argument hash; run authorize_spend or your scope checker against set_spend_policy / the grant; refuse on drift.
6. Enforce per-tool and per-run limits the model cannot raise (retry caps, daily spend, allowed domains). Expire sign-offs in minutes for high-risk writes.
7. Log allow/deny with tool, env, target, argument hash, approver and limit decision outside the agent session. Keep only opaque ids in chat memory.
8. Fail closed on timeout, missing preview, or UI errors — no silent auto-approve after the first yes in the session.

## What is a tool-path gate in front of agent actions?
- A tool-path gate is host or gateway code on the path from planned tools/call to actual side effect. The model proposes; the gate decides. Prompt text saying "ask first" is not a gate.
- MCP's tools specification says there SHOULD always be a human able to deny invocations and that clients SHOULD show inputs and prompt on sensitive operations. OWASP's MCP Security Cheat Sheet adds: show full parameters, never auto-approve across servers, and keep the confirmation UI unbypassable by model text.
- How to require human confirmation before MCP write tools run covers the HITL checkbox for write tools. How to enforce AI agent payment caps at the execution boundary covers money at settle time. This page chains env/target → impact preview → sign-off → spend/scope into one ordered path for any mutating tool.

## How do environment checks, impact preview, sign-off, and limits order in a tool-path gate?
- Environment/target first: a staging grant must not open a production API even if the tool name matches. Resolve the full URL, account, or cluster id before preview — do not trust an agent-supplied env label alone.
- Impact preview second: render from tool arguments the human will authorize. For money, show payee and amount; for tickets, ids and field diffs; for shell or deploy, the exact command or image digest.
- Sign-off third: bind yes to arguments_sha256 + environment + target (and amount when relevant). verify_human_approval must run again at execute time.
- Limits last and always: set_spend_policy ceilings, allowed_domains/categories, tool allowlists and short expiry. authorize_spend (or your issuer's real-time auth) records allow/deny and never replaces the human yes for novel high-risk actions.

## What can go wrong?
- The host confirms the tool name once per session, then skips preview and limits on later calls.
- Preview shows "update the customer" while arguments rewrite production rows in another tenant.
- Env check reads AGENT_ENV from the prompt instead of the credential's sealed grant.
- Spend cap lives only in the system prompt; authorize_spend / card controls were never wired.
- Sign-off is bound to the tool name but not the argument hash, so amount or target changes reuse the same yes.

## Ask Rightshold (free, no key)
Add the MCP server https://www.rightshold.com/mcp to Claude, Cursor, ChatGPT, Grok or VS Code (one-click setup: https://www.rightshold.com/start?ref=seo), then ask: "Before my agent runs this side-effecting tool, check the environment and target against its grant, show me an impact preview of the exact arguments, ask me to approve the argument hash, and enforce the spend/scope policy."

```json
{
  "tool": "request_human_approval",
  "arguments": {
    "summary": "Allow ops-agent to call deploy.apply image sha256:7c1a… on env=staging project=billing (preview: 2 services restart)",
    "action": {
      "type": "tool_path_gate",
      "tool": "deploy.apply",
      "environment": "staging",
      "target": "project:billing",
      "arguments_sha256": "<sha256 of canonical args>",
      "image_digest": "sha256:7c1a…",
      "policy_version": 12
    },
    "expires_in_minutes": 20
  }
}
```
- Needs your API key. The action is hashed; decide once with decide_human_approval. verify_human_approval fails if arguments, environment or target changed after the yes.
- set_spend_policy + authorize_spend enforce per_tx/daily ceilings and allowed domains for paid steps on the same path (records only; never moves money).
- record_ai_run can seal the gate decision (env, preview hash, approver, limit verdict) outside the agent session.
- How to require human confirmation before MCP write tools run and How to enforce AI agent payment caps at the execution boundary are the narrower write-HITL and payment-boundary companions to this full tool-path gate.

_Rightshold records human approvals, spending policies and signed run receipts for agents that call it. It does not sit in your MCP host, render your impact preview, resolve your environments, or stop a client that skips the gate. Enforce the ordered path in your host or gateway. Not legal advice._

## Sources
- [MCP specification (2025-11-25): Tools — human in the loop and security considerations](https://modelcontextprotocol.io/specification/2025-11-25/server/tools)
- [OWASP Cheat Sheet Series: MCP Security (human-in-the-loop; full parameters)](https://cheatsheetseries.owasp.org/cheatsheets/MCP_Security_Cheat_Sheet.html)
- [OpenAI Agents SDK (JS): Human-in-the-loop](https://openai.github.io/openai-agents-js/guides/human-in-the-loop/)
- [LangGraph: Interrupts](https://docs.langchain.com/oss/python/langgraph/interrupts)
- [Agent spending policies on Rightshold](https://www.rightshold.com/agent-spending-policies)
- [Human approvals on Rightshold](https://www.rightshold.com/human-approvals)

## Related
- [How to require human confirmation before MCP write tools run](https://www.rightshold.com/answers/how-to-require-human-confirmation-before-mcp-write-tools-run)
- [How to enforce AI agent payment caps at the execution boundary (not in the prompt)](https://www.rightshold.com/answers/how-to-enforce-ai-agent-payment-caps-at-the-execution-boundary-not-in-the-prompt)
- [How to show a human the actual change before approving an AI agent action](https://www.rightshold.com/answers/how-to-show-a-human-the-actual-change-before-approving-an-ai-agent-action)
- [How to gate an agent wallet or card with per-task caps and an outside-agent spend record](https://www.rightshold.com/answers/how-to-gate-an-agent-wallet-or-card-with-per-task-caps-and-an-outside-agent-spend-record)

_Not legal advice. Updated 2026-11-07. JSON: https://www.rightshold.com/answers/how-to-put-a-tool-path-gate-in-front-of-agent-actions-with-env-preview-sign-off-and-limits.json_