1.1.5
godot-mcp-bridge 1.1.5 — the edits you make can now be saved, and three "known bugs" were never bugs
Twelve tools added and a long backlog closed, but the part worth reading is the
pattern: five times a recorded cause turned out to be wrong, and each real
one came from a test that failed rather than from re-reading the code. Two of
this project's loudest known limitations — including one documented at length in
the 1.1.4 notes — were not defects at all.
save_scene: the loop was broken and nobody noticed
Every mutating tool edits the live tree when its target scene is open in the
editor. That is deliberate: it is what stops a tool call clobbering unsaved work.
But nothing could persist those edits. So the sequence any agent runs — edit a
scene, launch the game, look at the result — tested the previous version of the
file, silently, every time.
save_scene closes it. Every live-path response now also carries unsaved: true
and says to call it before run_scene.
Every write to an integer property was reported as a failure
_values_match compared values of different types as text. JSON has one
number type, so every integer an MCP client sends arrives as a float; setting an
int property with it works, Godot coerces it, and the read-back returns an int.
The check then compared "1" against "1.0" and called a correct write a
failure — and a single-property call, seeing a failure, saved nothing. Two
separate backlog entries ("a no-op reported as failure", "nothing was written to
the file") were this one bug.
Breakpoints work. They always did.
1.1.4 shipped a section explaining that breakpoints never pause the game, with a
Godot source reading to back it. That reading led to a drafted engine bug report.
Do not believe it. The blocker was the editor's "Skip Breakpoints" toggle,
which was on: it suppresses every breakpoint from every source, persists between
sessions, and cannot be read from GDScript.
With it off, on Godot 4.7, all eleven debug_* tools do exactly what their names
say — debug_launch stopped at a real line, debug_scopes returned real frames,
debug_evaluate read velocity = (0.0, 20.0) out of a paused frame, a
breakpoint added to an already-running game hit, and debug_step advanced.
Three independent investigations had each concluded the code was broken, each
one confirming the last, because every test ran with the same flag suppressing
the thing being measured. Nothing in the code was ever wrong.
game_eval does not kill the game either
Recorded as: takes ~24s, the game dies inside GDScript.reload(), the error
branch never runs. Measured, both ways, with the same broken snippet:
| game launched from | result | elapsed |
|---|---|---|
| the editor | Godot runtime disconnected |
~25 s |
| a plain CLI command | Compile error in eval snippet (err=43) |
0 s |
The error branch is fine. A parse error goes through the engine's global error
handler, and with the editor's debugger attached that handler breaks — the
game pauses, it does not die. Same family as the breakpoint finding.
Snippets are now compiled in the editor first, where nothing is debugging, and
rejected there, so a typo stays a typo. The throwaway compile is given a path
under res://addons/ on purpose: exclude_addons mutes warnings there, so a
project that promotes warnings to errors cannot make the pre-check reject a
snippet that would have run. With no editor connected there is no debugger
either, and the snippet goes straight through.
New tools
validate_references— checks that the names scripts use exist: groups,
input actions, and signals emitted but never declared.validate_scriptsonly
answers "does this parse"; these fail silently at runtime instead. Run against
a real project it found injected faults with the right lines and the right
suggestions (playr→player,move_lef→move_left).create_sprite_animation/create_sprite_frames— one call instead of
~10 per animation, with the layout tracks emitted before the frame track by
construction.SpriteFramescould not be built at all before, so the
AnimatedSprite2Droute — what most Godot tutorials teach — was simply
unavailable.get_skeleton_info/add_bone/set_bone_pose— 2D and 3D stay
distinct on purpose:Skeleton3Downs bones as internal indices,Skeleton2D
ownsBone2Dnodes.mp_set_authority— generates the code that claims authority.
multiplayer_authorityis runtime state with no scene-file representation, so
a tool that wrote it into a.tscnwould write a value Godot never reads.read_scenetakes apropertieslist — "where is everything" in one call
instead of an all-or-nothing dump of a fixed twelve. A misspelled name comes
back undermissing_propertiesrather than silently absent.
Context cost
This server's argument is that a large tool surface is expensive, so two paths
that quietly weren't cheap are fixed:
- The activity digest rides on every tool response, and nothing capped the
size of a single event. Godot handsresources_reimportedan array of every
path it just imported, so dropping an asset pack into a project made the next
unrelated tool call return 1.5 MB — about 390,000 tokens. - The unknown-tool error listed all ~180 registered names, and
batch_execute
repeats it per failed operation: one typo in a two-operation batch cost roughly
2,000 tokens.
The README now publishes the measurement instead of asserting it: core is 7,540
tokens of 45,132 across the full surface, and mcp-server/scripts/measure-tools.mjs
lets you re-run it.
Also fixed
validate_scriptwas leaving its throwaway scripts on disk. A real project
had__mcp_validate_1.gdand its.uidsitting next to the files they were
copies of, while the code's own comment claimed nothing was written. Both
validators clean up after themselves now.setup_collisionfills an emptyCollisionShapeinstead of adding a useless
sibling next to it.- A
res://path assigned to an Object-typed property is loaded instead of
silently rejected —set()refuses a String there, so the call reported
success and nothing happened. add_animation_trackwarns when aframetrack would land before its
hframestrack: Godot exposes no way to reorder tracks, and the result is
"Index p_frame is out of bounds" logged every frame, blamed on the wrong
animation.- Four handlers were wired with no schema, so no client could call them. The
registry test runs both ways now: a wired handler must be advertised, or
declared internal with a reason.
Testing
- GDScript suite: 375 → 526 checks.
- Node suite: 124 → 148.
- Live editor harness: 34 → 44, now covering
save_scene, live-tree reads,
and that an instanced child keeps its script through a full edit-and-save
cycle.
Upgrade notes
225 tools, up from 213.
Most of this release is in the addon, so reinstall it — updating only the npm
package leaves the fixes in place:
npx godot-mcp-bridge install
New tools additionally need the editor restarted, because the executor's dispatch
table is built once at startup.