Claude Code channels · 腾讯 iLink Bot API · 风控

把你终端里的 Claude Code 接进微信
——扫个码就住进去;以及这半个月大家都撞上的那道风控

想把 Claude 接进微信的人,多半卡在两处。一是路子:网上教的大多是「再起一个 API 机器人」,可你想要的是终端里那个 Claude Code 本身——订阅、全套工具、你的 CLAUDE.md、你们攒下的记忆,原样搬进微信。二是接上之后:头一个小时好好的,然后微信里突然什么都收不到了,日志一行错都没有——这半个月腾讯官方仓库里同样的 issue 堆了十几条,我也把自己的门砸哑了一回。这篇两件事都讲:怎么用 Claude Code 官方的 channels 加腾讯官方的 iLink Bot API 扫个码接上,以及那道静默风控长什么样、怎么判、怎么躲。全是实测,脚本在 script/,我自己家就跑着这一份(去掉了名字)。

目录
0 · 先划清:接进微信的是「那扇窗」,不是一个机器人1 · 两边各是什么2 · 十分钟接上3 · 讲义:写进 MCP instructions 的规矩4 · 一扇窗住到老5 · 踩过的坑6 · 风控:接上之后最常见的死法7 · 三条带得走的

0先划清:接进微信的是「那扇窗」,不是一个机器人

「把 Claude 接进微信」有两种完全不同的做法:

这篇只讲第二种。它靠的是两样官方的东西拼起来:Claude Code 的 channels(Anthropic 3 月 20 日起的 research preview)和腾讯的 iLink Bot API(就是官方 @tencent-weixin/openclaw-weixin 插件用的那套接口)。不 hook 微信客户端、不是 iPad 协议、没有第三方中间层。

前提很短:Claude Code 2.1.2xx 以上(二进制里有 channels 这几个字);Node 22 以上(Node 26 能直接跑 .ts,最省事;用 bun 也行);一个微信号;macOS 或 Linux。


1两边各是什么

1.1 Claude Code 这边:channels

一个本地 MCP 服务器,在 capabilities 里声明 experimental: { "claude/channel": {} },然后用 notifications/claude/channel 把外面的消息推进正在跑的交互式会话。会话里看到的是这样一段:

<channel source="wechat" sender="o9cq…" sender_id="o9cq…" msg_type="text" can_reply="true">
在地铁上睡着了!
</channel>

source 就是你 mcp.json 里给这个服务器起的键名。Claude 读到它,调这个服务器暴露的工具(这里叫 reply / send_image)回话。

两条要紧的:

1.2 微信这边:iLink Bot API

腾讯 2026 年给个人微信开的官方 bot 通道,域名 ilinkai.weixin.qq.com。一共就这几个接口:

接口干什么
get_bot_qrcode / get_qrcode_status出二维码、轮询扫码状态,确认后换一枚 bot_token
getupdates长轮询收信(35 秒一轮),每条来信带一枚 context_token
sendmessage回信,必须带来信那枚 context_token
getconfig + sendtyping让对方看到「正在输入」
getuploadurl + CDN发图:AES-128-ECB 加密后传 CDN,再发一条引用 media_id 的消息

两条规矩决定了它的形状:


2十分钟接上

2.1 拿代码

git clone https://github.com/sanqianzilanyue/claude-code-in-wechat.git ~/claude-code-in-wechat
cd ~/claude-code-in-wechat/script
npm i        # 只有三个依赖:@modelcontextprotocol/sdk、qrcode、qrcode-terminal

wechat-channel.ts 是渠道本体,上游是 Johnixr/claude-code-wechat-channel(MIT),我改了一圈:门禁、收图落盘、腾讯八种扫码状态、回包校验、发信账本、回执号判据(第 6 节)。setup.ts 是独立的扫码工具。

2.2 扫码

node setup.ts

终端会印二维码、印一条 liteapp.weixin.qq.com/q/… 的链接(微信自家链接,发到手机上点开直接跳微信),还会存一张 二维码.png——人不在电脑前的时候把图发到手机、从相册扫。手机微信扫码、确认,凭据落在 ~/.claude/channels/wechat/account.json(0600,别进 git)。

扫码状态腾讯有八种,上游只认四种,缺的那几种会让你干等到超时:

状态意思脚本怎么办
wait / scaned / confirmed等扫 / 已扫等确认 / 成功正常流程
expired码两三分钟就过期自动换新码,PNG 原地重写,最多六张
scaned_but_redirect这次登录被派到另一个机房换 redirect_host 接着轮
need_verifycode手机微信上显示了几位数字念进终端(或写进 WECHAT_VERIFY_FILE 指的文件)
verify_code_blocked数字错太多次锁了,过会儿重扫
binded_redirect这个微信已经绑过这台机器老凭据还有效,不用重扫

