qq-onebot-mcp
# qq-onebot-mcp
轻量 **MCP server**:把 **QQ**(NapCat / OneBot 11)接入任意 MCP 宿主(DSH、Claude、Cursor…)。
零 npm 依赖,纯 Node.js ≥ 20,仅用内置 `WebSocket`。
- **私聊**(白名单老大)→ 消息进 inbox → 宿主 agent 处理(完整工具权限)→ 回复。
- **群聊 @机器人**(白名单群)→ 桥直接用 LLM API 回答,**不经 agent、不碰本机**。
## 架构
```
QQ 老大 ──私聊──▶ NapCat(QQ小号) ──OneBot11/WS:3001──▶ qq-mcp-server.mjs ──MCP──▶ 宿主 agent
▲
(inbox / 工具)
```
| 层 | 文件 | 职责 |
|---|---|---|
| 接入 | NapCat | QQ 协议 → OneBot 11(WS 3001) |
| 桥 | `qq-mcp-server.mjs` | MCP server:工具、排他锁、inbox |
| 桥 | `onebot.mjs` | OneBot WS 客户端(零依赖) |
| 桥 | `group_llm.mjs` | 群聊纯 LLM 直答 |
| 唤醒 | `qq-listener.mjs` | 常驻监听 + 注入宿主席位(可选闭环) |
| 控制 | `qqctl.mjs` | 进程生命周期(start/stop/status) |
## 快速开始
1. **NapCat**:装好并有 QQ 小号登录,开启 OneBot WS(默认 `ws://127.0.0.1:3001`)。
2. **配置**:`cp .env.example .env`,填 `QQ_BOT`、`QQ_ALLOWED_SENDERS`(可加 `LLM_API_KEY` 开群聊)。
3. **注册 MCP**:宿主指向 `qq-mcp-server.mjs`(stdio)。DSH 用 `dsh-bundle/` 模板,见 `INSTALL-DSH.md`。
4. **上号**:告诉 agent「上QQ号」→ 按 `skills/qq-online/SKILL.md` 走 attach → 等消息 → 回复。
| 环境变量 | 必填 | 含义 |
|---|---|---|
| `QQ_BOT` | ✅ | 机器人 QQ 号 |
| `QQ_ALLOWED_SENDERS` | ✅ | 私聊白名单,逗号分隔 |
| `ONEBOT_WS_URL` | | NapCat WS 地址(默认 `ws://127.0.0.1:3001`) |
| `QQ_ALLOWED_GROUPS` | | 静态群白名单(留空=动态) |
| `LLM_API_KEY` / `LLM_BASE_URL` / `LLM_MODEL` | | 群聊直答用 |
> `.env` 已 git 忽略,绝不提交。
## MCP 工具
| 工具 | 说明 |
|---|---|
| `qq_attach` / `qq_detach` | 排他占用 / 释放桥(文件锁,跨宿主;崩溃残留自动抢占) |
| `qq_wait_inbox` | 阻塞等私聊(零轮询,推荐循环用) |
| `qq_poll_inbox` | 取 inbox(可设超时) |
| `qq_send` | 回复当前对话者(仅白名单) |
| `qq_status` | 桥状态 |
| `qq_get_agent_profile` | 读 AGENTS.md 角色设定 |
**待机模式**:server 启动不连 NapCat,`qq_attach` 才连、`qq_detach` 断开 —— 零资源占用。
## 全自动闭环(可选)
想让 QQ 消息**自动唤醒 agent**(不用每次喊「上号」):以独立进程跑 `qq-listener.mjs`:
```bash
DSH_API_URL=http://127.0.0.1:3080 DSH_SESSION_ID=<session-id> \
node qq-listener.mjs <tag> <workdir> 0
```
```
QQ 消息 → 监听器(wait_inbox) → 写入 <workdir>/inbox/ + POST http://127.0.0.1:3080/api/session.prompt
│
agent 自动醒来处理 → <workdir>/outbox/ → qq_send 回复
```
- 监听器独立于 agent 会话常驻;`session.prompt`(mode: queue)把消息注入宿主会话触发回合。
- 回复放 `<workdir>/outbox/*.json`(`{type:"send", message}`),监听器发送(无 chat target 时直连 OneBot WS)。
- 优雅停止:`<workdir>` 里写 `stop.flag`。
> ⚠️ `session.prompt` 无鉴权且仅限回环,只在本机信任环境使用。
## 安全
- 私聊:仅白名单;陌生私聊丢弃。
- 群聊:纯 LLM,永不接触本机文件/命令。
- `qq_send` 只能回当前对话者(白名单内)。
- 白名单用户拉机器人进群 → 自动加白并公告。
## 个性化
编辑 `AGENTS.md`(人设/职责/安全边界),桥每会话重新加载,无需重启。
> 本地隐私(如重要人物关系)可放 `data/`(git 忽略)并在 `AGENTS_MD` 里指向它 —— 不上 GitHub。
### 动态会话发现(闭环)
监听器不再写死 `DSH_SESSION_ID`:每次收到消息先调 `session.list` 找 **running + 标题含 上号/QQ/布卡** 的会话,找不到再回退 env。这样「上号」会话被替换/重开后闭环依然生效。
## 开发
```bash
npm test # 全部入口语法检查
```
## 文件
```
├── qq-mcp-server.mjs # MCP server(主入口)
├── onebot.mjs # OneBot WS 客户端
├── group_llm.mjs # 群聊 LLM 直答
├── bridge.mjs # 独立触发桥(无 MCP 宿主)
├── bridge-acp.mjs # ACP 连接器(持久 DSH 会话)
├── qq-listener.mjs # 闭环监听器
├── qqctl.mjs # 进程控制
├── dsh-bundle/ # DSH profile bundle 模板
├── skills/qq-online/ # 「上QQ号」技能
├── INSTALL-DSH.md # 新用户自装指南
└── .env.example # 配置模板
```
## License
MIT
TDQS
Scored across 8 tools
Each tool has a clearly distinct purpose: sending, receiving (with two variants for context), status, profile retrieval, disc-change signal, and lifecycle management (attach/detach). No overlap causes ambiguity.
All tools follow the consistent `qq_` prefix followed by an action verb (send, poll, wait, status, get, take, attach, detach). Naming is uniform, snake_case, and predictable.
With 8 tools, the server is well-scoped for a QQ bridge: it covers messaging, inbox handling, status, profile, and session control without excess. This is within the ideal 3-15 tool range.
Core private-message workflows and lifecycle are covered: send, receive, status, claim/release, and disc-change. Missing group-message tools and whitelist management, though these may be intentionally out of scope for a private-owner bridge.