Skip to content

v1.1.3 — what the tests found, and what hand-testing found after that

Choose a tag to compare

@TomasLucasUTN TomasLucasUTN released this 27 Jul 00:08
· 94 commits to main since this release

godot-mcp-bridge 1.1.3 — what the tests found, and what hand-testing found after that

Two exercises produced almost everything here. The first was finishing automated
coverage of every tool that writes — 52 of 99 at the start of the cycle, 99 of 99
now. The second was hand-testing the 28 tools added since the original 185-tool
pass, which had never had one.

Both found bugs the other would have missed. That is the point of doing both.


Every analysis tool was reading the wrong scene

analysis_tools was the one tool node the executor never called
set_editor_plugin on. Without the plugin, _edited_root_if_open can never find
the live tree — so every analysis tool silently read the last saved version of
a scene. scene_diff would report "no changes" for an edit sitting unsaved in
the editor in front of you.

This is the same stale-read class that eleven read tools were fixed for in 1.1.1,
reintroduced by adding a new file and forgetting one line. No test caught it,
because no test asserted the wiring. One does now: every _*_tools node the
executor declares must appear in a set_editor_plugin call.

Found by hand-testing scene_diff against a real editor. It would not have shown
up in the headless suite, which runs without an EditorPlugin by design.

close_scene_tab was broken on the minimum version we advertise

EditorInterface.get_unsaved_scenes() is Godot 4.6+. On 4.5 — which the README
promises — calling it aborted the handler mid-way and the caller got "Tool
returned no status". The tool simply did not work on the floor of our own
support range.

Caught by the two-version CI matrix added in 1.1.2, on its first real run: green
on 4.7, red on 4.5. It paid for itself immediately.

Where that API is missing there is no way to ask which scenes are dirty, so the
safe reading is to assume one might be: force is now required explicitly, with
a message that says why, rather than closing a tab that could be holding unsaved
work.

Three shapes of silent failure

Writing the last of the coverage turned up the same shape three times — a tool
reporting success for something that did not happen:

  • remove_state_machine_transition never worked. It called
    find_transition(), a method AnimationNodeStateMachine does not have. The
    handler aborted and returned an empty dictionary — no ok, no error, no
    message, undo action left open.
  • [x, y] was rejected wherever a vector was expected. {x, y} is
    canonical, but an agent that just wrote position: [100, 100] somewhere else
    reasonably tries an array here. set_node_properties handed it straight to
    node.set(), which no-ops on a type mismatch, so you got "set had no effect
    (type mismatch?)" for a perfectly natural value. Tilemap coordinates were
    worse: they fell through to (0, 0) and painted the wrong cell, reporting
    success. Fixed centrally in the shared codec, plus the two places that parsed
    on their own.
  • A res:// path for a Resource property did nothing. Assigning a resource
    by path is exactly what attach_script, set_sprite_texture and
    assign_shader_material take. set_node_properties now loads it.

Also: painting tilemap cells on a layer with no TileSet reported plain success,
when nothing can ever render. It warns now — and the warning disappears once a
TileSet is assigned, because a warning that never clears is one nobody reads.

scene_diff — stop re-reading the whole tree

The question an agent asks constantly is "what changed since I last looked",
and the only way to answer it was to call read_scene again and re-read
everything. On a scene of any size that is the largest single token cost in a
session, and nearly all of it is nodes that did not change.

scene_diff takes a snapshot and returns an id — no tree at all. Call it again
with that id and you get only the added, removed and modified nodes, with
per-property before/after for the ones that changed. It compares the actual
tree rather than tracking tool calls, so the developer's edits show up exactly
like the agent's own.

mp_diagnose — the multiplayer bugs that never error

Six independent Godot Forum threads over about a year describe the same failure
shapes: an RPC arriving before the node it targets has replicated, state
diverging per-peer in ways invisible from one machine. What they have in common
is that nothing errors when you write the code — the game looks fine until a
second peer joins.

mp_diagnose checks for the ones that are statically detectable: a method called
with .rpc() that has no @rpc annotation (the remote call is simply dropped),
a MultiplayerSynchronizer whose replication config is empty, a
MultiplayerSpawner with no spawnable scenes or a spawn_path that does not
resolve. The scaffolding tools build a correct setup; this one checks the setup
you already have.

Editor activity is pushed now, and reads as a sentence

The activity feed used to poll the editor every 1.5 seconds while a client was
subscribed. The editor knows the instant something happens, so it now says so:
each human action goes over the existing socket as it occurs, and the resource
notifies immediately. Polling stays as a fallback for older addons and drops to
a 30-second heartbeat once the first push arrives.

Reading the resource now leads with intent rather than records — "The developer
saved levels/one.tscn and changed the selection 12 times"
— because twelve
selection entries are what the summary exists to replace. Saves, script edits,
reimports and undo are named individually; selection churn, which a single drag
generates continuously, collapses to a count.


Known limitation: breakpoints do not pause the game

Stated plainly because the toolset previously implied otherwise.

debug_launch starts a session. debug_status reports the adapter connected.
Godot accepts and verifies each breakpoint — it responds with
{id, line, verified: true} and source checksums, so the file and the path
mapping are right. And then execution never stops. Reproduced against a line
inside _physics_process that runs every frame, against _ready, and with
stop_on_entry: true. Every downstream tool correctly refuses, because nothing
is paused.

The cause is not yet identified, so this ships as a documented limitation rather
than a guess at a fix. Two things did change: the debug toolset's descriptions
now say this instead of promising breakpoint debugging, and the
.catch(() => undefined) that swallowed breakpoint-application errors during the
handshake is gone — that swallow is why this never surfaced as an error in the
first place.

Until it is fixed, inspect a running game with get_runtime_log, game_eval
and query_runtime_node. The debug toolset is opt-in and not part of core,
so nothing enables it by accident.

C#: the spike is closed, and the answer is no

Four CI runs. The toolchain was never the blocker — Godot Mono, OmniSharp and
netcoredbg all install and start on a plain Linux runner in about a minute. The
blocker is that there is no non-interactive way to produce the .csproj:
--import does not emit it, and --build-solutions never returns (20 minutes
under --headless, exit 124 at a 300s timeout, and exit 124 again under
xvfb-run, so a missing display was the wrong diagnosis — it opens an editor
session and stays open).

cs_* tools built on that would only work for someone who had already opened
the project in a real editor. That is a precondition, and shipping tools that
quietly misbehave without it is worse than not shipping them. C# stays as
create_csharp_script plus an honest csharp_status.

Testing

  • GDScript suite: 285 → 358 assertions.
  • Live-editor harness: 28 → 31, and now covers the editor-only tools
    (select_nodes, close_scene_tab, selection, export presets) that a headless
    SceneTree cannot reach.
  • Node suite: 109 → 118.
  • 99 of 99 mutating tools have automated coverage. The ones that cannot do
    their real work in CI assert their refusal contract instead of being skipped.

Upgrade notes

213 tools (+scene_diff, +mp_diagnose). Nothing removed, no schemas changed
in a breaking way; 1.1.x usage keeps working.

The analysis_tools and close_scene_tab fixes are both in the addon, so
reinstall it (npx godot-mcp-bridge install) — updating only the npm package
leaves both bugs in place.