mcpField
P
psh.now

psh.now

远程服务
psh.now其他0今天更新

关于 psh.now

psh.now 是面向 AI Agent 的审批服务,会暂停 Agent 请求,直到有人批准、拒绝或回复。它适用于能运行命令行或发起 HTTP 请求的 Agent,也支持可自托管部署。

主要功能

  1. 01Agent 请求的人类审批
  2. 02通过手机批准或拒绝
  3. 03自由文本回复请求
  4. 04命令行与 HTTP API
  5. 05Claude Code 工具调用前钩子
  6. 06可自托管部署

适用场景

  1. 01执行破坏性命令前要求审批
  2. 02通过手机审核生产环境操作
  3. 03在 Agent 运行时回答问题
  4. 04拦截 Claude Code 的 Bash 命令

配置

远程服务无需本地安装。选择你使用的客户端,复制配置或使用一键安装。

服务地址https://psh.now/mcp
一键复制安装命令
Claude CodeTerminal
Cursor.cursor/mcp.json
VS Code.vscode/mcp.json
Claude Desktopclaude_desktop_config.json
Windsurf~/.codeium/windsurf/mcp_config.json

命令在终端中运行;JSON 粘贴到对应客户端的 MCP 配置后重启。需要授权的服务会在首次连接时提示登录。

全部服务地址
Streamable HTTPhttps://psh.now/mcp需要授权

工具

详细介绍

psh.now

为 AI Agent 提供人工审批:一个主机、一个密钥、一个布尔值。

请求出现在屏幕凹口中,输入并发送评论后,接着收到下一个请求

skills.sh

需要决策的 Agent 会向 psh.now 发送简短的标题和消息,然后等待。你可以在一个页面上轻点批准或拒绝,也可以用自己的话作答,Agent 会根据结果继续运行。它的存在,是因为 Agent 经常会卡在无人查看的终端中。

  • 适用于任何能运行 shell 命令或发送 HTTP 请求的 Agent。无需 SDK,也无需 MCP。
  • 一个页面管理所有 Agent 和所有机器,包括无法连接的沙盒。
  • 可自托管:采用 MIT 许可,需运行两个容器并设置三个环境变量。
┌────────────┐   blocking POST /        ┌────────────────┐   WebSocket    ┌─────────┐
│ AI agent   │ ───────────────────────► │ psh.now gateway │ ─────────────► │  phone  │
│ (terminal) │                          │  (Elysia +     │                │  (PWA)  │
│            │ ◄─────────────────────── │  Postgres)     │ ◄───────────── │         │
└────────────┘   { approved: true }     └────────────────┘  decision       └─────────┘

请求包含标题和消息,不只是 shell 命令:可以是要运行的命令、要执行的操作,也可以是要回答的问题。

接下来

我想要阅读
安装并处理我的第一个请求快速入门
在自己的服务器上运行docs/self-hosting.md 或任意实例上的 /self-hosting
从头到尾了解工作流程docs/how-it-works.md
直接调用 APIHTTP API
将提示词粘贴到 Agent 中docs/prompt-templates.md
报告漏洞SECURITY.md
参与贡献CONTRIBUTING.md

技术栈

层级技术
运行时Bun
HTTP / WSElysia
数据库PostgreSQL + Drizzle ORM
实时通信WebSockets + Postgres LISTEN/NOTIFY(多节点扇出)
前端无需构建的 PWA(原生 ES 模块 + 服务工作线程)

快速入门

# 1. install
bun install

# 2. configure
cp .env.example .env          # then set DATABASE_URL / PUBLIC_BASE_URL
createdb psh.now                 # if it doesn't exist

# 3. migrate
bun run migrate

# 4. run the gateway
bun run dev                   # http://localhost:3000

然后,在你想要保护的项目中:

bun /path/to/psh/cli/psh.ts init

这会创建一个工作区,显示你的 API 密钥,生成配对二维码,并将托管规则块写入 ./agents.md。用手机扫描二维码打开 PWA,轻点配对此设备,即可开始使用。

或在浏览器中创建频道