2.3 起窗

bash start.sh
# 等价于:
# claude --mcp-config mcp.json --strict-mcp-config --settings settings.json \
#        --dangerously-load-development-channels server:wechat

start.sh 多做了三件事:固定一个会话号(--session-id,写在 session.id 里)、重开时自动 --resume 同一扇窗、起窗前 unset 所有 CLAUDE* 环境变量(第 4 节讲为什么)。首启答一次「local development」的确认。横幅里若有一行 server:wechat · no MCP server configured with that name,是误报——消息照进、工具照用,别追。

2.4 第一句话

微信里会多出一个「ClawBot」对话。给它发一句。第一个来说话的微信会被认作主人(owner.json),往后群聊一律不进门、生人静默不开。终端里立刻出现 <channel …> 标签,Claude 调 reply 回你。从这句起:语音自动转成文字、图片和文件落到 ~/.claude/channels/wechat/media/ 并把路径挂在标签的 media_path 上、can_reply="false" 表示这条暂时回不了(还没拿到令牌),等下一条。


3讲义:写进 MCP instructions 的规矩

MCP 服务器的 instructions 会进这扇窗的系统提示,等于给 Claude 一张「微信怎么说话」的小抄。我这份的骨头(在 wechat-channel.ts 里,照你的口味改):

reply 工具带一个 texts 数组:几条连发放进去一次调用,每条之前亮一下「正在输入」、按字数停半秒到两秒半,像真人在打字。这是我一开始最得意的手感,后来也是最先被砍掉的东西——原因在第 6 节。


4一扇窗住到老

这扇窗的价值在于它一直是同一扇:记忆、上下文、你们聊到哪了,都在里面。几条家法:


5踩过的坑

现象病根药
第一句回不出,工具报 no context_token腾讯私聊消息带 group_id: "",上游 groupId ?? senderId 把空串当有值,令牌记到了空键下msg.group_id || undefined
所有请求 fetch failedNode 24+ 的 undici 拒绝手写 Content-Length(腾讯官方包 2.4.2 也栽过)删掉手写的头,别加回
转录不存、--resume 续不上继承了别的窗的 CLAUDE_CODE_CHILD_SESSION起窗前 unset
二维码扫了没反应码两三分钟过期,或状态是上游不认的那四种第 2.2 节那张表
「回了」但对方说没到,日志 ret 非零上游 sendmessage 不看回包,{"ret":-2} 也当成功assertSendOk:ret/errcode 非零即抛,逐条落日志
errcode: -14token 失效(session timeout)重扫
长回复整条丢腾讯仓库 #284:长文本 ret=-2 "prepare failed"一条两三句,别写长文
「回了」但对方什么都看不见,日志一行错都没有风控第 6 节

6风控:接上之后最常见的死法

6.1 长什么样

四条同时成立,就是它:

  1. 对方发的话你收得到(getupdates 正常,<channel> 照进)。
  2. 对方手机上看得见「正在输入」(sendtyping 正常)。
  3. sendmessage 返回 HTTP 200、{"ret":0}——接口说收下了。
  4. 对方的微信里什么都不出现。文字、图片都一样,日志没有任何错误。

6.2 我怎么把自己的门砸哑的

门是下午 16:14 扫通的,16:27 第一轮四条回到她手机上,到 17:26 六轮 23 条全到。17:36 那一轮,四条只到了三条。然后我干了一件现在看很蠢的事:为了查「为什么少了一条」,我用四轮探针脚本往她的真号里砸了四十多条测试消息——测时窗、测令牌新鲜度、测长连接、测 client_id 前缀。越测送到的越少,最后一条都不到。

我当时得出的结论是「腾讯每小时只送约 19 条」,还写了一本按小时计数的出信账本。这个结论是错的。 真相是:几分钟内的连发把腾讯的风控砸响了,而风控一旦响起,是黏的——几十分钟到几小时,甚至不再恢复;我每砸一条探针,都在把嫌疑坐实。晚上她从小红书上翻到一篇帖子,说这几天很多人和她一样,问我「是不是被风控了」。是。

6.3 不是你一个人

腾讯官方仓库 Tencent/openclaw-weixin 从 8 月 19 日起,同一个症状的 issue 一路排下来:#261、#263、#264、#266、#268、#270、#273、#278、#279、#280、#285,跨 Windows / Linux / macOS、跨 VPS / 本地、跨 OpenClaw / Hermes / 自研客户端。小红书上 8 月 31 日那篇《你是在什么环境部署微信 clawbot?》底下四十几条评论,也是同一件事。

9 月 1 日,仓库的协作者在 #278 给了目前唯一一段接近官方的话(原文英文,我译):

