pendnt

dev.pendnt由 pendnt.dev 發布官方發布者v0.2.0更新於 Oct 24, 2026

Human approvals, notifications, inbound webhooks, wake-ups for headless agents. Free trial: /try

已驗證Streamable HTTP可網頁執行效率與工作流溝通與協作

概覽

AI 產生的概覽

遠端 MCP 伺服器,為無人看管的代理提供持久的人工核准、通知、入站 webhook、排程喚醒和一個小型鍵值儲存。

可以做什麼
發起並查詢人工核准請求,讓遠端操作者代替終端回答 Claude Code 的權限提示。向已設定的頻道發送通知和執行結束提醒。建立並列出入站 webhook 端點,並等待事件到達。為無人看管的執行安排、列出和取消喚醒。讀取、寫入和刪除小型鍵值項目,並查詢目前身分。
適用情境
適合無人看管執行代理的情境,例如用 claude -p 搭配 cron 或在 CI 中執行,此時工具呼叫提示會卡在無人查看的終端上。它讓操作者從手機或信箱核准或拒絕,使執行繼續,並可在執行結束時發出提醒。
執行需求
透過 streamable HTTP 連線 api.pendnt.dev 遠端端點,使用 Authorization 標頭中的 bearer API 金鑰(aio_ 前綴)驗證;不需帳號即可取得免費試用金鑰。Claude Code 外掛還會讀取 PENDNT_API_KEY、選用的 PENDNT_URL 和 PENDNT_APPROVAL_TIMEOUT_S,其掛鉤需要 Node 18 以上。使用權限提示路徑時需把 MCP_TOOL_TIMEOUT 調高於伺服器端等待時間。
安裝前請注意
API 金鑰是放在 Authorization 標頭中的機密,不要寫進共用設定。核准請求會把工具呼叫的摘要送到 pendnt 的伺服器,通知也會經其轉送。PermissionRequest 掛鉤採失敗即拒絕策略,缺少金鑰、網路錯誤或逾時都會拒絕而非放行。Notification 掛鉤預設轉送所有類型通知,除非縮小比對範圍。權限提示工具會讓呼叫保持開啟數分鐘,且無法覆寫被標記為需要使用者互動的工具。

安裝

在 SourceWeft 中

  1. 開啟 儀表板中的 pendnt,將其新增到工作區。
  2. 連接 Authorization token 憑證。它們會被私密儲存,絕不會在公開頁面上展示。
  3. 為需要使用其工具的對話啟用該服務。

Web executable,透過 Streamable HTTP。 遠端服務在工作區中設定後即可從網頁執行環境執行。

交給代理程式安裝

把這段提示詞貼上到 Claude Code、Codex、Cursor 等代理程式,或 SourceWeft 對話中。代理程式會讀取該伺服器的安裝指南,先向你展示發布者、端點和登入方式,經你同意後再把它新增到你的客戶端。金鑰不會寫進任何命令。

閱讀 https://sourceweft.com/mcp/dev.pendnt%2Fpendnt/install.md,並按其中說明把這個 MCP 伺服器接入我的客戶端。修改任何設定之前,先告訴我它的發布者、端點和登入方式,等我確認。不要把 API 金鑰寫進命令或我會提交的檔案;問我金鑰應從哪裡取得。

檢視代理程式所依據的安裝指南

其他 MCP 客戶端

把它新增到你客戶端的 mcpServers 設定中。

{
  "mcpServers": {
    "pendnt": {
      "type": "http",
      "url": "https://api.pendnt.dev/mcp",
      "headers": {
        "Authorization": "Bearer <YOUR_TOKEN>"
      }
    }
  }
}

README

pendnt (Claude Code plugin)

Try it in 10 seconds — no account: curl https://api.pendnt.dev/try?plain=1 returns a 72-hour trial key (20 requests) with a quickstart.

Wires a Claude Code session — interactive or headless (claude -p) — up to a pendnt workspace: durable human approvals, notifications, and a "run finished" ping, without the agent needing a terminal.

"pendnt" is a placeholder product name. It's kept in exactly one place — PRODUCT_NAME in lib/config.mjs — plus the name fields in plugin.json, marketplace.json and .mcp.json, and the matching MCP server name registered in /app/src/routes/mcp.ts. Rename all of those together and it's renamed everywhere that matters.

This plugin ships two independent ways to answer permission prompts headlessly — pick one (or both; --permission-prompt-tool takes priority when both are wired up, see §1a below):

  1. A PermissionRequest hook (hooks/permission-request.mjs) — works with plain claude -p, no extra flags. Runs automatically before every tool-use prompt.
  2. The permission_prompt MCP tool, via --permission-prompt-tool mcp__pendnt__permission_prompt — Claude Code's own dedicated mechanism for headless permission prompts (see INTEGRATIONS.md §1a).

