Approval Gate MCP
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@Approval Gate MCPget approval before emailing alice@example.com subject: Invoice 1042"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
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.
Related MCP server: actionproxy
30-second quickstart
claude mcp add approval-gate -- npx -y @itcustomsolution/approval-gate-mcpClaude 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
approvedand 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, so the agent cannot talk itself through the gate.
Everything is audited. Every request, decision, and expiry is appended to
~/.approval-gate/audit.jsonl.Requests expire. Default TTL is 1 hour; a stale approval is not an approval.
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 PATHWire it into an MCP client
Claude Code:
claude mcp add approval-gate -- node /path/to/approval-gate-mcp/dist/index.jsOr in any MCP client config:
{
"mcpServers": {
"approval-gate": {
"command": "node",
"args": ["/path/to/approval-gate-mcp/dist/index.js"]
}
}
}Tools
Tool | Purpose |
| Register an intended action ( |
| Poll a request's status: |
| Block up to |
| List requests awaiting a human. |
| Record a decision when the human is driving the session. Agents must never self-approve; prefer the CLI. |
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 recipientSuggested 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. Proceed only if the returned status is exactlyapproved. Never calldecide_approvalfor your own requests.
State
Everything lives in ~/.approval-gate/ (override with APPROVAL_GATE_DIR):
requests/*.json for current state, audit.jsonl for the append-only history.
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 turned entire classes of automation incidents into structural impossibilities. 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
Available Tools
5 toolscheck_approvalA
Check the current status of an approval request. Statuses: pending, approved, denied, expired. Only 'approved' authorizes the action.
| Name | Required | Description | Default |
|---|---|---|---|
| id | Yes | The request id returned by request_approval |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full burden and delivers the key behavior: the status value set (pending, approved, denied, expired) and the decision rule 'Only approved authorizes the action.' That is genuinely useful semantics not present in the schema. It stops short of stating whether the call is side-effect-free or requires permissions.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three short sentences, front-loaded with the core action, followed by the status set and the one rule that actually changes agent behavior. No wasted words.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a single-parameter read tool with no output schema, the description supplies the return values (the statuses) and the interpretation rule, which is what the missing output schema would otherwise need to convey. Only the safety/permission profile is left unstated, which is minor here.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100% and the single id parameter is documented there as the value returned by request_approval. The description adds no syntax or format detail beyond the schema, so the baseline 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a specific verb and resource ('Check the current status of an approval request'), which is unambiguous on its own. It does not explicitly name how it differs from siblings like wait_for_approval (blocking) or list_pending (bulk), though the point-in-time framing implicitly separates it.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Usage is only implied: 'check the current status' suggests a non-blocking poll, but the description never states when to prefer this over wait_for_approval or list_pending, nor any prerequisites or exclusions.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
decide_approvalA
Record a human decision on a pending request. IMPORTANT: this tool exists for setups where the human is driving this very session and asks the agent to record their decision. An agent must NEVER call this on its own initiative to approve its own request; self-approval defeats the gate. Prefer the out-of-band CLI: approval-gate approve .
| Name | Required | Description | Default |
|---|---|---|---|
| id | Yes | ||
| reason | No | Human's stated reason, verbatim | |
| approve | Yes | true to approve, false to deny |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full burden and does disclose the key behavioral trait: this is a gated operation that must not be self-invoked, and a safer out-of-band channel exists. It does not describe the downstream effect of a decision, idempotency, or error behavior for an unknown id, which keeps it short of a 5.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three sentences, front-loaded with the core action, then the critical guardrail, then the alternate channel. No sentence is redundant and the IMPORTANT marker directs attention to the highest-risk instruction.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a 3-parameter, no-output-schema mutation gate with no annotations, the description supplies the essential decision-routing guidance an agent needs. It stops short of describing the post-decision effect or failure modes, which would round it out.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 67%: 'reason' and 'approve' are documented in the schema, while 'id' is undocumented. The description adds no parameter-level meaning beyond the schema, so the baseline of 3 is appropriate.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource: 'Record a human decision on a pending request.' The decision-recording role is clearly distinct from siblings like request_approval and check_approval, though no sibling is named explicitly.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicitly defines when to use (only when the human driving the session asks the agent to record their decision), when NOT to use (an agent must never self-approve), and the preferred alternative (the out-of-band CLI 'approval-gate approve <id>'). This is a textbook when/when-not/alternative statement.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_pendingB
List all approval requests currently awaiting a human decision.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations provided, the description carries the full behavioral burden. 'List' implies a read-only operation and it discloses the pending filter, but says nothing about ordering, pagination, volume limits, or auth requirements.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
A single sentence with zero waste; the object of the listing and the pending scope are front-loaded and immediately actionable.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a simple parameterless list tool this covers the essential purpose, but with no annotations and no output schema the description omits any hint about what a returned record looks like or how many results to expect.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The tool takes zero parameters, so the baseline is 4. There are no parameters whose semantics could be misread, and the description's scoping phrase fully defines the implicit filter.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb (List) and resource (approval requests) with a scoping qualifier (currently awaiting a human decision). It is clear what it returns, though it does not explicitly name how it differs from siblings like check_approval or wait_for_approval.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The phrase 'currently awaiting a human decision' implies the usage context, but there is no explicit when-to-use/when-not guidance or reference to the alternative siblings such as check_approval or decide_approval.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
request_approvalA
Register a consequential action for human approval BEFORE performing it. Returns a request id. The action is NOT executed by this server; the calling agent must check approval status and only proceed on an explicit 'approved'. Anything else means no (fail closed).
| Name | Required | Description | Default |
|---|---|---|---|
| action | Yes | Precise description of the action you intend to take, e.g. 'send email to alice@example.com with subject X' | |
| reason | Yes | Why this action is needed right now | |
| ttl_seconds | No | How long the request stays pending before it expires (default 1 hour) | |
| requested_by | No | Identifier of the requesting agent or workflow |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries full burden and discloses the two most important non-obvious behaviors: the server does NOT execute the action, and anything other than 'approved' means no (fail closed). It also notes a request id is returned. Gaps remain on auth requirements, whether the action payload is re-verified at approval time, and pending-request lifecycle beyond the schema's ttl field.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Four short sentences, front-loaded with the core purpose and then the critical fail-closed contract. No filler, and each sentence adds a distinct operational fact.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With no output schema, the description appropriately states the return value (a request id) and the full workflow contract an agent needs. Combined with the fully documented schema, nothing required to call this correctly is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so all four parameters are already documented with useful examples (action, reason, ttl_seconds default/limits, requested_by). The description adds no parameter-level detail beyond that, making the baseline 3 appropriate.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb+resource ('register a consequential action for human approval') and explicitly scopes when in the lifecycle it runs ('BEFORE performing it'). This cleanly separates it from check_approval/wait_for_approval/decide_approval, which operate on an already-registered request rather than creating one.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives clear context: register before acting, then check status and proceed only on 'approved', with fail-closed semantics spelled out. It does not name the concrete sibling (check_approval/wait_for_approval) to call next, so the routing is implied rather than explicit.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
wait_for_approvalA
Block until a human decides the request, it expires, or the timeout elapses. Returns the final (or still-pending) request. A timeout returns status 'pending': treat it as NOT approved.
| Name | Required | Description | Default |
|---|---|---|---|
| id | Yes | The request id returned by request_approval | |
| poll_seconds | No | Polling interval | |
| timeout_seconds | No | Maximum time to wait (default 5 minutes) |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description carries the full burden and does so well: it discloses blocking behavior, the three termination conditions (decision, expiry, timeout), the return value, and the critical interpretation rule that a pending timeout is NOT approval. It omits auth/permission requirements and any rate or polling cost caveats.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three short sentences, no waste, and the blocking behavior is front-loaded followed immediately by the safety-critical timeout rule. Every sentence earns its place.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With no annotations and no output schema, the description must explain the interaction contract, and it covers the blocking lifecycle, the return content, and the timeout interpretation. It leaves a small gap around what 'expires' means versus a timeout and offers no comparison to the other approval siblings.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so id, poll_seconds, and timeout_seconds are already fully documented in the schema, including defaults and bounds. The description adds only the interpretation of the timeout outcome, which is useful behavior-level context rather than additional parameter semantics, so the baseline 3 holds.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a specific verb and behavior: 'Block until a human decides the request, it expires, or the timeout elapses.' The blocking semantics inherently distinguish it from the non-blocking check_approval/list_pending siblings, but it never names an alternative, so the differentiation is implicit rather than explicit.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It gives clear operational context for handling outcomes ('A timeout returns status pending: treat it as NOT approved'), which is exactly the guidance an agent needs to avoid misinterpreting a timeout as consent. It stops short of saying when to prefer this over check_approval or poll-based siblings.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
5 tool updates
v0.1.0- First observed
check_approval - First observed
decide_approval - First observed
list_pending - First observed
request_approval - First observed
wait_for_approval
TDQS
Scored across 5 tools
Each tool maps to a distinct action in the approval lifecycle (request, check, wait, list, decide), and descriptions make the boundaries clear. The only mild overlap is check_approval vs wait_for_approval, which both return status but differ in blocking behavior, so an agent must read carefully to pick the right one.
Most names follow a verb_noun pattern with a consistent '_approval' suffix (request_approval, check_approval, wait_for_approval, decide_approval). list_pending breaks the pattern by naming on state rather than the resource, a minor deviation but still readable.
Five tools is well-scoped for a human-in-the-loop gate: each covers a necessary stage (create request, poll, block, enumerate, decide). No redundant or filler tools are present.
The surface covers the core lifecycle including creation, status checks, blocking waits, listing, and decision recording, with expiry handled implicitly. A cancel/revoke tool for withdrawing a pending request is the notable missing operation, but agents can work around it via expiry.
Maintenance
Related MCP Connectors
Supervised API-write gateway for AI agents with policy, human approval and execution receipts.
Preventive human-approval write-gate for AI agents: writes commit only after a human approves.
Set up human approval for your AI agents' tool calls.
Runtime permission, approval, and audit layer for AI agent tool execution.
Related MCP Servers
- AlicenseAqualityDmaintenanceHuman-in-the-loop approval gate for AI agents. Your agent calls submit_approval before any irreversible action; a human reviews on a branded page; a signed webhook fires back with the decision.11MIT
- AlicenseNot gradedqualityBmaintenanceProvides a human-in-the-loop approval gateway for AI agents, enforcing policies and audit logging for MCP-compatible tool calls.Apache 2.0
- AlicenseNot gradedqualityCmaintenanceA local human-in-the-loop gate for AI agents that blocks actions until human approval, with timeout defaulting to denial.37 npmMIT

raposa-mcpofficial
AlicenseAqualityBmaintenanceHuman approval for AI agents: request_human_approval pauses a high-stakes action until a named person approves or rejects (console, email, Telegram, Slack); silence is not consent. Every decision is sealed in a hash-chained audit log. EU-hosted.318 PyPIMIT