钉钉飞书集体抛弃 MCP,CLI 才是 Agent 的终局#飞书与钉钉 ypxx.net

同一周,钉钉和飞书不约而同做了同一件事: 把整个产品「压扁」成了命令行。

3 月 17 日,钉钉发布「悟空」平台,宣布完成全面 CLI 化改造。10 天后,CLI 代码开源。

3 月 28 日,飞书跟上,CLI 开源,Go 语言,MIT 协议。

两家……都没有选 MCP。

这背后,是一个正在成型的行业共识:Agent 操作软件的最佳方式,恐怕就是那个最古老的命令行。

读过我之前文章的朋友应该有印象,我一直在实践和呼吁软件的 CLI 化,见:

之前主要都是开源社区在推,而这一次,是国内两大办公平台官方亲自下场了。

所以,我今天把两个 CLI 都装上,仔细看了一遍。

下面聊聊它们各自做了什么,差在哪,以及为什么整个行业都在朝这个方向跑。

钉钉先出手

钉钉的动作更早,也更激进。

3 月 17 日阿里发布「悟空」平台时,钉钉 CTO 朱鸿说的是:

“

我们希望每一个 AI Agent,都能像调用系统命令一样自然地调用钉钉。

注意用词,「系统命令」,不是「API」,不是「协议」,是 ls、cd、grep那种东西。

DingTalk Workspace CLI

钉钉做的事情是重写底层代码,把整个产品 CLI 化。并非在现有 GUI 上包一层壳,是让 Agent 直接调用底层能力,绕过图形界面。

GitHub 项目叫 dingtalk-workspace-cli,Go 语言写的,8MB 的原生二进制文件,Apache-2.0 协议。安装方式是一行 curl 脚本,装完之后本地多一个 dws命令。

实际装完跑一下 dws --help,能看到 12 个服务模块:

aitable AI 表格操作

attendance 考勤打卡 / 排班 / 统计

bot 机器人消息 / Webhook

calendar 日历日程 / 会议室 / 闲忙

chat 群聊 / 会话 / 群组管理

contact 通讯录 / 用户 / 部门

devdoc 开放平台文档搜索

ding DING 消息 / 发送 / 撤回

oa OA 审批 / 同意 / 拒绝 / 撤销

report 日志 / 模版 / 统计

todo 待办任务管理

workbench 工作台应用查询

命令结构是标准的「服务/资源/动作」三级,比如 dws calendar event create、dws contact user search --keyword "张三"。

也没什么花哨的东西,但直觉上倒是挺好理解的。

钉钉还做了几个面向 Agent 的设计细节:

--yes参数。这个参数的描述是「跳过确认提示(AI Agent 模式)」。加上它之后,Agent 执行操作不会被交互式确认卡住。这个看似不起眼,但做过 Agent 开发的应该都懂:一个交互式 prompt 就能让整个自动化流程崩溃。

--mock参数。可以用模拟数据测试,不用真的连钉钉后台。开发调试的时候非常实用。

--dry-run预览。所有可能产生副作用的操作都能先预览再执行。Agent 要删个日程、发个 DING 消息之前,先看看要干什么。

安全方面,钉钉做了三件事:无感认证(Agent 自动继承企业权限)、批量熔断(防止 Agent 失控批量操作)、安全沙箱(所有操作在沙箱内执行)。

钉钉还搞了个叫 RealDoc 的 AI 原生文件系统,号称有 10000+ 条可用命令行指令,支持原子级文件操作,所有操作保留完整快照。

飞书的三层架构

飞书晚了 10 天,但在架构设计上明显花了更多心思。

飞书 CLI 叫 lark-cli,同样是 Go 写的,但通过 npm 分发(包了一层 Node.js wrapper),14MB。MIT 协议。

一行命令装完:npm install -g @larksuite/cli

跑一下 lark-cli --help,第一眼就能看出跟钉钉的差异:飞书的命令体系是三层设计。

飞书 CLI 三层架构

第一层:Shortcuts(+前缀命令)。

这是飞书最有辨识度的设计。所有快捷命令都带 +前缀,内置智能默认值:

lark-cli calendar +agenda # 看今天日程

lark-cli im +messages-send --text "hello" --chat-id oc_xxx