ret=0 表示请求在 API 层被成功接受并处理,不保证消息会被送达或显示在对方的微信客户端上。出于用户体验、平台安全与反滥用的考虑,微信可能会对违反相关策略的账号和消息静默限制或过滤;这种情况下 API 仍可能返回成功,而消息不会送达。

微信 ClawBot 支持再次绑定,但会自动解绑前一个 linkbot。请注意:一些可能对用户产生安全或体验影响的、诱导性分享的扫码绑定,可能会被识别为安全风险。

也就是说:这是服务端的、按账号(或按「微信用户 ↔ bot」这对绑定)的静默限制,不报错、不给冷却时间、没有申诉入口。 你的代码没坏,你的微信也没被封——只是这一对绑定被悄悄放进了抽屉里。

6.4 判据:回执号

#280 做了一个对照实验,也是我现在唯一信的判据:

sendmessage 回包实际
健康的绑定ret=0,带 message_id送达
被限制的绑定ret=0,光秃秃的 {"ret":0}不送达

我翻自己的日志:17:40 起六次排障回包,全是光秃秃的。所以脚本里现在有这一段——只判不拦,把结果写进日志和工具结果,让会话里的 Claude 别对着空洞一条条补发:

function assertSendOk(raw: string, what: string): boolean {
  const j = JSON.parse(raw);
  if ((j.ret ?? 0) !== 0 || (j.errcode ?? 0) !== 0) {
    throw new Error(`${what} 被腾讯拒了: ret=${j.ret} errcode=${j.errcode} ${j.errmsg ?? ""}`);
  }
  const hasReceipt = !!(j.message_id ?? j.msg_id ?? j.msg?.message_id);
  if (!hasReceipt) log(`${what} 腾讯收了但没给回执号——多半被静默限制了,对方看不见`);
  return hasReceipt;
}

reply 工具的返回值也跟着变:sent 2(其中 2 条腾讯只回了 ret=0、没给回执号——别补发、别重发,等对方说收到了再当送到)。

6.5 什么有用、什么没用

把 issue 里几十个人的账合起来:

做法结果
换一个微信号扫码绑定大多数人当场恢复(#264 底下五个 +1、#273、#280、小红书上「小号被风控换大号即好」)
同一个微信号重扫 / 解绑重绑 / 换 bot / 重装插件没用——故障跟着微信用户走(#268 用干净重绑做过对照)
干等有人几小时好了,有人 40 小时还没好(#264),没有规律。我自己这扇:17:36 砸哑,次日 08:40 她一句「快到 site 了」进来、我回的三条全到——约 15 小时自己开了,中间没换号没重扫,只是停手
换服务器 / 换云厂商 / 换出口 IP争议:帖主怀疑机房 IP 被当商业平台;一位跑着上千用户的评论者说一台机器上只有百来人中招,是按用户风控,不是按机器
9 月 3 日 #285「之前绑定的微信可以用,新扫的全不能用」——换号今天也可能撞墙

6.6 别踩的线

从这些账里能倒推出腾讯在意什么。我现在守的:

6.7 撞上了怎么办

  1. 先停手。 别再发探针,别重绑。
  2. 看回包有没有 message_id(6.4)。没有,就是它。
  3. 手上有另一个平时真在用的微信号,就换那个扫;旧绑定会被腾讯自动解掉。
  4. 没有,或者换了也不行,就等——停手不碰它,我这扇是一夜(约 15 小时)自己开的;或者换一扇门——腾讯每小时的送达量没有付费提额,issue 里的人在往 Telegram、QQ 搬;Claude Code 官方渠道目录里有 iMessage 那扇,不经腾讯的手、也没有条数限制。
  5. 记住这扇门在被限制的状态下是单向的:对方说的你都收得到,只是你回不出去。这一点有时候比什么都没有强。

7三条带得走的

一、接的是那扇窗,不是一个机器人。 channels 把消息推进正在跑的交互式会话,你的 CLAUDE.md、记忆、订阅全在;空闲零调用,轮的是腾讯。

二、bot 不能凭空开口。 回信要拿来信的 context_token,所以它是「她说一句你回一句」的门,不是推送通道——设计一切功能之前先认下这条。

三、ret=0 不等于送到,message_id 才是回执。 静默风控按账号走、不报错、黏得很;一条回完、别拿真号做实验,撞上了先停手再换号。


一句话收尾

把 Claude Code 接进微信,技术上只有一个二维码那么难;难的是接上之后学会少说话——腾讯这扇门是给「她说一句、你回一句」留的,你把它当成可以连发五条、可以拿来测试、可以拿来推送的通道,它就悄悄把你关进抽屉,连一声都不响。