Gate Sensitive MCP Tool Calls With Human Approval in Coding Agent Runs
Last reviewed: 2026-08-13
Direct answer
Put an approval gate immediately before an MCP tool dispatch. Let the coding agent propose a call, but make the host or gateway decide whether that exact call can run. Start with a current inventory of servers and tools, classify the operation by its side effect and data destination, and apply an explicit allow, ask, or deny rule. Low-risk reads can proceed within a narrow scope. Writes, external actions, data exports, access changes, and deployment operations should pause for a person. Calls outside the task scope should be denied.
The MCP tools specification says that tools are model-controlled, while recommending a human in the loop who can deny tool invocations. It also recommends clear tool indicators, confirmation prompts, input validation, access controls, rate limits, output validation, and audit logging. That is the right boundary: a model can describe intent, but it cannot prove that a side effect is authorized. A prompt instruction such as ask before changing anything is useful guidance, not enforcement.
A useful approval request is bound to one pending call. It should show the trusted server label, tool name, concise purpose, risk class, destination or scope, safe argument summary, expiry time, and policy revision. Store a digest of the approved arguments rather than raw private data in the main event record. The reviewer can approve, reject, or let the request expire. Approval dispatches only the reviewed call. Rejection returns a clear cancellation to the run. Expiry fails closed.
Operator workflow
Discover and classify. At startup, list each server’s available tools and record the server identity, tool names, descriptions, schemas, and manifest revision. Refresh the inventory when a server reports a changed tool list. Mark every tool as read-only, mutating, externally visible, or destructive. A tool that sounds like a lookup can still send sensitive output elsewhere, so classify output destination as well as verb.
Establish server trust. Review the publisher, launch configuration, workspace location, and network scope before enabling a server. The VS Code MCP server guide warns that local MCP servers can run arbitrary code, documents first-use trust confirmation, and describes per-invocation confirmation prompts and tool controls. Trusting a server is separate from approving a future action by that server.
Evaluate policy. Maintain a policy table that makes the decision explainable. Repository inspection inside the current worktree may be allowed. Creating a branch, changing an issue, or writing a file may require approval. A production mutation, a broad deletion, or an outbound transfer should be denied unless the run has an explicitly documented exception. The Claude Code permissions documentation provides a useful host-side pattern: allow, ask, and deny rules are distinct, ordered deliberately, and enforced by the host rather than model instructions.
Render the request. Present the reviewer with the server label, tool title, intended effect, bounded scope, safe argument summary, expiry, and policy version. Do not make a person infer impact from an opaque tool name. If the server identity, tool schema, arguments, or scope changes after the request is created, invalidate the request and create a new one.
Pause, decide, and resume. Persist the pending state before waiting. On approval, confirm the request has not expired, re-evaluate policy, compare the argument digest, and dispatch once. On rejection, return a specific cancellation that does not invite an automatic retry. The OpenAI Agents SDK human-in-the-loop guide describes the same shape: approval-required calls interrupt a run, paused state can be serialized, and the original run resumes after a decision.
Validate and close. Validate the result before passing it back to the model. Record success, rejection, expiry, policy denial, validation failure, and uncertain outcomes. A successful approval proves authorization for one reviewed call; it does not authorize later calls with different arguments or a wider destination.
Use a sanitized event that supports investigation without copying tool inputs or outputs into broad-access logs:
event: mcp_tool_approval
request_id: req_example
run_id: run_example
server_label: repository-tools
tool_name: create_branch
tool_manifest_revision: manifest-7
arguments_digest: '[HASH]'
risk_class: mutating
scope: worktree-only
decision: approved
decision_actor: human-reviewer
policy_version: policy-3
requested_at: 2026-08-13T09:00:00Z
decided_at: 2026-08-13T09:01:12Z
outcome: dispatched
error_class: none
The digest allows an investigator to compare the reviewed call with the dispatched call. The scope and policy version explain why it was eligible. Keep any more detailed request view access-controlled and short-lived. Do not treat a missing approval event as an implied approval.
Who this is for
This guide is for platform engineers, developer-tool maintainers, security reviewers, and team leads who operate coding agents with local or remote MCP servers. It applies to interactive IDE sessions, terminal agents, CI repair jobs, and long-running work in containers or worktrees. It is especially relevant when an agent can write files, open pull requests, modify tickets, query sensitive systems, or call an external service on a developer’s behalf.
The operational responsibilities should be explicit. The person operating the agent owns the approval decision. The tool-server owner owns input validation and access control. The platform owner owns the policy, the event trail, and recovery from an uncertain outcome. Naming those responsibilities prevents a vague handoff based only on the statement that an agent made the request.
Key takeaways
- Separate server trust, tool eligibility, and per-call approval because they answer different questions.
- Classify operations by their side effect and data destination, not by a friendly tool name.
- Show enough bounded intent for a person to decide without exposing raw private input.
- Bind a decision to one call identifier and an argument digest, with a clear expiry.
- Re-check policy, expiry, tool identity, schema, and scope immediately before dispatch.
- Fail closed on rejection, timeout, malformed arguments, schema drift, or uncertain side effects.
- Log sanitized fields for approvals and every no-decision path.
- Test the host-side approval adapter independently from the model so prompt text cannot bypass it.
For a companion evidence pattern, read Agent Run Evidence Ledgers for Human Review . If your server inventory is still informal, start with Declare MCP Tool Manifests Before Coding Agents Call CometAPI .
Sources checked
This article uses four refetched public documents:
- The MCP tools specification recommends a human in the loop with the ability to deny invocations, confirmation prompts for operations, clear tool indicators, and client-side validation and logging.
- Microsoft’s Add and manage MCP servers in VS Code covers server trust confirmation, tool controls, local-server risk, and sandbox-related behavior.
- Anthropic’s Configure permissions documents fine-grained allow, ask, and deny rules, precedence, persistence differences, and permission modes.
- The OpenAI Agents SDK human-in-the-loop documentation documents approval-required tools, interruption objects, serialized run state, rejection handling, and resume behavior.
These sources describe different hosts and APIs. They do not define one universal approval configuration or interface. Use them as evidence for the properties an adapter should preserve, then verify the exact behavior of the runtime you deploy.
Contract details to verify
Before enabling an approval gate, write down and test these contracts with a controlled tool stub.
Discovery contract. Capture the server identity, tool name, title, description, input schema, output schema, and manifest revision. The MCP specification describes valid schemas and a tool-list change notification. A change should invalidate any pending approval that relied on the old definition.
Risk contract. Define which operations are read-only, mutating, externally visible, or destructive. Define approved destinations and scope boundaries. A broad safe-server label must not override a risky tool.
Decision contract. Specify what the reviewer sees, whether the decision is tied to one call, how long it remains valid, and whether it can ever be reused. The OpenAI guidance distinguishes per-call from sticky decisions; make any remembered decision visible and narrowly scoped.
Persistence contract. Verify that a paused run can survive a restart or handoff without losing the call identifier, policy revision, and expiry. A state that cannot be revalidated must not resume.
Execution contract. Decide how the host prevents duplicate side effects. Record the request identifier at the server boundary and reconcile ambiguous results before retrying. A timeout does not prove that an action did not happen.
Logging contract. Define retention, redaction, access, clock source, and correlation fields. Log rejections, expirations, policy denials, and validation failures as carefully as approvals.
Host contract. Confirm whether a sandbox, IDE integration, CI runner, or remote environment alters prompts or automatic approval behavior. Document the deployed mode in the event record and test that mode rather than assuming the default is in effect.
Failure modes
The reviewer approves the wrong server. A familiar tool name can be advertised by a different server. Display a stable server label and configuration fingerprint, and invalidate pending requests when either changes.
A schema changes after approval. The reviewed arguments may no longer have the same meaning. Reject the stale request, refresh discovery, and ask again.
Prompt injection claims approval exists. Repository text or an issue can tell the model to assert that approval was granted. Ignore model claims about authorization. Accept a decision only through the host’s approval channel and record the actor and policy version.
A timeout causes a duplicate action. The server may have completed the side effect before the client lost the response. Mark the result uncertain, reconcile it with the server, and require a new decision before any retry.
A rejection creates a retry loop. A generic error can lead the model to repeat the same action. Return a specific cancellation reason, cap retries, and require changed intent or a fresh approval.
Malformed arguments reach the server. Validate arguments against the current schema before dispatch. The OpenAI guidance describes fail-closed behavior when approval logic cannot safely inspect arguments. Treat malformed JSON, non-object arguments, and unsupported values as manual-review or deny cases.
Nested work hides a pending call. A sub-agent or handoff can issue the sensitive action while the top-level workflow appears idle. Preserve the child tool name and argument summary in the outer approval view, then resume only the original validated run.
Logs leak protected data. Raw arguments and tool output can contain source code, private paths, or customer information. Keep a digest and bounded summary in the durable event, redact detail views, and test log sinks with synthetic sensitive inputs.
Sandbox settings silently widen access. Automatic approval inside a controlled sandbox may be appropriate, but changes to mounts or network restrictions alter the risk. Treat sandbox configuration as part of the approval contract and record its revision.
FAQ
Does MCP require a human prompt for every tool call? No. MCP does not mandate one interaction pattern, but its tools specification recommends a human who can deny invocations and confirmation prompts for operations. Use a risk-based policy rather than prompting mechanically for harmless reads or silently allowing impactful writes.
Is trusting an MCP server the same as approving a call? No. Trust determines whether the server and its capabilities may be exposed to the agent. Approval determines whether this exact call, with this scope and these arguments, may run. Both decisions should be visible and independently revocable.
Can an approval be remembered? It depends on the host. Claude Code documents persistent rules for some tool permissions, while some approvals are session-scoped. The OpenAI Agents SDK documents per-call and optional sticky decisions in run state. Any remembered decision should be bound to server identity, tool identity, policy revision, and explicit scope.
What happens if no reviewer responds? Let the request expire and fail closed. Persist the pending state, notify the normal operator channel, and do not transform a timeout into automatic approval or retry.
How much of the arguments should a reviewer see? Show enough to understand effect and scope, but no more than needed. Prefer a typed summary, destination, and digest. Reserve a controlled detail view for authorized reviewers when it is genuinely necessary.
Do approval logs replace server security? No. MCP servers still need input validation, access controls, rate limits, and output sanitization. The gate controls whether a host permits a call; it does not make an untrusted server safe.
Reader next step
Choose one mutating MCP tool in a non-production worktree and build a small adapter with four states: pending, approved, rejected, and expired. Add the sanitized event fields shown above. Then test the happy path and error paths in order: an approved call dispatches once; a rejection returns a cancellation; expiry does not dispatch; schema drift invalidates the request; a restart resumes only valid state; and an ambiguous timeout blocks a blind retry.
Review those events with a second operator before widening the policy. Then connect the resulting evidence to Agent Run Evidence Ledgers for Human Review and keep the inventory current with Declare MCP Tool Manifests Before Coding Agents Call CometAPI . Start with one side effect, prove the error paths, and only then expand the agent’s operating scope.