给第三方API Claude Code 接上飞书:从零写一个 Channels 插件
给第三方API Claude Code 接上飞书:从零写一个 Channels 插件
给第三方API Claude Code 接上飞书:从零写一个 Channels 插件 给第三方API Claude Code 接上飞书:从零写一个 Channels 插件 Modified March 21 5. 在 事件与回调 中: ◦ 添加事件 im.message.receive v1 6. 版本管理 → 创建版本 → 申请发布 记下 App ID 和 App Secret 。 2. 插件文件结构 Code block Plain Text Copy feishu channel/ ├── .claude/ │ └── skills/ │ ├── access feishu/ │ │ └── SKILL.md /access feishu 配对与权限管理 │ └── configure feishu/ │ └── SKILL.md /configure feishu 凭证配置 ├── .claude plugin/ │ └── plugin.json 插件元数据 ├── .mcp.json MCP Server 启动配置 ├── package.json 依赖声明 ├── server.ts 核心实现( 600 行) └── README.md 3. 核心依赖 Code block Plain Text Copy { "dependencies": { "@modelcontextprotocol/sdk": "^1.12.1", "@larksuiteoapi/node sdk": "^1.50.0" } } • MCP SDK — 和 Claude Code 通信的标准协议 • 飞书 Node SDK — 官方 SDK,内置 WebSocket client 4. server.ts 核心逻辑 4.1 MCP Server 声明 Channel 能力 Code block Plain Text Copy const server = new McpServer({ name: "feishu channel", version: "0.1.0", }, { capabilities: { experimental: { "claude/channel": {} }, tools: {}, }, }); 这里的 "claude/channel": {} 就是告诉 Claude Code:「我是一个 Channel 插件,不是普通 MCP Server」。这是上篇文章中提到的七层检查的 第 ① 层 ——也是唯一一层我们不绕过、而是正常通过的。 4.2 飞书 WebSocket 连接 Code block Plain Text Copy import { Client, WSClient } from"@larksuiteoapi/node sdk"; const feishuClient = new Client({ appId: FEISHU APP ID, appSecret: FEISHU APP SECRET, appType: AppType.SelfBuild, }); const wsClient = new WSClient({ appId: FEISHU APP ID, appSecret: FEISHU APP SECRET, eventDispatcher, // 消息事件分发器 loggerLevel: LoggerLevel.info, }); wsClient.start(); // 自动连接、自动重连 飞书 SDK 的 WSClient 会自动处理连接建立、心跳和断线重连——这就是为什么说飞书的 API 比 Telegram 好用,人家拉个 WebSocket 就完事了,不用我们操心轮询和重试逻辑。 4.3 消息转发到 Claude Code Code block Plain Text Copy // 收到飞书消息后,通过 MCP notification 转发给 Claude Code await mcp.notification({ method: "notifications/claude/channel", params: { content: extractedText, meta: { chat id: chatId, sender id: senderId, sender name: senderName, }, }, }); 4.4 Reply Tool — 回复飞书消息 Code block Plain Text Copy server.tool("reply", { chat id: z.string(), text: z.string() }, async ({ chat id, text }) = { // 长文本自动分块 const chunks = splitText(text, chunkLimit); for (const chunk of chunks) { await feishuClient.im.message.create({ params: { receive id type: "chat id" }, data: { receive id: chat id, msg type: "text", content: JSON.stringify({ text: chunk }), }, }); } return { content: [{ type: "text", text: "已发送" }] }; } ); 4.5 配对与访问控制 跟 Telegram 插件一样,我们实现了 配对码 机制——毕竟不能让随便谁都能通过飞书给你的 Claude 发指令(想想就知道多可怕 😨): 1. 陌生人给你的机器人发消息 → 生成 6 位配对码 → 飞书回复 "请在 Claude Code 中确认" 2. 你 在 Claude Code 中执行 /access feishu pair <配对码 ——只有你的终端能执行这个命令 3. 配对成功,对方加入白名单 → 后续消息直达 Claude 🚀 跑起来 Code block Plain Text Copy 1. 克隆仓库并安装依赖 git clone https://github.com/czm15053/claude code feishu channel.git cd claude code feishu channel && bun install 2. 配置凭证 mkdir p /.claude/channels/feishu cat /.claude/channels/feishu/.env << EOF FEISHU APP ID=cli xxxxxxxxxxxx FEISHU APP SECRET=xxxxxxxxxxxxxxxxxxxxxxxx EOF chmod 600 /.claude/channels/feishu/.env 3. 打补丁(如果还没打) python3 patch claude.py 应输出 ✅ 补丁1/2 4. 以开发模式启动 claude add dir ./ \ dangerously load development channels server:feishu 启动后你应该看到: Code block Plain Text Copy Listening for channel messages from: server:feishu 在飞书上给机器人发一条消息,Claude Code 就会收到并自动处理! 🔧 踩坑指南 以下是我调试时踩过的坑,希望你不用再踩一遍。 🔴 发消息没任何反应? → 99% 是飞书后台的事件订阅没选「长连接」模式。默认是 Webhook,但我们没用 Webhook,所以什么都收不到。 🔴 配对不生效? → 看看 /.claude/channels/feishu/access.json ,确认 pending 里有你的配对码。急的话可以直接手动把 open id 加到 allowFrom 数组里。 🔴 /access feishu 命令找不到? → 必须用 add dir ./ 加载插件目录,单独 claude mcp add 只注册 MCP server,不会加载 skills。 🔴 旧进程赖着不走? → ps aux | grep bun 检查有没有残留的旧 bun 进程,有的话 kill 掉再重启。飞书的 WebSocket 是独占连接,旧进程占着新进程就收不到消息。 📝 新版补丁脚本 适配 v2.1.81+,使用正则表达式自动匹配混淆函数名,不再依赖硬编码。 完整代码见 GitHub: patch claude.py 脚本做了三件事: 补丁 1: tengu harbor flag → true 通过正则匹配 function XXX(){return YYY("tengu harbor",!1)} ,将返回值改为 !0 (始终启用 Channels 功能)。 补丁 2: Gate 函数 → 只保留能力检查 通过搜索 "server did not declare claude/channel capability" 和 "channels feature is not currently available" 两个 不会被混淆的字符串常量 来定位 gate 函数,然后删除 disabled / auth / policy / session / allowlist 共 5 层检查,只保留第 ① 层能力声明检查。 如果一次性正则匹配不上,还有 fallback 方案 :逐项定位并移除每一层检查(2a 2e),确保不同版本的微调都能覆盖。 补丁 3: UI 层面检查(旧版兼容) 移除 noAuth 和 policyBlocked 两个前端显示拦截。新版可能已无此结构,脚本会自动跳过。 Code block Plain Text Copy 用法 python3 patch claude.py 输出示例 ✅ 补丁1: Ho6() tengu harbor flag → 始终 true ✅ 补丁2: xXq() channel gate → 只保留能力检查 ⏭️ 补丁3a: noAuth 字段不存在(新版不需要) ⏭️ 补丁3b: policyBlocked 字段不存在(新版不需要) 🎉 补丁完成! 🎯 总结 对比 Telegram 飞书 消息接收 长轮询 WebSocket 长连接 5. 在 事件与回调 中: ◦ 添加事件 im.message.receive v1 ◦ 添加事件 im.message.receive v1 6. 版本管理 → 创建版本 → 申请发布 记下 App ID 和 App Secret 。 2. 插件文件结构 3. 核心依赖 • MCP SDK — 和 Claude Code 通信的标准协议 • 飞书 Node SDK — 官方 SDK,内置 WebSocket client 4. server.ts 核心逻辑 4.1 MCP Server 声明 Channel 能力 这里的 "claude/channel": {} 就是告诉 Claude Code:「我是一个 Channel 插件,不是普通 MCP Server」。这是上篇文章中提到的七层检查的 第 ① 层 ——也是唯一一层我们不绕过、而是正常通过的。 4.2 飞书 WebSocket 连接 飞书 SDK 的 WSClient 会自动处理连接建立、心跳和断线重连——这就是为什么说飞书的 API 比 Telegram 好用,人家拉个 WebSocket 就完事了,不用我们操心轮询和重试逻辑。 4.3 消息转发到 Claude Code 4.4 Reply Tool — 回复飞书消息 4.5 配对与访问控制 跟 Telegram 插件一样,我们实现了 配对码 机制——毕竟不能让随便谁都能通过飞书给你的 Claude 发指令(想想就知道多可怕 😨): 1. 陌生人给你的机器人发消息 → 生成 6 位配对码 → 飞书回复 "请在 Claude Code 中确认" 2. 你 在 Claude Code 中执行 /access feishu pair <配对码 ——只有你的终端能执行这个命令 3. 配对成功,对方加入白名单 → 后续消息直达 Claude 🚀 跑起来 启动后你应该看到: 在飞书上给机器人发一条消息,Claude Code 就会收到并自动处理! 🔧 踩坑指南 以下是我调试时踩过的坑,希望你不用再踩一遍。 🔴 发消息没任何反应? → 99% 是飞书后台的事件订阅没选「长连接」模式。默认是 Webhook,但我们没用 Webhook,所以什么都收不到。 🔴 配对不生效? → 看看 /.claude/channels/feishu/access.json ,确认 pending 里有你的配对码。急的话可以直接手动把 open id 加到 allowFrom 数组里。 🔴 /access feishu 命令找不到? → 必须用 add dir ./ 加载插件目录,单独 claude mcp add 只注册 MCP server,不会加载 skills。 🔴 旧进程赖着不走? → ps aux | grep bun 检查有没有残留的旧 bun 进程,有的话 kill 掉再重启。飞书的 WebSocket 是独占连接,旧进程占着新进程就收不到消息。 📝 新版补丁脚本 适配 v2.1.81+,使用正则表达式自动匹配混淆函数名,不再依赖硬编码。 完整代码见 GitHub: patch claude.py 脚本做了三件事: 补丁 1: tengu harbor flag → true 通过正则匹配 function XXX(){return YYY("tengu harbor",!1)} ,将返回值改为 !0 (始终启用 Channels 功能)。 补丁 2: Gate 函数 → 只保留能力检查 通过搜索 "server did not declare claude/channel capability" 和 "channels feature is not currently available" 两个 不会被混淆的字符串常量 来定位 gate 函数,然后删除 disabled / auth / policy / session / allowlist 共 5 层检查,只保留第 ① 层能力声明检查。 如果一次性正则匹配不上,还有 fallback 方案 :逐项定位并移除每一层检查(2a 2e),确保不同版本的微调都能覆盖。 补丁 3: UI 层面检查(旧版兼容) 移除 noAuth 和 policyBlocked 两个前端显示拦截。新版可能已无此结构,脚本会自动跳过。 🎯 总结 对比 Telegram 飞书 消息接收 长轮询 WebSocket 长连接 对比 对比 Telegram Telegram 飞书 飞书 消息接收 消息接收 长轮询 长轮询 WebSocket 长连接 WebSocket 长连接 公网 IP 不需要 不需要 官方支持 ✅ 插件市场 ❌ 需自建 国内可用性 🔧 需梯子 ✅ 原生 SDK 质量 Telegraf(社区) 官方 Node SDK 飞书的技术方案其实比 Telegram 更优雅。而且说实话,在国内能直接用这一点就已经赢了。 整个插件 600 行 TypeScript,核心逻辑参照了官方 Telegram 插件的架构。代码开源在 GitHub ,欢迎 Star 和贡献 🤝 如果你也想写其他平台的 Channel 插件(钉钉?企微?Slack?),欢迎参考这个项目的架构,套路都是一样的: WebSocket/轮询接收消息 → MCP notification 转发 → reply tool 回复 。 下一篇写什么?也许是《让 Claude Code 自己部署自己》?敲码不如让 AI 干 😏 上一篇: 《用 API Key 也能玩 Channels:Claude Code 接入 Telegram/Discord 全攻略》 《用 API Key 也能玩 Channels:Claude Code 接入 Telegram/Discord 全攻略》 免责声明:本文仅供技术研究和学习交流。修改商业软件的行为请自行评估法律和安全风险。 🔗 原文链接: https://mp.weixin.qq.com/s/pIIF10z2... https://mp.weixin.qq.com/s/pIIF10z2... czm czm 小陈的AI随笔2026年3月21日 16:03 广东 上篇把 Telegram/Discord 接上了 Claude Code,但 Telegram/Discord 在国内都不方便。这次我们写一个飞书 Channel,600 行 TypeScript,消息通道国内直连,不用公网 IP ⚡ 太长不看版 飞书应用需要:创建自建应用 → 添加机器人 → 开通权限 → 事件订阅选「 长连接 」→ 发布。详见下文。 📖 前情提要 在 上一篇文章 中,我们深入 Claude Code 的 cli.js (一个 30MB 的巨型混淆 JS),发现了隐藏的 Channels 功能,然后用一个 Python 补丁脚本绕过了七层门禁,成功把 Telegram 和 Discord 接入了 Claude Code。 上一篇文章 但很快我就发现了一个尴尬的现实: Telegram 和 Discord 在国内都不太方便…… 🫠 Telegram/Discord 的消息收发本身就需要特殊网络环境,用起来多了一层麻烦。 所以这一次,我们不用官方插件了——直接 自己动手写一个飞书(Lark)Channel 插件 ,让 Claude Code 变成你的飞书机器人。在地铁上、在床上、在马桶上,随时随地给 Claude 发消息让它帮你写代码 😏 ⚠️ 版本更新:补丁脚本也升级了 上篇文章基于 Claude Code v2.1.80 ,补丁脚本使用硬编码的混淆函数名( Ra6 、 qMq 、 cA 等)。但到了 v2.1.81 ,Anthropic 更新了代码,混淆名全部变了: v2.1.80 v2.1.81 功能 Ra6() Ho6() 读取 tengu harbor feature flag qMq() xXq() Channel 注册决策(七层检查) cA() hA() 获取 OAuth Token A1() l8() 读取远程 flag v2.1.80 v2.1.80 v2.1.81 v2.1.81 功能 功能 Ra6() Ra6() Ho6() Ho6() 读取 tengu harbor feature flag 读取 tengu harbor feature flag qMq() qMq() xXq() xXq() Channel 注册决策(七层检查) Channel 注册决策(七层检查) cA() cA() hA() hA() 获取 OAuth Token 获取 OAuth Token A1() A1() l8() l8() 读取远程 flag 读取远程 flag 代码结构也有变化:旧版有独立的 noAuth: 和 policyBlocked: 字段,新版把所有检查都合并到了 gate 函数 xXq() 里。简单来说,就是从“七个小守卫各管一道门”变成了“一个大老管管所有门”: 结果就是: 旧版补丁脚本在新版上会报 ⚠️ 找不到函数 。别慌,新版脚本已经搞定了 👇 新版自适应补丁 新版补丁脚本改用 正则表达式 匹配,不再依赖具体的混淆函数名: Gate 函数的处理也类似——通过搜索 "server did not declare claude/channel capability" 和 "channels feature is not currently available" 两个 不会被混淆的字符串常量 来定位函数,然后用正则提取参数名和函数名: 这样无论 Anthropic 怎么改混淆名,只要字符串常量不变,补丁就能自动适配。跟 Anthropic 打游击战,就是要这种“以不变应万变”的思路 😎 完整脚本见文末。 🤔 为什么是飞书? 官方的 Channels 插件仓库 (anthropics/claude plugins official) 只有 Telegram 和 Discord。飞书?官方估计都不知道这是什么。 但说实话, 飞书的 Bot API 比 Telegram 强多了 。Telegram 还在用老套的长轮询(long polling),飞书直接上了 WebSocket 长连接 ——不需要轮询、不需要 Webhook、不需要公网 IP: • ✅ 没有公网暴露,不会有数据泄漏风险 • ✅ 延迟更低(实时推送 vs Telegram 的「每秒问一次有没有新消息」) • ✅ 消息通道国内直连 ,Telegram/Discord 做不到这一点 🏗️ 架构概览 先看大图,整个数据流就像一个“翻译官”:飞书用户说中文(飞书消息),翻译官转成英文(MCP 协议),Claude 听懂后回复,翻译官再转回去: 整个插件就是一个 MCP Server ——左手拉着飞书(WebSocket),右手拉着 Claude Code(stdio),两边传话。 📋 实现步骤 1. 创建飞书应用 1. 打开 飞书开放平台 2. 创建企业自建应用 3. 添加 机器人 能力 4. 在 权限管理 中点击「 批量开通 」,粘贴以下 JSON 一键开通所有需要的权限: ◦ 订阅方式选择 「使用长连接接收事件」 (⚠️ 关键!不选这个就收不到消息)