打开 /setup(例如 http://localhost:3000/setup)。这会创建一个工作区,仅显示一次 API 密钥,并生成配对二维码。配对设备后会进入仪表板,仪表板会立即发送一个测试审批,让你无需使用终端即可确认提醒及完整的批准/拒绝流程。仪表板上的发送测试审批按钮可随时重复此操作,而邀请可让任何已配对设备生成新的配对码。

手动检查
# commands, actions, and questions all use the same call
psh ask "Drop the users table and reseed?" --title "Database reset"
Claude Code 钩子

在 .claude/settings.json 中注册一次钩子:

{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Bash",
        "hooks": [{ "type": "command", "command": "psh hook" }]
      }
    ]
  }
}

psh hook 会从 stdin 读取 Claude 的 PreToolUse JSON,并将决策约定写入 stdout(permissionDecision: "allow" | "deny")。每个 Bash 命令都会等待你的手机确认。非 Bash 工具则直接通过。将 PSH_SKIP_PATTERN 设为正则表达式,即可自动允许只读命令:

PSH_SKIP_PATTERN='^(ls|cat|git status|rg)\b' psh hook

使用自有密钥连接托管实例

注册后会获得一个工作区和一把密钥。这把密钥是 Agent 的凭据:它能让请求显示在你的账户中,而不是其他人的账户中。

  1. 获取密钥。 打开托管仪表板,创建工作区并复制密钥。 密钥只会显示一次。同一页面还会生成供手机使用的配对二维码。
  2. 将密钥放在项目中,而不是 Shell 配置文件中。 在你希望 Agent 操作的项目中安装技能;它会写入 <project>/.psh/keys.json (并在 ~/.psh/keys.json 中写入一条机器记录)。密钥按项目区分是有意为之,这样两个项目可以属于两个不同的工作区,而且密钥文件绝不能纳入版本控制。
  3. 发起请求。 CLI 和技能的 psh 垫片会读取 <project>/.psh/keys.json, 并从工作目录开始向上查找。无需设置任何全局配置。
  4. 从刘海屏或手机上批准。 刘海屏完全不会使用 Agent 密钥:它会配对一台设备(在仪表板中依次选择 Devices、Connect a device),并在 ~/.config/psh-notch/device.json 中存储该设备专属的令牌,权限模式为 0600。该令牌可以批准请求并读取信息,但不能轮换密钥;你可以按设备撤销令牌。

因此,这两种凭据刻意彼此独立:密钥让 Agent 可以发起请求,设备令牌让人类可以作出回应。在不同机器间复制密钥,转移的是 Agent;复制设备令牌,转移的是审批界面。

托管与自托管

托管版 psh.now 和自托管版都是同一个单进程。唯一能让部署变成“公开”的是 PUBLIC_BASE_URL:

PUBLIC_BASE_URL=https://psh.now

设置后,所有生成的配对链接都会变成 https://psh.now/pair/<code>,可在任何地点通过任何手机打开。 Agent 端点就是相同的源:

curl -s -X POST https://psh.now \
  -H "x-psh-key: psh_live_…" \
  -H "Content-Type: application/json" \
  -d '{"title":"Reinstall deps","message":"rm -rf node_modules && npm install --force"}'

PWA 会根据 location.host 推导 WebSocket URL,因此通过 HTTPS 提供服务时会自动使用 wss://…,无需重新构建。一个实例可为多个相互隔离的工作区/租户提供服务。

最简单的部署方式(无需 Docker 或反向代理)

Bun 就是完整的运行环境。将它指向 Postgres 并运行:

cp .env.example .env          # set DATABASE_URL + PUBLIC_BASE_URL
bun src/db/migrate.ts
bun src/index.ts

就这么简单。将其交由 systemd(或 tmux/pm2)运行,即可拥有一个主机节点。

不使用 Caddy 的 HTTPS/WSS

