Beckett — MCP for Godot
Server Configuration
Describes the environment variables required to run the server.
| Name | Required | Description | Default |
|---|---|---|---|
| BECKETT_PORT | No | Port for the MCP server (default 8770) | 8770 |
| BECKETT_TOKEN | No | Optional bearer token for authentication | |
| BECKETT_READONLY | No | Set to 1 to enable read-only mode | |
| BECKETT_ALLOWLIST | No | Comma-separated list of allowed paths or patterns | |
| BECKETT_CONFIRM_DESTRUCTIVE | No | Set to 1 to require confirmation for destructive actions |
Instructions
Guidance the server publishes about itself, which clients place ahead of the tool catalog so the model reads it before choosing anything.
This server publishes no instructions, or was last inspected before Glama recorded them.
Capabilities
Features and capabilities supported by this server
Protocol revision2025-11-25
| Capability | Details |
|---|---|
| tools | {
"listChanged": false
} |
Tools
Functions exposed to the LLM to take actions
| Name | Description |
|---|---|
| apply_templateA | Instantiate a bundled (or project) template into res:// in one call — copies its files and, if the template declares a main_scene, sets and opens it. Generic: a template can be a game starter, a UI screen, a settings menu, a test harness. Project templates under res://.beckett/templates/ override bundled ones. Call with no 'template' to list what's available. |
| attach_scriptA | Attach a script (res:// path) to a node in the open scene (undoable). |
| batch_executeA | Run several tool calls in one request, in order. steps = [{tool, args}]. Stops at the first failure (stop_on_error, default true). When a step fails, scene edits made by the batch are rolled back via the editor undo history (rollback, default true) — file/resource writes are not. Use to collapse multi-step authoring (create node → set props → attach script) into one atomic call. ok per step means the handler completed - verify EFFECTS with a trailing read-back step (assert_scene / assert_node_state / a get_*) before trusting a mutation batch. |
| build_csharpA | Compile-check a C#/.NET Godot project with |
| call_methodA | Invoke a method on a resolved object. args = a positional array, coerced to the declared param types: vectors accept [x,y,z] / {"x":..} / "x y z", colors hex or [r,g,b,a], object params a node name/path or res:// path. Wrong types or counts return an ERROR (never a silent no-op). Returns the result as JSON. |
| connect_signalA | Connect a node's signal to a method on another node, persisted into the scene (undoable). from/to = node path/name in the open scene. |
| create_nodeA | Create a node of the given class and add it to the open scene (undoable). parent = a node path/name (default: scene root). |
| create_resourceA | Create a Resource of the given class and save it to a res:// path (.tres). Optional 'properties' dict sets initial values. |
| delete_nodeB | Remove a node from the open scene (undoable). |
| describe_classA | List a class's properties and methods (with signatures) so you know exactly what to set_property / call_method. The discovery key for full domain coverage. |
| describe_objectA | Dump a live object's properties as JSON. target = a res:// path, a node name/path in the OPEN scene, or a class name (falls back to describe_class). While a game is running it also resolves live nodes (/root/Main/Player), the same paths runtime_get_property takes; the answer says which scope it came from, since the edited scene and the running game share one path syntax but are different worlds. |
| disconnect_signalA | Disconnect a previously connected signal (undoable). |
| doctorA | Beckett self-diagnosis — one call answers 'why can't the agent see or do X?'. Reports: edition (Lite/Full), the effort dial vs its ceiling AND where the cap comes from (a beckett/effort= line committed in project.godot silently trims every clone's tool list), advertised-vs-ceiling tool counts, dock-disabled tools, server/port/auth state, per-client config freshness (does each written config still carry the CURRENT endpoint URL?), runtime-bridge liveness, what this tool surface costs your context (exact tools/list bytes and approximate tokens for every effort tier, measured on THIS install, so you can price a tier before dialing to it), whether the game plays EMBEDDED in the editor's Game workspace or in its own window (embedded means the Suspend button freezes every runtime call and window-mode asserts can never pass), and whether the editor auto-reloads externally-changed scripts (off = every script this server writes waits behind a modal the human must click). Run this FIRST when tools seem missing, counts look wrong, or calls fail unexpectedly. |
| duplicate_nodeA | Duplicate a node (with its children) under the same parent (undoable). Optional 'name' for the copy. |
| find_classesA | Search classes by name substring — engine classes AND your project's own types (GDScript class_name + C# [GlobalClass]). Optional 'base' restricts to subclasses (e.g. base=Node2D). The discovery entry point — pair with describe_class. |
| find_methodsA | Search methods by name substring, optionally restricted to a class (incl. inherited). Any result is invokable via call_method. |
| find_nodesA | Find LIVE nodes in the RUNNING game by type and/or name; returns their paths to feed into runtime_call/runtime_get_property/runtime_set_property. 'class' matches native classes AND custom class_name scripts (is_class alone misses custom nodes — they read as @Node@NN). name=substring on the node name. path=scope root (default scene root). recursive=true. max=cap (default 100). |
| game_logsA | Read the RUNNING game's captured output off the runtime channel (real-time, no file logging): runtime SCRIPT errors WITH stack traces, push_error/push_warning, and print(). This is the play->see-error->fix signal — the blind spot logs_read (file-based) can't reliably cover. level=error (default: errors+script+shader) | warning (adds warnings) | all (adds print/stderr). limit=newest N (default 100), filter=substring, clear=true empties the buffer after reading. |
| get_godot_versionA | Return the running Godot engine version info. |
| get_performance_monitorsA | Profiling: read Performance monitors (fps, frame time, memory, object/node counts, draw calls, video mem, physics) — measured engine counters, never estimates. target=game (default with a play session) | editor. duration_s>0 samples over time and returns per-monitor {min, avg, p95, max}. Sampling rules and why an editor-target window is refused: help(tool="get_performance_monitors"). |
| get_play_stateA | Report whether a scene is playing and whether the runtime channel to the game is connected. |
| get_project_settingA | Read a ProjectSettings value by its property path (e.g. application/run/main_scene). Pass it as 'setting' ('name' is also accepted). |
| get_project_statisticsA | Project overview: file/script/scene/resource counts, total GDScript lines, autoloads, main scene, input-action count, Godot version. Read-only static scan. |
| get_remote_treeA | Dump the live scene tree of the RUNNING game (runtime counterpart of get_scene_tree). SCOPE IT to stay under token limits — a full game tree blows the budget. path=subtree root (name, relative, or absolute /root/...); depth=levels (-1=all); max_nodes (default 250); max_children per node (default 50); collapse=true groups runs of identical leaf siblings (e.g. '8x CPUParticles2D'). Returns {tree, node_count, truncated?}. |
| get_scene_treeA | Return the node tree of the scene currently open in the editor (name/class/script, nested). |
| helpA | Full syntax for one tool - the argument catalogue and worked examples that descriptions no longer carry. Call help(tool="NAME") before a call you are unsure of; bare help() lists what is documented. |
| instance_sceneA | Instantiate a packed scene (res://*.tscn) as a child in the open scene (undoable). |
| list_dirA | List entries (dirs + files) of a res:// directory. |
| list_signalsA | List a node's signals and their current connections (target node + method). |
| logs_readA | Tail Godot's log FILE (the editor session and any played game log here). For the RUNNING game's errors/stack traces/prints in REAL TIME, prefer game_logs (runtime channel, no file needed) — this file reader is a fallback and needs file logging enabled (off by default; the result tells you how). Optional: level='error'|'warning', 'filter' substring, 'lines' (default 200), 'path' to override. |
| monitor_propertiesA | Sample a node's property in the running game over several frames (detect movement/changes). Returns the sample series. |
| move_nodeA | Reorder a node within its parent to a new child index (undoable). |
| open_sceneA | Open a scene by res:// path in the editor (makes it the edited scene). |
| play_sceneA | Play a scene in the editor. 'scene' (res://) plays a specific scene; current=true plays the open scene; otherwise the project's main scene. Then wait_until condition=play_started, and logs_read for errors. on_ready queues runtime property writes applied the moment the new game connects — the restart boundary batch_execute cannot cross. on_ready shape and its retry behaviour: help(tool="play_scene"). |
| read_fileA | Read a text file by res:// (or user://) path. |
| read_scriptA | Read a script/text file from res://. |
| rename_nodeA | Rename a node in the open scene (undoable). |
| render_probeA | Ask WHY a 3D node is or is not on screen, as data instead of pixels — the "node exists, visible is true, log is clean, and I still see nothing" case. Returns a 'warnings' list naming the stage that broke, or a verdict that the geometry does reach the camera. USE THIS BEFORE tuning lighting, fog, exposure or palette on anything you cannot clearly see. The stages it checks: help(tool="render_probe"). |
| reparent_nodeA | Move a node under a new parent in the open scene (undoable). |
| runtime_get_propertyA | Read a property of a node in the RUNNING game. Address by path (node path/name) OR a live selector: class (native or custom class_name) / name / text [+ nth, default 0]. The selector resolves fresh each call — no need to re-fetch volatile @Node@NN paths. Returns the value plus the 'resolved' path that matched. |
| save_sceneA | Save the scene currently open in the editor. Pass 'path' (res://) to save-as. |
| screenshotA | Capture an image the agent can see. target=game (default) captures the RUNNING game; target=editor captures the 2D editor viewport (PNG only). A bare call caps the long edge at max_dim=1280 — pass scale, region, max_dim=0, format or save_to to opt out. annotate=ui draws numbered Set-of-Mark boxes and returns the legend. For pure functional state ui_snapshot is cheaper. Token dials + delivery: help(tool="screenshot"). |
| script_patchA | Surgically edit an existing res:// file without rewriting it whole. edits = an ordered array; each item is {find, replace[, all]} (find must match EXACTLY once unless all:true), {append: text}, or {prepend: text}. Atomic + safe: nothing is written if any anchor is missing/ambiguous or (for .gd) the result fails to compile. Prefer this over write_script for small changes. |
| search_filesA | Search file contents under res:// for a substring (or regex with regex=true). Returns file:line matches. |
| set_debug_drawA | Switch the RUNNING game's viewport debug draw mode, then screenshot to see one render stage in isolation. unshaded = albedo only (clears lighting/fog/exposure as suspects in one shot). wireframe = is the geometry even there (culled or degenerate meshes show as nothing). overdraw = transparency cost. normal_buffer = flipped or NaN normals. lighting = light contribution only. normal = back to the real image. Reach for this FIRST when the picture is wrong; render_probe then answers the same question in numbers. |
| set_project_settingA | Set a ProjectSettings value and persist project.godot. The property path goes in 'setting' ('name' is also accepted); e.g. set application/run/main_scene to res://main.tscn. |
| set_propertyA | Set a property on a resolved object (undoable). value is coerced to the property's type (vectors accept "x y z" or [x,y,z]). |
| set_resourceA | Assign a resource to a node's property (undoable). Use 'resource' (res:// path to load) OR 'class' (mint a new inline sub-resource of that class). e.g. set Sprite2D.texture from a path, or a fresh RectangleShape2D on CollisionShape2D.shape. |
| stop_sceneA | Stop the running play session. |
| ui_snapshotA | One-call UI snapshot of the RUNNING game: every visible Control as structured data — path, class, text, rect, and the semantic state pixels cannot tell you (disabled, focused, checked, value, selected, editable, tooltip) plus per-control honesty flags. For FUNCTIONAL UI checks this replaces screenshot + find_ui_elements + get_control_rect + runtime_get_property; keep screenshot for visual/render bugs. Every field, and the free since_hash re-read: help(tool="ui_snapshot"). |
| validate_scriptA | Parse/compile GDScript WITHOUT writing it. Pass 'content' (source) or 'path' (res://). Returns whether it compiles — use before write_script to catch hallucinated APIs. Scripts whose class_name is already registered validate correctly (v1.9; the old false 'hides a global class' error is fixed); when validating 'content' destined for an existing file, ALSO pass its 'path' so a real cross-file class_name duplicate is still reported as the error it is. |
| wait_for_nodeA | Block until a node appears in the RUNNING game (by path/name) or timeout. Use after play_scene to sync before driving. |
| wait_untilA | Wait for a condition. Blocks the editor at most ~1.5 s per call — longer would stall the editor's own game-launch pipeline and background jobs (they need main-thread frames). If not met yet it answers 'not yet': just call it again. condition = play_started | play_stopped | game_connected | seconds:N | file_exists:res://path. |
| write_fileA | Write a text file under res:// (or user://), path-traversal guarded. Refreshes the editor filesystem. If the file is a .tscn the editor currently has OPEN, the result says so: Godot prompts the human to reload it and until they do the editor still holds the old version (scripts have no such problem, the editor auto-reloads them). Set beckett/auto_reload_scenes=true to reload open scenes automatically. Prefer the scene tools (create_node / set_property / save_scene) over writing .tscn text at all - editor-side edits never go stale. |
| write_scriptA | Write a GDScript (or other text, e.g. .cs) file under res://. GDScript is validated first by default — refuses code that doesn't compile; non-.gd files (C#, config…) are written as-is (use build_csharp to compile-check C#). Set validate=false to force. |
Prompts
Interactive templates invoked by user choice
| Name | Description |
|---|---|
No prompts | |
Resources
Contextual data attached and managed by the client
| Name | Description |
|---|---|
No resources | |
TDQS
Scored across 55 tools
Most tools target a distinct resource+action (scene nodes vs runtime nodes vs files vs signals), and the few close pairs like read_file/read_script and write_file/write_script are disambiguated by validation and scope details. No cluster of tools appears to do the same thing.
The set overwhelmingly uses snake_case verb_noun names (create_node, set_property, get_remote_tree), with only minor deviations like logs_read, ui_snapshot, game_logs, and single-word help/doctor. The pattern is predictable enough for an agent to guess tool names reliably.
At 55 tools, this is well into the 'too many' range and will consume significant agent context just to enumerate the surface. The tools are all domain-relevant, so it is not an extreme mismatch, but the set is considerably heavier than typical MCP servers.
The surface covers the core Godot loop: file/project editing, scene/node lifecycle, script validation, play/stop, runtime inspection, logging, screenshots, and render diagnostics. Notable gaps are file deletion/renaming and a dedicated runtime property setter (find_nodes even references runtime_set_property that is not exposed), but most workflows can be completed via call_method or set_property.