lark-cli contact +search-user --query "John"

lark-cli docs +fetch --doc-id xxx

这些命令做了大量参数简化。比如 +messages-send,支持 --text、--markdown、--image、--file这些直接参数,不用自己拼 JSON content 。

对 Agent 来说,写 --markdown "会议纪要已生成"比拼一段 {"msg_type":"post","content":{"post":{"zh_cn":...}}}要友好得多。

光是 base(多维表格)模块,就有 68 个 shortcut 命令,从创建仪表盘到管理工作流,覆盖得挺全。

第二层:API Commands。

100 多条命令,跟飞书平台 API 一一对应。

比如 lark-cli calendar events list、lark-cli im messages create。

第三层:Raw API。

直接调用飞书底层 2500 多个 OpenAPI 端点:

lark-cli api GET /open-apis/calendar/v4/calendars

lark-cli api POST /open-apis/im/v1/messages --data '{"receive_id":"ou_xxx",...}'

这层相当于一个万能逃生舱:不管飞书有什么 API,即使 CLI 没有封装对应的命令,你也能直接调。

从而让 Agent 遇到边缘场景的时候不会被卡住。

飞书还内置了一个 schema命令,可以查看任何 API 方法的参数、类型和所需权限:

lark-cli schema calendar.events.list --format pretty

这对 Agent 来说相当于一本随时可查的 API 字典。

输出格式上,飞书支持 JSON、NDJSON、table、CSV、pretty 五种格式。钉钉支持 JSON、table、raw 三种。

飞书多出来的 NDJSON 和 CSV 在数据处理场景下挺关键的,可以直接 pipe 给 jq或者 csvtool做后续处理。

认证方面,飞书的设计也更细致一些。

lark-cli auth login支持按域(domain)申请权限,比如 --domain calendar,task只申请日历和任务相关的权限,不用一口气开全。还支持 --as user和 --as bot切换身份,同一个 CLI 可以模拟用户操作,也可以用应用身份批量处理。

还有个 lark-cli doctor命令,一键检查配置、认证和网络连通性,排查问题的时候应该比较省心。

两家对比

钉钉 vs 飞书 CLI 能力对比

两个 CLI 都装过用过之后,差异就出来了。

钉钉的优势侧重在企业管理场景。OA 审批(approve/reject/revoke)、考勤(打卡/排班/统计)、DING 消息、日志/周报,这些飞书 CLI 里完全没有。如果你的 Agent 需要帮老板批审批单、查考勤、催日报,钉钉目前是唯一选择。

飞书的优势在开发者体验和文档协作。完整的邮件客户端(搜索/起草/发送/转发/监听新邮件)、文档的 Markdown 互转、电子表格的读写追加查找、知识库管理、会议纪要搜索,这些钉钉 CLI 目前都还没覆盖到。

用一个比喻来说,钉钉 CLI 像是给企业行政部门配的数字助理,飞书 CLI 更像是给研发团队配的效率工具。

架构哲学上的差异也比较明显:

钉钉走的是「服务发现」路线,dws --help里写的是「Discovered MCP Services」,命令帮助全部是中文。

飞书走的是「开发者工具」路线,三层架构从快捷到通用逐级递进,全英文界面,还附带了 19 个 AI Skill 可以直接装进 Claude Code。

全局参数上,两家都有 --dry-run和 --format。钉钉独有 --mock(模拟数据)和 --yes(跳过确认),飞书独有 --page-all(自动翻页)和 --as(身份切换)。

开源层面,飞书的 GitHub 星标(1313)几乎是钉钉(815)的 1.6 倍。

差点自己动手

说句实话,看到飞书出 CLI 的时候,我的第一反应是: 总算特么来了。

因为我其实,差点就上手自己做了。

Skill + CLI 的组合架构

我之前文章里聊过,我从去年起就一直偏爱用 CLI + Skill 的方式操控各种服务:Cloudflare 的 CLI 管域名解析和 Workers 部署,aliyunCLI 管 RAM 用户和 OSS 存储,gcloudCLI 操作 Google Cloud。

我会把这些 CLI 的用法写成 Skill(更早时还没有 Skill),告诉 Claude Code 每个命令该怎么用,Agent 就能直接上手。

