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?), and runtime-bridge liveness. 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 when a play session is connected) reads the RUNNING game; target=editor reads the editor. duration_s>0 (game only, max 30) SAMPLES OVER TIME: polls every interval_ms (default 100, min 30) while the game keeps running, then returns per-monitor stats {min,avg,p95,max} â e.g. fps.p95 or process_time.max over a stress window; series=true also returns the raw per-sample series (token-heavy). Editor-target sampling is refused honestly: a tool call blocks the editor's own loop, so an over-time editor read would only measure a stalled editor. |
| 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). |
| 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=[{path|class|name, property, value}, ...] queues runtime writes that are applied automatically the moment the new game connects â the restart boundary batch_execute cannot cross. Use it to restore camera pose, debug flags or spawn state in ONE call instead of re-issuing them after every restart; wait_until condition=game_connected then reports whether each one landed. Writes whose target is still spawning are retried for a few seconds, then reported as failures rather than dropped. |
| 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. Answers the 'the node exists, visible is true, the log is clean, and I still see nothing' case: visibility chain, world AABB, frustum test, distance vs far plane and visibility range, layers vs the camera cull_mask, per-surface material + cull mode, and the triangle winding the camera actually sees (facing_camera=0 with back-face culling means a reversed index buffer â Godot treats CLOCKWISE winding as the FRONT face). Returns a 'warnings' list naming the stage that broke, or a verdict saying the geometry does reach the camera. USE THIS BEFORE tuning lighting, fog, exposure or palette on anything you cannot clearly see â those are invisible-mesh symptoms far more often than they are art problems. |
| 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) screenshots the RUNNING game via the runtime channel; target=editor captures the 2D editor viewport (PNG only). Token-cost dials (game target, 1.10+): scale=0.5 quarters the pixels; format=jpeg|webp with quality (default 0.8) compresses far below PNG for game frames; region=[x,y,w,h] crops (clamped). annotate=ui draws numbered Set-of-Mark boxes over every visible interactive control and ALSO returns the legend as structured {marks:[{i, path, rect, text?}]} â one glance answers both 'does it look right' and 'what can I click where'; follow up with click_control path=. For pure functional state, ui_snapshot is cheaper than any image. |
| 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 (+custom class_name), text, rect [x,y,w,h] (gui space, ints), and the semantic state pixels can't tell you: disabled, focused, checked (toggles), value + range (sliders/spin/progress), selected (+selected_text / tabs / item_count), editable / placeholder / secret (text fields), tooltip, mouse_ignore. Interactive controls also get honesty flags: clipped (scrolled out of view) and occluded_by (another control would swallow the click â popup/modal/overlay). Top level: focus owner, open popup/dialog windows (exclusive = modal), viewport size, and a stable content 'hash' â pass it back as since_hash and an unchanged UI returns {unchanged:true} for ~free. For functional UI checks this replaces the screenshot + find_ui_elements + get_control_rect + runtime_get_property round-trips (keep screenshot for VISUAL/render bugs). Walks the whole SceneTree root (autoload HUD layers and popups included); scope with path=, slim with interactive_only=true, cap with max_nodes (default 400). |
| 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. |
| 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 | |
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/beckettlab/beckett-godot-mcp'
If you have feedback or need assistance with the MCP directory API, please join our Discord server