1.1.4
godot-mcp-bridge 1.1.4 — run_scene stops freezing the editor, and the game gets a voice
Everything here came from one decision: make the test harness actually launch a
game. Nothing in this project ever had. The moment it did, it found a bug in a
core tool that had been there the whole time and was hiding behind a comment
that described its own symptom as normal.
run_scene froze the editor for its entire timeout, on every call
run_scene waits for the game to come up. Both of its wait loops did that with
OS.delay_msec, which blocks Godot's main thread. With the main thread blocked
the addon's _process never runs, so it never pumps its WebSocket and never
answers a ping — and after two missed ping intervals the server force-closes the
connection. The agent got Godot disconnected back from a call that had launched
the game perfectly well.
It was worse than a freeze, because the conditions those loops were waiting on —
is_playing_scene(), and the runtime-connected flag the server sets — are
themselves updated by the main loop. Blocking it meant they could never flip, so
every call ran the full startup_timeout_ms, whatever actually happened.
That is what this comment, sitting above the timeout default, was really
measuring:
MCPRuntime connects anywhere from ~11s to ~20s after run_scene is called
(engine boot + autoload init + WS handshake — timing varies with system load)
It does not take 11–20 seconds. The default had been raised from 10s to 20s to
accommodate a measurement of the bug, which pushed it past the 20s watchdog and
guaranteed the disconnect.
run_scene is now a coroutine and yields to the SceneTree, the way the wait
tool already did — wait even carries a comment warning about this exact hazard.
It just never reached run_scene.
A test now enforces it. Any tool handler containing an await must be
registered in the executor's coroutine set with a dispatch case, or GDScript
hands the caller a GDScriptFunctionState instead of a Dictionary and the agent
sees "Tool returned no status". The check is verified against a deliberate
regression rather than assumed to work.
The running game now reports what only it can see
1.1.3 gave the developer's editor activity a push channel. The game had none.
Split by what each side can actually observe, because they are not
interchangeable:
- The runtime autoload reports its own scene swaps (
game_started,
game_scene_changed). The editor cannot see achange_scene_to_file(), and
it is the event that matters most: every runtime node path the agent is
holding points at a freed node afterwards. Compared by object identity, so
reloading the same scene still counts. - The editor's debugger reports the game's life and death (
game_running,
game_paused,game_crashed,game_stopped,game_resumed), through a new
passiveEditorDebuggerPlugin. This has to live on the editor side: an engine
error inside a running game is not observable from GDScript in that game.
The activity summary gained a sentence for the game, which reports state rather
than counting transitions — three scene changes mean the game is in the third
scene — and always calls out a crash.
Also corrected: a comment in mcp_runtime.gd claimed engine errors were captured
into the runtime log ring. Nothing captured them. It now says so, and points at
where they are actually visible.
The activity feed could go silent for an hour
begin_agent_call() opened the agent-attribution window for a full hour, closed
by end_agent_call() at the end of the tool call. A handler that dies mid
coroutine never reaches that second call — and 1.1.3 shipped fixes for three
handlers that did exactly that. Until the editor restarted, every action the
developer took was then filed as the agent's own work and the feed reported
nothing.
The window is now bounded whether or not it is closed properly, and counted
rather than flagged, so two overlapping tool calls no longer un-tag each other.
Testing
- The e2e harness launches a real game for the first time: 31 → 34
assertions, covering the runtime feed end to end rather than by source
inspection. CI runs it under Xvfb, because the game is a separate process that
does not inherit the editor's--headless. - GDScript suite: 358 → 375 assertions.
- Node suite: 118 → 124.
Also
take_screenshotwrites intoaddons/godot_mcp/cache. With the addon
junctioned into a project, those images could be picked up by the build and
shipped inside the npm package. Excluded now.
Known limitation: breakpoints still do not pause the game
Unchanged from 1.1.3 in effect, but the investigation moved a long way.
A real bug was found in Godot itself, from source: the debug adapter's
update_breakpoints calls ScriptEditorDebugger::_set_breakpoint, which only
draws the editor's gutter marker, instead of the public set_breakpoint, which
is the one that actually messages the running game. That is exactly why the
adapter answers verified: true and nothing ever stops. Identical in master
and 4.5-stable.
It is not the whole story, and this is stated rather than glossed:
EditorDebuggerSession.set_breakpoint reaches the correct function, and testing
it against a live game — armed twice, on a line running every physics frame —
still did not pause anything. So the remaining fault is downstream of the
message. No fix is shipped on the strength of the source reading alone, because
shipping an unverified debugger fix is the precise failure 1.1.3 documented.
Upgrade notes
213 tools, unchanged. No schema changes.
The run_scene and activity fixes are all in the addon, so reinstall it
(npx godot-mcp-bridge install) — updating only the npm package leaves both in
place. run_scene additionally needs the editor restarted, because the
executor's dispatch table is built once at startup.