关于 pendnt
pendnt 是面向交互式或无头 Agent 的 Claude Code 插件,可将权限请求交由人工审批并转发通知。它结合审批钩子与 MCP 权限工具,让无人值守运行等待明确决定,而非依赖终端。
主要功能
- 01无头运行权限审批
- 02MCP 权限提示工具
- 03通知与运行结束钩子
- 04持久化审批请求
- 05出错时默认拒绝
适用场景
- 01审批无人值守 Claude Code 运行中的工具调用
- 02接收 Agent 运行结束通知
- 03通过手机处理审批请求
MCP 相关
插件注册 pendnt 远程 MCP 服务及其工具,包括供 Claude Code 无头权限机制使用的 `permission_prompt`。其他工具支持审批、通知、Webhook、唤醒和键值存储。
配置
远程服务无需本地安装。选择你使用的客户端,复制配置或使用一键安装。
https://api.pendnt.dev/mcpclaude mcp add --transport http dev-pendnt-pendnt https://api.pendnt.dev/mcp{"mcpServers":{"dev-pendnt-pendnt":{"type":"http","url":"https://api.pendnt.dev/mcp"}}}在 Cursor 中打开{"servers":{"dev-pendnt-pendnt":{"type":"http","url":"https://api.pendnt.dev/mcp"}}}在 VS Code 中打开{"mcpServers":{"dev-pendnt-pendnt":{"type":"http","url":"https://api.pendnt.dev/mcp"}}}{"mcpServers":{"dev-pendnt-pendnt":{"serverUrl":"https://api.pendnt.dev/mcp"}}}命令在终端中运行;JSON 粘贴到对应客户端的 MCP 配置后重启。需要授权的服务会在首次连接时提示登录。
https://api.pendnt.dev/mcp需要授权工具
详细介绍
pendnt(Claude Code 插件)
10 秒上手——无需账户:
curl https://api.pendnt.dev/try?plain=1会返回一个有效期为 72 小时的试用密钥(20 次请求)和快速入门指南。
将 Claude Code 会话(交互式或无头模式 claude -p)连接到 pendnt 工作区:支持持久的人类审批、通知和“运行完成”提醒,无需 Agent 使用终端。
“pendnt”是一个占位产品名称。它只保存在一个位置——lib/config.mjs 中的 PRODUCT_NAME——此外还出现在 plugin.json、marketplace.json 和 .mcp.json 中的 name 字段,以及在 /app/src/routes/mcp.ts 注册的对应 MCP 服务名称中。将这些位置的名称一并重命名,就能完成所有相关位置的重命名。
此插件提供两种相互独立的方式,用于在无头模式下响应权限提示——任选其一(或同时使用;若两者都已接入,则优先使用 --permission-prompt-tool,见下文 §1a):
PermissionRequest钩子(hooks/permission-request.mjs)——适用于原生claude -p,无需额外标志。每次工具使用提示前都会自动运行。- 通过
--permission-prompt-tool mcp__pendnt__permission_prompt使用permission_promptMCP 工具——Claude Code 专为无头权限提示提供的机制(见INTEGRATIONS.md§1a)。
此外还有一个 Notification 钩子和一个 Stop 钩子,都会将通知转发到 POST /v1/notify——见下文包含内容。
安装
本地插件市场(用于发布前试用)
此仓库也可作为自己的本地插件市场——.claude-plugin/marketplace.json 将此插件列出,并设置 source: "./" 指向 plugin.json 所在的同一目录。在 Claude Code 中:
/plugin marketplace add Pendnt/pendnt-plugin
/plugin install pendnt@pendnt
(或以非交互方式运行:claude plugin marketplace add Pendnt/pendnt-plugin && claude plugin install pendnt@pendnt)
之后若要正式发布,请将 marketplace.json 拆分到独立仓库,并将 source 指向此插件的仓库(有关市场清单格式以及 github/git-subdir/npm/archive 源类型,请见 INTEGRATIONS.md §1d),然后可在任意位置运行 claude plugin marketplace add <owner>/<repo>。
环境变量
| 变量 | 必需 | 默认值 | 含义 |
|---|---|---|---|
PENDNT_API_KEY | 是 | — | 每次调用 API 时使用的 Authorization: Bearer <key>(aio_...,本地环境中由 POST /dev/bootstrap 获取,或在生产环境中使用真实工作区的 API 密钥)。如果未设置,PermissionRequest/Notification/Stop 钩子都会安全失败关闭(拒绝 / 不执行任何操作),而不是让会话报错。 |
PENDNT_URL | 否 | https://api.pendnt.dev | pendnt REST API 的基础 URL——不包含 /mcp 或 /v1。在本地开发时,可将其设为 http://localhost:8787,以通过 wrangler dev 连接本地服务(见下文)。 |
PENDNT_APPROVAL_TIMEOUT_S | 否 | 600(10 分钟) | PermissionRequest 钩子反复轮询、直至放弃并拒绝前可用的总墙钟时间预算。每次轮询的服务端时限为 25 秒(wait_s),因此钩子会循环调用 GET /v1/requests/:id?wait_s=25,直到预算耗尽。 |
可在 shell 中设置这些变量,也可在 .claude/settings.json 的 env 中设置——见 settings.json 文档。.mcp.json 中的 ${PENDNT_URL:-...} / ${PENDNT_API_KEY} 语法是 Claude Code 自带的 .mcp.json 值环境变量展开功能,适用于请求头和 URL——见 INTEGRATIONS.md §1e。
包含内容
.mcp.json— 注册pendnt远程 MCP 服务(${PENDNT_URL:-https://api.pendnt.dev}/mcp、Authorization: Bearer ${PENDNT_API_KEY}),使模型可以直接使用全部 14 个工具(request_approval、check_request、permission_prompt、notify、create_endpoint、list_endpoints、wait_for_event、schedule_wakeup、list_wakeups、cancel_wakeup、kv_get、kv_set、kv_delete、whoami),工具名称为mcp__pendnt__<tool>。不过,Claude Code 会在permission_prompt被指定为--permission-prompt-tool后,将其从自身显示的工具列表中移除(见下文),因为它应该由 CLI 自身调用,而不是由模型调用。hooks/hooks.json— 配置三个钩子(结构与settings.json的hooks键一致,参见INTEGRATIONS.md§1d):PermissionRequest→hooks/permission-request.mjs。在每次工具调用提示前触发。将工具调用摘要 POST 到POST /v1/requests(kind: "approval"、wait_s: 25、timeout_s: $PENDNT_APPROVAL_TIMEOUT_S),然后反复轮询GET /v1/requests/:id?wait_s=25,直到请求得到答复或总计的PENDNT_APPROVAL_TIMEOUT_S时限耗尽。按照INTEGRATIONS.md§1b 中的PermissionRequest约定,精确输出一个 JSON 对象:
或{ "hookSpecificOutput": { "hookEventName": "PermissionRequest", "decision": { "behavior": "allow", "updatedInput": {} } } }{"behavior": "deny", "message": "..."}。遇到任何错误都默认拒绝(缺少 API 密钥、网络故障、操作员拒绝、请求过期、超时)——只有明确批准才能获得allow。即使请求的kind: "approval",回答页面也始终显示自由文本输入框;只有当操作员输入的文本以 yes/y/allow/approve/ok 开头时,才视为批准,否则会以该文本作为拒绝原因。Notification→hooks/notify.mjs。将notification_type/message转发到POST /v1/notify。根据钩子自身的语义,它无法阻止 Claude Code,也不会尝试阻止——始终以 0 退出。Stop→hooks/stop.mjs。在每轮结束时,将"run finished"消息转发到POST /v1/notify。绝不返回{"decision":"block"}——它只发送通知,不会让 Agent 继续运行。
lib/— 三个钩子脚本的共用部分:config.mjs(环境变量和PRODUCT_NAME常量)、client.mjs(针对/v1/requests和/v1/notify的轻量fetch封装)、stdin.mjs(解析钩子标准输入中的 JSON)。没有 npm 依赖——只需纯 Node 18+(fetch、AbortController)即可运行。
--permission-prompt-tool 路径(§1a)
你可以将 Claude Code 专用的权限提示机制直接指向此插件的 .mcp.json 注册的 permission_prompt MCP 工具,而不是(或除了——两者都适用时,Claude Code 优先使用 --permission-prompt-tool 而非 hooks)使用 PermissionRequest hook。该工具是此服务中专为此标志打造的工具(完整契约请参见 /app/README.md 的 permission_prompt 部分):
export PENDNT_API_KEY=aio_...
export PENDNT_URL=https://api.pendnt.dev # or http://localhost:8787 for local dev
export MCP_TOOL_TIMEOUT=600000 # ms — must exceed PERMISSION_PROMPT_WAIT_S (default 540s)
claude -p --permission-prompt-tool mcp__pendnt__permission_prompt "deploy to prod"
依赖此路径前,有三点值得了解:
- 在
pendntMCP 服务连接之前,Claude Code 会阻塞第一个回合,等待时间上限由MCP_TIMEOUT控制(默认 30s,环境变量,单位为毫秒)——如果网络较慢,请调高该值:export MCP_TIMEOUT=60000(摘自INTEGRATIONS.md§1a)。 - 从 CLI ≥2.1.199 开始,对于标记了
_meta["anthropic/requiresUserInteraction"]的任何 MCP 工具调用,--permission-prompt-tool返回的allow会被转换为deny——无论操作人员如何作答,此提示工具都无法直接批准这类调用(同样摘自INTEGRATIONS.md§1a)。 permission_prompt会在服务端保持 MCP 工具调用处于打开状态,最长等待PERMISSION_PROMPT_WAIT_S(/app上的环境变量,默认 540s = 9 min),等待操作人员响应;与此不同,其他工具的wait_s均不超过 25s。Claude Code 自身的MCP_TOOL_TIMEOUT(每次工具调用的超时时间,单位为毫秒,默认 30000)必须设置得更长,否则 CLI 会先放弃等待——因此上面设置了export MCP_TOOL_TIMEOUT=600000。
不同于 request_approval,permission_prompt 会原生返回 Claude Code 的确切 {behavior, updatedInput, updatedPermissions, interrupt} / {behavior:"deny", message, interrupt} 契约——allow 会将原始 input 回传为 updatedInput,deny(或等待超时仍未收到响应)会包含面向用户的 message。这与下文的 PermissionRequest hook 为其自身的 hook 形式契约手动完成的转换相同;permission_prompt 则直接通过 MCP 工具结果完成该转换,而这正是 --permission-prompt-tool 实际读取的内容。
无头模式示例
export PENDNT_API_KEY=aio_...
export PENDNT_URL=https://api.pendnt.dev
export MCP_TOOL_TIMEOUT=600000
claude -p --permission-prompt-tool mcp__pendnt__permission_prompt \
"review open PRs and merge the ones that pass CI"
或者,让 PermissionRequest hook 来处理(安装插件后无需额外标志):
export PENDNT_API_KEY=aio_...
export PENDNT_URL=https://api.pendnt.dev
claude -p "review open PRs and merge the ones that pass CI"
无论哪种方式,每次工具使用提示现在都会创建一个持久的审批请求,而不是阻塞在并不存在的终端上——查看已配置的渠道(电子邮件/网页收件箱——要了解当前实际实现的渠道,请参见 /app/README.md 的“Channels”部分),然后用手机作答,Agent 就会继续运行。
在本地针对 wrangler dev 运行 hook
在 /app 中:
cd ../app
npm install
npm run db:migrate:local
npm run dev # http://localhost:8787
在另一个终端中,初始化工作区和 API 密钥(参见 /app/README.md),并将插件的环境变量指向该环境:
BOOT=$(curl -s -X POST http://localhost:8787/dev/bootstrap -d '{}')
export PENDNT_API_KEY=$(echo "$BOOT" | jq -r .api_key)
export PENDNT_URL=http://localhost:8787
然后,可以直接运行 hook 脚本,并通过 stdin 输入真实 Claude Code hook 调用会发送的 JSON(适合在不启动完整 Claude Code 会话的情况下迭代调试 hook):
echo '{"session_id":"s1","cwd":"'"$PWD"'","tool_name":"Bash","tool_use_id":"toolu_1","tool_input":{"command":"deploy prod"}}' \
| PENDNT_APPROVAL_TIMEOUT_S=60 node hooks/permission-request.mjs
……或者在本地安装插件(在 Claude Code 中运行 /plugin marketplace add Pendnt/pendnt-plugin,参见安装)并启动真实会话——只要在 Claude Code 运行的 shell 中导出 PENDNT_URL/PENDNT_API_KEY,每次工具使用提示都会经由本地 wrangler dev 实例往返处理。按照 /app/README.md 中的 curl 操作示例来响应请求:自行计算 HMAC 签名(它是请求 id 和 SIGNING_SECRET 的纯函数),然后 POST /a/<id>/<sig>;或者,在接入真实渠道后,从 wrangler dev 中查看 log 投递渠道的控制台输出,获取答复链接。
注意事项
- 按设计不依赖 npm(仅使用
fetch/AbortController)——每个 hook 脚本都通过纯node hooks/*.mjs运行,插件本身无需执行npm install。 PermissionRequesthook 的默认失败关闭行为(缺少密钥、网络错误、超时 → 拒绝)是有意为之的安全选择,并非需要设法绕过的限制——没有人可以询问的无头 Agent 默认不应继续执行。hooks/hooks.json的Notification匹配器没有限定具体的notification_type——每条通知(包括与权限提示无关的通知)都会被转发。如果觉得这比预期更吵闹,可以缩小匹配范围,或在hooks/notify.mjs内进行过滤。
指南
关于如何在无人值守的情况下运行 Agent 的实用指南,见 pendnt.dev/guides: --dangerously-skip-permissions 的替代方案 · 定时任务中的 claude -p · --permission-prompt-tool 契约 · 用于无人值守运行的 hooks · 退出代码:重试还是保持终止
评论
一个开放协议,规定了 AI 应用如何以统一方式连接外部工具与数据源。客户端负责与模型对话,MCP 服务负责提供工具、资源和提示模板,两者通过标准消息通信,同一个服务可以被不同客户端复用。