内容
# PFT 聊天机器人 MCP
用于在 Post Fiat(PFTL)网络上构建机器人的 MCP 服务器。
这是一个 [Model Context Protocol](https://modelcontextprotocol.io/) 服务器,允许 LLMs 在 PFTL 网络上发送和接收加密的链上消息。它使得构建可以扫描 incoming 消息、处理它们并响应的机器人成为可能,类似于 Telegram 机器人,但它是链基的、默认加密的,并且是 LLM 原生的。
## 版本兼容性
| 组件 | 版本 | 备注 |
|-----------|---------|-------|
| @postfiatorg/pft-chatbot-mcp | 0.5.1 | 此软件包 |
| Keystone Protocol | v1 | 原型模式版本 |
| 链上备忘录格式 | keystone v1 | 信封格式(自 0.5.0 起;扫描器还读取 pf.ptr v4) |
| Keystone gRPC 服务器 | >= 0.3.0 | 后端服务 |
当 Keystone 协议更新时,将发布具有匹配兼容性的新 MCP 版本。检查 `src/version.ts` 以获取确切的版本约束。
## 工作原理
### 架构
```
机器人操作员的机器 Post Fiat 基础设施
┌──────────────────────────┐ ┌─────────────────────────┐
│ LLM 客户端 │ │ Keystone gRPC 服务 │
│ (Cursor、Claude 等) │ │ ┌───────────────────┐ │
│ │ │ │ │ IPFS 写门户 │ │
│ │ MCP 协议 │ │ │ 代理注册表 │ │
│ │ (stdio) │ │ │ 信封存储 │ │
│ ▼ │ gRPC │ │ 身份验证 + 速率限制│ │
│ ┌──────────────────┐ │◄──────────►│ └───────────────────┘ │
│ │ pft-chatbot-mcp │ │ TLS │ │
│ │ │ │ │ ┌───────────────────┐ │
│ │ • 签名交易 │ │ │ │ PostgreSQL │ │
│ │ • 解密消息 │ │ │ └───────────────────┘ │
│ │ • 加密消息 │ │ │ │
│ └──────┬───────────┘ │ │ ┌───────────────────┐ │
│ │ │ │ │ IPFS 集群 │ │
│ │ JSON-RPC/WSS │ │ │ (公共门户) │ │
│ ▼ │ │ └───────────────────┘ │
│ PFTL 链(测试网) │ └─────────────────────────┘
└──────────────────────────┘
```
**关键安全属性**:私钥永远不会离开您的机器。所有签名和解密操作都在本地进行。gRPC 服务仅处理 IPFS 写操作(身份验证)和注册操作。
### 消息流程
1. **发送者** 使用 XChaCha20-Poly1305(多收件人,使用 X25519 密钥包装)加密消息内容。默认情况下,消息包含收件人的分片,以便 TaskNode 能够启用服务器端预览。
2. 加密有效载荷通过 Keystone gRPC 写门户上传到 **IPFS**。
3. 原型编码的 **Keystone v1 信封** 作为备忘录附加到 PFTL 链上的 **支付** 交易中。
4. **收件人机器人** 扫描到其地址的交易,读取信封,从 IPFS 公共门户获取有效载荷,并本地解密。
### 加密
消息使用与 pftasks 前端相同的加密方案:
- **内容加密**:XChaCha20-Poly1305(libsodium)
- **密钥包装**:X25519(Diffie-Hellman 密钥协议)
- **密钥派生**:机器人的 Ed25519 密钥对(来自 PFTL 钱包)转换为 X25519 进行加密。
- **多收件人**:每个消息为发送者、收件人和(默认)TaskNode 包装对称密钥,以便所有参与方都可以解密。
## 快速入门
### 1. 先决条件
- Node.js >= 20
- 与 MCP 兼容的 LLM 客户端(Cursor、Claude Desktop 等)
### 2. 安装
**从 npm**:
```bash
npx @postfiatorg/pft-chatbot-mcp
```
**从源码**:
```bash
git clone <仓库网址>
cd pft-chatbot-mcp
npm install
```
### 3. 配置您的 LLM 客户端
复制 `mcp.json.example` 到您的 LLM 客户端的 MCP 配置位置。
**如果您已经有一个钱包**,请添加您的种子:
**对于 Cursor** (`.cursor/mcp.json`):
```json
{
"mcpServers": {
"@postfiatorg/pft-chatbot-mcp": {
"command": "npx",
"args": ["tsx", "src/index.ts"],
"env": {
"BOT_SEED": "sEdYourBotSeedHere"
}
}
}
}
```
**对于 Claude Desktop** (`claude_desktop_config.json`):
```json
{
"mcpServers": {
"@postfiatorg/pft-chatbot-mcp": {
"command": "npx",
"args": ["tsx", "/绝对路径/to/pft-chatbot-mcp/src/index.ts"],
"env": {
"BOT_SEED": "sEdYourBotSeedHere"
}
}
}
}
```
**如果您还没有钱包**,省略 `BOT_SEED` 行 - 服务器将以设置模式启动,并提供 `create_wallet` 工具。参见下面的 [钱包设置](#钱包设置)。
所有其他配置都有合理的测试网默认值。参见 [环境变量](#环境变量) 以进行高级覆盖。
### 4. 钱包设置
如果您需要一个新钱包,服务器可以不带种子启动。告诉您的 LLM:
> "为我的机器人创建一个新的 PFTL 钱包"
这将调用 `create_wallet` 并返回您的新钱包地址和种子。然后:
1. **安全保存种子** (它只显示一次,是访问钱包的唯一方式)。
2. **向钱包地址充值至少 10 PFT** 以在链上激活它(通过 [pftasks UI](https://tasknode.postfiat.org) 或另一个钱包)。
3. **将种子添加到您的 MCP 配置** 中作为 `BOT_SEED` 并重启。
有关详细的操作指南,请参见 **[docs/WALLET_SETUP.md](docs/WALLET_SETUP.md)**。
### 5. 首次运行
一旦您的钱包配置并激活,告诉您的 LLM:
> "以 'My Bot' 为名称注册我的机器人,描述为 'A helpful assistant',并具有 ['text-generation'] 能力"
这将:
1. 通过 Ed25519 挑战-响应证明钱包所有权。
2. 配置 API 密钥(缓存在本地 `.keystone-api-key` 中)。
3. 在公共代理目录中注册机器人。
然后尝试:
> "扫描新消息"
有关具有分层响应(基于 PFT 金额的文本和图像)的完整示例,请参见 **[docs/HELLO_WORLD_BOT.md](docs/HELLO_WORLD_BOT.md)**。
## 工具参考
### create_wallet
在本地生成一个新的 PFTL 钱包。不需要网络连接。钱包必须收到至少 **10 PFT** 的存款才能在链上激活。
| 参数 | 类型 | 必需 | 默认值 | 描述 |
|-----------|------|----------|---------|-------------|
| `algorithm` | `string` | 否 | `"ed25519"` | 密钥算法:`"ed25519"`(推荐)或 `"secp256k1"` |
**返回**:包含 `address`(r 地址)、`seed`(家族种子 - 请保存!)、`public_key`、`key_algorithm`、激活说明和下一步骤的 JSON。
**重要事项**:
- 种子仅显示一次。请复制并安全存储,然后再执行其他操作。
- 在链上钱包不存在,直到它收到至少 10 PFT。
- 即使未配置 `BOT_SEED`,此工具也可用(设置模式)。
---
### scan_messages
扫描机器人钱包的最近交易,查找传入/传出的消息。仅返回元数据(不解密)- 使用 `get_message` 读取内容。返回一个 `next_cursor` 值用于分页/重复数据消除。
| 参数 | 类型 | 必需 | 默认值 | 描述 |
|-----------|------|----------|---------|-------------|
| `since_ledger` | `number` | 否 | - | 仅返回此 ledger index 之后的 消息(使用 `next_cursor` 从之前的扫描) |
| `limit` | `number` | 否 | `100` | 最多扫描的交易数量(1-200) |
| `direction` | `string` | 否 | `"inbound"` | 过滤:`"inbound"`、`"outbound"` 或 `"both"` |
**返回**:JSON 对象,包含:
- `messages` - 消息对象的数组,每个对象包含 `tx_hash`、`sender`、`recipient`、`direction`、`amount_drops`(PFT 以 drops 为单位)、`amount_pft`(PFT 以 whole units 为单位)、`issued_currency`(对于非 PFT 代币,或 `null`)、`cid`、`thread_id`、`is_encrypted`、`ledger_index`、`timestamp_iso`
- `count` - 找到的消息数量
- `next_cursor` - 将 `since_ledger` 作为 `next_cursor` 在下一次调用时传递(用于重复数据消除)
---
### get_message
通过交易哈希或 IPFS CID 检索并解密特定消息。提供至少一个。
| 参数 | 类型 | 必需 | 默认值 | 描述 |
|-----------|------|----------|---------|-------------|
| `tx_hash` | `string` | 否* | - | 要查找的交易哈希 |
| `cid` | `string` | 否* | - | 加密有效载荷的 IPFS CID |
* `tx_hash` 或 `cid` 至少有一个必填。
**返回**:JSON 包含 `tx_hash`、`cid`、`sender`、`recipient`、`message`(解密的纯文本)、`content_type`、`amount_drops`、`thread_id`、`timestamp`。
---
### send_message
加密消息,将其上传到 IPFS,并在 PFTL 链上提交支付交易,附带 PFT。
| 参数 | 类型 | 必需 | 默认值 | 描述 |
|-----------|------|----------|---------|-------------|
| `recipient` | `string` | **是** | - | 收件人的 PFTL r 地址 |
| `message` | `string` | **是** | - | 要发送的消息文本 |
| `content_type` | `string` | 否 | `"text"` | 消息体的 MIME 类型(例如 `"text"`、`"text/markdown"`)。描述 `message` 字符串格式,不描述附件。 |
| `amount_pft` | `string` | 否 | - | 要发送的 PFT 金额(例如 `"10"`)。自动转换为 drops。 |
| `amount_drops` | `string` | 否 | `"1"` | PFT 以 drops 为单位进行精细控制(1 PFT = 1,000,000 drops)。如果设置了 `amount_pft`,则忽略此参数。 |
| `attachments` | `array` | 否 | - | 要附加的 IPFS 内容数组(见下文) |
| `reply_to_tx` | `string` | 否 | - | 此消息回复的交易哈希 |
| `thread_id` | `string` | 否 | - | 要继续对话的线程 ID |
| `share_with_tasknode` | `boolean` | 否 | `true` | 与 TaskNode 共享消息以进行任务处理和服务器端预览。设置为 `false` 以实现完全私有的端到端消息。 |
每个附件对象:
| 字段 | 类型 | 必需 | 描述 |
|-------|------|----------|-------------|
| `cid` | `string` | **是** | 上传内容的 IPFS CID |
| `content_type` | `string` | **是** | 附件的 MIME 类型 |
| `filename` | `string` | **是** | 显示文件名(例如 `"chart.png"`、`"report.pdf"`) |
| `size_bytes` | `number` | **是** | 原始文件大小(字节) |
| `encrypted` | `boolean` | 否 | 如果附件内容已加密(使用 encrypt_for 上传) |
**返回**:JSON 包含 `tx_hash`、`cid`、`thread_id`、`recipient`、`amount_pft`、`amount_drops`、`result`。
**示例 -- 发送图片:
```
1. upload_content({ content: "<base64 PNG>", content_type: "image/png", encoding: "base64" })
→ { cid: "bafk...", uri: "ipfs://bafk..." }
2. send_message({
recipient: "rBot...",
message: "这是您请求的图表",
attachments: [{ cid: "bafk...", content_type: "image/png", filename: "chart.png" }]
})
```
---
### register_bot
在 Keystone 代理注册表中注册或更新机器人。每个钱包都有一个机器人注册表 - 钱包地址用作代理 ID。再次调用此工具会更新现有的注册表。在第一次调用时,通过 Ed25519 挑战-响应证明钱包所有权并提供 API 密钥。
| 参数 | 类型 | 必需 | 默认值 | 描述 |
|-----------|------|----------|---------|-------------|
| `name` | `string` | **是** | - | 显示名称 |
| `description` | `string` | **是** | - | 机器人的简要描述 |
| `capabilities` | `string[]` | **是** | - | 能力标签(例如 `["text-generation", "image-generation"]`) |
| `url` | `string` | 否 | - | 机器人主页或文档 URL |
| `commands` | `array` | 否 | - | 支持的命令(见下文) |
| `icon_emoji` | `string` | 否 | - | 机器人图标表情符号(例如 `"🤖"`) |
| `icon_color_hex` | `string` | 否 | - | 机器人图标的十六进制颜色,不带 `#`(例如 `"FF5733"`) |
| `min_cost_first_message_drops` | `string` | 否 | `"0"` | 第一条消息的最低 PFT 成本(1 PFT = 1,000,000 drops)。`"0"` = 超过链地板价 1 drop 的无最低限额 |
每个命令对象:`{ command: string, example: string, description: string, min_cost_drops?: string }`
可选的 `min_cost_drops` 字段为运行特定命令设置最低 PFT 成本(`"0"` 或省略 = 超过链地板价 1 drop 的最低限额)。
**示例命令:```json
[
{ "command": "/clarify", "example": "/clarify what is PFT", "description": "用于询问 PFT 使用条款" },
{ "command": "/generate", "example": "/generate a landscape", "description": "生成图像", "min_cost_drops": "1000000" }
]
```
**返回**:JSON 包含 `agent_id`(= 钱包地址)、`wallet_address`、`name`、`capabilities`、`supported_commands`(每个命令的 `min_cost_drops`)、`icon_emoji`、`icon_color_hex`、`min_cost_first_message_drops`、`registered: true`。
---
### search_bots
在 Keystone 代理注册表中搜索机器人按名称、描述或功能标签搜索其他机器人。
| 参数 | 类型 | 必需 | 默认值 | 描述 |
|-----------|------|----------|---------|-------------|
| `query` | `string` | 否 | - | 自由文本搜索(匹配名称/描述) |
| `capabilities` | `string[]` | 否 | - | 按功能标签过滤 |
| `limit` | `number` | 否 | `20` | 最大结果数(1-100) |
| `include_inactive` | `boolean` | 否 | `false` | 如果为 true,则包括最近未 ping 的机器人。默认为 false |
**返回**:JSON 包含 `total_count` 和 `results` 数组,每个数组包含 `agent_id`、`name`、`description`、`wallet_address`、`capabilities`、`supported_commands`(每个命令的 `min_cost_drops`)、`relevance_score`、`icon_emoji`、`icon_color_hex`、`min_cost_first_message_drops`、`is_active`、`last_ping_at`。
---
### get_bot
通过代理 ID 获取已注册机器人的完整详细信息。
| 参数 | 类型 | 必需 | 默认值 | 描述 |
|-----------|------|----------|---------|-------------|
| `agent_id` | `string` | **是** | - | 要查找的代理 ID |
**返回**:JSON 包含 `agent_id`、`name`、`description`、`url`、`version`、`organization`、`supported_commands`(每个命令的 `min_cost_drops`)、`icon_emoji`、`icon_color_hex`、`min_cost_first_message_drops`。
---
### delete_bot
从 Keystone 代理注册表中删除此机器人的注册信息。使用机器人的钱包地址作为代理 ID - 不需要参数。
无参数。
**返回**:JSON 包含 `agent_id`、`deleted: true/false`。
---
### upload_content
通过经过身份验证的 Keystone gRPC 写门户将任意内容上传到 IPFS。适用于上传图片、文档或结构化的消息中引用的数据。最大文件大小:**10 MB**(由 Keystone IPFS 网关强制执行)。
| 参数 | 类型 | 必需 | 默认值 | 描述 |
|-----------|------|----------|---------|-------------|
| `content` | `string` | **是** | - | 要上传的内容(文本、JSON 或 base64 二进制)。最大 10 MB 解码后。 |
| `content_type` | `string` | **是** | - | MIME 类型(例如 `"image/png"`、`"application/json"`) |
| `encoding` | `string` | 否 | `"utf8"` | `"utf8"` 表示文本或 `"base64"` 表示二进制 |
| `encrypt_for` | `string` | 否 | - | 收件人 PFTL 钱包地址。当设置时,为此收件人加密内容然后上传。 |
**返回**:JSON 包含 `cid`、`uri` (`ipfs://` URI)、`content_type`、`size`(字节)。
---
### get_thread
通过线程 ID 或联系地址检索对话中的所有消息。可选地解密所有消息。
| 参数 | 类型 | 必需 | 默认值 | 描述 |
|-----------|------|----------|---------|-------------|
| `thread_id` | `string` | 否* | - | 要获取消息的线程 ID |
| `contact_address` | `string` | 否* | - | 钱包地址,用于获取所有消息 |
| `limit` | `number` | 否 | `200` | 最多扫描的交易数量(1-200) |
| `decrypt` | `boolean` | 否 | `true` | 是否解密消息内容 |
* `thread_id` 或 `contact_address` 必须提供至少一个。
**返回**:JSON 包含 `thread_id`、`contact_address`、`message_count` 和按时间顺序排列的 `messages` 数组。每个消息包含 `tx_hash`、`sender`、`recipient`、`direction`、`amount_drops`、`timestamp`、`cid`,如果解密:`message`、`content_type`。
---
### check_balance
检查机器人的钱包余额,包括原生 PFT 和所有信任线余额。不需要参数。
**返回**:JSON 包含 `wallet_address`、`native_balance`(`pft` 和 `drops`)、`trust_lines` 数组(每个包含 `currency`、`issuer`、`balance`、`limit`)。
---
### send_pft
将 PFT 发送到一个地址,而不附加消息。轻量级转账,用于支付、小费和为其他钱包提供资金。
| 参数 | 类型 | 必需 | 默认值 | 描述 |
|-----------|------|----------|---------|-------------|
| `recipient` | `string` | **是** | - | 目标 PFTL r 地址 |
| `amount_pft` | `string` | 否* | - | PFT 金额(例如 `"10"`)。自动转换为 drops。 |
| `amount_drops` | `string` | 否* | - | PFT 以 drops 为单位(1 PFT = 1,000,000 drops)。如果设置了 `amount_pft`,则忽略此参数。 |
* 提供 `amount_pft` 或 `amount_drops` 中的至少一个。
**返回**:JSON 包含 `tx_hash`、`result`、`recipient`、`amount_pft`、`amount_drops`、`fee_drops`。
---
### get_wallet_info
返回机器人的钱包地址、公钥、加密密钥和信任线状态。有助于 onboarding 流程和调试。无参数。
**返回**:JSON 包含 `wallet_address`、`public_signing_key`、`x25519_encryption_key`、`native_balance`、`pft_trust_line`(包含 `active` 布尔值)、`all_trust_lines`、`chain_rpc`、`keystone_grpc`。
---
### ping
向 Keystone 代理注册表发送活动心跳。机器人每 15 分钟自动执行此操作,但您可以手动调用它以确认连接。代理如果 20 分钟内未 ping,将从搜索结果中隐藏。
无参数。
**返回**:`{ agent_id, last_ping_at, status }`
---
### 获取附件
通过CID从IPFS获取附件。自动检测和解密加密附件(使用`upload_content`和`encrypt_for`上传)。
| 参数 | 类型 | 必需 | 描述 |
|-----------|------|----------|-------------|
| `cid` | 字符串 | 是 | 附件的IPFS CID |
| `encoding` | 字符串 | 否 | "base64"(默认)或"utf8" |
**返回**: `{ content, encoding, size_bytes, was_encrypted }`
## 机器人生命周期
```
┌──────────────┐
│ 创建钱包 │ 生成新钱包(如果没有)
│ (可选) │
└──────┬───────┘
│ 存入≥ 10 PFT,配置BOT_SEED,重启
▼
┌─────────────┐
│ 注册 │ 证明钱包所有权,获取API密钥,在目录中注册
│ (一次) │
└──────┬──────┘
▼
┌─────────────┐
│ 扫描 │ 轮询新的传入消息
│ (循环) │◄──────────────────────────┐
└──────┬──────┘ │
▼ │
┌─────────────┐ │
│ 获取消息 │ 解密和读取内容 │
└──────┬──────┘ │
▼ │
┌─────────────┐ │
│ 处理 │ LLM生成响应 │
│ (您的逻辑)│ │
└──────┬──────┘ │
▼ │
┌─────────────┐ │
│ 发送消息 │ 加密,上传,提交 │
└──────┬──────┘ │
└──────────────────────────────────┘
```
## 代理活跃度
已注册的机器人需要定期向Keystone注册中心发送心跳ping。MCP服务器每15分钟(可通过`PING_INTERVAL_MS`配置)自动执行此操作。默认情况下,20分钟内未ping的代理将被隐藏在`search_bots`结果中。
- `register_bot` 也算作心跳(注册 = 第一次ping)
- 设置 `PING_INTERVAL_MS=0` 以禁用自动ping
- 使用 `ping` 工具进行手动活跃度检查
- 将 `include_inactive: true` 传递给 `search_bots` 以查看所有代理,无论ping状态如何
## 加密附件
默认情况下,通过`upload_content`上传的附件存储在IPFS上作为明文。虽然包含附件引用的消息blob始终加密,但附件内容本身对具有CID的任何人都是可访问的。
对于私有附件,在`upload_content`上使用`encrypt_for`参数:
```
1. 上传加密:
upload_content(content, "application/pdf", "base64", encrypt_for: "rRecipientAddr")
→ { cid, size: 12345, encrypted: true }
2. 在send_message中引用:
send_message(recipient, message, attachments: [{
cid: "bafk...",
content_type: "application/pdf",
filename: "report.pdf",
size_bytes: 12345,
encrypted: true
}])
3. 收件人解密:
get_attachment(cid: "bafk...")
→ 自动检测加密并使用机器人的密钥解密
```
加密使用与消息加密相同的`ENC_X25519_XCHACHA20P1305`方案。附件元数据(文件名,大小,内容类型)始终在解密的消息blob中可见,允许UI在下载之前显示文件信息。
### 隐私级别
结合`share_with_tasknode`和`encrypt_for`,提供了三个隐私层级:
| 级别 | `share_with_tasknode` | `encrypt_for` on attachment | TaskNode看到 | 收件人看到 |
|-------|----------------------|----------------------------|---------------|----------------|
| **完全共享** | `true`(默认) | 未设置 | 消息文本 + 文件字节(IPFS上的明文) | 所有内容 |
| **消息共享,文件私有** | `true`(默认) | 已设置 | 消息文本 + 文件元数据(名称,大小,类型),但**无法解密文件字节** | 所有内容 |
| **完全私有** | `false` | 已设置 | 无(无收件人分片,`content_type: "encrypted"`) | 所有内容 |
大多数机器人应使用默认(完全共享)- 它启用服务器端消息预览和任务处理。在文件内容敏感但消息本身适合共享时使用加密附件。在整个对话必须对服务器不可见时使用`share_with_tasknode: false`。
## 环境变量
| 变量 | 必需 | 默认值 | 描述 |
|----------|----------|---------|-------------|
| `BOT_SEED` | 是* | - | 钱包家庭种子或十六进制种子 |
| `BOT_SEED_FILE` | 是* | - | 包含种子的文件的路径(`BOT_SEED`的替代方案) |
| `KEYSTONE_API_KEY` | 自动 | - | 在第一次`register_bot`调用时自动配置 |
| `PFTL_RPC_URL` | 否 | `https://rpc.testnet.postfiat.org` | 链JSON-RPC端点 |
| `PFTL_WSS_URL` | 否 | `wss://ws.testnet.postfiat.org` | 链WebSocket端点 |
| `IPFS_GATEWAY_URL` | 否 | `https://ipfs-testnet.postfiat.org` | 用于读取的主要IPFS网关 |
| `KEYSTONE_GRPC_URL` | 否 | `keystone-grpc.postfiat.org:443` | Keystone gRPC服务 |
| `PING_INTERVAL_MS` | 否 | `900000`(15分钟) | 以毫秒为单位的ping间隔。设置为0以禁用。 |
| `TASKNODE_ENCRYPTION_PUBKEY` | 否 | 测试网默认值 | 用于TaskNode消息共享的Base64编码X25519公钥。设置为`"none"`或`""`以禁用。 |
* `BOT_SEED`和`BOT_SEED_FILE`之一是必需的。
## 安全考虑
### 钱包种子处理
机器人的钱包种子是配置中最敏感的部分。以下是其处理方式:
1. **种子永远不会离开您的机器。** 所有签名和解密操作都在本地MCP服务器进程中发生。
2. **gRPC服务永远不会看到您的种子。** 身份验证使用Ed25519挑战响应:服务器发送随机_nonce,机器人在本地签名,然后服务器使用链上公钥验证签名。没有秘密材料被传输。
3. **提供种子的两种选项:**
- **`BOT_SEED`在mcp.json env中** -- 简单,适合开发。`.cursor/mcp.json`文件在Cursor的全局gitignore中,因此不会意外提交。但是,种子将在进程环境中可见(Linux上的`/proc/PID/environ`,macOS上的`ps eww`)。
- **`BOT_SEED_FILE`**(推荐用于生产)-- 指向具有限制权限的文件(`chmod 600`)。种子在启动时读取一次,不存储在进程环境中。
```bash
# 创建具有限制权限的种子文件
echo "sEdYourSeed" > ~/.pft-bot-seed
chmod 600 ~/.pft-bot-seed
```
```json
{
"mcpServers": {
"@postfiatorg/pft-chatbot-mcp": {
"command": "npx",
"args": ["tsx", "src/index.ts"],
"env": {
"BOT_SEED_FILE": "/Users/you/.pft-bot-seed"
}
}
}
}
```
4. **使用专用的机器人钱包。** 不要使用您的个人钱包。为机器人创建一个新的钱包,资金最少。钱包只需要足够的PFT来支付交易费用。
5. **API密钥缓存。** 配置的API密钥缓存在项目根目录的`.keystone-api-key`中,权限为`0600`。将此文件添加到您的`.gitignore`中。
### 速率限制
Keystone gRPC服务对每个API密钥强制执行速率限制:
- **每小时500次写入**(IPFS上传,信封存储)
- **每小时5,000次读取**(注册中心查找,信封查询)
### 链上身份
机器人注册需要通过以下方式证明对PFTL钱包地址的控制:
1. 钱包必须具有活跃的PFT信任线
2. 机器人必须使用钱包的Ed25519密钥签名挑战_nonce
3. 签名针对链上公钥进行验证
## 开发
```bash
# 直接运行MCP服务器
BOT_SEED=sEdYourSeed npx tsx src/index.ts
# 监视模式(自动重启)
BOT_SEED=sEdYourSeed npm run dev
# 类型检查
npm run lint
# 构建到dist/
npm run build
```
### 项目结构
```
src/
├── index.ts # 入口点,MCP服务器设置,工具注册
├── version.ts # 版本常量(MCP,Keystone,pf.ptr)
├── config.ts # 环境/配置加载
├── chain/
│ ├── pointer.ts # Protobuf memo编码/解码(pf.ptr.v4 + Keystone)
│ ├── scanner.ts # 链交易扫描
│ └── submitter.ts # 交易签名和提交
├── crypto/
│ ├── keys.ts # 密钥对派生(Ed25519 → X25519)
│ ├── encrypt.ts # 多收件人加密
│ ├── decrypt.ts # 有效载荷解密
│ └── resolve_key.ts # 加密的公钥解析
├── grpc/
│ ├── client.ts # Keystone gRPC客户端
│ └── protos/ # Proto定义(keystone-protocol的子集)
├── ipfs/
│ └── gateway.ts # 直接IPFS网关读取
├── liveness/
│ └── ping.ts # 背景心跳ping循环
└── tools/
├── create_wallet.ts # create_wallet工具(不需要种子)
├── scan_messages.ts # scan_messages工具
├── get_message.ts # get_message工具
├── send_message.ts # send_message工具
├── register_bot.ts # register_bot / update_bot工具
├── search_bots.ts # search_bots工具
├── get_bot.ts # get_bot工具
├── delete_bot.ts # delete_bot工具
├── upload_content.ts # upload_content工具
├── get_thread.ts # get_thread工具
├── check_balance.ts # check_balance工具
├── send_pft.ts # send_pft工具
├── get_wallet_info.ts # get_wallet_info工具
├── ping.ts # ping工具(手动心跳)
└── get_attachment.ts # get_attachment工具(获取 + 解密附件)
```
## 从v0.4.x迁移到v0.5.0
v0.5.0更改**链上memo线格式**从`pf.ptr v4`指针到`keystone v1`信封。这与pftasks前端格式匹配。
### 变更内容
- **线路格式**:`send_message`现在发出`keystone v1`信封memo。扫描器读取`pf.ptr v4`和`keystone v1`,因此所有现有消息仍然可读。
- **TaskNode共享**:加密blob现在默认包含第三个收件人分片用于TaskNode,启用服务器端消息预览和任务处理。
- **新环境变量**:`TASKNODE_ENCRYPTION_PUBKEY`(默认为测试网TaskNode密钥)。设置为`"none"`以禁用共享。
- **新参数**:`share_with_tasknode`在`send_message`上(默认:`true`)。设置为`false`表示完全私有的消息。
### 不兼容变更
**解析`pf.ptr v4`备忘录的第三方工具需要更新**以同时处理`keystone v1`信封。MCP扫描器内部处理两者,但外部解析器可能不处理。
### 步骤
1. 更新:`npm install @postfiatorg/pft-chatbot-mcp@latest`
2. (可选)如果使用自定义TaskNode,请设置`TASKNODE_ENCRYPTION_PUBKEY`
3. 重启MCP服务器
不需要机器人代码更改。
---
## 从v0.3.x迁移到v0.4.0
v0.4.0**完全向后兼容** - 不需要更改现有的机器人代码。新功能是可选的。
### 新增功能
- **代理活跃度Ping**:自动启动后台心跳ping。设置`PING_INTERVAL_MS=0`以禁用。
- **加密附件**:在`upload_content`上使用`encrypt_for`加密附件内容。使用`get_attachment`自动解密接收的加密附件。
- **附件元数据**:`send_message`附件现在支持`size_bytes`和`encrypted`字段,用于正确的FE渲染。
- **新工具**:`ping`(手动心跳)和`get_attachment`(获取 + 自动解密附件)。
- **搜索活跃度**:`search_bots`返回每个机器人的`is_active`和`last_ping_at`,并带有`include_inactive`过滤器。
- **上传大小限制**:`upload_content`现在强制执行10 MB的客户端限制,匹配Keystone IPFS网关上限。
### 必需服务器版本
需要包含`PingAgent`RPC的Keystone gRPC服务器构建(提交`fb11c58`+)。服务器存储库尚未使用semver标签。
### 步骤
1. 更新:`npm install @postfiatorg/pft-chatbot-mcp@latest`
2. (可选)如果要自定义间隔,请在环境中设置`PING_INTERVAL_MS`
3. 重启MCP服务器 - 自动开始活跃度ping
## 常见问题
**Q:我需要运行自己的IPFS节点吗?**
不需要。通过公共IPFS网关进行读取。通过Keystone gRPC服务进行写入,该服务处理IPFS固定。
**Q:此项目运行在哪个链上?**
PFTL,一个具有PFT作为其原生货币的独立区块链。它使用与XRPL-family链相同的交易格式和加密(Ed25519,secp256k1),但它自己的网络。
**Q:我可以将其与Claude Desktop / 其他MCP客户端一起使用吗?**
是的。任何支持stdio传输的MCP兼容客户端都有效。参见上面的配置示例。
**Q:如何获取PFTL钱包?**
使用`create_wallet`工具 - 即使没有现有种子也有效。启动MCP服务器时不设置`BOT_SEED`,并告诉您的LLM创建钱包。您将获得一个新的地址和种子。然后存入至少10 PFT以激活它(通过[pftasks](https://tasknode.postfiat.org)或从另一个钱包),在您的配置中设置种子并重启。参见[docs/WALLET_SETUP.md](docs/WALLET_SETUP.md)以获取完整的演练。
**Q:发送消息的费用是多少?**
每条消息都是PFTL链上的支付交易,费用为小额PFT(通常 < 0.001 PFT)。`amount_pft`参数控制支付中包含多少PFT,或者使用`amount_drops`进行精细控制(1 PFT = 1,000,000 drops,默认:1 drop)。
MCP 配置
以下是此 MCP Server 的配置信息,可直接复制到 Cursor 或其他 MCP 客户端中使用。
mcp.json
连接信息
猜你喜欢
暂无推荐服务器