AI Agents (MCP)
The Estella editor speaks the Model Context Protocol (MCP). Any MCP-capable AI tool — Claude Code, Cursor, or your own agent — can drive the real editor: open or create projects, open scenes, spawn entities from the same Create-menu catalog you use, edit component fields, verify the result in the live engine World, enter play mode, take screenshots to see what it built, and export the finished game — the exact pipelines the UI uses, sixty-five tools in all.
Connecting an AI tool
Section titled “Connecting an AI tool”The MCP server is a small node script that ships inside the editor. It talks MCP over stdio to your AI tool and drives an editor instance for you (spawning one, or attaching to one that’s already open).
Its path inside an installed editor:
- 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
claude mcp add estella --env ESTELLA_MCP_ALLOW_WRITES=1 -- \ node "<path-to>/editor-mcp.mjs" --editor{ "mcpServers": { "estella": { "command": "node", "args": ["<path-to>/editor-mcp.mjs", "--editor"], "env": { "ESTELLA_MCP_ALLOW_WRITES": "1" } } }}--editor launches the installed editor with the MCP endpoint enabled. Node.js 20+
must be on your PATH.
Driving the editor you’re looking at
Section titled “Driving the editor you’re looking at”To let an agent work inside an editor session you already have open, use --attach
instead of --editor:
-
Configure your AI tool with
--attach:"args": ["<path-to>/editor-mcp.mjs", "--attach"] -
Turn on Settings → AI Agents → Allow AI agents to connect. The editor opens a local-only port and writes a discovery file
mcp-endpoint.jsoninto its user-data folder, which--attachfinds on its own — pass an explicit path only if you moved it. The row reports the port it is listening on, and the setting is remembered, so an editor you start by double-clicking it is ready from then on.Launching from a terminal with
--mcp(estella-editor --mcp) does the same thing for one session, and outranks the setting while it lasts. -
The agent now drives the same window you see — selections, edits, play mode and all — while you watch and intervene.
Order doesn’t matter: the server resolves the editor per call, so you can start your AI tool first and open the editor later, and restarting the editor mid-session reconnects automatically rather than stranding the agent.
What the agent can do
Section titled “What the agent can do”| Area | Tools (excerpt) |
|---|---|
| Observe | get_scene_tree, get_inspector, get_stats, get_diagnostics, capture_viewport (PNG), screenshot (whole window, includes play), world_component (live-World probe) |
| Edit scenes | apply_scene_ops (batch authoring), create_entity (the Create-menu catalog via list_entity_templates), set_field, set_entity_xy, set_parent, duplicate_entity, undo / redo |
| Projects & assets | create_project / open_project, open_scene, open_asset (any asset in its own editor), get_document, save_scene, create_scene_file, create_asset, import_assets, list_assets, get_import_settings / set_import_settings |
| Prefabs | create_prefab_from_entity, edit_prefab / exit_prefab_mode (Prefab Mode), apply_prefab, revert_prefab, unpack_prefab, create_prefab_variant |
| Behaviour without code | get_event_bindings / set_event_bindings (wire a button), add_component / remove_component |
| Game code | read_project_file, write_project_file, list_project_files |
| Run & ship | toggle_play + get_play_state, export_game (web / desktop / wechat / playable) |
A typical agent loop: open_project → open_scene → list_entity_templates →
apply_scene_ops → get_diagnostics → screenshot to check its work →
save_scene → toggle_play → screenshot again → export_game.
Editing a prefab
Section titled “Editing a prefab”open_asset on a .esprefab (or edit_prefab on an instance) enters Prefab Mode:
from then on every scene tool acts on the prefab, and save_scene writes the asset
for every instance. get_document says which document is open — check it after opening,
and before assuming a save writes a scene. exit_prefab_mode goes back.
Where a person gets a dialog, an agent gets an answer it can act on: opening something
that would discard unsaved work is refused unless you pass discardChanges, and
apply_prefab — which rewrites the base for every instance — requires confirm: true
instead of the itemized diff a person confirms.
Building scenes at scale
Section titled “Building scenes at scale”set_field writes one field per call, which is fine for a tweak and hopeless for a
scene: a single UI panel is easily a hundred nodes with a dozen fields each.
apply_scene_ops takes a program instead — creates, re-parents, component adds
and field writes, executed in order as one undoable step. Ops address entities
they create by name, so a whole subtree lands in one call:
{ "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 } } ]}It is atomic: if any op fails, the error names the op that failed (op[7] set: …)
and the whole batch rolls back — entities it had already created included — so a
bad program never leaves a half-built subtree behind.
A field path may name one member of a structural field ("Transform.position.x",
"FlexContainer.gap.y", "UINode.width.value"), which reads and writes back the
rest, so moving a node one axis does not cost a read-modify-write.
Past a few hundred nodes the program itself is the problem — a real panel is
hundreds of KB of JSON, which does not belong in a chat message. Write it with
write_project_file and hand apply_scene_ops the path instead:
{ "opsPath": "assets/scenes/shop.ops.json", "label": "Build the shop" }Wiring a button
Section titled “Wiring a button”A scene can give a button behaviour without any game code — an
Event Binding row says when this event fires, run that
named action. set_event_bindings replaces an entity’s rows in one undo step
(an empty list unwires it), and get_event_bindings reads them back:
{ "entity": 42, "rows": [ { "event": "click", "action": "panel.open", "params": { "prefab": "assets/prefabs/Shop.esprefab" } }] }action is any name in the action registry — an engine built-in (property.set,
ui.setVisible, fsm.fire, …) or one the project registered — and target names
another entity to run it on, resolved nearest-first from this one.
From the repository (contributors)
Section titled “From the repository (contributors)”In a source checkout, pnpm --filter @estella/editor editor:mcp serves the same
registry against a headless fixtures host (scene tools only), editor:mcp -- --editor
boots the dev editor, and two e2e suites (editor:mcp:e2e,
editor:mcp:editor-e2e) prove the full loop.
See also
Section titled “See also”- The Editor — the visual editor this automation surface drives.
- Scripting — the same scene / component model, from game code.