飞书是我日常用得最多的办公工具之一,但之前一直没有官方 CLI。社区里虽然有个 feishu-cli(500 多颗星),能做 Markdown 和飞书文档的双向转换,但覆盖面远远不够。我已经在琢磨自己基于飞书 OpenAPI 包一套 CLI 出来了。

结果飞书官方直接出了,还一上来就是 2500+ API 端点全覆盖。

省了我不少事,但也说明了一个问题:当用户都开始自己动手给你的产品做 CLI 的时候,说明官方已经晚了。飞书这次,算是踩在了临界点上。

钉钉和飞书之后,企业微信、Notion、Slack、……等应该都不会坐得住太久了。

它们都清楚,谁先出 CLI,谁就先拿到 Agent 时代的入场券。

MCP 的 17 倍成本

技术选型上,两家绕开 MCP 是有充分理由的。

ScaleKit 做过一组 benchmark,拿 GitHub 官方 MCP 服务器和 ghCLI 做了一组对照实验,跑的模型是 Claude Sonnet 4。

各任务的 Token 消耗对比

查一个仓库用什么语言,CLI 消耗 1,365 tokens,MCP 消耗 44,026 tokens。

足足 32 倍!

查 PR 详情和审核状态?CLI 1,648 tokens,MCP 32,279 tokens。20 倍。

查仓库元数据和安装方式?CLI 9,386 tokens,MCP 82,835 tokens。9 倍。

所有 5 项任务的差异都具有统计显著性(p < 0.05)。

MCP 有 28% 的失败率

可靠性的差距更大:

CLI 跑了 25 次全部成功。MCP 只成功了 18 次,失败率 28%。7 次失败全是 TCP 层面的超时。

成本与可靠性对比

按月算就更直观了:每月 1 万次操作,CLI 大约 3.2 美元,MCP 大约 55.2 美元。17 倍的成本差距。

问题出在哪呢?

Schema 膨胀的解剖

MCP 的 schema bloat。GitHub 的 MCP 服务器带了 43 个工具定义,每次对话都得把这 43 个工具的完整描述全塞进上下文。你只是想查个仓库语言,但模型得先读完所有 43 个工具的说明书。

光一个 list_stars_language_is_known工具的定义就占了 4,026 tokens。

这就像去便利店买瓶水,店员非要先把整本商品目录念给你听。

ScaleKit 指出了一个关键判断:MCP 的效率问题不在于协议本身,而在于 schema 注入机制。但问题是,这个机制恰恰是 MCP 设计的核心,你没法绕开它。

而 CLI 呢?Agent 只需要跑一下 --help,按需读取某个子命令的参数说明就行。不用、也不会把所有命令的文档一股脑塞进上下文。

Perplexity 的 CTO Denis Yarats 在今年的 Ask 开发者大会上也表了态:Perplexity 内部正在远离 MCP,原因是 72% 的上下文窗口被 MCP 占掉了,再加上认证带来的摩擦成本。

旧金山街头投票

Composio 的联合创始人 Karan Vaidya 上周跑到旧金山街头做了个随机调查,就问路过的开发者一个问题:CLI 还是 MCP?

结果是:CLI 17 票,MCP 3 票。

OpenAI 前联合创始人 Greg Brockman 站了 CLI。Y Combinator CEO 陈嘉兴的态度更干脆:MCP sucks。一位被采访的开发者则贡献了全场最佳金句:

“

MCP 像 Java 一样臃肿。

Composio 顺势发了自己的 Universal CLI,并给出了一个很精准的重新定义:这场争论的本质不是品味之争,是延迟之争。

CLI 和 MCP 的核心差异,归根到底就是一个快一个慢,一个轻一个重。35 岁以下的开发者基本上全选了 CLI。

这说明什么呢?

新一代开发者已经形成了一种直觉:能用一行命令解决的事,别搞一套协议。

安全是伪命题吗

当然,也不是所有人都买账。

Okta(Auth0 的母公司)的研发副总裁 Damian Schenkelman 写了篇文章,标题就很刚:「如果你要杀死 MCP,说明你根本不在乎安全」。

核心论点是:CLI 调 API 要是认真做安全的话,你最终得加上 OAuth 授权、动态客户端注册、敏感操作审批、服务端鉴权……加完这些,你其实就重新发明了 MCP。

