Modao CLI
墨刀(MockingBot)离线包 CLI 与 MCP 服务器:在终端读取、浏览、检索墨刀设计资产,也可作为 stdio MCP 服务供 Claude Code、Cursor 等客户端调用——项目 → 画布 → 页面 → 元素树,以及批注与图片资源。
墨刀官方 MCP(modao-proto-mcp)只做 AI 生成 HTML / 导入,不读取已有设计。本项目补的是「加载并理解既有设计文件」这个空位,不与官方冲突。
Modao (MockingBot) offline-package CLI and MCP server: list/search/read projects, pages, element trees, annotations and image assets from exported Modao HTML packages. Complements the official generation-oriented modao-proto-mcp.
重要前置说明
本工具的输入是墨刀的「HTML 离线演示包」,这是付费导出功能(个人版/团队版付费用户可用,免费版不支持)。获取步骤:
- 在墨刀网页版(modao.cc)打开目标项目;
- 使用「导出 → HTML 离线演示包」;
- 解压导出的压缩包,得到一个项目目录(内含
extra/、uploads7/、index.html); - 用
--dir指向该目录(或其父目录,可放多个项目)。
分享链接(modao.cc/app/<hash>)目前仅支持占位识别与降级指引,不做数据抓取。 原因:墨刀没有公开可用的读取型 API(历史 OAuth2 API 已被官方废弃且本就不含页面数据),分享页的设计数据由前端经未公开 XHR 接口加载,属非公开契约、随时可变更。把分享链接传给 --url(向后兼容也可传给 --dir)时,list / list_projects 中会出现一个 status: unsupported 的占位项目并附降级说明;对其做任何数据访问都会返回上述导出指引。
安装
需要 Node.js ≥ 18。
npm install -g @deeploop-ai/modao-cli
也可不安装、用 npx:
npx @deeploop-ai/modao-cli --dir <离线包目录或其父目录>
命令
全局选项:--dir <path>、--url <url>(均可重复)、--json(结构化输出)。
| 命令 | 说明 | 示例 |
|---|---|---|
mcp |
以 stdio 启动 MCP 服务器(可裸启,数据源由工具调用参数指定) | modao mcp / modao mcp --dir D:/design/modao-exports |
list [project] |
无参列出项目;带 project id 列出页面 | modao list --dir ./pkgs / modao list <project> --dir ./pkgs --json |
dsl <project> <page> |
输出页面裁剪 DSL(--format yaml|json、--depth n) |
modao dsl <project> <page> --dir ./pkgs --format yaml |
search <query> |
全文检索(--project、--limit) |
modao search 首页 --dir ./pkgs --json |
images <project> <page> |
页面元素级图片清单(含缓存绝对路径) | modao images <project> <page> --dir ./pkgs |
menu <project> |
提取播放器菜单树:画布顺序、分组与叶子画布 id(含 flpk 解析缺失的画布) | modao menu <project> --url http://intranet/pkg/ |
snapshot <project> <page> |
整页长图 PNG(可选 --out、--zoom 1~4);远程目录源同时打印预览 URL |
modao snapshot <project> <page> --dir ./pkgs |
snapshot-canvas <project> <canvas> |
画布总览长图 PNG(该画布全部页面缩略图+页名;可选 --out、--zoom 1~4 默认 2、--clip x,y,w,h 裁剪、--split 分片输出) |
modao snapshot-canvas <project> <canvas> --url http://intranet/pkg/ --zoom 3 |
pull [url...] |
预拉/刷新远程包缓存 | modao pull --url http://intranet/pkg/ / modao pull http://intranet/pkg.zip --url http://intranet/pkg/ |
默认命令
不带子命令时等同 mcp,兼容旧的直挂用法:
modao --dir D:/design/modao-exports
# 等同于
modao mcp --dir D:/design/modao-exports
--dir 可重复;值为分享链接 URL 时注册为占位项目。也可用 --url 指向远程离线包(内网静态目录或 zip)或分享链接:
modao list --dir D:/design/mdao-exports --url "https://modao.cc/app/<40位hash>"
modao mcp --url "http://192.168.12.67:18080/docs/6.2.6-pkg/"
modao mcp --url "http://192.168.12.67:18080/exports/pkg.zip"
modao mcp(不带 --dir/--url、也无相关环境变量)同样可以启动:此时没有默认数据源,每次工具调用需以 dir / url 入参指定(见「MCP 客户端配置」)。
MCP 客户端配置
推荐裸启:客户端配置只写 modao mcp,数据源由每次工具调用的 dir / url 入参指定(Agent 无需改配置即可切换多个项目/内网包);--dir/--url 与环境变量配置的数据源作为未传参时的默认值。
Claude Desktop(claude_desktop_config.json)/ Cursor / Kimi Code:
{
"mcpServers": {
"modao": {
"command": "modao",
"args": ["mcp"]
}
}
}
未全局安装时可用 npx:
{
"mcpServers": {
"modao": {
"command": "npx",
"args": ["-y", "@deeploop-ai/modao-cli", "mcp"]
}
}
}
Claude Code:
claude mcp add modao -- modao mcp
也可在启动参数里固定默认数据源(向后兼容,工具调用未传参时使用):
{
"mcpServers": {
"modao": {
"command": "modao",
"args": ["mcp", "--dir", "D:/design/modao-exports"]
}
}
}
MCP 工具数据源入参
每个工具都接受可选的 dir / url 入参(单值或数组均可,语义同 CLI 的 --dir/--url):
- 传了
dir/url:以调用参数为准(不与默认源合并),相同组合的结果在服务内缓存复用; - 都不传:使用服务器启动配置(
--dir/--url或MODO_DATA_DIR/MODO_DATA_URL)的默认数据源; - 两者都未配置时调用会返回指引错误,提示传
dir或url。
MCP 工具列表
| Tool | 说明 |
|---|---|
list_projects |
列出所有已识别项目(id、名称、来源、更新时间;分享链接显示为占位) |
list_pages |
列出项目页面(id、名称、所属画布——区分用户画布/动态组件画布、批注数) |
get_page_dsl |
页面裁剪 DSL(元素类型/名称/位置尺寸/文本/层级),yaml/json 双格式,depth 截断 |
get_element_detail |
单个元素完整属性(含 DSL 裁掉的 zIndex、原始字段等) |
get_annotations |
页面批注(富文本说明) |
search_assets |
跨项目全文检索:项目名/页面名/元素名/文本内容,返回定位路径与片段 |
get_page_image |
页面元素级图片清单(复制到缓存目录,返回绝对路径;不做整页合成渲染) |
get_page_snapshot |
整页长图 PNG:传 page_id 截单页(原尺寸);传 canvas_id 截画布总览长图(全部页面缩略图+页名一图纵览);canvas_id + split: true 追加分片输出(总览+按空白沟切的 N 张可读宽度小图,返回 tiles 清单,每片带墙内 clip 坐标,适合逐片读小字)。返回磁盘绝对路径(及远程目录源的预览 URL),Agent 自行读取该图;需要 Playwright |
refresh_projects |
刷新数据源:远程离线包重新拉取,本地目录重新扫描(范围同上:调用参数优先,未传则默认源) |
以上所有工具均接受可选 dir / url 入参指定数据源(见「MCP 工具数据源入参」)。
典型用法流程:先检索定位,再精读——用 search_assets / list_pages 找到目标页面,再用 get_page_dsl 拉裁剪后的 DSL;超大页面先用 depth 看骨架,按截断提示用 get_element_detail 精读子树。看稿用 get_page_snapshot(读取返回的 path 直接看整页长图),读结构与文案用 get_page_dsl。
环境变量
| 环境变量 | 说明 |
|---|---|
MODO_DATA_DIR |
数据源(等价 --dir,逗号分隔多个值;CLI 有值时不生效)。MCP 模式下作为工具未传 dir/url 入参时的默认数据源 |
MODO_DATA_URL |
远程数据源(等价 --url,逗号分隔多个值;CLI 有值时不生效)。MCP 模式下作为工具未传 dir/url 入参时的默认数据源 |
MODO_CACHE_DIR |
缓存目录(图片、远程数据),默认 Windows 为 %LOCALAPPDATA%\modao-mcp,macOS/Linux 为 ~/.cache/modao-mcp |
数据源形态
支持三种输入(CLI 用 --dir/--url,MCP 工具调用用 dir/url 入参,形态一致):
- 本地目录(一等):
dir指向已解压的离线包根目录,或其父目录(扫描含extra/data.0.js的子目录)。 - 远程离线包:
url指向内网静态服务器上的解压目录,或 zip 下载地址;会下载到本地缓存后再解析。 - 分享链接:
url(或向后兼容写在dir/--dir)识别为占位项目,不抓取数据,仅返回导出离线包的降级指引。
远程数据缓存于 MODO_CACHE_DIR(或系统默认缓存目录)下的 remote/。MCP 启动时会自动检查默认远程源的更新,工具调用首次使用某个 url 数据源时同样做一次检查(目录形态对比 updated_at,zip 对比 ETag/Last-Modified);运行期间可调用 refresh_projects 工具重新拉取,或在 CLI 使用 modao pull 检查并在有更新时拉取。
图片缓存
images 命令与 MCP 工具 get_page_image 不做整页合成渲染,只收集页面元素级图片:从包内 uploads7/images/ 按需复制到缓存目录,返回绝对路径。远程目录形态若本地未带图片,会按 uploads7/images/<file> 回源拉取并落盘;失败则跳过该图片。缓存根目录由 MODO_CACHE_DIR 控制。
整页截图(snapshot)
snapshot 命令与 MCP 工具 get_page_snapshot 用 Playwright 打开官方离线 HTML 播放器,按页面画板实际宽度截取整页长图 PNG:
- 默认落盘
<缓存目录>/snapshots/<project>/<画布序>-<页序>-<页面名>.png(画布总览为overview-<画布序>-<画布名>.png),序号 1 起零填充两位,目录按名排序即设计稿顺序;页面不在模型中(远程源宽容放行)时回退用页面 id。CLI 可用--out覆盖;返回值含path、width、height。 - 数据源为远程目录形态(
--url http://...)时一并返回previewUrl(包根地址,可直接打开播放器);zip 与本地--dir源只返回path(本地源截图期间会临时起一个仅绑定 127.0.0.1 的静态服务,进程退出即关闭)。 - Playwright 为可选依赖:未安装时报错并提示安装,不做静默降级;托管 chromium 未下载时会自动回退本机 Chrome/Edge(
channel方式),无需 150MB 浏览器下载:
npm install playwright # 未安装时
npx playwright install chromium # 可选:下载托管浏览器(无系统 Chrome/Edge 时)
- 跳页采用官方播放器深链
?view_mode=device&canvasId=<页面id>直达目标页,并按画板自然尺寸(非模拟器缩放尺寸)输出 PNG。 - 画布总览:
snapshot-canvas命令(或get_page_snapshot传canvas_id,来自list_pages的canvasId,或menu命令输出的叶子画布 id)切换到播放器总览模式,一面长图截下该画布全部页面缩略图与页名——适合一图纵览多页结构。默认 2 倍像素输出,--zoom 1~4调节;--clip x,y,w,h(相对墙左上 CSS 像素)可只截批注/文档区域。页面级snapshot --zoom同理。 - 分片输出(读小字推荐):整墙长图送入读图模型会被降采样,批注小字必然不可读。
--split在同一次渲染内追加输出:总览 1 张(看结构)+ 按内容空白沟切的 N 张可读宽度分片(逐片读文字,无需手工估算 clip 坐标),并写tiles.json清单——每片带墙内 CSS 像素clip坐标与切法(gutter=刀口在空白沟,uniform=等宽退化切),可溯源、可定点复查。--split auto按空白沟自适应片数(默认片宽 520 CSS px,--band调节);--split <n>强制片数;墙内容过密无沟可切时退化为等宽切并留--overlap(默认 60 CSS px);沟内有内容贯穿(表格行线、白卡连续区——切开会把一张表/一张卡劈到两片)时不下刀,整块内容并入同一条分片(最宽 band+200 CSS px,超宽才等宽切);墙缘滚动条等过窄伪内容不参与切线。--out此时为输出目录(默认snapshots/<project>/split-<画布序>-<画布名>/);--skip-existing在清单与文件齐全时直接复用不重截。与--clip互斥。 - 画布 id 校验规则:id 在解析结果中时直接使用;不在时,远程目录源会放行并由播放器侧选中态校验(覆盖菜单中存在但解析缺失的画布),本地源则严格报错并列出可用画布。
典型工作流:从设计稿到需求文档(Agent 自主完成)
modao list --url http://intranet/pkg/ # 1. 找到项目 id
modao menu <project> --url http://intranet/pkg/ # 2. 菜单顺序 + 全部画布 id(含解析缺失的)
modao snapshot-canvas <project> <canvasId> \
--url http://intranet/pkg/ --zoom 3 \
--split auto --out shots/<canvasId>/ # 3. 总览 + 按空白沟分片 + tiles.json
# Agent 识读:先读总览看结构,再按 tiles.json 顺序逐片读文字;
# 个别没读清的行用 tiles.json 的 clip 坐标 --clip 定点复查
全程只需要 CLI 返回的信息:菜单给出顺序与 id,snapshot 返回 PNG 绝对路径与尺寸(分片模式附每片墙内坐标),无需了解墨刀文件结构,也无需人工估算裁剪坐标。
数据格式说明
离线包内 extra/data.0.js 为项目元信息,extra/data.1.js 为设计数据,核心是 window.hzv5.flpk 操作码序列:
- v1(旧版):明文操作码数组;
- v2(新版):gzip+base64 压缩块 + 明文增量更新。
解析器做操作码回放(I 定义元素 / A 更新属性 / B@ref-danli 动态组件画布 / @@T 外部引用跳过),用 rRBPK 索引区分用户画布与动态组件画布。flpk 是墨刀内部格式、非公开契约,解析器采用防御式解析:无法识别的操作码跳过并计数,不会崩溃。
本项目的 flpk 解析逻辑移植自 modao-exporter(MIT 许可证)的 src/parser/,特此致谢。本项目同样以 MIT 许可证发布。
开发
npm install
npm run build # tsc → dist/
npm test # vitest
npm run dev # tsx 直接跑 src/index.ts(需 -- --dir <path> 或子命令)
项目结构:
modao-cli/
├── src/
│ ├── index.ts # 入口:分发到 cli
│ ├── cli.ts # cac 命令定义与分发
│ ├── config.ts # configFromOptions(CLI 选项 + 环境变量)
│ ├── bootstrap.ts # createSource / checkRemoteUpdates
│ ├── cli-output.ts # 人类可读格式化
│ ├── mcp-command.ts # mcp 子命令:stdio 启动│ ├── commands/ # list / dsl / search / images / pull
│ ├── model/ # Project/Canvas/Page/Element/Annotation/Asset 统一模型
│ ├── flpk/
│ │ ├── decode.ts # flpk v1/v2 解包(gzip+base64 → 操作码行)
│ │ └── replay.ts # 操作码回放 → 统一文档模型
│ ├── sources/
│ │ ├── source.ts # Source 接口
│ │ ├── offline-package.ts# 本地离线包目录(惰性解析)
│ │ ├── remote-package.ts # 远程离线包目录 / zip 拉取与缓存
│ │ ├── share-link.ts # 分享链接占位(降级指引,不抓取)
│ │ └── combined.ts # 多数据源组合
│ ├── services/
│ │ ├── dsl.ts # 文档模型 → 裁剪 DSL(json/yaml、depth 截断)
│ │ ├── index.ts # 内存检索索引与打分
│ │ ├── assets.ts # uploads7/images 资源读取与缓存目录落盘
│ │ └── pages.ts # 页面查找辅助
│ └── mcp/
│ ├── server.ts # McpServer 装配
│ ├── source-manager.ts # 工具调用 dir/url 入参 → 数据源解析与缓存
│ └── tools.ts # tool 注册
└── test/ # vitest + 手工构造的微型离线包 fixtures
License
MIT deeploop-ai