v1.1.0 — a debugger, a language server, and honest C#
godot-mcp-bridge 1.1.0 — A debugger, a language server, and honest C#
Until now, when an agent hit a bug in your game it did what it could: read
get_errors, add a print(), re-run, and infer what the value must have been.
That works until the interesting state isn't printed — a wrong number deep in a
physics step, a null that only appears on the third frame, a branch nobody
expected to be taken.
1.1.0 adds the other option: stop the program at the failure and look.
The debugger
Godot already runs a Debug Adapter (the same protocol VS Code uses) on port
6006, alongside its GDScript language server on 6005. Both are on by default —
the editor prints "Debug adapter server started on port 6006" at startup. This
release adds a DAP client to the MCP server that talks to it directly.
That's an architectural first for this project: the debug_* tools do not
go through the WebSocket bridge to the editor addon. They are answered inside
the Node server, which is also why they keep working when get_godot_status
reports the addon as disconnected — the adapter is a separate listener owned by
the editor.
A session looks like this:
debug_set_breakpoints({path: "res://scenes/player.gd", lines: [17]})
debug_launch({scene: "res://scenes/level.tscn"})
→ { state: "stopped", stopped_reason: "breakpoint" }
debug_stack_trace()
→ _physics_process at player.gd:17
debug_scopes() → debug_variables({variables_reference: 1})
→ delta = 0.01666666666667, direction = <null>
debug_evaluate({expression: "velocity"})
→ (0.0, 0.0)
debug_step({mode: "over"})
→ now at line 18
Eleven tools: debug_launch, debug_attach, debug_set_breakpoints,
debug_continue, debug_step, debug_stack_trace, debug_scopes,
debug_variables, debug_evaluate, debug_status, debug_disconnect.
They are not in core. A debugger is a deliberate move, not something an
agent should wander into while doing routine scene edits — run
enable_toolset({name: "debug"}) first. There's a debugging guide in
get_guide (and in docs/TOOLS.md) covering the loop and the engine quirks.
Two things learned by running it, not by reading the spec
Godot fills frame variables asynchronously. scopes returns variable
references immediately, but the values arrive from the debuggee a moment later.
A variables request that lands first is rejected with a bare "unknown" —
which reads exactly like a bug in your own code. The client now retries briefly,
so this is invisible to callers.
Conditional breakpoints may not work. Godot's adapter does not advertise
supportsConditionalBreakpoints in its capabilities. The conditions argument
is forwarded, but the engine may break unconditionally. Documented rather than
quietly promised.
The language server: renames that are actually correct
Godot runs a GDScript language server on port 6005 alongside the debug adapter,
and it understands the real symbol table. That matters because of a correctness
bug this project has been shipping: rename_symbol_project_wide does
word-boundary text substitution. Rename a local speed and it will also rename
an unrelated class's speed, silently.
gd_rename goes through the language server, so it doesn't. gd_references
finds the real references rather than string matches. gd_diagnostics reports
type errors without running the game — the old validate_script only told you
whether a file parsed.
Eight tools in the new code_intel toolset. Only what Godot actually advertises
is exposed: it reports no support for workspace symbols, code actions,
formatting or folding ranges, so there are no tools pretending otherwise.
gd_lsp_status shows what the connected server really supports.
The transport was free — Godot serves LSP with the same Content-Length framing
as DAP, so the client written for the debugger was factored into framing.ts and
reused.
Multiplayer scaffolding
The runtime side could already test netcode (spawn_headless_peers,
call_rpc_runtime). Now it can build it:
mp_add_spawner/mp_add_synchronizer— Godot 4's replication nodes. The
synchronizer is the fiddly one: its replicated property list lives in a
SceneReplicationConfigsub-resource, so the test asserts the config survives
a round-trip to disk rather than just checking the call returned ok.mp_wire_rpc— writes a correctly-annotated@rpcmethod. A wrong annotation
is the classic Godot 4 multiplayer bug: the remote call silently does nothing,
with no error.mp_scaffold_lobby— the ENet host/join plumbing every project rewrites.
C#, stated honestly
The standard Godot build has no C# support at all — no CSharpScript class.
A .cs file written there saves fine, attaches to nothing, and fails silently.
Rather than ship C# tools that couldn't be verified, this release adds
csharp_status: it reports whether C# can work in this editor and project before
any is written, and create_csharp_script now carries the same warning in its
result. Full C# language-server and debugger support (OmniSharp, netcoredbg) is
deliberately not in this release — it could not be tested against a standard
build, and shipping unverified tools would undercut the one claim this project
actually cares about.
An opt-in safety gate
GODOT_MCP_REQUIRE_CONFIRM=true makes operations with no undo path require an
explicit confirm: true: file deletes and renames, script rewrites, mass
renames, project settings, autoloads.
Scene edits are deliberately exempt. When the scene is open they go through
Godot's undo history — Ctrl+Z already covers them, and gating them would be
noise. Off by default so nothing built against 1.0 breaks.
Bug fixes: the same shape, three more times
1.0.0 shipped a fix for set_particle_material, which applied several
properties before validating the last one — and on a scene open in the editor,
_discard_scene is a no-op (the target is the editor's live node, not a
copy), so a late validation failure left the earlier writes applied while the
tool reported total failure.
That's a shape, not an incident. Sweeping for it found three more:
set_physics_layers— appliedcollision_layer, then validated
collision_mask. An invalid mask name left the layer applied.set_material_3d— appliedmetallic/roughnessbefore validating
emission_color.setup_environment— worst of the three: it creates a
WorldEnvironmentnode and adds it to the live tree, and only then validated
the sky colours. A bad colour left a stray node in your scene while reporting
failure.
All three now resolve and validate every argument before writing anything.
Also in this release
- CI runs the GDScript handlers against a real headless Godot, not just the
Node-side suite. The half of the codebase that actually mutates scenes was
previously only covered by tests run by hand. llms.txtat the repo root — a machine-readable project summary, including
an explicit limitations section.- The README now leads with what actually makes this different: it's
bidirectional (get_editor_activityreports what you did, not just what the
agent did), and every claim in it maps to a tool that was run by hand.
Upgrade notes
- Versions bumped to 1.1.0 across
mcp-server/package.json,
mcp-server/server.json, andaddons/godot_mcp/plugin.cfg. - 209 tools total (185 + 11 debugger + 8 language server + 4 multiplayer +
csharp_status). The defaultcoreset is unchanged at 35. - Nothing removed, no schemas changed. 1.0.0 usage keeps working as-is.