npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

douyin-devtools-mcp

v0.0.1

Published

MCP server for Douyin Mini Program automation via Chrome DevTools Protocol

Readme

douyin-devtools-mcp

通过 MCP 协议把抖音小程序的自动化能力暴露给 Claude / Cursor / 任何 LLM Agent。

架构:Agent → MCP Server → 抖音开发者工具的 Chrome DevTools Protocol → MiniApp Webview。 零 SDK 依赖:不需要 tt-automator(它不存在),直接连 IDE 内置的 CDP 端口。


当前状态(Phase 2 进行中)

| 能力 | 状态 | |------|------| | 自动发现 IDE CDP 端口 | ✅ | | 连接 MiniApp Webview / IDE Workbench(双 target) | ✅ | | 执行任意 JS(Runtime.evaluate) | ✅ | | 截图(Page.captureScreenshot) | ✅ | | 列出所有 target | ✅ | | 页面导航(走 IDE Compile Mode 工作流) | ✅ | | 启动参数热更新 | ✅ | | 元素点击(CSS selector + 视觉光标) | ✅ | | 元素输入(React 兼容 setter) | ✅ | | 等待元素出现/消失(轮询 + 超时) | ✅ | | 文本断言(equals / contains / regex) | ✅ | | 元素滑动 / 长按 | ⏳ Phase 2 续 | | 逻辑层 worker attach + Mock SDK | ⏳ Phase 3 |

12 个可用 Tool:

  • 连接:tt_auto_connecttt_auto_disconnecttt_list_targets
  • 观察:tt_screenshottt_evaluatett_get_current_route
  • 导航:tt_navigate_tott_update_launch_params
  • 操作:tt_element_taptt_element_input
  • 等待 / 断言:tt_wait_for_elementtt_assert_text

先决条件

  • Node.js >= 18(需要原生 fetchWebSocket,实测 v22 OK)
  • Windows / macOS / Linux(目前在 Windows 上完成 PoC,其他平台路径已写但未实测)
  • 已安装并能正常运行的抖音开发者工具
  • 一个已加载的小程序项目,模拟器可见

与开发流程的关系(职责边界)

MCP Server 只负责"连接已运行的 IDE + 操控小程序",不接管编译/构建。具体来说:

| 谁做 | 做什么 | |------|--------| | 你 | 启动小程序的编译产物(Taro / uni-app 的 watch、原生项目无需此步) | | 你 | 启动抖音开发者工具,加载产物目录(如 dist/tt) | | MCP Server | 通过 CDP 连接 IDE,执行 navigate / evaluate / screenshot 等操控 |

类比:Playwright 不负责启动你的 webpack,MCP 也不负责启动你的 Taro。


Node 多版本共存(Taro / uni-app 用户必看)

很多业务项目(尤其 Taro 3.x / uni-app)要用 Node 16 才能编译,但本 MCP Server 必须 Node ≥ 18。两套 runtime 完全可以并存,关键是别让它们抢同一个 PATH。

方案 A — 两个终端(开发时推荐,立刻能用)

终端 1(Node 16):
  nvm use 16
  cd D:\path\to\your-taro-project
  npm run dev:tt          # Taro watch,一直挂着

终端 2(Node 22):
  nvm use 22
  cd D:\myProject\douyinmcp
  node tests/e2e-manual.mjs

抖音开发者工具:
  自己开着,加载 dist/tt

每个终端独立切版本,互不影响。

方案 B — Claude Desktop 配置里写死 Node 22 绝对路径(长期方案)

⚠️ 不要在 claude_desktop_config.json 里写 "command": "node" —— PATH 里第一个 node 是哪个版本不可控,nvm 切了一次就崩。直接给绝对路径:

{
  "mcpServers": {
    "douyin-devtools": {
      "command": "D:\\software\\nvm\\v22.12.0\\node.exe",
      "args": ["D:\\myProject\\douyinmcp\\dist\\index.js"]
    }
  }
}

查具体路径:终端里 nvm use 22 && where node,把第一行复制进去(Windows 反斜杠记得双写)。

这样 Claude Desktop 永远用 Node 22 起 MCP,你在别的终端用 Node 16 跑 Taro,完全解耦


安装与运行

git clone <repo>
cd douyin-devtools-mcp
npm install
npm run dev          # tsx src/index.ts,stdio 模式
npm run typecheck    # 类型检查
npm run build        # 编译到 dist/

在 Claude Desktop 里使用

编辑 %APPDATA%\Claude\claude_desktop_config.json(macOS:~/Library/Application Support/Claude/):

