内容
# ask-a-human
<p align="center">
<img src=".github/assets/pager.svg" width="120" alt="ask-a-human pager logo" />
</p>
<p align="center">
<a href="https://www.npmjs.com/package/@askahuman/mcp"><img src="https://img.shields.io/npm/v/@askahuman/mcp?style=for-the-badge&logo=npm&logoColor=white&label=npm&color=39d98a" alt="npm version" /></a>
<a href="LICENSE"><img src="https://img.shields.io/badge/License-MIT-39d98a?style=for-the-badge" alt="MIT License" /></a>
<img src="https://img.shields.io/badge/E2E-encrypted-39d98a?style=for-the-badge" alt="端到端加密" />
<img src="https://img.shields.io/badge/no-database-2dd4bf?style=for-the-badge" alt="无数据库" />
<img src="https://img.shields.io/badge/MCP-server-2dd4bf?style=for-the-badge" alt="MCP 服务器" />
</p>
<p align="center"><b>您的智能代理分页器。</b></p>
<p align="center">
<a href="https://ask-a-human.ai">官网</a> .
<a href="https://ask-a-human.ai/app">手机应用</a> .
<a href="https://www.npmjs.com/package/@askahuman/mcp">npm</a> .
<a href="https://github.com/askahuman/askahuman">仓库</a> .
<a href="https://ask-a-human.ai/llms.txt">适用于智能代理</a> .
<a href="SECURITY.md">安全</a>
</p>
## 您的智能代理运行在全自动循环中,直到其中一个需要您。
您运行了许多智能代理在循环中,全权限,大多数情况下是在您睡觉或离开键盘时运行。它们不应该需要您。然后,偶尔,**其中一个** 遇到它不应该单独处理的单个步骤,并且它没有办法联系您。
所以联系吧。`ask-a-human` 让那个智能代理给您发信号:它会给您的手机发送通知并 **阻塞**,直到您回应,然后解锁并继续。几秒钟,而不是几分钟。
> 多年来,CAPTCHA 使人类证明他们不是机器人。
> 现在,您将自己注册为您的智能代理调用的工具。
**100 个智能代理。一个人。一次一个通知。**
<!-- HERO DEMO(最大的病毒传播杠杆)在这里录制:一段约 5 秒的循环,
终端在 request_approval 上阻塞 -> iPhone 通知 + 是/否卡片 + 点击 -> 终端解锁。
然后插入:<p align="center"><img src="https://ask-a-human.ai/demo.gif" width="720" alt="ask-a-human: 智能代理询问,您手机通知,您点击,它继续" /></p> -->
## 30 秒设置
零安装。零账户。零 API 密钥。
将此内容粘贴到您的 MCP 客户端配置中(Cursor `~/.cursor/mcp.json`,Claude Desktop `claude_desktop_config.json`,Codex 或任何 MCP 客户端),然后重启智能代理。
```json
{
"mcpServers": {
"ask-a-human": {
"command": "npx",
"args": ["-y", "@askahuman/mcp", "serve"]
}
}
}
```
就是这样。以下是发生的情况:
- `npx` 在首次运行时获取一个静态发布二进制文件。
- 它默认为托管的中继 `wss://ask-a-human.ai/ws` 和 PWA `https://ask-a-human.ai`。
- 第一个 `request_approval` 将配对代码打印到 stderr **和** 打开一个本地环回浏览器页面显示它。代码永远不会出现在 URL 中。
- 在您的 iPhone 上将 `https://ask-a-human.ai/app` 固定到首页作为 PWA,然后输入代码。(在 iOS 上,Web Push 仅在应用安装到首页时才有效,并且唤醒是尽力而为的;当您打开应用时,它会显示一个待处理计数徽章。)
运行您自己的中继?使用 `--relay <wss-url>` (和 `--public-relay <wss-url>` 如果您的手机通过不同的地址访问中继)将其指向智能代理。参见 [自托管](#自托管).
## 与您的智能代理配合使用
<table>
<tr>
<td align="center" width="16%"><img src=".github/assets/agents/claude.svg" width="30" height="30" alt="Claude 代码" /><br /><sub>Claude 代码</sub></td>
<td align="center" width="16%"><img src=".github/assets/agents/codex.svg" width="30" height="30" alt="Codex" /><br /><sub>Codex</sub></td>
<td align="center" width="16%"><img src=".github/assets/agents/cursor.svg" width="30" height="30" alt="Cursor" /><br /><sub>Cursor</sub></td>
<td align="center" width="16%"><img src=".github/assets/agents/copilot.svg" width="30" height="30" alt="Copilot" /><br /><sub>Copilot</sub></td>
<td align="center" width="16%"><img src=".github/assets/agents/gemini.svg" width="30" height="30" alt="Gemini" /><br /><sub>Gemini</sub></td>
<td align="center" width="16%"><img src=".github/assets/agents/mcp.svg" width="30" height="30" alt="任何 MCP 客户端" /><br /><sub><b>任何 MCP 客户端</b></sub></td>
</tr>
</table>
如果它支持 MCP,它就可以联系您。相同的单行配置,零额外设置。
## 您的手机收到什么
四件事,就是整个产品。您配对一次,然后每个 `request_approval` 都会阻塞智能代理,直到您回应。
<table>
<tr>
<td width="50%" valign="top">
<img src=".github/assets/pager.svg" width="26" height="26" align="left" alt="" />
<b>新智能代理</b><br />
<sub>1 · 配对</sub>
<br /><br />
在手机上打开 <code>ask-a-human.ai/app</code> 并输入它打印的 10 个字符的代码。
<br /><br />
<code>A B C D E - 2 3 4 5 6</code>
</td>
<td width="50%" valign="top">
<img src=".github/assets/agents/claude.svg" width="26" height="26" align="left" alt="" />
<b>Claude 代码</b><br />
<sub>2 · 是/否 · <code>response_kind: "yesno"</code></sub>
<br /><br />
所有测试通过,但此版本还运行一个迁移,删除 prod 上的 <code>orders.coupon_code</code>。是否发布?
<br /><br />
<code>✓ 批准</code> <code>✗ 拒绝</code>
</td>
</tr>
<tr>
<td valign="top">
<img src=".github/assets/agents/codex.svg" width="26" height="26" align="left" alt="" />
<b>Codex</b><br />
<sub>3 · 多选题 · <code>response_kind: "choice"</code></sub>
<br /><br />
<code>main</code> 已红色 20 分钟,3 个部署卡在它后面。我如何解锁它?
<br /><br />
<code>恢复它</code> <code>热修复向前</code> <code>保持,我会查看</code>
</td>
<td valign="top">
<img src=".github/assets/agents/cursor.svg" width="26" height="26" align="left" alt="" />
<b>Cursor</b><br />
<sub>4 · 自由表单回复 · <code>response_kind: "text"</code></sub>
<br /><br />
客户在支持线程中升级并要求退款我不允许批准。 我应该如何回复?
<br /><br />
<i>输入您的回复…</i>
</td>
</tr>
</table>
**它 **绝不** 自动批准。** 拒绝、超时或错误绝不会作为批准返回。沉默不是是。
## 一个手机。每个智能代理。
这是 100 个智能代理如何变成一次一个通知的过程。每个智能代理配对一次,它在条形图中获得自己的芯片,由 `--name` 标记(例如 `cursor @ workstation` 或 `nightly-deploy-bot`),因此您始终知道谁在询问。当智能代理需要您时,其芯片会亮起红色圆点并跳到条形图的前面。点击它,回答,然后继续。您可以随意配对。
## 流程
```
1. 智能代理遇到它应该不单独通过的墙
2. 请求被封存在虫洞中
3. 您的手机收到通知
4. 您点击:批准,拒绝或回复
5. 智能代理解锁并继续
```
几秒钟,而不是几分钟。
## 我们为什么要构建它
我们首先为自己构建了它。运行大量智能代理的难点从来不是工作,而是很少需要人工判断调用,而我们不在键盘上。
我们不想要仪表盘、账户或另一家公司保存我们的消息。所以它是私有的:所有内容都通过神奇的虫洞进行端到端加密,中继在中间是盲的。我们不跟踪任何内容,没有数据库,我们自己支付托管费用。
无数据可卖,无漏斗,无陷阱。我们构建它是因为我们需要它,我们的唯一目标是让它传播。
---
## 它是如何工作的
MCP 服务器 **本地** 在您的机器上运行。出于这个原因,它是持有密钥和明文的唯一方,所以它从不被托管。只有内容盲中继生活在服务器上,它是一个愚蠢的管道。
```
智能代理端 中继(内容盲) 您的手机
+--------------+ 密封 +------------------+ 数据块 +----------------+
| MCP 智能代理 | ----------> | 两个房间的 WebSocket | -------> | 手机 PWA |
| 请求_审批 | | 原样转发 | | 滑动 / 选择 |
| 审批 | <---------- | 仅限 RAM,无数据库 | <------- | / 回复 -> 密封|
+--------------+ 打开 +------------------+ 数据块 +----------------+
中继只看到密文 + 哪个房间 ID 与哪个聊天
```
## MCP 工具
三个工具。没有惊喜。
### `request_approval`
询问人类。**阻塞** 直到他们响应。传递 `expires_in_s` 也会超时 N 秒;省略它,调用无限期等待(直到回答,或连接断开)。
| 字段 | 类型 | 必需 | 注释 |
|---|---|---|---|
| `title` | 字符串 | 是 | 短标题。 |
| `summary` | 字符串 | 是 | 问题主体。 |
| `response_kind` | 字符串 | 是 | `"yesno"` \| `"choice"` \| `"text"`。 |
| `category` | 字符串 | 否 | 徽章。识别:`cash` \| `deploy` \| `data` \| `access` \| `other`。其他值仍显示,只是颜色为中性 `other`。 |
| `options` | 字符串[] | 否 | `response_kind` 为 `"choice"` 时的选择。 |
| `placeholder` | 字符串 | 否 | `"text"` 时的输入提示。 |
| `max_len` | 整数 | 否 | `"text"` 时的最大输入长度。 |
| `expires_in_s` | 整数 | 否 | 倒数秒数,超时前。省略它,请求永远不会超时。 |
**返回** 您要求的形状:`yesno` 给出一个 `approved` 布尔值,`choice` 给出所选选项,`text` 给出输入的回复。拒绝作为非批准返回;超时或传输错误作为智能代理可以分支的错误返回。它从不悄悄进行,从不返回失败的批准。
### `pair_status`
只读。报告智能代理是否已配对,等待配对或空闲(作为短状态消息)。永远不会返回代码。不启动配对(使用 `start_pairing` 进行)。
### `start_pairing`
只读触发器。与您的手机开始配对,急切地,而不是等待第一个 `request_approval`。在智能代理终端中打印短代码供您输入到应用中;握手在后台运行,工具立即返回。仅返回非秘密状态。代码从不出现在结果中。
智能代理:[`https://ask-a-human.ai/llms.txt`](https://ask-a-human.ai/llms.txt)
## 加密方式
这是全部内容,所以它构建起来很无聊且可验证。
- **端到端加密。** 明文只存在于您的机器和手机上。
- **内容盲中继。** 它只转发 `base64(nonce‖ciphertext)` 加上哪个房间 ID 与哪个聊天。它无法读取、记录或伪造决定(重放由电话 PWA 上的请求 ID 单独阻止)。它是一个愚蠢的管道。
- **无账户,无数据库。** 配对在服务器生命周期内存在于 RAM 中。重启 = 重新配对。中继上没有什么可侵犯的:没有账户,没有数据库,内容盲。(实际攻击面是手机的 PWA 和配对通道。参见 [`SECURITY.md`](SECURITY.md).)
- **配对是 SPAKE2 风格的 PAKE。** 短代码成为强共享密钥。即使代码被肩部监视,攻击者恰好获得 **一次** 在线猜测对抗实时握手。
- **应用流量用 NaCl secretbox 密封** (XSalsa20-Poly1305),由对称 SPAKE2 会话密钥密钥。
PAKE 是根据 [RFC 9382](https://www.rfc-editor.org/rfc/rfc9382) 使用 ristretto255 组 ([RFC 9496](https://www.rfc-editor.org/rfc/rfc9496)) 的内部构造。Go 使用 [`gtank/ristretto255`](https://github.com/gtank/ristretto255),PWA 使用 [`@noble/curves`](https://github.com/paulmillr/noble-curves),Go 到 JS 互操作由 `frontend/test/spake2-interop.mjs` 固定。短代码是 PAKE 密码:它从不到达模型并且从不出现在 URL 中。
阅读每行。参见 [`SECURITY.md`](SECURITY.md) 和 [`docs/decisions/architecture/`](docs/decisions/architecture/) 中的 ADRs(从 [`0002_spake2_ristretto255_secretbox.md`](docs/decisions/architecture/0002_spake2_ristretto255_secretbox.md)开始)。