approval-gate-mcp
approval-gate-mcp
一个 MCP 服务器,为长时间运行的自主进程加上一道人工审批门,并提供实际与之共处所需的运维工具:状态、日志、重启、热重载参数,以及它已完成操作的摘要。
基于 FastMCP 构建,可与任何 MCP 客户端配合使用。
问题
一个自主行动的进程,在它的某个动作产生重大影响之前都很有用。常见的两种应对方式都不好:关掉它,你会失去它所有做得好的部分;任由它运行,你只能事后才知道发生了什么。
审批门是第三种选择。进程在无人值守的情况下继续运行,但当它想要执行你标记为有重大影响的动作时,它会写下一份提案并继续推进,而不是执行该动作。你随时可以在已经打开的任意 MCP 客户端中审查提案并批准或拒绝。进程会在下一个周期获取你的决定。
双方互不阻塞。中间没有任何服务。契约就是两个 JSON 文件。
process you
| |
|-- writes proposal ----> pending.json
| |
| list_pending_approvals
| approve(0) / reject(1)
| |
|<-- reads on next cycle -- approved.json
|
|-- acts, appends to records.json工具
审批门
工具 | 功能 |
| 所有等待决定的提案及其全部字段 |
| 将一个提案移入已批准文件 |
| 丢弃一个提案 |
进程控制
工具 | 功能 |
| 是否在运行、PID、运行时间、CPU、内存、磁盘、最后一行日志 |
| 查看日志文件尾部 |
| 通过你的启动脚本重启,以分离方式运行,因此 SSH 会话结束后仍然存活 |
| 一次性检查的应急通道 |
记录
工具 | 功能 |
| 总数、已解决与未解决对比、按类型细分、最近条目 |
| 更宽的表格视图,加上当前未解决的记录及其暴露程度 |
参数 — 仅在 PARAMS_SCHEMA 指向你的清单时注册
工具 | 功能 |
| 此部署声明的可调参数,以及当前被覆盖了哪些 |
| 写入一个覆盖值,并根据你的清单进行校验 |
| 移除一个覆盖值,或全部移除 |
链 — 仅在 EVM_RPC_URL、WALLET_ADDRESS 和 TOKEN_CONTRACT 都已设置时注册
工具 | 功能 |
| 只读查询监控地址的 ERC-20 和原生代币余额。不会签署任何内容 |
安装
git clone https://github.com/WillyV347/approval-gate-mcp
cd approval-gate-mcp
pip install -r requirements.txt
cp .env.example .env # then edit it在接入客户端之前,先在检查器中试用:
fastmcp dev server.py然后注册它。对于读取 JSON 配置的客户端:
{
"mcpServers": {
"approval-gate": {
"command": "python3",
"args": ["/absolute/path/to/approval-gate-mcp/server.py"],
"env": {
"VPS_HOST": "your.host.or.ip",
"VPS_USER": "your-ssh-user",
"PROCESS_DIR": "/srv/my-process",
"PROCESS_MATCH": "my_process.py",
"PARAMS_SCHEMA": "/absolute/path/to/params.schema.json"
}
}
}
}VPS_HOST、VPS_USER 和 PROCESS_DIR 没有默认值。 如果缺少这些变量,服务器会以清晰的错误信息退出。一个静默回退到作者硬编码主机的监控工具本身就是个 bug,因此本服务器拒绝猜测。
身份验证就是你现有的 SSH 配置。服务器调用系统中的 ssh 可执行文件,因此 SSH agent、硬件密钥,以及提供了 agent 支持的密码管理器都能无需修改地工作。它自己从不读取私钥。
你的进程需要实现的契约
进程侧需要三样东西,它们都不需要任何库。
1. 记录。 追加到一个 JSON 数组。四个键如果存在会被解析,其他所有内容都会原样保留:
[
{
"id": "job-1041",
"record_type": "reindex",
"resolved": true,
"outcome": "win",
"cost": 4.25,
"result": 11.80,
"label": "nightly reindex, shard 3"
}
]2. 提案。 以审批模式运行时,写入这里而不是执行动作:
{
"proposals": [
{
"id": "job-1042",
"label": "reindex shard 7",
"action": "reindex",
"cost": 6.00,
"created_at": "2026-08-18T22:14:07Z"
}
]
}你包含的每个字段都会被显示。服务器没有提案的 schema,也不想要一个。
3. 轮询已批准文件。 每个周期读取 approved.json,对其中的内容执行动作,然后清空它。大致如下:
approved = read_json(APPROVED_FILE) or {"proposals": []}
for proposal in approved["proposals"]:
execute(proposal)
write_json(APPROVED_FILE, {"proposals": []})服务器端的顺序是刻意为之的。做出决定时,会先将提案从 pending.json 中移除,然后写入 approved.json,因此决定执行到一半时的故障模式是提案被丢弃,而绝不会是动作被重复执行。
参数,以及为什么本仓库中没有参数
热重载只有在服务器知道哪些参数可调时才有用,而把某个部署的参数硬编码进共享工具会让它变成单一用途。所以你在清单中声明自己的参数,并让 PARAMS_SCHEMA 指向它:
{
"poll_interval_seconds": { "type": "int", "description": "Seconds between work cycles" },
"max_concurrent_jobs": { "type": "int", "description": "Jobs in flight at once" },
"dry_run": { "type": "bool", "description": "Plan work but do not execute" },
"approval_mode": { "type": "bool", "description": "Queue proposals instead of acting" }
}支持的类型有 int、float、bool、str、dict 和 list。set_param 会据此进行强制转换和校验,并拒绝任何无法转换的值。没有清单时,参数工具根本不会注册,这比暴露一个没有任何校验依据的写入路径要好。
params.schema.json 已被 gitignore,因为你的调优配置属于你自己。params.schema.example.json 作为起点随仓库提供。
让进程在启动时读取覆盖文件;如果你希望更改无需重启即可生效,则每个周期都读取:
overrides = read_json(PARAMS_FILE) or {}
poll_interval = overrides.get("poll_interval_seconds", POLL_INTERVAL_DEFAULT)示例会话
> is it running?
Process RUNNING
PID: 31882
Uptime: 14h 22m (51720s)
CPU: 0.6%
Memory: 84.3 MB
Disk: 212M
Last log: 2026-08-18 22:03:11 cycle complete, 2 proposals queued
> anything waiting on me?
2 proposal(s) awaiting approval
--- Proposal #0 ------------------------------
id: job-1042
label: reindex shard 7
action: reindex
cost: 6.00
created_at: 2026-08-18T22:14:07Z
--- Proposal #1 ------------------------------
id: job-1043
label: reindex shard 12
action: reindex
cost: 6.00
created_at: 2026-08-18T22:14:07Z
Use approve(index) or reject(index) to decide.
> approve 0, reject 1
Approved and queued for execution: reindex shard 7
Rejected and removed: reindex shard 12上面的输出仅供示意。
安全说明
run_command会在远程主机上运行任意 shell 命令。它存在的原因是,另一种选择归根结底还是要打开终端,但它是这里最危险的工具。请将 SSH 用户的权限范围限定在其实际所需范围内,而不是什么都用 root 运行。wallet_balance是只读的,从不接触密钥。如果你没有配置它,它就不存在。本仓库不存储任何凭据。RPC URL 在路径中携带服务商密钥,因此请把
EVM_RPC_URL放在环境中,而不是放进配置文件。StrictHostKeyChecking设置为accept-new:未知主机在首次连接时会被信任,已变更的主机密钥仍然会失败。如果你想要更严格的行为,请将其设置为yes并预先填充known_hosts。
许可证
MIT
This server cannot be installed
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Related MCP Connectors
Control plane for autonomous software labor. Agents claim objectives over MCP with audit trail.
A paid remote MCP for CLI tool MCP, built to return verdicts, receipts, usage logs, and audit-ready
A paid remote MCP for hosted MCP server, built to return verdicts, receipts, usage logs, and audit-r
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/WillyV347/approval-gate-mcp'
If you have feedback or need assistance with the MCP directory API, please join our Discord server