Bun 会自行终止 TLS,无需 Caddy 或 nginx。获取证书(例如从 Let's Encrypt 获取),然后将 psh.now 指向该证书:

export TLS_CERT_FILE=/etc/letsencrypt/live/psh.now/fullchain.pem
export TLS_KEY_FILE=/etc/letsencrypt/live/psh.now/privkey.pem
export PUBLIC_BASE_URL=https://psh.now
bun src/index.ts

服务器会记录 https://…,PWA 会自动使用 wss://…。如果未设置 TLS_CERT_FILE/TLS_KEY_FILE,则会提供纯 HTTP 服务(并在启动时说明)。使用 certbot certonly 并配置部署钩子进行续期,或者使用你已在管理的任意证书。

只有在你已经运行反向代理、想在一个 IP 上托管多个服务,或需要自动续期证书而不改动 psh 时,反向代理才有用。 此类场景可使用 deploy/Caddyfile,但它不是必需的。

阻塞请求与代理超时。 POST / 会保持连接打开,直到有人作出回应。Cloudflare 和许多代理会在约 100 秒后切断源站响应(Cloudflare 会返回 524)。请将 DEFAULT_TIMEOUT_MS 设为低于代理的限制(默认值为 90s),或者直接运行 psh.now/自托管且不经过 CDN。Agent 必须将 524/超时视为未获批准(技能中对此有说明)。

Docker(可选)

如果你偏好使用容器,Dockerfile + docker-compose.yml 会将 Postgres 和网关打包在一起。它们不是必需项,也不是默认方案:

cp .env.example .env
# edit PUBLIC_BASE_URL (or keep http://localhost:3000 for local)
docker compose up -d --build

迁移具有幂等性,因此每次启动时运行都是安全的。


集成:agents.md(或技能)中的一个密钥

整个接入只需一个主机、一个密钥和一条指令。psh init 会将下面的代码块写入 ./agents.md,并填入你的实际主机和密钥(参见 templates/agents-snippet.md):

## Ask before you act

Before any destructive, irreversible, or production action, ask first:

curl -s -X POST https://psh.now \
  -H "x-psh-key: psh_live_…" \
  -H "Content-Type: application/json" \
  -d '{"title":"<short label>","message":"<what you are about to do>"}'

Proceed only if the response is {"approved":true}. Otherwise do not act.

支持技能的运行环境也可以加载 skills/psh-now/SKILL.md 来替代(或同时使用)。它以 Anthropic Agent Skills / Hermes 格式向任何 LLM 说明相同的约定,其中包含 metadata.hermes 代码块,并补充了关于何时询问以及何时不询问的指导。

安装技能(格式与 here.now 的相同):

# if you have npm/npx: one command, so the harness asks for approval once.
# It installs machine-wide and mints in the same run.
npx skills add passy-ai/psh-now-skill -g -y

# no npm? the hosted installer (works in a sandbox too, no credentials needed)
curl -fsSL https://psh.now/install.sh | sh

然后向 Agent 提供主机和密钥(通过环境变量或 agents.md):

export PSH_BASE_URL="https://psh.now"
export PSH_API_KEY="psh_live_..."

服务本身提供技能和安装程序:/skill.md、/install.sh、/llms.txt、/llms-full.txt 和 /.well-known/* 清单。

这就是任意 Agent 所需的全部集成接口:

  • 询问:模型遵循 agents.md / 技能并调用主机。任何可使用 shell 或 HTTP 工具的 LLM 都能做到。
  • 拦截:将 psh hook 接入运行环境的工具调用前钩子,且无法跳过。此项可选,仅适用于支持它的运行环境。

agents.md 中的 API 密钥属于机密。如果要提交该文件,请将其加入 gitignore,或将密钥保存在 PSH_API_KEY 中并引用该环境变量。


代码块的工作原理

  1. Agent → 网关。 Agent 使用 x-psh-key 请求头,将 { title, message, kind?, cwd?, agent? } 发送到 POST /(或 /api/v1/hook)。(command 仍作为 message 的旧版别名接受。)
  2. 风险扫描。 系统会根据规则集扫描标题和消息(rm -rf、--force、sudo、curl | sh、DROP TABLE、强制推送等),并按 low → critical 进行分级,同时给出易于理解的原因。
  3. 等待。 请求的 promise 会暂存在进程内的等待者注册表中,并设置超时。HTTP 连接保持打开状态,终端会冻结。**异步选项:**发送 wait:false 后,调用会立即返回 pollUrl,因此不会阻塞,也不会因代理/CDN 超时而中断。使用 GET /api/v1/prompts/:id?wait=30 进行轮询。
  4. 提醒。 提示会广播给该租户所有已配对的设备。
  5. 决策。 手机通过 WebSocket 发送 { type: "decision", promptId, approved }(或在备用情况下使用 POST /api/v1/prompts/:id/decision)。决策会以原子方式持久化(pending → approved/denied),通过 NOTIFY psh_decisions 扇出,然后解除等待者的等待。
  6. 解除阻塞。 Agent 会收到 { approved: true|false } 并采取相应操作。

超时或 Agent 连接断开时会自动拒绝(status: "expired"),因此即使手机丢失,也不会让构建永远卡住。对于等待答复的时间窗口已过期的待处理提示,系统会将其清理为 expired(异步请求没有等待者,因此无需处理超时)。


HTTP API

方法路径身份验证用途
POST/ · /api/v1/hookx-psh-key审批请求(阻塞,或使用 wait:false)
POST/mcpx-psh-keyMCP:一个工具 psh_ask(可流式传输的 HTTP,JSON)
GET/.well-known/mcp.json-面向客户端和扫描器的 MCP 描述文件
POST/api/v1/channels-创建工作区(使用 pair:true 创建配对链接)
POST/api/v1/claimskey / device为匿名工作区申请认领码
POST/api/v1/claims/:id/verify-验证代码;使工作区永久有效
POST/api/v1/pairingkey / device生成配对链接/二维码
GET/api/v1/qr-将任意字符串渲染为 SVG 二维码
GET/api/v1/pairing/:token-验证配对令牌
POST/api/v1/pairing/:token/claim-将令牌兑换为设备令牌
GET/api/v1/mex-psh-key工作区概览
GET/api/v1/promptskey / device列出提示词(?status=、?limit=)
GET/api/v1/prompts/:idkey / device获取提示词;?wait=<s> 会长轮询
POST/api/v1/prompts/:id/cancelkey / device取消待处理的请求
POST/api/v1/connectionskey / device注册连接(Agent/项目)
GET/api/v1/connectionskey / device列出连接(一个账户 → 多个连接)
GET/api/v1/connections/:idkey / device一个连接及其请求
DELETE/api/v1/connections/:idkey / device删除连接
POST/api/v1/testkey / device发送非阻塞测试审批
POST/api/v1/prompts/:id/decisionkey / device通过 HTTP 决策(WS 回退)
GET/api/v1/deviceskey / device列出已配对设备
DELETE/api/v1/devices/:idkey / device撤销设备
GET/api/v1/keyskey / device列出 Agent 密钥
POST/api/v1/keyskey / device生成可恢复的 Agent 密钥
GET/api/v1/keys/:id/revealkey / device向操作员显示密钥的原始值
DELETE/api/v1/keys/:idkey / device撤销 Agent 密钥
GET/api/v1/health-健康检查
WS/ws?token=<deviceToken>device token实时提示词流 + 决策

交互式文档见 /docs(Swagger)。

MCP

HTTP 调用是契约;MCP 则是为无法安装技能的客户端(托管式构建器、连接器 UI、仅支持该协议的应用)提供的第二个入口。一个端点、一个工具、无需 OAuth,也没有服务端主动发起的流——这是围绕同一处理程序构建的轻量 JSON-RPC 封装,因此两个入口的计量、过期时间和决策路径不会出现偏差。

claude mcp add --transport http psh https://psh.now/mcp --header "x-psh-key: psh_agent_..."
{ "mcpServers": { "psh": { "url": "https://psh.now/mcp",
    "headers": { "x-psh-key": "psh_agent_..." } } } }

psh_ask 接受 {title?, message, timeoutSec?},会阻塞,并返回 {"approved":bool,"status":"approved|denied|answered|expired","answer":string|null,"promptId":"..."}。 只有 approved: true 才表示同意;denied、expired 和错误均表示不得采取行动。与技能一样,MCP 是协作式的:它无法阻止一个从未调用它的 Agent。真正把关的是钩子。

协议详情、错误代码以及采用更精简接口的原因:docs/mcp.md。

WebSocket 帧

服务端 → 手机:

{ "type": "hello",         "workspace": {…}, "device": {…}, "pending": [...] }
{ "type": "prompt.created", "prompt": { "id": "pr8x1k…", "title": "Reinstall deps", "message": "rm -rf node_modules", "kind": "command", "risk": "critical", "riskReasons": [...] } }
{ "type": "prompt.decided", "promptId": "…", "approved": true }

手机 → 服务端:

{ "type": "decision", "promptId": "pr8x1k…", "approved": true, "reason": "ok" }
{ "type": "ping" }

安全模型

  • API 密钥仅显示一次,且只以 SHA-256 哈希形式存储。
  • 设备令牌为随机生成,以哈希形式存储,并可按设备撤销。
  • 配对令牌只能使用一次,且会过期(默认 10 分钟)。
  • 短 ID。 所有公开标识符均采用 base62,长度 ≤ 32 个字符,因此所有 URL 都保持 YouTube 短链接长度(/pair/UpDbWPKjQjoAqVtLdehnwQ)。
  • 仅在传输过程中使用短期凭证;配对后,绝不会向 Agent 发送机密信息,也不会将其嵌入 URL。
  • 每项决策都会记录在只追加的 audit_log 中。

多节点 / 扩展

阻塞中的 Promise 存在于接收 Agent 请求的节点上;手机可能连接到另一个节点。NOTIFY psh_decisions 会将每项决策广播给所有节点,每个节点都会处理与之匹配的本地等待项。无需粘性会话,也不需要 Redis。Postgres 是唯一的协调原语。


项目布局

src/
  index.ts            Elysia app + graceful shutdown
  env.ts              Validated configuration
  db/
    schema.ts         Drizzle tables (tenants, devices, prompts, …)
    index.ts          postgres.js pool + Drizzle client
    migrate.ts        Migration runner
  lib/
    ids.ts            Short base62 ID generator
    crypto.ts         API key generation, SHA-256, header parsing
    risk.ts           Command risk scanner
    waiters.ts        In-process blocked-request registry
    realtime.ts       WebSocket per-tenant hub
    pubsub.ts         Postgres LISTEN/NOTIFY fan-out
    tenant-auth.ts    Request authentication
    http.ts           Typed HTTP errors
  services/           Business logic (tenants, devices, prompts, decisions)
  routes/             auth · hook · prompts · ws
public/               PWA (index/pair HTML, app.js, sw.js, manifest)
cli/psh.ts           init · pair · ask · hook · status · doctor
tests/e2e.ts          Full approval-loop integration test
drizzle/              Generated SQL migrations

测试

bun tests/e2e.ts      # boots the gateway, pairs a fake phone, exercises approve/deny/timeout
bunx tsc --noEmit     # type check

CLI

psh init        Create a workspace + pairing QR
psh pair        Mint a new pairing link
psh ask "cmd"   Block until a human approves/denies  [--timeout <seconds>]
psh hook        Agent hook (reads JSON on stdin)
psh status      Workspace + pending requests
psh doctor      Connectivity + credential check

许可证

MIT,版权所有 (c) 2026 Absolum。参见 LICENSE。托管实例 psh.now 是一项服务,不属于本许可证的范围。

评论

支持 Markdown

第一次接触 MCP?

从协议是什么,到在客户端里装上第一个服务,这几条回答覆盖了大多数入门问题。

一个开放协议,规定了 AI 应用如何以统一方式连接外部工具与数据源。客户端负责与模型对话,MCP 服务负责提供工具、资源和提示模板,两者通过标准消息通信,同一个服务可以被不同客户端复用。