Plus a Notification hook and a Stop hook that both relay to POST /v1/notify — see What's included below.

Install

Local marketplace (for trying this out before publishing anywhere)

This repo doubles as its own local marketplace — .claude-plugin/marketplace.json lists this plugin with source: "./", pointing at the same directory plugin.json lives in. From Claude Code:

/plugin marketplace add Pendnt/pendnt-plugin/plugin install pendnt@pendnt

(or non-interactively: claude plugin marketplace add Pendnt/pendnt-plugin && claude plugin install pendnt@pendnt)

To publish for real later, split marketplace.json out into its own repo with source pointing at this plugin's repo (see INTEGRATIONS.md §1d for the marketplace manifest shape and github/git-subdir/npm/archive source types), then claude plugin marketplace add <owner>/<repo> from anywhere.

Env vars

VariableRequiredDefaultMeaning
PENDNT_API_KEYyes—Authorization: Bearer <key> for every call to the API (aio_..., from POST /dev/bootstrap locally, or your real workspace's API key in production). Without it, the PermissionRequest/Notification/Stop hooks all fail closed (deny / no-op) rather than erroring the session.
PENDNT_URLnohttps://api.pendnt.devBase URL of the pendnt REST API — not including /mcp or /v1. Point this at http://localhost:8787 for local dev against wrangler dev (see below).
PENDNT_APPROVAL_TIMEOUT_Sno600 (10 min)Total wall-clock budget the PermissionRequest hook spends re-polling before it gives up and denies. Each individual poll is capped server-side at 25s (wait_s), so the hook loops GET /v1/requests/:id?wait_s=25 until this budget runs out.

Set them in your shell, or in .claude/settings.json under env — see settings.json docs. .mcp.json's ${PENDNT_URL:-...} / ${PENDNT_API_KEY} syntax is Claude Code's own env-var expansion for .mcp.json values (headers and URLs) — see INTEGRATIONS.md §1e.

What's included

  • .mcp.json — registers the pendnt remote MCP server (${PENDNT_URL:-https://api.pendnt.dev}/mcp, Authorization: Bearer ${PENDNT_API_KEY}) so all 14 tools (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) are available to the model directly, under mcp__pendnt__<tool> — except permission_prompt, which Claude Code removes from its own visible tool list once named by --permission-prompt-tool (see below), since it's meant to be called by the CLI itself, not by the model.
  • hooks/hooks.json — wires three hooks (shape matches settings.json's hooks key, see INTEGRATIONS.md §1d):
    • PermissionRequest → hooks/permission-request.mjs. Fires before every tool-use prompt. POSTs a summary of the tool call to POST /v1/requests (kind: "approval", wait_s: 25, timeout_s: $PENDNT_APPROVAL_TIMEOUT_S), then re-polls GET /v1/requests/:id?wait_s=25 until it's answered or the total PENDNT_APPROVAL_TIMEOUT_S budget elapses. Prints exactly one JSON object per INTEGRATIONS.md §1b's PermissionRequest contract:
      json
      { "hookSpecificOutput": { "hookEventName": "PermissionRequest", "decision": { "behavior": "allow", "updatedInput": {} } } }
      or {"behavior": "deny", "message": "..."}. Fails closed on every error path (missing API key, network failure, operator denies, request expires, timeout) — the only way to get allow is an explicit approval. An operator using the answer page's free-text box (always shown, even for kind: "approval" requests) is treated as approval only if the text starts with yes/y/allow/approve/ok — anything else denies with that text as the reason.
    • Notification → hooks/notify.mjs. Relays notification_type/message to POST /v1/notify. Cannot block Claude Code (per the hook's own semantics) and never tries to — always exits 0.
    • Stop → hooks/stop.mjs. Relays a "run finished" message to POST /v1/notify at the end of every turn. Never returns {"decision":"block"} — it only notifies, it doesn't keep the agent going.
  • lib/ — the three hook scripts' shared bits: config.mjs (env vars + the PRODUCT_NAME constant), client.mjs (thin fetch wrappers for /v1/requests and /v1/notify), stdin.mjs (hook stdin JSON parsing). No npm dependencies — plain Node 18+ (fetch, AbortController) is enough.

The --permission-prompt-tool path (§1a)

Instead of (or in addition to — Claude Code prefers --permission-prompt-tool over hooks when both apply) the PermissionRequest hook, you can point Claude Code's dedicated permission-prompt mechanism directly at the permission_prompt MCP tool this plugin's .mcp.json registers — the one tool in this server purpose-built for this flag (see /app/README.md's permission_prompt section for the full contract):

bash
export PENDNT_API_KEY=aio_...export PENDNT_URL=https://api.pendnt.dev   # or http://localhost:8787 for local devexport 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"

Three things worth knowing before you rely on this path:

  • Claude Code blocks the first turn until the pendnt MCP server connects, capped by MCP_TIMEOUT (default 30s, env var, milliseconds) — bump it if your network is slow: export MCP_TIMEOUT=60000 (from INTEGRATIONS.md §1a).
  • As of CLI ≥2.1.199, an allow from a --permission-prompt-tool is converted to deny for any MCP tool call flagged _meta["anthropic/requiresUserInteraction"] — this prompt tool can't rubber-stamp those regardless of what the operator answers (also from INTEGRATIONS.md §1a).
  • permission_prompt holds the MCP tool call open server-side for up to PERMISSION_PROMPT_WAIT_S (env var on /app, default 540s = 9 min) waiting for the operator, unlike every other tool's ≤25s wait_s. Claude Code's own MCP_TOOL_TIMEOUT (its per-tool-call timeout, ms, default 30000) must be set higher than that or the CLI gives up first — hence export MCP_TOOL_TIMEOUT=600000 above.

Unlike request_approval, permission_prompt does return Claude Code's exact {behavior, updatedInput, updatedPermissions, interrupt} / {behavior:"deny", message, interrupt} contract natively — an allow echoes the original input back as updatedInput, a deny (or an unanswered timeout) carries a human-readable message. That's the same translation the PermissionRequest hook below does by hand for its own hook-shaped contract; permission_prompt does it as the MCP tool result directly, which is what --permission-prompt-tool actually reads.

Headless example

bash
export PENDNT_API_KEY=aio_...export PENDNT_URL=https://api.pendnt.devexport MCP_TOOL_TIMEOUT=600000
claude -p --permission-prompt-tool mcp__pendnt__permission_prompt \  "review open PRs and merge the ones that pass CI"

Or, with the PermissionRequest hook doing the work instead (no extra flag needed once the plugin is installed):

bash
export PENDNT_API_KEY=aio_...export PENDNT_URL=https://api.pendnt.dev
claude -p "review open PRs and merge the ones that pass CI"

Either way, every tool-use prompt now creates a durable approval request instead of blocking on a terminal that doesn't exist — check your configured channels (email/web inbox — see /app/README.md's "Channels" section for what's actually implemented today), answer from your phone, and the agent resumes.

Running the hook locally against wrangler dev

From /app:

bash
cd ../appnpm installnpm run db:migrate:localnpm run dev   # http://localhost:8787

In another terminal, bootstrap a workspace + API key (see /app/README.md) and point the plugin's env vars at it:

bash
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

Then either run a hook script directly, feeding it the JSON a real Claude Code hook invocation would send on stdin (useful for iterating on the hook without a full Claude Code session):

bash
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

...or install the plugin locally (/plugin marketplace add Pendnt/pendnt-plugin from Claude Code, see Install) and drive a real session — with PENDNT_URL/PENDNT_API_KEY exported in the shell Claude Code runs in, every tool-use prompt round-trips through your local wrangler dev instance. Answer the request the same way /app/README.md's curl walkthrough does: compute the HMAC signature yourself (it's a pure function of the request id and SIGNING_SECRET) and POST /a/<id>/<sig>, or watch the log delivery channel's console output from wrangler dev for the answer link once a real channel is wired up.

Caveats

  • No npm dependencies by design (fetch/AbortController only) — every hook script runs under plain node hooks/*.mjs, no npm install step inside the plugin itself.
  • The PermissionRequest hook's fail-closed defaults (missing key, network error, timeout → deny) are a deliberate safety choice, not a limitation to work around — a headless agent with nobody to ask should not proceed by default.
  • hooks/hooks.json's Notification matcher is not narrowed to specific notification_types — every notification (including ones that aren't permission-prompt-related) gets relayed. Narrow the matcher or filter inside hooks/notify.mjs if that's noisier than you want.

Guides

Practical writeups on running agents unattended, at pendnt.dev/guides: --dangerously-skip-permissions alternatives · claude -p on cron · the --permission-prompt-tool contract · hooks for unattended runs · exit codes: retry vs stay dead

來源:README.md,提交 1c5509a

工具

0
該伺服器需要 API 金鑰等憑證,因此 SourceWeft 無法在沒有憑證的情況下讀取其工具,也未收錄。

版本歷史

1
  1. v0.2.0最新Sep 16, 2026

評分

已滿足適用檢查項的 85%

該評分衡量此收錄條目的完整程度,依據註冊中心條目、端點與公開來源計算得出。它不是對伺服器本身的評價,也不表示伺服器安全或目前可用:可連通性是帶日期的檢查結果,評分也不包含安裝量或使用者評價。

  • 近 30 天內可連通必需25 分
  • 已宣告認證方式必需10 分
  • 已列出工具15 分

    請讓伺服器在無憑證時回應 tools/list,或發布可在沙箱中無憑證啟動的軟體包。

  • 描述必需15 分
  • 圖示10 分
  • 文件15 分
  • 授權條款10 分