cocos-mcp-2x
Provides tools for working with Cocos Creator 2.x projects: reading and writing project files, creating and editing scenes and prefabs, inspecting scene trees and layouts, diagnosing asset/uuid issues, launching the engine's web preview, and driving the running game (dispatching touches, reading state, capturing console output and screenshots).
This server does not currently have a deployable release on Glama. Follow the repository's setup instructions to install and configure it for your MCP client, including any required credentials and local dependencies.
cocos-mcp-2x
简体中文 | English
Cocos Creator 2.x 的 MCP 服务端 —— 让 AI 直接读写项目文件、增删改场景与预制体、启动引擎 Web 预览并真的把游戏玩一遍。
v0.8.0 · 28 个工具 · 面向 Cocos Creator 2.4.x(开发验证环境 2.4.15)· MIT
Cocos Creator 3.x 的扩展 API 与 2.x 完全不同(Editor.Message 取代了 Editor.Ipc,场景是纯 3D 结构),
本仓库只管 2.x,不要混用。
目录
Related MCP server: cocos-mcp
它能做什么
能力 | 靠什么工具 | 为什么这件事重要 |
读写项目文件 |
| 写 |
读场景结构 |
| 不打开编辑器也能知道场景里有什么、长什么样 |
造场景 |
| 空项目也能起:内置引擎同款模板,直接产出 SceneAsset + Scene + Canvas + Main Camera |
造预制体 |
| 声明式 spec:图片只给路径、脚本只给路径,序列化细节全包 |
改节点 / 组件 |
| 批量事务 + |
检查布局 |
| 不截图就能发现「文字压在图标上」「越出画布」 |
项目体检 |
| 抓编辑器导入不报、运行时才炸的问题(悬空 uuid、错 spriteFrame、孤儿 meta) |
跑起来看 |
| 走即时编译,改完 |
真的玩一遍 |
| 点按钮、派发触摸、读状态、抓 console、截图 |
一致性自检 |
| 三张表(声明 / 实现 / 探针)必须一一对应,漏登记直接进 |
设计目标是可验证的自动化:不是"发出指令就算成功",而是每一步都能回读证据
(verified: true、errorTotal: 0、8/8 断言通过)。
30 秒上手
1. 部署扩展
扩展是全局安装的,所有 2.x 项目共用一份:
cd <本仓库目录>
node deploy.js部署到 ~/.CocosCreator/packages/cocos-mcp-2x/(该目录不存在时自动回退 .../packages/mcp/,
即编辑器实际加载的那个)。详见部署。
2. 打开编辑器
Cocos Creator 2.x 会自动加载全局扩展。启动后菜单栏出现 扩展 / Cocos MCP 2.x:
菜单项 | 作用 |
状态与端口 | 当前实例跑在哪个端口、目标项目是谁 |
列出已打开项目 | 本机所有开着编辑器的项目 |
开启 / 停止中继服务 | 中继是常驻进程,编辑器关了链路也在 |
切换目标项目 | 轮换 AI 操作的项目 |
重启服务 | 改了 |
3. 配置 MCP 客户端
~/.workbuddy/mcp.json(Claude Desktop / Cursor 等同理):
{
"mcpServers": {
"cocos-mcp-2x": {
"type": "http",
"url": "http://127.0.0.1:25800/mcp"
}
}
}指向 25800(中继),不要指向编辑器的 25900。
编辑器端口按启动顺序分配(25900、25901…),一重启就可能互换 —— 写死编辑器端口会指错项目。 中继常驻,每次请求都按项目身份(不是端口)解析目标,所以永远指得对。
4. 验证
node dev-client.js 25800 get_project_info
node dev-client.js 25800 mcp_selftest看到项目路径、引擎版本、problems: [] 就成了。
核心思想
这九条是整套工具的行为来源,出问题时先回来对一遍。
1. 文件层优先,能不碰编辑器 IPC 就不碰
.fire / .prefab 是纯 JSON。文件层能做的事比编辑器私有 API 还多:可 diff、可离线测、
可在编辑器没开的时候跑、失败不会留下半改的内存状态。
所以 8 个写盘的 scene_edit 走的是 writeRoute: 'file' ——
直改磁盘 JSON,不依赖场景脚本通道。场景脚本只用于「必须访问活对象」的场合(读运行时属性、执行 JS)。
2. 空值 ≠ 失败
每个工具的返回都带 __status / __emptyFields / __reason / __hint:
empty是正常结果("这个目录下没有匹配文件"),不是错误真正失败才抛错,且错误信息必须写清原因 + 下一步
约定字段一律带
__前缀,不会和业务字段撞名(preview的status是 HTTP 码)
tools/list 里每个工具的描述都自动追加这份约定 —— 光看描述就知道该怎么解读返回值,不用试错。
3. 协议面收敛,行为不变
v0.8.0 把 30 个「同一动作域」的工具并成 8 个 cmd 型入口(50 → 28),tools/list 载荷缩了约三分之一。
dispatchByCmd 只做两件事:按 cmd 挑原实现、把 cmd 从参数里摘掉。
原实现一行没改 —— 合并只动入口不动行为,回归测试才能证明等价。
旧的 46 个工具名仍然可调用,callTool 沿 RENAMED 链自动翻译(最多 2 跳,防环 4 跳),
返回里带 __renamedFrom / __hops / __hint 提示改口。老脚本、老提示词不会突然失效。
4. 决不手写 .meta
.meta 是 AssetDB 的身份(uuid / importer / subMetas),手写等于给项目换身份。
缺 .meta 时正确做法是对所在目录 refresh_assets,让编辑器自己生成。
同理:自分配 uuid 是错的。prefab cmd:create 先写文件,等导入完成再回读 .meta 的真实 uuid,
把文件里两处引用改齐 —— 否则 project_doctor 会报悬空 uuid。
5. 写入台账:谁动过这个文件
每次写盘记下那一刻的 mtime / size / 节点 id 到 temp/mcp-state/ledger.json。
下次写之前比一下:
情况 | 判定 | 该怎么办 |
磁盘有、内存没有 |
| 文件是新的 → |
内存有、磁盘没有(刚删的) |
| 重载无损 |
内存有、磁盘没有(你建的) |
| 重载会丢,先 Ctrl+S |
上次写入后被改过 |
| 上一批改动已被覆盖,要重做 |
台账放在 temp/,不进 assets、不会被导入、git 里本来就忽略。
6. 不手搓序列化对象
克隆场景里已有的同类对象再改字段。_trs / _color / _contentSize / _anchorPoint / _objFlags
一律继承引擎值 —— 这些字段的手工值极易和引擎版本对不上(_trs 是 10 元素 TypedArray,
顺序错一位就是位置错乱,而且不报错)。
7. 写盘保留原文件格式
CRLF 项目不能被写成 LF,否则 git diff 全量重写、版本历史废掉。
write_file / edit_file 都先读原文件判断换行风格再对齐写入。
8. 删对象必须全局重映射 __id__
序列化文件里删一个对象会让后面所有 __id__ 平移。所以先摘掉父节点 _children 里的引用,
再扫全文件外部引用,有残留就整体拒绝,不写半坏场景。
9. 部署也是一次可验证操作
deploy.js 部署前做两件事:语法预检(vm.Script 编译,语法错直接拒绝,否则扩展开机就崩、
报错信息还跟真实原因对不上)、冲突检测(部署目录被别处改过就停下报告,除非 --force)。
架构与代码结构
全景
┌─────────────────────────────────────────────────────┐
│ 客户端 (mcp.json) │
│ "url": "http://127.0.0.1:25800/mcp" │
└──────────────────────┬──────────────────────────────┘
│ HTTP
▼
┌─────────────────────────────────────────────────────┐
│ hub.js —— 常驻中继(独立进程,编辑器关了也在) │
│ 每次请求读 target.json → 解析项目身份 → 转发 │
└──────────────────────┬──────────────────────────────┘
│
┌──────────────┴──────────────┐
▼ ▼
┌────────────────┐ ┌────────────────┐
│ 编辑器 A (25900)│ │ 编辑器 B (25901)│
│ main.js 扩展 │ │ main.js 扩展 │
└────────┬───────┘ └────────┬───────┘
│ │
├─→ 文件层 → .fire / .prefab / assets(最可靠)
├─→ 场景脚本 → scene.js(渲染进程,能用 cc)
├─→ 预览服务 → PreviewServer → bridge.js(浏览器侧)
└─→ 构建产物 → injector.js → inject-runtime.js(浏览器侧)四条通道,读的东西不一样
这是最容易搞混的地方。 同一个游戏,四种"看到它的方式":
通道 | 工具 | 读的是 | 状态 |
静态设计态 |
|
| ✅ 一直可用 |
编辑器内运行时 |
| 场景进程里的活对象 | ✅ 可用 |
引擎 Web 预览 |
| 预览页里跑着的游戏 | ✅ 可用,不用打包 |
构建产物运行时 |
|
| ✅ 可用,但要先 build |
优先用预览:走引擎的 __quick_compile__.js 即时编译,改完 .ts 等重编译完刷新就是新的。
构建那条路(build + runtime cmd:inject)是备选,用于「构建产物里跑起来的游戏」。
文件结构
mcp/
├── main.js 7948 行 扩展主进程入口:MCP 协议、工具分发、场景脚本通道、预览服务、中继、构建
├── scene.js 993 行 场景脚本(渲染进程):能用 cc、能执行 JS、能回传结果
├── bridge.js 1094 行 浏览器侧桥接:接收指令、执行、回报
├── injector.js 251 行 构建产物注入器(可逆)
├── inject-runtime.js 365 行 被注入的运行时上报脚本
├── hub.js 345 行 常驻中继:按项目身份转发(独立 Node 进程)
├── reload.js 207 行 开发期热重载(只影响指定端口)
├── deploy.js 165 行 带冲突检测 + 语法预检的部署
├── test.js 3309 行 回归测试(mock Editor + 真发 HTTP)
├── bootstrap-probe.js 209 行 冷启动探针:自建临时空项目,跑 8 项断言后清理
├── accept.js 99 行 端到端验收
├── dev-client.js 109 行 直连端口的调试客户端(故意不进扩展目录)
├── package.json 扩展清单:main / scene-script / main-menu
├── lib/
│ ├── fsutil.js 113 行 纯文件系统工具
│ ├── uuid.js 283 行 uuid ↔ 路径索引(按 mtime 增量)
│ ├── scene-parse.js 422 行 .fire / .prefab **只读**解析 + 唯一根定位
│ ├── scene-tools.js 1230 行 场景 / 预制体**写入** + 批量 op 引擎
│ ├── scene-template.js 207 行 内置空场景模板:buildEmptyScene / attachCanvas / hasCanvas
│ ├── prefab.js 864 行 预制体装配 / 结构校验 / 布局自检(纯逻辑,无 fs 无 Editor)
│ ├── doc.js 326 行 文档校验 + 节点级 diff(prefab diff 的核心)
│ ├── asset-graph.js 188 行 引用图(谁引用我 / 我引用谁),按 mtime 增量
│ ├── editor-state.js 404 行 写入台账 + 节点差异 + 子树重合度匹配(纯逻辑)
│ └── tool-schema.js 613 行 工具声明表(纯数据,28 条)
├── README.md / README.en.md / DEVELOP.md / HANDOFF.md
└── .deploy-manifest.json 上次部署后的 md5 快照分层与依赖规则
main.js(编排层)
│
┌─────────┼──────────┬─────────────┐
▼ ▼ ▼ ▼
lib/ scene.js bridge.js hub.js
(纯逻辑) (渲染进程) (浏览器) (中继)三条硬规则:
lib/不引用Editor全局 —— 通过setContext()拿注入的宿主能力。 为什么:lib/是最需要单测的部分,绑死Editor就没法脱离编辑器测。lib/模块之间不互相 require —— 依赖统一由main.js注入,main.js是唯一组装点。 为什么:避免循环依赖,依赖关系一目了然。工具声明与工具实现分离 ——
lib/tool-schema.js只放数据,main.js的callTool()放分发。 为什么:加工具时改两个明确的地方,不用在 8000 行文件里翻。
加工具的具体步骤见 DEVELOP.md。
工具速查(28 个)
8 个聚合入口必须传
cmd,每个 cmd 要哪些参数都写在工具描述里(tools/list可见)。 46 个旧工具名仍可调用,返回带__renamedFrom/__hint,对照见附录。
普通工具(20 个)
分组 | 工具 | 说明 |
自检(1) |
| 把工具实际跑一遍,检查返回值形态、空值标注、错误信息。默认只跑无副作用的; |
文件与代码(7) |
| 项目信息 / 列目录 / 全文搜索 / 读原文 / 写文件(写 |
场景视图(5) |
| 读节点树 / 建场景(内置模板,空项目也能起) / 诊断通道 / 磁盘与编辑器内存差异 / 截干净场景图 |
资源诊断(3) |
| 路径↔uuid 互转(图片给 |
路由与兜底(4) |
| 列出打开的项目 / 指定操作哪个项目 / 中继开关 / 主进程跑任意 JS(长脚本用 |
scene_create 的两个关键参数:withCanvas(默认 true,保证有 Canvas + Main Camera)、
startScene(默认 true,自动写 start-scene 与设计分辨率)。空项目不传任何模板也能直接建场景。
聚合入口(8 个,必填 cmd)
工具 |
| 吸收的旧工具 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
8 个写盘的 scene_edit cmd 都支持 .fire 和 .prefab:path 直接传 .prefab 即可,
不传 path 才是"编辑器当前场景"。
为什么外层用 cmd 而不是 action:runtime cmd:inject、preview cmd:control/command、
hub_control、editor_sync 本来就有自己的 action 子命令,外层再用 action 会撞车。
实战:从零搭一个能跑的工程
这是 v0.8.0 新增的能力 —— 不需要先在编辑器里手工建场景。
// 1. 建场景(空项目也能用:内置引擎同款模板 + Canvas + Main Camera + 写 start-scene)
{ "name": "scene_create", "arguments": { "path": "assets/scene/Main.fire", "canvas": [750, 1334] } }
// 2. 建预制体(图片只给路径,脚本只给路径,序列化细节全包)
{
"name": "prefab",
"arguments": {
"cmd": "create",
"path": "assets/resources/prefab/ChoiceItem.prefab",
"root": {
"name": "ChoiceItem", "size": [640, 88],
"sprite": "assets/art/panel.png",
"children": [{ "name": "Label", "size": [580, 60], "label": "选项文案" }]
},
"script": "assets/scripts/ChoiceItem.ts"
}
}
// 3. 写脚本(长文件用 path 从文件读,避免 JSON 转义地狱)
{ "name": "write_file", "arguments": { "path": "assets/scripts/ChoiceItem.ts", "content": "..." } }
// 4. 导入 + 看编译状态
{ "name": "refresh_assets", "arguments": {} }
{ "name": "editor", "arguments": { "cmd": "compile-status" } }
// 5. 起预览,验证真的跑起来了
{ "name": "preview", "arguments": { "cmd": "control", "action": "start" } }
{ "name": "runtime", "arguments": { "cmd": "report", "source": "preview", "limit": 50 } }
// 6. 交付前体检
{ "name": "project_doctor", "arguments": {} }第 1 步的坑(已在 v0.8.0 修掉):以前空项目没有 .fire 可克隆就直接失败。
现在走 lib/scene-template.js 的 buildEmptyScene(),按内置 canvas prefab 的完整字段生成
—— 少一个 _id、_trs 顺序差一位都不会立刻报错,但会在运行时炸。
bootstrap-probe.js 就是专门验证这条链路的:自建临时空项目,跑 8 项断言,然后清理。
实战:改场景 / 改预制体
改节点属性
{ "name": "scene_edit", "arguments": {
"cmd": "set-props", "node": "Canvas/topUI/btnKey", "position": { "x": 100, "y": 200 } } }换图片(最容易踩坑的地方)
{ "name": "resolve_asset", "arguments": { "input": "assets/game/images/ys01.png" } }一张 png 有两个 uuid:
uuid | 是什么 | 填进 |
主 uuid(meta 里第一个 | texture | ❌ 报 |
| sprite-frame | ✅ |
看返回的 usableAsSpriteFrame 字段(图片还会直接给 spriteFrames)。
换图后记得同步改尺寸和缩放 —— 新图原始尺寸要塞进按钮,否则会被拉伸。
批量改一个界面(一次写盘)
改 20 个节点时不要连续调 20 次 set-props —— 那是 20 次整文件读写,中途失败会留半成品。
{
"name": "scene_edit", "arguments": {
"cmd": "apply",
"path": "assets/ui/Foo.prefab",
"dryRun": true,
"ops": [
{ "op": "addNode", "parent": "panel", "name": "title", "position": { "x": 0, "y": 500 } },
{ "op": "setProps", "node": "panel/title", "size": { "width": 400, "height": 60 } },
{ "op": "addComponent", "node": "panel/title", "type": "cc.Label" },
{ "op": "addPrefab", "prefab": "assets/ui/Item.prefab", "parent": "panel" }
]
}
}dryRun: true 只试算:给出 before/after 对象数、每个 op 的结果、结构校验有没有问题,不写盘。
确认后去掉 dryRun 再跑 —— 只有一次写盘;任何一步失败整批放弃,文件一个字节没动。
布局自检(不用截图)
{ "name": "prefab", "arguments": { "cmd": "check-layout", "path": "assets/ui/Foo.prefab" } }报 outOfBounds(越出画布)、overlaps(同级重叠,带重叠比例)、outsideParent(超出父容器)、
inactiveHidden(active:false 但兄弟仍占位)。
看一眼,比算一遍更靠得住
{ "name": "scene_capture", "arguments": {} }返回 {file: "temp/mcp-state/shots/scene-<时间戳>.png", width: 915, height: 594},直接打开看。
默认会临时关掉网格、设计分辨率框和 gizmo 再截(它们是场景里的装饰节点
Editor Scene Background / Editor Scene Foreground,截完立刻恢复,不改文件也不改设置),并裁掉顶部工具栏。
传 clean: false 保留编辑器原样。
能看出几何检查算不出的问题:文字压得难看、九宫格切边画错、图片被拉伸、字体没生效。
反过来 check-layout 能给到具体节点名和重叠比例 —— 两个一起用:先截图看到问题,再定位到是哪个节点。
改完到底改了什么
{ "name": "prefab", "arguments": { "cmd": "diff",
"a": "assets/ui/Foo.prefab", "against": "temp/Foo.bak.prefab" } }序列化文件里加一个节点会让后面所有 __id__ 平移,字节 diff 会从头到尾全是"变了",没法读。
这个按节点路径配对,只回答四件事:
added 1 CircleView/panel/__DiffA(含 1 个组件)
removed 0
changed 1 CircleView/panel/titleBg opacity: [255, 128]
renamed 0改名按 _id 匹配,不会被算成一删一增。预制体里节点 _id 是空串,
所以预制体内部改名会显示成删除+新增 —— 这是引擎约定,不是工具的锅。
改完之后,让编辑器跟上(最容易出事的一步)
这套 MCP 是直接改文件的。代价是编辑器内存里还是旧的:你在编辑器里按一次 Ctrl+S, 文件就被内存里的旧版本覆盖,而且没有任何提示。
写完 scene_edit 之后看返回里的 editor 字段:
{ "saved": true,
"editor": { "openInEditor": true, "needsReload": true, "reloadWith": "editor_sync(action: reload)" } }openInEditor: true 就接着调:
{ "name": "editor_sync", "arguments": { "action": "reload" } }它会把场景面板重新从磁盘加载,然后轮询到节点集合和文件一致才返回 verified: true
(实测约 350ms)。不是"发出指令就算成功"。
editor_sync 也能提前发现问题,看核心思想 5 的那张表。
预制体没法从外部重载(_loadScene 只认场景),所以 action:"reload" 对预制体会明确拒绝,
告诉你"别保存,关掉重开" —— 而不是假装成功。
体检发现问题,能修的直接修
{ "name": "project_doctor", "arguments": { "fix": "preview" } } // 先看清单,不动文件
{ "name": "project_doctor", "arguments": { "fix": true } } // 真修只修三类不会把事情弄更糟的:
问题 | 怎么修 | 为什么安全 |
| 换成同一张图的 sprite-frame uuid | 那是唯一正确的值,没有第二种可能 |
孤儿 | 移到 | 不是删除,随时能搬回去 |
缺 | 对所在目录 | 不手写 uuid / importer |
悬空 __uuid__ 一律不修:修它得先知道原来想引什么,猜不出来。
实战:试玩一个游戏
这是这个 MCP 最有价值的能力:不用打包,改完代码刷新就能玩。
// 起预览:返回地址 + 自动开窗
{ "name": "preview", "arguments": { "cmd": "control", "action": "start" } }先看清有什么,再决定点哪个
FairyGUI 的界面不是 cc.Node 树,运行时上报的树里看不到。用 fguiTree:
{ "name": "preview", "arguments": { "cmd": "command", "action": "fguiTree", "depth": 8 } }
{ "name": "preview", "arguments": { "cmd": "command", "action": "fguiTree", "filter": "btn" } }点按钮的两种方式
方式 | 用于 | 机制 |
| FairyGUI 按钮 | 官方 |
| cc.Button | 走 |
{ "name": "preview", "arguments": { "cmd": "command", "action": "fguiClick", "path": "btnStart", "type": "GButton" } }节点路径找不到时会按名字全树搜 —— UI 常常挂在猜不到的容器下。
读状态 / 观察变化
script 支持 await —— 这样才能看到状态变化,而不是变化前的快照:
var btn = findButton('btnStart');
if (btn) btn.click();
await new Promise(function (r) { setTimeout(r, 1000); });
return cc.director.getScene().name;preview cmd:command 全部 11 个动作
动作 | 作用 |
| 确认通道通 |
| 求值单个表达式 |
| 执行多语句 JS 源码(支持 await),复杂逻辑用这个 |
| 读某个节点的组件属性( |
| 触发节点上组件的 |
| 点 cc.Button(走 clickEvents) |
| 真派发触摸事件到 canvas |
| 加载项目模块( |
| 列 FairyGUI 对象树 |
| 点 FairyGUI 按钮(官方 simulateClick) |
| 抓 canvas 像素,返回尺寸和平均色 |
抓日志
{ "name": "runtime", "arguments": { "cmd": "report", "source": "preview", "limit": 50 } }返回运行时状态 + console 日志 + 错误,并带 noiseFiltered(过滤掉多少噪声行)。
console.error 不会被限流丢掉。
已验证的完整链路
preview control start → 预览 + 注入 + 开窗
fguiClick btnStart → GameView + level1[Game](物理体、球、倒计时全实例化)
clickButton btnBack → LevelView(12 个关卡项)
clickButton btnBack → HomeView(这个按钮是代码绑定的,走兜底逻辑)四步各有各的入口,这就是"完全可控"的证据 —— 不依赖任何写死的流程。
返回约定
每个工具的返回都带这四个字段:
字段 | 含义 |
|
|
| 哪些字段是空的 |
| 为什么空 |
| 接下来该做什么 |
空值 ≠ 调用失败。 真正失败会直接报错,错误信息里带原因和下一步。
约定字段都带 __ 前缀 —— 不会和业务字段撞名。
资源标识的约定
资源路径一律用
path(相对项目根,如assets/game/x.prefab)只有
assetcmd:query/search_files用pattern(搜索模式)节点路径用
Canvas/panel/title这种斜杠路径;同名节点必须写完整路径
部署
一条命令
node deploy.js # 正常部署(有冲突会拒绝)
node deploy.js --check # 只检查:报告待部署的文件,不落盘
node deploy.js --force # 强制覆盖(确认过冲突内容再用)部署目标:~/.CocosCreator/packages/cocos-mcp-2x/;
该目录不存在时自动回退 ~/.CocosCreator/packages/mcp/(编辑器实际加载的目录名在不同安装方式下不统一)。
优先标准名,避免把代码部署到编辑器根本不看的目录。
--check 是安全的:不写盘、不改清单,适合在 CI 或提交前确认「编辑器里跑的确实是这份代码」。
部署了哪些文件
deploy.js 的 FILES 白名单,其余文件不进扩展目录:
扩展本体:
main.jsscene.jspackage.jsonreload.jstest.jshub.jsinjector.jsinject-runtime.jsbridge.js文档:
README.mdREADME.en.mdDEVELOP.mdHANDOFF.md纯逻辑层:
lib/下 10 个模块(少一个就是Cannot find module的启动失败)
dev-client.js / deploy.js / bootstrap-probe.js / accept.js 是开发期工具,故意不部署。
手动部署(不想用脚本)
# 确认目标目录
ls ~/.CocosCreator/packages/
# 整目录拷过去(注意保留 lib/ 结构)
cp -r . ~/.CocosCreator/packages/cocos-mcp-2x/手工部署的代价是没有冲突检测和语法预检 —— 语法错的 js 进了扩展目录,
编辑器启动时只会报"未知工具"之类,跟真实原因对不上,很难查。建议还是用 deploy.js。
部署后
菜单 扩展 / Cocos MCP 2.x / 重启服务(或重开编辑器)
node dev-client.js 25800 get_project_info验证node dev-client.js 25800 mcp_selftest看problems是否为空
测试与自检
三层,从便宜到贵:
层次 | 命令 / 工具 | 需要编辑器 | 验的是什么 |
自检 |
| 需要 | 每个工具实际跑一遍,返回值形态、空值标注、错误信息、三张表一致性 |
回归 |
| 不需要(mock | 120+ 条断言:序列化正确性、删除重映射、批量事务、改名链、参数边界 |
冷启动 |
| 不需要 | 自建临时空项目,验证「从零搭建」8 项断言,跑完清理 |
端到端 |
| 需要 | 真编辑器里走一条完整链路,看 |
mcp_selftest 的 sideEffects: true 会在副本上跑有副作用的工具,跑完删除并校验 md5 ——
不会污染你的项目。换机器、换项目、隔段时间再用,先跑这两个:
node dev-client.js 25800 mcp_selftest
node dev-client.js 25800 mcp_selftest '{"sideEffects":true}'改完代码怎么生效
node test.js # 1. 回归(不需要编辑器)
node deploy.js # 2. 部署(带语法预检 + 冲突检测)
node reload.js # 3. 热重载(只影响指定端口,不用重启编辑器)常见报错与处理
现象 | 原因 | 怎么办 |
|
| 用 |
| 部署漏了 lib 目录 |
|
| 用了绝对路径 | 用相对项目根的相对路径 |
编辑器里看不到刚改的场景 | 没刷新,或内存里是旧场景 |
|
| 路径不对 | 错误信息会列出当前场景的节点名;先 |
| 同名节点 | 写完整路径 |
| 悬空引用风险 | 先解除引用( |
| 没在编辑器里跑 | 这是编辑器内才能用的工具 |
git diff 全量重写 | 换行风格被改了 | 用 |
| 场景窗口没起 | 编辑器里打开场景窗口;先 |
| 部署没生效 / 拼错旧名 |
|
两个特别容易踩的坑
1. 中文在编译产物里被转义
.ts 编译出的 JS 里中文是 \uXXXX,grep 搜中文搜不到 —— 会误判成"新代码没进产物":
const esc = Array.from('钥匙不足').map(function (c) {
return '\\u' + c.charCodeAt(0).toString(16).padStart(4, '0');
}).join('');
s.indexOf(esc)2. 改 .ts 不等于改了游戏(构建这条路)
构建用的是编译后的 JS(temp/quick-scripts/dst/ 和 library/imports/<uuid>.js)。
构建选项里 autoCompile: false —— 构建不触发编译,用的是缓存。
改完源码要等编辑器编译完(看 library/imports/<uuid>.js 的 mtime)再构建,
用 editor cmd:compile-status 查有没有 stale。
用引擎预览则没这个问题 —— 预览走即时编译。
兼容性与已知限制
目标环境:Cocos Creator 2.4.x(开发验证环境 2.4.15)。3.x 不支持。
2.4 内置 Node 版本较老 —— 主进程代码不能用可选链
?.、空值合并??、顶层await。deploy.js的语法预检会拦住,但报错位置可能不准,看到"语法错误"先怀疑新语法糖。场景窗口不会重新加载场景脚本 —— 改了
scene.js要重启编辑器(或用reload.js)。预制体不能从外部重载 —— 只能关掉重开。
__id__平移是结构性的 —— 任何插入/删除都会让后面所有对象 id 变化,所以用节点级 diff,别看字节 diff。编辑器内运行时(
source: scene)依赖场景窗口打开errorTotal里混有编辑器自身噪声 ——runtimecmd:report会过滤并给出noiseFiltered计数
更多踩坑记录见 HANDOFF.md,架构与开发约定见 DEVELOP.md。
附录:旧工具名对照
v0.8.0 合并表(8 个 cmd 型入口吸收的 30 个工具):
旧名 | 现在 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
v0.4.0 合并表(同名参数合流,旧名仍转发):
旧名 | 现在 | 参数怎么变 |
|
| 加 |
|
| 默认就是无副作用模式 |
|
| 加 |
|
| 统一用 |
|
| 用 |
|
| 加 |
|
| 加 |
|
| 加 |
|
| 加 |
|
| 用 |
旧名可能要走 2 跳(v0.4.0 名 → v0.7.0 中继名 → v0.8.0 聚合名),
callTool 沿链转发并在返回里写明 __hops 与最终 __hint。最多 4 跳防环。
MIT License · 作者 UC-RX0
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
Loading tool schema changelog…
This server cannot be deployed
Maintenance
Related MCP Connectors
Control Unreal Engine to browse assets, import content, and manage levels and sequences. Automate…
Drive real devices from your AI Coding tool. Embed a client SDK (Unity, Godot, Flutter, iOS/macOS, Android, React Native, Web) in your app, then capture screenshots, traverse the UI tree, inject taps and key events, and run automated test tasks on the physical device over a secure relay.
Build and inspect browser-based 3D games: projects, scenes, Lua scripts, assets and publishing.
Drive a live Cinevva game session: edit game files, import CC0 assets, preview changes.
Related MCP Servers
- FlicenseNot gradedqualityDmaintenanceEnables AI clients to control Cocos Creator editor projects, scenes, nodes, components, assets, Prefabs, building, and diagnostics via the MCP protocol.-
- AlicenseNot gradedqualityBmaintenanceLets AI assistants drive the Cocos Creator editor in-process: querying the live scene graph, reading and writing assets, starting builds, tailing logs, and capturing editor screenshots.14 npmMIT
- AlicenseCqualityBmaintenanceEnables AI clients to automate and inspect Cocos Creator 2.x/3.x projects through scene, node, component, asset, prefab, runtime, build, shader/material, and workflow operations, with capability discovery and validation levels.413MIT
- AlicenseNot gradedqualityBmaintenanceEnables AI clients to directly control the Cocos Creator 3.8+ editor, including scene and node manipulation, UI building, script attachment, validation, preview runtime logs, and screenshots.1MIT