MCP server
confirm-mcp gives any MCP-compatible agent a human-approval tool. Before the agent does something irreversible, it calls request_approval, a human approves or edits the action, and the agent proceeds with the approved result. Every decision is logged.
Setup
Create an API key under Dashboard → API Keys, then add the server to your MCP client. The same block works in Claude Desktop (claude_desktop_config.json) and Cursor (~/.cursor/mcp.json, or .cursor/mcp.json for one project):
{
"mcpServers": {
"confirm": {
"command": "npx",
"args": ["-y", "confirm-mcp"],
"env": { "CONFIRM_API_KEY": "cfm_live_..." }
}
}
}Restart the client. The agent now has two tools, request_approval and check_approval. Needs Node 18+ (the npx command pulls confirm-mcp on first run).
In practice
Tell the agent who approves what, and it calls the tool on its own before the risky step:
You: You can issue refunds. Anything over $100 needs my approval
at me@acme.com before you do it.
Agent: [calls request_approval]
summary: "Refund $240 to customer #4821"
payload: { "customerId": "4821", "amount": 240 }
notify: "me@acme.com"
reasoning: "Customer was double-charged on order #88213."
... you get an email, open the link, approve (or edit the amount) ...
Agent: Approved. I've issued the $240 refund to customer #4821.The agent decides when to ask; the tool enforces that it actually waits for a human and executes the approved effectivePayload. Pair it with the agent skill so the model reliably knows which actions to gate.
Tools
request_approval
Pause and ask a human to approve a sensitive action. Blocks until the human decides or the wait elapses. Inputs: summary, notify (email or group:<key>), payload, reasoning, recent_actions, ttl_minutes, and wait_minutes (how long to block, default 15).
On APPROVED it returns the effectivePayload to use (the human may have edited it). On REJECTED or EXPIRED it tells the agent to stop. If the wait elapses while still pending, it returns the request id.
check_approval
Poll a previously created request by id to see whether a human has decided.
ENFORCEMENT VS COVERAGE
guard()) rather than relying on the model to remember.