Use when working on this Godot 4.7 C# project's scenes, GridMaps, mesh libraries, or `.tres`/`.tscn` resources — including hand-authoring or validating resources, fixing UID/import issues, and editor or headless game smoke checks. Covers this machine's Godot and dotnet binary paths, the build->import->validate workflow, and a headless GDScript validation harness. Not needed for pure C# logic changes where `dotnet build` alone verifies the work.
Resources
2Install
npx skillscat add arabold/rogue-gauntlet/godot-mcp Install via the SkillsCat registry.
Godot (MCP + headless) for Rogue Gauntlet
Purpose
Validate real Godot behavior — scene/resource loading, UID resolution, mesh-library
alignment, editor-authored data, runtime smoke checks — and author/edit .tres/.tscn
correctly. Keep ordinary C# verification on dotnet build; reach for Godot only when the
task depends on scenes, resources, or runtime behavior.
Project setup
- Project root: the repo root. In a git worktree the root is the worktree directory.
- Gameplay scene:
res://scenes/main/main.tscn— run this for level-generation/gameplay checks. - Project main scene:
res://scenes/menu/main_menu.tscn. - Godot binary:
/Applications/Godot_mono.app/Contents/MacOS/Godot(the mono/C# build; notGodot.app). Usescripts/godot.shto resolve it automatically. dotnetbinary:/usr/local/share/dotnet/dotnet— it is not on the agent shell's PATH.
Gotchas
Concrete corrections — each is a mistake that happens without being told otherwise:
dotnetis not on PATH. A baredotnet buildfails with "command not found". Use/usr/local/share/dotnet/dotnet build "Rogue Gauntlet.sln".- Import before headless-loading any resource. A fresh or worktree checkout has no
.godot/imported/cache, so loading a.tres/scene fails withUnable to open file: res://.godot/imported/...ctex|.scnplus cascading parse errors that
look real but are not. Run the import step (below) once first. - Wrong Godot binary. The MCP server may default to
/Applications/Godot.app/...and
reportspawn ... ENOENT. Fall back to the local binary viascripts/godot.sh. - Worktree path discipline. When in a worktree, the project root is the worktree dir, not
the main checkout. Pass--path "<worktree>"to Godot and use absolute worktree paths when
editing, or builds/edits silently hit the wrong tree. - One
[GlobalClass]Resource per.csfile. A.tresreferences a script by file, so
multiple resource classes in one file make sub-resource typing ambiguous and break loads. A
plainenummay share a file. (Detail:references/tres-authoring.md.) - New C# scripts need a
.cs.uidsidecar that.tresfiles reference; the import step
generates it. (Detail:references/tres-authoring.md.) - GDScript can validate C# without a test project. A loaded resource exposes public C#
properties viaobj.get("PropName")— even computed, non-[Export]ones — and public
methods viaobj.call("Method", args), but only when the signature is Godot-marshalable.
Methods takingobjector genericIEnumerable<T>are not exposed (has_methodreturns
false); give logic you want to probe simple/Godot-typed signatures. - Shutdown noise. Headless leak/ObjectDB "resources still in use / leaked at exit" messages
on forced quit are noise unless preceded by real load/script/resource errors during the run. - Headless navmesh bake error is expected. A headless
main.tscnrun prints an error +
C# backtrace fromNavigationRegion3D.BakeNavigationMesh(MapGenerator.BakeNavigationMesh);
generation continues and logsMap generated.It is a NavigationServer-in-headless
limitation, not a real failure. ConfirmMap generated.and that the player spawns; bake
navmesh visually in the editor when it actually matters. - Bulk-generating files via Bash bypasses the Read-before-Write safety check. Writing many
new files at once (e.g. a script/heredoc loop creating a batch of wrapper.tscns) is easy to
reach for over N individual Write calls, but it skips the "must Read before overwrite"
protection Write gets — a filename collision with an existing (even orphaned/dead) file
silently clobbers it with no diff shown. Checkgit status/existence for every target
filename first, or use Write per-file when the count is manageable. - A model that renders fine in the item catalog can still be broken when equipped. See the
assetsskill's in-hand verification section — floating-and-auto-framed vs. bone-attached
are different enough contexts that one passing does not imply the other passes. _ready()on freshly-added nodes is deferred, not synchronous. In a--scriptmain-loop
script,some_node.add_child(x)does NOT runx's (or an autoload's)_ready()before the
next call returns — it fires on a later frame. Calling logic that depends on a node's own_ready()-wired references (e.g.MapGenerator.GenerateMap(), which needs its GridMap child
refs) immediately afteradd_childruns against not-yet-initialized state and silently
produces empty/wrong results, no error printed. Wait at least one_process()tick after
adding the node before calling into it (seerender_level_topdown.gd's state machine).
Core workflow
- Compile:
/usr/local/share/dotnet/dotnet build "Rogue Gauntlet.sln"(the default check
for any C# change; do this before touching Godot). - Import (only after adding/changing scripts or resources, or on a fresh/worktree checkout):
scripts/godot.sh --headless --path "$PWD" --import. This builds the import cache and
generates.cs.uidsidecars. - Validate / smoke-test the specific thing that changed — a resource load, a scene boot,
or a logic probe (below). Prefer a targeted scene + seed over the whole game.
Commands
# Compile (default verification)
/usr/local/share/dotnet/dotnet build "Rogue Gauntlet.sln"
# Build the import cache + UIDs (run from the project/worktree root)
.agents/skills/godot-mcp/scripts/godot.sh --headless --path "$PWD" --import
# Headless gameplay smoke (spawns player + level, then quits after N frames)
.agents/skills/godot-mcp/scripts/godot.sh --headless --path "$PWD" res://scenes/main/main.tscn --quit-after 150
# Launch the editor for visual checks (GridMaps, tiles, lighting, UI)
.agents/skills/godot-mcp/scripts/godot.sh --editor --path "$PWD"Headless validation harness
Run a GDScript file as the main loop to exercise the project without the editor:scripts/godot.sh --headless --path "$PWD" --script <file.gd> -- <args...>. The scriptextends SceneTree, does its work in _init(), reads args after -- viaOS.get_cmdline_user_args(), and calls quit().
- Validate a resource loads and reads back correctly (use after hand-authoring a
.tres):.agents/skills/godot-mcp/scripts/godot.sh --headless --path "$PWD" --script \ .agents/skills/godot-mcp/scripts/inspect_resource.gd -- res://path/to/new.tres - Probe C# logic for a one-off check: write a small
extends SceneTreescript in the
scratchpad that loads a resource and calls its marshalable methods / reads its properties
(see the GDScript gotcha above), then run it with--script. Do not commit one-offs.
Visual verification: top-down level/room screenshots
Reasoning about tile coordinates or trusting an editor-only gizmo (e.g. DoorwayMarker's arrow,
which only draws inside the actual Godot editor process) can't confirm what a generated level or
room actually looks like. scripts/render_level_topdown.gd renders a real top-down screenshot of
a generated level instead, with an overlay drawn straight from MapGenerator.GetConnectorDebugInfo()
(Godot-native return types, since MapData itself can't marshal to GDScript) showing every
connector's position and per-direction open (green) / sealed (red) status, plus doorway (yellow)
vs inferred (cyan) markers. This must run windowed, not headless — the headless renderer
produces blank images:
.agents/skills/godot-mcp/scripts/godot.sh --path "$PWD" --script \
.agents/skills/godot-mcp/scripts/render_level_topdown.gd -- <outfile.png> [seed] [image_size]Then Read the resulting PNG to inspect it. Use this whenever a change to room layout, doorway
placement, wall generation, or rotation needs a visual sanity check instead of (or in addition to)
numeric probes/tests — e.g. confirming a doorway's connector tile is flush with its wall gap, or
that a rotated room's markers still point the right way.
MCP tools
When the MCP server is correctly configured, prefer it for editor/runtime interaction:godot_get_project_info (open check), godot_launch_editor, godot_run_project +godot_get_debug_output + godot_stop_project (run and inspect), godot_get_uid /godot_update_project_uids (UID issues), godot_export_mesh_library (intentional library
changes). If MCP reports ENOENT on Godot.app, use scripts/godot.sh via Bash instead.
Bundled scripts
scripts/godot.sh— resolves the working Godot binary and runs it with the given args.scripts/inspect_resource.gd— loads one or moreres://resources and prints their script
properties; reportsOK/FAIL/MISSINGper path. The reusable resource validator.scripts/render_level_topdown.gd— renders a windowed top-down screenshot of a generated
level with a connector/doorway overlay. See "Visual verification" above.
Authoring .tres / .tscn by text
Before creating or editing a .tres/.tscn in a text editor (rather than the Godot editor),
read references/tres-authoring.md — it covers load_steps counting, enum-as-int and
array serialization, sub-resource layout, the one-[GlobalClass]-per-file rule, UID sidecars,
the missing-res://-prefix trap, and the wrapper-.tscn pattern for correcting a raw model's
grip orientation or scale. Always validate the result with inspect_resource.gd.
Rules
- Do not replace
dotnet buildwith Godot's C# solution build on this machine; the Godot CLI
solution build times out with engine shutdown errors. Usedotnet. - Do not commit temporary probe scenes/scripts. Put one-offs in the scratchpad; if a
res://tmp_*file is unavoidable, delete it before finishing. - Do not edit
.tscn/.tresblindly when a visual result matters; launch the editor or build
a focused test scene. - Prefer deterministic checks: run a specific scene and seed when debugging generation.
- Keep this skill focused on Godot-specific validation; do not use it for general file search
or ordinary C# refactors.