{
  "mcpServers": {
    "douyin-devtools": {
      "command": "node",
      "args": ["D:\\myProject\\douyinmcp\\dist\\index.js"]
    }
  }
}

或者用 tsx 直接跑源码:

{
  "mcpServers": {
    "douyin-devtools": {
      "command": "npx",
      "args": ["tsx", "D:\\myProject\\douyinmcp\\src\\index.ts"]
    }
  }
}

端到端冒烟测试

node tests/e2e-manual.mjs

需要先手动打开抖音开发者工具并加载一个小程序项目。


Tool 速查

tt_auto_connect

连到正在运行的抖音开发者工具。端口自动发现(读 %APPDATA%\@byted\vela\DevToolsActivePort),通常不用传参数。

{ "host": "127.0.0.1", "port": 8803, "timeoutMs": 5000 }

返回 targetIdtargetTitlewebSocketDebuggerUrlminiappOrigin

tt_list_targets

诊断用 — 列出 CDP 上所有 target(包括 MiniApp Webview、IDE workbench、worker)。

tt_evaluate

在 MiniApp Webview 上下文执行任意 JS。

{
  "expression": "document.title",
  "awaitPromise": true,
  "returnByValue": true,
  "timeout": 10000
}

⚠️ 当前连的是渲染层(WebView),tt.navigateTo 这类 SDK API 在逻辑层(Service Worker)。Phase 3 会做 worker attach;如果只是想换页,直接用 tt_navigate_to

tt_screenshot

对当前 webview 截图。默认只写文件不返回 base64(避免撑爆 LLM 上下文)。

{
  "path": "output/foo.png",
  "format": "png",       // 或 "jpeg"
  "quality": 80,         // jpeg 时
  "includeBase64": false
}

tt_navigate_to

切换小程序到指定页面。走的是 IDE 官方的 Compile Mode 工作流:在顶部"普通编译"下拉里新建一个编译模式 → 填模式名、启动页面、启动参数、进入场景 → 点确定 → IDE 自己重启小程序到目标页。

{
  "url": "/pages/activity/sign-in/index?instanceId=abc",
  "modeName": "mcp-nav-xxxxx",   // 可选,不传则自动生成
  "waitForRouteMs": 60000        // IDE 首次编译某页可能 30-60s
}

⚠️ MiniApp Webview 里的 tt.navigateTo 是宿主 shim,不能真的换页;这是抖音 IDE 的设计,不是 bug。本 Tool 是唯一可靠的换页方式,稳定但慢(25-60s/次,取决于 IDE 编译时间)。

前置:目标页面必须已经在 dist/ 编译产物里(否则 IDE 启动页下拉里看不到这个 page)。

实现细节(踩坑沉淀):

  • "普通编译"下拉用的 selector 必须过滤掉空文本的 select(IDE 工具栏里有好几个图标按钮也是 Tila Select),否则会点错(如"清除缓存")
  • 启动页面是 search-on-type 下拉,输入 pagePath + Enter 选中,不要滚虚拟列表 — 后者对深层路径不可靠
  • 选完启动页面要验证 selection-text == pagePath,否则可能搜索没匹配上、流程静默继续用默认值,直到点确定才暴露

tt_update_launch_params

编辑已有编译模式的启动参数,只改 query 不重建模式。适合"重新跑一遍但换个 id"的场景。

{
  "modeName": "mcp-nav-xxxxx",
  "newQuery": "instanceId=123&a=2",   // 不带前导 ?, 空串表示清空
  "waitForRelaunchMs": 60000
}

实现是定位下拉里该模式行的铅笔图标 → 打开编辑弹窗 → 只改第二个 input(启动参数)→ 确定。

tt_get_current_route

读 IDE 底部状态栏的当前页面路径。用于验证导航是否生效。无参数。

tt_element_tap

在 MiniApp Webview 上点击 CSS selector 命中的元素。默认开启视觉光标:派发点击前先用 Overlay.highlightRect 画红色高亮框停留 500ms,再真实派发鼠标事件 — 肉眼能跟得上,debug 友好。

{
  "selector": ".btn-submit",
  "index": 0,                // 命中多个时取第几个
  "showCursor": true,        // CI 场景可关掉以加速
  "cursorDurationMs": 500,
  "scrollIntoView": true     // 不在视口内先滚动到可见
}

selector 解析路径:先查顶层 document(IDE shell),没命中再穿透 iframe[id^="miniapp-frame-"]contentDocument(小程序业务渲染在那里)。坐标自动加 iframe offset,直接派发鼠标事件可用。

tt_auto_disconnect

断开 CDP 连接(不会关闭 IDE)。


