Skip to content

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.

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
Terminal window
claude mcp add estella --env ESTELLA_MCP_ALLOW_WRITES=1 -- \
node "<path-to>/editor-mcp.mjs" --editor

--editor launches the installed editor with the MCP endpoint enabled. Node.js 20+ must be on your PATH.

To let an agent work inside an editor session you already have open, use --attach instead of --editor:

  1. Configure your AI tool with --attach:

    "args": ["<path-to>/editor-mcp.mjs", "--attach"]
  2. Turn on Settings → AI Agents → Allow AI agents to connect. The editor opens a local-only port and writes a discovery file mcp-endpoint.json into its user-data folder, which --attach finds 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.

  3. 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.

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_projectopen_scenelist_entity_templatesapply_scene_opsget_diagnosticsscreenshot to check its work → save_scenetoggle_playscreenshot again → export_game.

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.

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" }

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.

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.

  • The Editor — the visual editor this automation surface drives.
  • Scripting — the same scene / component model, from game code.