How to require human approval before an MCP tool call
· By the Shotoku team
Short answer: put a proxy MCP server between the agent and your real servers, so the proxy is the only server the agent can reach. It checks each tool call against a policy, lets safe calls through and holds risky ones until a person approves them outside the agent.
The MCP specificationrecommends this kind of control: “a human in the loop with the ability to deny tool invocations.” It leaves the how to each application.
What are the ways to add approval?
| Approach | Can the agent skip it? | Trade-off |
|---|---|---|
| Host confirmation prompts | Depends on the host and its settings | Simple, but differs per host and keeps no shared record |
| An approval tool the agent should call | Yes | The model decides whether to ask, so it isn't a real gate |
| A proxy in front of your servers | Not through MCP | Takes some setup, and works across MCP hosts |
Asking for approval on everything has its own cost: people stop reading and click yes. Let reads run freely and save the prompts for calls that change something.
How do you set it up?
Install the CLI and give Shotoku a fixed home:
Move your servers into an upstreams file. It uses the same format as your host config:
Make Shotoku the only server in your host config, for example in Claude Desktop:
Wrapped tools are named <server>__<tool>, and that name is the resource in your policy. Your tool names will differ from these:
defaultVerdict covers everything else, so a tool added to the server later is held instead of quietly allowed. When a call is held, approve it from ~/shotoku-home in your terminal:
What does the agent see?
We connected an MCP client to the current npm release of shotoku-mcp, with a stand-in server behind it that reports when a tool really runs:
| Call | Result | Reached the server? |
|---|---|---|
| postgres__query | approved | Yes |
| postgres__drop_table | denied | No |
| postgres__delete_rows on users | pending_approval | No |
| Same call, after a human approved it | approved | Yes |
| Same call a third time | pending_approval | No |
| postgres__delete_rows on orders | pending_approval | No |
| approve_decision, called by the agent | refused | No |
An approval works once, for the exact call you approved. Approving a delete on users gave the agent no way to delete orders. For standing permission, write a rule in the policy.
What doesn’t this cover?
- Anything outside MCP. An agent with shell access or an API token can skip the proxy. See the production database post.
- Blocked work waits. Someone has to answer. The terminal queue and TUI are on npm today. The local dashboard and Telegram approvals are in the repo and arrive in the next npm release.
- The rule sees the tool name. To allow a tool for some arguments and not others, split it across tools or hold it for a human.
Common questions
Does this work with Cursor and other hosts?
Shotoku is a standard MCP server, so it fits any host that launches MCP servers. We ran this test with our own MCP client, so check your host’s config format.
Can the agent approve its own request?
No. The approval tools are withheld by default and refused if called. Approval happens in a place the agent can’t reach through MCP.
Is every decision recorded?
Yes, in a local, tamper-evident log, including denied and held calls.
Full details are in the MCP guide.