端口发现的优先级

  1. 调用方显式传入的 port 参数
  2. 环境变量 TT_AUTO_PORT
  3. ${TT_USER_DATA_DIR}/DevToolsActivePort
  4. 平台默认 user-data-dir 下的 DevToolsActivePort:
    • Windows: %APPDATA%\@byted\vela\
    • macOS: ~/Library/Application Support/@byted/vela/
    • Linux: ~/.config/@byted/vela/

抖音开发者工具的 CDP 端口是动态的(每次启动可能不一样),不要硬编码。


关键已知坑(填好了)

  1. Node 必须 ≥ 18,需要原生 fetch/WebSocket。Node 16 会报 fetch is not defined
  2. 必须用 127.0.0.1 不能用 localhost — Node 22 默认走 IPv6,IDE 只监听 IPv4。
  3. CDP 端口不固定,从 DevToolsActivePort 读取,不要假设是 8220/9420 之类。
  4. MCP 默认 30s 超时,截图、tt_navigate_to 等慢操作要在客户端侧加 timeout 参数。
  5. MiniApp Webview 是渲染层,小程序逻辑层在 worker target,需要分别 attach 才能调用 tt.* API(Phase 3)。
  6. 小程序业务渲染在同源 iframe #miniapp-frame-N(blob: URL),不暴露为独立 CDP target,要从顶层 contentDocument 穿透。tt_element_tap 已内置这个 fallback,自己写 tt_evaluate 时要注意。
  7. Overlay domain 依赖 DOM domain — 用 Overlay.highlightRect 前必须先 DOM.enable,否则静默失败。
  8. tt.navigateTo 在 Webview 里是宿主 shim,不会真的换页;要换页必须走 IDE Compile Mode(tt_navigate_to 已封装)。
  9. tt_navigate_to 走的是 IDE Workbench target(不是 Webview)— getWorkbenchSession()workbenchMode=workbench 标题匹配,首次连接要等 workbench 加载完成。
  10. IDE 工具栏的 Tila Select 有好几个,光定位 .tila-select-selection 会撞上"清除缓存"等图标按钮。selector 必须过滤掉 selection-text 为空的元素 + 锚定 [class*=compile-mode] 祖先 + 文本启发式兜底(见 navigation.tsCOMPILE_MODE_SELECT_EXPR)。
  11. Tila Select 是 search-on-type 下拉,选项用输入 + Enter 选中,不要滚虚拟列表 — 深层路径(pages/activity/sign-in/index 这种)在初始可视区外,querySelectorAll 拿不到。select 选中后必须.tila-select-selection-text 验证,搜索无匹配会静默用默认值。

目录结构

src/
├── index.ts              # MCP server entry(stdio transport)
├── server.ts             # McpServer 实例 + Tool 注册
├── core/
│   ├── cdp-connection.ts # CDP 客户端 + 端口自动发现 + 多 target session 管理
│   ├── errors.ts         # TT_E001..TT_E011 错误码
│   └── session.ts        # 进程内 connection singleton + view/workbench session helper
└── tools/
    ├── connection.ts     # tt_auto_connect / disconnect / list_targets
    ├── evaluate.ts       # tt_evaluate
    ├── screenshot.ts     # tt_screenshot
    ├── navigation.ts     # tt_navigate_to / tt_update_launch_params / tt_get_current_route
    ├── element.ts        # tt_element_tap / tt_element_input(含 iframe 穿透 + Overlay 视觉光标)
    ├── wait.ts           # tt_wait_for_element(轮询 + 超时,iframe 穿透)
    └── assert.ts         # tt_assert_text(equals / contains / not_contains / regex)

tests/
└── e2e-manual.mjs        # 端到端冒烟测试

poc/                       # Phase 0 探测脚本和样本项目(保留作历史)
├── screenshot-test.mjs   # 49 行 PoC 验证
└── hello-world/          # 最小抖音小程序示例

后续 Phase

抖音小程序AI测试Agent_PRD_v1.0 (1).md 的第 15 章(v1.2 重构版里程碑)。下一阶段:

  • Phase 2(进行中):元素操作扩展 — tt_element_input / tt_element_swipe / tt_element_longpress,以及 tt_element_inspect(只读不点)
  • Phase 3:逻辑层 worker target attach + tt_call_api(直接调 tt.* SDK)、Mock 注入
  • Phase 4:tt_analyze_project + tt_suggest_test_cases(模板规则,非 LLM)
  • Phase 5:tt_run_test_case / tt_generate_report
  • Phase 6:CI/CD + npm 发布

License

MIT