跳转到内容

AI 代理 (MCP)

Estella 编辑器支持 Model Context Protocol (MCP)。任何支持 MCP 的 AI 工具—— Claude Code、Cursor,或你自己写的代理——都能驱动真实的编辑器:打开或创建项目、 打开场景、用与你相同的“创建”菜单目录生成实体、编辑组件字段、在活的引擎 World 里验证结果、进入 Play 模式、截图亲眼看到它搭出来的东西,并把成品游戏导出 ——走的都是 UI 自己的管线,共 65 个工具。

MCP 服务器是随编辑器一起分发的一个小 node 脚本。它对你的 AI 工具讲 stdio MCP, 并为你驱动一个编辑器实例(拉起新的,或挂到已打开的那个上)。

它在安装版编辑器里的路径:

  • Windows%LOCALAPPDATA%\Programs\@estellaeditor\resources\app.asar.unpacked\dist-electron\mcp\editor-mcp.mjs
  • macOS/Applications/Estella Editor.app/Contents/Resources/app.asar.unpacked/dist-electron/mcp/editor-mcp.mjs
Terminal window
claude mcp add estella --env ESTELLA_MCP_ALLOW_WRITES=1 -- \
node "<path-to>/editor-mcp.mjs" --editor

--editor 会以启用 MCP 端点的方式启动安装版编辑器。PATH 里需要 Node.js 20+。

想让代理在你已经打开的编辑器会话里干活,把 --editor 换成 --attach 即可:

  1. AI 工具的配置里用 --attach

    "args": ["<path-to>/editor-mcp.mjs", "--attach"]
  2. 打开设置 → AI 代理 → 允许 AI 代理连接。编辑器会开启一个仅限本机的端口, 并往自己的 user-data 目录写一个发现文件 mcp-endpoint.json--attach 会自己 找到它——只有你把它挪了位置,才需要显式传路径。那一行会显示当前监听的端口; 这个开关会被记住,所以此后你双击图标启动的编辑器同样是就绪状态。

    在终端里用 --mcp 启动(estella-editor --mcp)效果相同,只对当次会话生效, 且在该会话内优先于这个设置。

  3. 代理现在驱动的就是你眼前的这个窗口——选择、编辑、Play 全部同步——你可以 一边看一边随时介入。

启动顺序无所谓:服务器每次调用时才去解析编辑器,所以你可以先开 AI 工具、 后开编辑器;会话中途重启编辑器也会自动重连,不会把代理晾在那儿。

领域 工具(节选)
观察 get_scene_treeget_inspectorget_statsget_diagnosticscapture_viewport(PNG)、screenshot(整窗截图,含 Play 画面)、world_component(活 World 探针)
编辑场景 apply_scene_ops(批量搭建)、create_entity(配合 list_entity_templates 的创建目录)、set_fieldset_entity_xyset_parentduplicate_entityundo / redo
项目与资产 create_project / open_projectopen_sceneopen_asset(把任意资产在它自己的编辑器里打开)、get_documentsave_scenecreate_scene_filecreate_assetimport_assetslist_assetsget_import_settings / set_import_settings
预制体 create_prefab_from_entityedit_prefab / exit_prefab_mode(Prefab Mode)、apply_prefabrevert_prefabunpack_prefabcreate_prefab_variant
零代码行为 get_event_bindings / set_event_bindings(给按钮接线)、add_component / remove_component
游戏代码 read_project_filewrite_project_filelist_project_files
运行与发布 toggle_play + get_play_stateexport_game(web / desktop / wechat / playable)

典型的代理循环:open_projectopen_scenelist_entity_templatesapply_scene_opsget_diagnosticsscreenshot 检查成果 → save_scenetoggle_play → 再次 screenshotexport_game

.esprefabopen_asset(或对实例调 edit_prefab)就进入 Prefab Mode: 从此每个场景工具作用的都是那个预制体save_scene 写的是资产——每个实例都会跟着变。 get_document 告诉你当前开着哪个文档:打开之后先查它,别默认保存写的是场景。 exit_prefab_mode 回到原来的场景。

人看到对话框的地方,代理拿到的是能据此行动的答复:会丢掉未保存改动的打开一律被拒绝, 除非你传 discardChanges;而 apply_prefab(它会重写每个实例的基)要求 confirm: true ——人是靠那张逐条 diff 确认的,代理则把意图直接说出来。

set_field 一次只写一个字段——改一个值够用,搭一个场景就没戏了:一个 UI 面板 动辄上百个节点、每个十几个字段。apply_scene_ops 收的是一段程序:创建、 改父子、加组件、写字段按顺序执行,合成一个可撤销步骤。操作之间用名字互相 引用,所以整棵子树一次调用就能落地:

{
"label": "Build HUD",
"ops": [
{ "op": "create", "ref": "hud", "name": "HUD", "template": "ui-container" },
{ "op": "create", "ref": "coins", "name": "Coins", "template": "ui-text", "parent": "$hud",
"fields": { "Text.content": "1440", "Text.fontSize": 28 } }
]
}

它是原子的:任何一步失败,报错会指名是哪一步挂的(op[7] set: …),整批回滚 ——包括它已经创建出来的实体——一段写错的程序不会留下一棵搭到一半的子树。

字段路径可以只点名结构字段里的一个成员"Transform.position.x""FlexContainer.gap.y""UINode.width.value"),其余部分会被读出来原样写回, 所以只挪一个轴不必先读再改再写。

节点数量上到几百之后,程序本身就成了负担——一个真实面板是几百 KB 的 JSON, 不该塞进对话里。用 write_project_file 写成文件,再把路径交给 apply_scene_ops

{ "opsPath": "assets/scenes/shop.ops.json", "label": "搭建商店" }

场景不写一行游戏代码也能给按钮行为——一行事件绑定 说的是当这个事件发生,就跑那个具名动作set_event_bindings一个撤销步骤 里整体替换某实体的绑定行(传空列表即拆线),get_event_bindings 读回来:

{ "entity": 42, "rows": [
{ "event": "click", "action": "panel.open",
"params": { "prefab": "assets/prefabs/Shop.esprefab" } }
] }

action 是动作注册表里的任意名字——引擎内置的(property.setui.setVisiblefsm.fire……)或项目自己注册的——而 target 点名要在哪个实体上跑,从当前实体 就近解析。

源码仓库里,pnpm --filter @estella/editor editor:mcp 用无头夹具宿主提供同一套 注册表(仅场景工具),editor:mcp -- --editor 拉起开发版编辑器;两套 e2e (editor:mcp:e2eeditor:mcp:editor-e2e)验证完整闭环。

  • 编辑器 —— 这个自动化面驱动的可视化编辑器。
  • 脚本 —— 同一套场景 / 组件模型,从游戏代码这边看。