Skip to main content
Glama
wanwujiehuyi-web

qq-mcp-bridge

README.md
# qq-mcp-bridge

把 **QQ 官方机器人**([bot.q.qq.com](https://bot.q.qq.com/open))接入 DeepSeek Harness 的 MCP 桥。

只做两件事:

| 能力 | 说明 |
|---|---|
| 私聊收发 | 用户私聊机器人 → 消息落到本地队列 → DSH 用 `fetch_messages` 取走,用 `send_private_message` 回复 |
| 主动推送 | DSH 随时可调 `send_private_message`(不传 `msg_id`),用于任务完成、定时提醒 |

> 不包含群聊消息。需要群聊请自行增加 `send_group_message` 工具,并注意每个工具 schema 都会进入每次模型请求。

## 需要什么

1. 在 [QQ 开放平台](https://bot.q.qq.com/open) 注册开发者、创建机器人并通过审核;
2. 记下 **AppID**、**ClientSecret**(WebSocket 鉴权用;不是 QQ 密码);
3. Node.js >= 22.4;
4. 本机网络能访问 `api.bot.qq.com`。

## 安装(DSH bundle)

```powershell
npx -p @deepseek-ai/dsh dsh plugin --profile web add qq-mcp-bridge@0.1.0
```

重启 DSH 后,工具以 `mcp__qq__*` 出现。

包通过 `cordis.patch.yml` 注册 `@deepseek-ai/dsh-mcp-client`:

```yaml
- insert:
    - id: qq-mcp
      name: '@deepseek-ai/dsh-mcp-client'
      config:
        serverName: qq
        transport: stdio
        command: npx
        args: ['-y', '-p', 'qq-mcp-bridge@0.1.0', 'qq-mcp-bridge']
```

## 配置(不要把 AppSecret 提交进 Git)

复制示例:

```powershell
New-Item -ItemType Directory -Force "$env:USERPROFILE\.qq-mcp-bridge" | Out-Null
Copy-Item .\config.example.json "$env:USERPROFILE\.qq-mcp-bridge\config.local.json"
```

编辑 `%USERPROFILE%\.qq-mcp-bridge\config.local.json`:

```json
{
  "appId": "你的 AppID",
  "clientSecret": "你的 ClientSecret",
  "appToken": "",
  "apiBase": "https://api.bot.qq.com"
}
```

读取顺序:

1. `QQ_CONFIG_FILE` 指定的文件;
2. 包根目录的 `config.local.json`;
3. `%USERPROFILE%\.qq-mcp-bridge\config.local.json`。

也支持环境变量 `QQ_BOT_APPID` / `QQ_BOT_CLIENT_SECRET` / `QQ_BOT_APP_TOKEN`,但 DSH 启动 MCP 子进程时会清洗含 `SECRET/TOKEN` 的父环境变量,所以最稳的是本地 `config.local.json`,或在 DSH profile 的 `env` 块显式注入。

没有凭证时服务自动进入 **mock 模式**:不发网络请求,可用于验证 MCP 协议。

## 工具

| 工具 | 用途 |
|---|---|
| `mcp__qq__fetch_messages` | 取用户发来的待处理私聊消息 |
| `mcp__qq__send_private_message` | 回复;带 `msg_id` 为被动回复,不带则为主动推送 |
| `mcp__qq__bot_info` | 查看机器人身份、mock/网关状态、待处理队列、已知联系人 |

主动推送需要 `user_openid`。它只能从对方发来的消息里获得;QQ 不提供“按 QQ 号查 openid”。同一个用户在不同机器人下的 openid 不同。

## 本地运行 / 自检

```powershell
node src/mcp-server.js        # stdio MCP
node src/doctor.js            # 配置与连通性诊断
npm test                      # selftest + gateway 状态机测试
```

Waker 插件(可选,本机 profile 使用):

```yaml
- insert:
    - id: qq-waker
      name: '<qq-mcp-bridge 包路径>/waker/index.js'
      config:
        sessionId: '<目标 DSH 会话 ID>'
        bridgeDir: '<qq-mcp-bridge 包路径>'
        env:
          QQ_BOT_APPID: '<你的 AppID>'
          QQ_BOT_CLIENT_SECRET: '<你的 ClientSecret>'
```

Waker 会持有 WebSocket,将入站消息直接注入指定会话;如果只用 MCP 工具,不需要它。

## 安全边界

- 本仓库不包含任何真实 AppID/AppSecret/openid/会话 ID;
- `state/`、`config.local.json`、日志、测试抓包已被 `.gitignore` 排除;
- 消息队列和联系人只写本机;
- 只支持 QQ 官方机器人私聊,不读取个人 QQ 协议,不模拟登录。

## License

MIT

TDQS

A4/5.0

Scored across 3 tools

Disambiguation5/5

The three tools cover three clearly distinct roles: sending a message, draining the inbound message queue, and inspecting bot/bridge status. There is no plausible way to confuse send_private_message with fetch_messages or bot_info, and the descriptions reinforce the send/receive/observe split.

Naming Consistency4/5

send_private_message and fetch_messages both follow a consistent snake_case verb_noun pattern and pair naturally as outbound/inbound counterparts. bot_info breaks the pattern by using a bare noun with no verb, which is a minor deviation but a readable one.

Tool Count4/5

Three tools is lean but appropriate for a thin WebSocket-to-MCP bridge whose job is just relay plus status. The surface is not padded, though it sits near the lower bound where an agent might want one or two more capabilities.

Completeness3/5

The core poll-then-reply loop is covered, but the surface stops at private chat: there is no group/conversation messaging, no media or non-text sending, no history or message-lookup beyond the live queue, and no acknowledgement semantics for processed messages. These are notable gaps for a general QQ bot bridge even if private-only was intentional.

Maintenance

ActivityNo data
ResponsivenessNo issues