Skip to content

1.1.5

Choose a tag to compare

@TomasLucasUTN TomasLucasUTN released this 27 Jul 20:33
· 82 commits to main since this release

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_scripts only
    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 (playrplayer, move_lefmove_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. SpriteFrames could not be built at all before, so the
    AnimatedSprite2D route — what most Godot tutorials teach — was simply
    unavailable.
  • get_skeleton_info / add_bone / set_bone_pose — 2D and 3D stay
    distinct on purpose: Skeleton3D owns bones as internal indices, Skeleton2D
    owns Bone2D nodes.
  • mp_set_authority — generates the code that claims authority.
    multiplayer_authority is runtime state with no scene-file representation, so
    a tool that wrote it into a .tscn would write a value Godot never reads.
  • read_scene takes a properties list — "where is everything" in one call
    instead of an all-or-nothing dump of a fixed twelve. A misspelled name comes
    back under missing_properties rather 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 hands resources_reimported an 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_script was leaving its throwaway scripts on disk. A real project
    had __mcp_validate_1.gd and its .uid sitting 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_collision fills an empty CollisionShape instead 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_track warns when a frame track would land before its
    hframes track: 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.