Server data from the Official MCP Registry
Fail-closed human approval gates for AI agent actions. Default-deny, TTL expiry, audit log.
About
Fail-closed human approval gates for AI agent actions. Default-deny, TTL expiry, audit log.
Security Report
Valid MCP server (2 strong, 4 medium validity signals). No known CVEs in dependencies. Package registry verified. Imported from the Official MCP Registry.
7 files analyzed · 1 issue found
Security scores are indicators to help you make informed decisions, not guarantees. Always review permissions before connecting any MCP server.
Permissions Required
This plugin requests these system permissions. Most are normal for its category.
How to Install
Add this to your MCP configuration file:
{
"mcpServers": {
"io-github-itcustomsolution-approval-gate-mcp": {
"args": [
"-y",
"@itcustomsolution/approval-gate-mcp"
],
"command": "npx"
}
}
}Documentation
View on GitHubFrom the project's GitHub README.
approval-gate-mcp
An MCP server that makes your AI agent stop and ask a human before it sends, deletes, publishes, pays or deploys.
Why
Agents are good at doing things. The hard part is making sure the consequential things (sending an email, deleting data, publishing, spending money) only happen when a human said yes. This server is that gate, extracted from a system I have run in production for years: after an automation incident taught me the lesson the hard way, my standing rule became no automated destructive action without a human gate, ever. This is the generic, reusable version of that rule.
30-second quickstart
claude mcp add approval-gate -- npx -y @itcustomsolution/approval-gate-mcp
Claude Desktop (claude_desktop_config.json):
{
"mcpServers": {
"approval-gate": {
"command": "npx",
"args": ["-y", "@itcustomsolution/approval-gate-mcp"]
}
}
}
Approve or deny from your terminal with npx -p @itcustomsolution/approval-gate-mcp approval-gate list.
Example
- Your agent wants to email a customer. It calls
request_approvalwithaction: "send email to alice@example.com, subject: Invoice 1042"and gets back ida1b2c3d4e5f6. - It calls
wait_for_approval. Nothing is sent. - In your own terminal:
approval-gate list, thenapproval-gate approve a1b2c3d4e5f6 looks right. - The agent sees
approved, callsconsume_approvalwith the same id and the exact same action text (single use), and only then sends. Had you denied, ignored it, or let it expire, the answer is no. ~/.approval-gate/audit.jsonlnow has the request and your decision.
Design principles
- Fail closed. The only thing that authorizes an action is an explicit
approved. Pending, denied, expired, timeout, error: all of those mean no. - The gate never executes anything. It records intent and decisions. Your agent asks first, then acts only on approval. Separation of decision and execution keeps the gate simple and auditable.
- Decisions are out-of-band. A human approves or denies with a CLI in their own terminal, not inside the agent's context. The MCP tools cannot approve. The CLI asks for an interactive terminal and a re-typed confirmation, which is a speed bump, not authentication: anything running as your OS user (a shell, a PTY, or file access) can still get past it. See Threat model.
- Only
consume_approvalauthorizes.status: "approved"is informational. Status responses carryauthorizesExecution: falseand aneffectiveStatus(approved_unconsumed,approved_expired,consumed,revoked, ...). Your trusted execution boundary must check a consume result (assertConsumed(result, id, action)from the library) right before acting. - Everything is audited. Every request, decision, expiry, and consumption is appended to
~/.approval-gate/audit.jsonl(an append-only convention, not a tamper-proof log). - Requests expire. Default TTL is 1 hour; a stale approval is not an approval.
- Approvals are single-use and bound to the action.
consume_approvalsucceeds once, only for the exact action text that was approved, and only before the request's expiry.
Install
From npm:
npm install -g @itcustomsolution/approval-gate-mcp # installs `approval-gate` and `approval-gate-mcp`
From source:
npm install
npm run build
npm link # makes `approval-gate` and `approval-gate-mcp` available on PATH
Wire it into an MCP client
Claude Code:
claude mcp add approval-gate -- node /path/to/approval-gate-mcp/dist/index.js
Or in any MCP client config:
{
"mcpServers": {
"approval-gate": {
"command": "node",
"args": ["/path/to/approval-gate-mcp/dist/index.js"]
}
}
}
Tools
| Tool | Purpose |
|---|---|
request_approval | Register an intended action (action, reason, optional ttl_seconds). Returns an id. |
check_approval | Poll a request's status: pending / approved / denied / expired. |
wait_for_approval | Block up to timeout_seconds for a decision. Timeout = still pending = not approved. |
list_pending | List requests awaiting a human. |
consume_approval | Call right before acting. Succeeds once, only if approved, unexpired, and action matches the approved text exactly. Anything else: do not proceed. |
decide_approval | Deny a pending request, or revoke an approved one that has not been consumed. Approving through MCP is refused by default, so an agent cannot approve its own request; approvals come from the CLI. Operators can opt in with APPROVAL_GATE_ALLOW_MCP_APPROVE=1 (not recommended). |
The human side
approval-gate list # pending requests
approval-gate show a1b2c3d4e5f6
approval-gate approve a1b2c3d4e5f6 looks right, ship it
approval-gate deny a1b2c3d4e5f6 wrong recipient
approval-gate revoke a1b2c3d4e5f6 changed my mind # approved but not yet consumed
Suggested agent policy
Put something like this in your agent's system prompt or policy file:
Before any outbound or destructive action (send, publish, delete, purchase, deploy), call
request_approvaland thenwait_for_approval. When it returnsapproved, callconsume_approvalwith the same id and exact action text, and proceed only if it returnsok: true. Never calldecide_approvalfor your own requests.
State
Everything lives in ~/.approval-gate/ (override with APPROVAL_GATE_DIR):
requests/*.json for current state, requests/*.final / *.used one-time decision and
consumption markers, and audit.jsonl for the history. The directory is created 0700 and
files 0600.
Threat model
What the gate does protect against:
- An agent that can only reach this server over MCP approving its own request (MCP cannot approve).
- An agent driving the CLI from a non-interactive shell (
approverequires a TTY plus a typed confirmation). - Reusing one approval for a second or different action (
consume_approvalis single-use and action-bound). - Using an approval after the request's expiry, races between approve/deny/expiry, guessed ids (128-bit random), malformed or hand-edited state files without a matching decision record, and terminal escape sequences in request text that try to disguise what you are approving.
What it does not protect against:
- Trust limitation, not a bug that has been fixed: an agent with a shell, a PTY, or file access as your OS user. It can drive a pseudo-terminal, edit
~/.approval-gate/, or simply skip the gate and perform the action. The gate is a cooperation protocol plus an audit trail, not a sandbox. For hard enforcement, run the agent as a separate OS user (or in a container) that cannot read or write the gate directory, and keep the gate's CLI for yourself. - The actual payload.
consume_approvalmatches the action text. It cannot prove that the email, SQL, or deploy the agent then runs equals what you read. That binding is cooperative. See docs/design-trusted-executor.md for an enforced design (proposal only). - Unattended, consequential use. Without OS-level separation (see above), do not treat this gate as the only control for unattended agents doing irreversible things. Keep those paths fail-closed, with no automatic execution.
- An agent that never calls the gate. Enforcement of asking is up to your agent's policy and tooling.
- Tampering with
audit.jsonlby anyone with write access to it.
Setting APPROVAL_GATE_ALLOW_MCP_APPROVE=1 re-enables approval over MCP and removes the main
protection. Only use it when a human is the only one driving the MCP client.
State transitions, revocation, and crash behavior are specified in
docs/authorization-states.md. approval-gate revoke <id> (or deny
on an approved request) cancels an approval that has not been consumed yet.
Why so small?
Because the pattern matters more than the plumbing. In my production systems this same shape (request, out-of-band human decision, fail-closed default, audit trail) sits in front of email, publishing, and deployments, and it has removed entire classes of automation incidents. Start small, gate the scary things, and let your incident postmortems tell you what to gate next.
Contributing
Issues and pull requests are welcome. Keep changes small and fail-closed: anything that
could turn a "no" into a "yes" needs a test. Run npm test before opening a PR.
See CHANGELOG.md for release history.
License
MIT, see LICENSE.
Built by Olufela "Lu" Fagbure · itcustomsolution.com · MIT license
Reviews
No reviews yet
Be the first to review this server!
More Developer Tools MCP Servers
Fetch
Freeby Modelcontextprotocol · Developer Tools
Web content fetching and conversion for efficient LLM usage
Git
Freeby Modelcontextprotocol · Developer Tools
Read, search, and manipulate Git repositories programmatically
Toleno
Freeby Toleno · Developer Tools
Toleno Network MCP Server — Manage your Toleno mining account with Claude AI using natural language.
MCP Marketplace
Freeby mcp-marketplace · Developer Tools
Search and install MCP servers from inside your AI client.
mcp-creator-python
Freeby mcp-marketplace · Developer Tools
Create, build, and publish Python MCP servers to PyPI — conversationally.
FinAgent
Freeby mcp-marketplace · Finance
Free stock data and market news for any MCP-compatible AI assistant.