他列了几条:没法基于 Agent 身份做策略管控(比如只允许特定 AI 厂商的 Agent 接入);鉴权应该在服务端,不能信任客户端;敏感操作需要人工审批,Agent 搞砸了得有人能拦住。

这个论证乍一看确实有些道理,不过仔细想想,其实犯了一个典型的「过度泛化」错误。

Schenkelman 描述的是一个完全开放的生态场景:你做了一个 SaaS,互联网上任何 Agent 都可能来调你的 API,你不知道对方是谁,不知道它要干什么。

在这个场景下,确实需要 MCP 那套完整的协议握手。

但钉钉和飞书面对的场景则完全不同。

企业内部的 Agent 身份是已知的,权限是预设的,操作在沙箱里跑,日志全程可追溯。钉钉的批量熔断机制,飞书的 dry-run 预览和按域权限申请,本质上就是在 CLI 层面实现了 Schenkelman 所说的那些安全措施。

只是没套 MCP 那个协议壳子而已。

换个说法:你家里人进厨房拿刀切菜,不需要先通过安检、出示身份证、签免责协议。但如果是陌生人进你的厨房,那确实应该先问问他是谁、要干什么。

MCP 是给陌生人设计的安检流程,CLI 是给自家人用的厨房工具。

硬把安检流程套在自家人身上,除了浪费时间,没有任何安全增益。

翻译层的演化

从更长的时间线看,这件事几乎是必然的。

在之前的 中,我提过一个「第四次迁移」的框架:大型机 → PC → 移动 → Agent,每一次迁移都是因为出现了新的用户。

而每次迁移,旧时代的巨头恰恰因为在旧界面上做得太好,反而无法适应新界面。Nokia 的实体键盘体验全球第一,但触屏时代这成了累赘。

翻译层的演化:从 CLI 回到 CLI

这次也一样。计算机诞生以来,人和机器的交互方式经历了三次大迁移:命令行 → 图形界面 → 触屏。每一次迁移,都是因为出现了新的「用户」,需要新的翻译层。

普通人不会打命令,所以有了 GUI。手机用户不方便用鼠标,所以有了触屏。

现在又来了一种新用户:AI Agent。

Agent 不需要按钮和菜单,那些是给人类视觉系统设计的翻译层。Agent 不需要触屏手势,那是给人类手指设计的。

Agent 要的是结构化的输入输出,要的是可以 pipe 的文本流,要的是 --help就能自描述的命令接口。

GUI 是翻译层:人类需要,Agent 不需要

而这恰恰就是 CLI 在五十年前就已经实现的东西。

LLM 的训练数据里有数十亿行 shell 命令和脚本。对模型来说,写一行 lark-cli calendar +agenda | jq '.items[]'比理解一个 MCP 工具的 JSON Schema 定义要自然得多了。

Unix 哲学里的 pipe、组合、文本流,这些设计范式已经稳定运行了五十年。

CLI 是 LLM 的母语,MCP 是后天学的外语。

所以这轮迁移出现了一个反直觉的现象:不是从旧到新,是从新回到旧。GUI 是 CLI 之后发明的「翻译层」,而 Agent 时代的最佳接口,恰恰就是翻译层之前的原始形态。

钉钉和飞书的选择,本质上是在顺应这个事实。

当你的用户从人变成了 AI,你就该用 AI 最擅长的方式暴露你的能力。

回头看几个时间线:

……

CLI-Anything 在 GitHub 上拿了 15000 颗星,证明了开发者社区对「万物 CLI 化」的热情。

然后 OpenCLI 把浏览器和 Electron 应用也 CLI 化了,30 多个站点和应用被拉通。现在,钉钉和飞书官方亲自下场。

……

从社区自发 → 第三方工具 → 官方亲自做,这条路正在成为共识。

MCP 会死吗?

倒也不会。

它会退到它该待的地方:开放生态的接入协议层。就像 SOAP 没有死,只是退回到了企业内部集成的角落,大部分开发者已经忘了它的存在。

而 CLI,将成为 Agent 操作一切软件的默认界面。

钉钉和飞书,只是第一批想明白这件事的。

接下来,整个 SaaS 的 API surface,将全都暴露成 CLI。

◇ ◆ ◇