Skip to content

客户端 SDK 使用指南

OneBots 提供两类客户端:imhelper 面向事件驱动的机器人业务,@onebots/mcp-client 面向 AI Agent 和自动化工具调用。两者连接同一网关,但协议模型不同。

客户端适用场景协议
imhelper机器人框架、业务服务、事件消费OneBot 11/12、Milky、Satori
@onebots/mcp-clientAI Agent、自动化脚本MCP

imhelper

安装并选择协议

安装核心包和一个协议包:

bash
pnpm add imhelper @imhelper/onebot-v12
协议Client factory
OneBot 11@imhelper/onebot-v11createOnebot11Client()
OneBot 12@imhelper/onebot-v12createOnebot12Client()
Milky@imhelper/milky-v1createMilkyClient()
Satori@imhelper/satori-v1createSatoriClient()

具体 factory 返回保留协议 Adapter、原始事件和 call() 类型的 Client。应用代码通常无需先创建 Adapter,也无需调用已移除的 registerAdapter()connect()

创建 Client

baseUrl 是完整的账号协议根地址。SDK 不会根据 platformselfId 或其他字段猜测 OneBots 网关布局。

typescript
import { createOnebot12Client } from '@imhelper/onebot-v12';

const client = createOnebot12Client({
  baseUrl: 'http://localhost:6727/qq/my-bot/onebot/v12',
  apiBaseUrl: 'http://localhost:6727/qq/my-bot/onebot/v12',
  wsUrl: 'ws://localhost:6727/qq/my-bot/onebot/v12',
  selfId: 'my-bot',
  accessToken: 'your-token',
  receiveMode: 'ws',
});

client.on('message.private', async message => {
  await message.reply('收到!');
});

client.on('message.group', async message => {
  console.log(message.sender.user_id, message.content);
});

await client.start();

应用退出时调用 await client.stop()。并发 start() / stop() 由当前 Adapter 的生命周期实现负责。

API 地址与自定义调用

apiBaseUrl 仅在事件和 API 部署在不同地址时设置。OneBot action 追加到 API 根地址,Milky 使用 /api/{action},Satori 使用 /{resource}.{method}

typescript
const status = await client.call('get_status');
await client.sendPrivateMessage('user-id', '你好');
await client.sendGroupMessage('group-id', '大家好');

特殊部署可使用 resolveActionUrl 改写动作 URL,或注入 call 完全接管协议请求。HTTP、协议或平台错误会以结构化 ProtocolError 抛出。

Satori 的原生调用使用资源和方法两个参数:

typescript
import { createSatoriClient } from '@imhelper/satori-v1';

const satori = createSatoriClient({
  baseUrl: 'http://localhost:6727/discord/my-bot/satori/v1',
  selfId: 'my-bot',
  platform: 'discord',
  accessToken: 'your-token',
  receiveMode: 'manual',
});

await satori.call('guild', 'list', {});

事件与实体

Client 提供类型化事件:

  • message.privatemessage.groupmessage.channel
  • notice.*request.*meta.*
  • event:当前协议的原始事件

查询 API 会把 DTO 投影为绑定当前 Client 的实体。同一实体刷新后保持对象身份,已有引用会看到最新资料。

typescript
const users = await client.getUserList();
const groups = await client.getGroupList();
const group = await client.getGroupInfo('group-id');
const members = await client.getGroupMemberList('group-id');

await users[0].sendMessage('你好');
await group.sendMessage('群消息');
await members[0].refresh();

pickUser()pickGroup()pickChannel() 只选择已经由事件或查询写入缓存的实体,不发起网络请求。

频道属于 Guild 时必须显式提供父级上下文:

typescript
const channels = await client.getChannelList({
  scope: { type: 'guild', id: 'guild-id' },
});

await client.sendChannelMessage('channel-id', '频道消息', 'guild-id');
await channels[0].sendMessage('频道消息');

接收模式

receiveMode 支持 wsssewsswebhookmanual

模式行为启动方式
ws主动连接正向 WebSocketclient.start()
sse主动连接 SSEclient.start()
wss独立监听反向 WebSocketclient.start(port)
webhook独立监听 HTTP Webhookclient.start(port)
manual不创建连接或端口由宿主调用接入方法

WebSocket 默认无限重连。可通过 webSocket 配置 AbortSignal、退避、随机抖动和 logger。

接入已有 Host

已有 HTTP 服务、反向 WebSocket、队列或框架连接应使用 manual。所有入口最终交给同一个 Client,不需要 SDK 再开端口。

typescript
const manual = createOnebot12Client({
  baseUrl: 'http://localhost:6727/qq/my-bot/onebot/v12',
  selfId: 'my-bot',
  receiveMode: 'manual',
});

manual.ingest(rawEvent);

Node.js HTTP Host 可以直接传入 request/response:

typescript
import { createServer } from 'node:http';

createServer(async (request, response) => {
  if (request.url === '/events') {
    await manual.acceptHttp(request, response);
    return;
  }
  response.writeHead(404).end();
}).listen(8080);

宿主希望自行写响应时省略第二个参数,使用 { status, headers, body } 结构化结果。路由与鉴权仍由宿主负责。

已完成 Upgrade 的 WebSocket 可直接交付:

typescript
webSocketServer.on('connection', socket => {
  const detach = manual.acceptWebSocket(socket);
  socket.once('close', detach);
});

请求和文件

通用入口包括:

  • 用户、好友、群组、成员、Guild 和 Channel 目录
  • getMessage()uploadFile()getFile()
  • approveFriendRequest()approveGroupRequest()
  • 消息实体的 reply()recall()edit() 与 reaction 动作

协议不支持的可选动作会抛出 UnsupportedAdapterOperationError,不会用空数组或伪成功结果掩盖能力缺失。

MCP 客户端

@onebots/mcp-client 通过 JSON-RPC 主动调用工具,独立于 imhelper 的事件模型。Cursor、Claude Code 等 Agent 通常直接连接 onebots mcp,无需安装此包。

bash
pnpm add @onebots/mcp-client
typescript
import { McpStdioClient } from '@onebots/mcp-client';

const client = new McpStdioClient({
  command: 'onebots',
  args: ['mcp', '--data-dir', '/path/to/onebots-data', '--account', 'qq/my-bot'],
});

await client.connect();
const tools = await client.listTools();
const result = await client.callTool('send_message', {
  scene_type: 'group',
  scene_id: 'group-id',
  message: 'Hello from MCP!',
});
await client.close();

远程服务使用 McpSseClient。完整说明见 MCP 协议

下一步