A generic, game-agnostic Model Context Protocol (MCP) server for AI-driven Godot development. An AI agent (Claude Code, OpenCode, Cursor, or any stdio MCP client) connects to a live Godot 4.4+ editor and controls it programmatically — inspecting scenes, editing nodes, writing scripts, running the game, and exporting builds — all through a typed, structured API with no built-in game vocabulary.
Status: feature-complete across the planned ecosystem. 175 tools across 29 categories — always-on
coreplus 28 toggleable toolsets, of which onlyinspectionis enabled by default (the other 27 are gated off). Every capability is documented, tested, and ready for agent use.
- What is this?
- Architecture
- Prerequisites
- Quick Start
- Setup Guide
- Using godot-mcp
- Live Runtime & The Probe Autoload
- All Toolsets
- Configuration Reference
- Troubleshooting
- Repository Layout
- Contributing
- License
godot-mcp bridges an AI agent and a live Godot editor. Instead of editing files blindly on disk, the agent drives the editor directly:
- Inspect the scene tree, selected nodes, and project settings live
- Mutate scenes — create nodes, attach scripts, connect signals — with undo support
- Edit GDScript files and check them for parse errors
- Run the game headless or control an editor play session
- Drive input, record replays, take screenshots, and profile performance
- Export builds, analyze code statically, and refactor across scenes
The server is game-agnostic — it knows Godot, not your game. A tower-defense roguelite, a 3D platformer, and a visual novel all use the same generic tools. Game-specific vocabulary ("spawn wave", "upgrade tower") belongs in a separate project that consumes this server.
Every agent action crosses a four-layer chain:
flowchart TD
AI["AI client<br/>Claude Code · OpenCode · Cursor · any stdio MCP client"]
SRV["FastMCP server · Python 3.11+ · <code>mcp_server/</code><br/>Pydantic schemas · safety classes · preconditions · no Godot logic"]
ADDON["Godot addon · GDScript · <code>godot/addons/godot_mcp/</code><br/>EditorPlugin: WebSocketPeer client (connects out, reconnects) · routes cmd_* envelopes"]
PROJ["Live Godot project"]
AI -->|"stdio · MCP protocol (JSON-RPC)"| SRV
ADDON ==>|"WebSocket connect (editor dials) · ws://127.0.0.1:9080"| SRV
SRV -.->|"{id, command, params}"| ADDON
ADDON -->|"Godot Editor API"| PROJ
ADDON -.->|"{id, ok, result, error, hint}"| SRV
SRV -.->|"typed tool result"| AI
The editor dials the connection (bold arrow) and reconnects on its own; the server still drives every command (dashed {id, command, …}). Those two directions are decoupled — the bridge inversion (#276) only changed who connects.
A single tool call — godot_scene_edit_create_node — travels the full chain and back:
sequenceDiagram
participant AI as AI client
participant SRV as FastMCP server
participant ADDON as Godot addon
participant GD as Godot editor
AI->>SRV: godot_scene_edit_create_node(parent_path, node_type, node_name)
Note over SRV: validate typed args ·<br/>check safety class + preconditions
SRV->>ADDON: {id, command: "cmd_create_node", params}
ADDON->>GD: EditorInterface API (UndoRedo-wrapped)
GD-->>ADDON: node created
ADDON-->>SRV: {id, ok: true, result: {node_path, created}}
SRV-->>AI: CreateNodeResult { node_path, created }
Solid arrows are the request path (top-down); dashed arrows are the response envelope flowing back up.
The boundary is deliberate and enforced by design rules:
- Only the addon touches Godot. The server has no Godot imports.
- Only the server owns safety. All
dry_run,confirm, and precondition logic lives in Python. - JSON envelopes everywhere. Commands and responses carry
{id, ok, result, error, hint}— structured, versioned, and never a Python traceback.
Read docs/architecture.md for the full bridge contract, envelope spec, and type coercion rules.
| Component | Minimum | Recommended |
|---|---|---|
| Godot | 4.4 | 4.7 (validated target) |
| Python | 3.11 | 3.13 |
| Package manager | uv | uv |
| OS | macOS / Linux / Windows | Any desktop |
Godot 4.4 is the minimum. The addon checks the editor version on enable and warns if it is older. Some toolsets (
scene_edit,input_map,tilemap,scene_3d) are version-gated and refuse to enable on older editors.
# Clone or navigate to the repo
cd godot-mcp
# Create venv and install everything (runtime + dev)
uv sync
# Verify it works
uv run godot-mcp --help# Copy the addon into your Godot project's addons/ folder
cp -r godot/addons/godot_mcp /path/to/your/project/addons/Then in Godot: Project → Project Settings → Plugins → godot_mcp → Enable.
A status dock appears (bottom panel). It shows connection state, project name, active scene, and selected node. The addon connects out to the MCP server's bridge listener (ws://127.0.0.1:9080 by default) and reconnects automatically — so editor and server can start in either order.
OpenCode (opencode.json in project root or ~/.config/opencode/opencode.json):
{
"mcp": {
"godot": {
"type": "local",
"command": ["uv", "run", "godot-mcp"]
}
}
}Claude Code (.mcp.json in project root, or claude mcp add):
{
"mcpServers": {
"godot": {
"command": "uv",
"args": ["run", "godot-mcp"]
}
}
}Both assume the command runs from the repo root (so
uvresolves this project's environment). Use absolute paths or--directoryif launching elsewhere.
- Open your Godot project and enable the addon.
- Start your MCP client (Claude Code, OpenCode, etc.).
- Ask the agent to inspect the project:
- "Show me the scene tree" →
godot_inspection_get_scene_tree - "What node is selected?" →
godot_inspection_get_selected_node - "List available toolsets" →
godot_list_toolsets
- "Show me the scene tree" →
- Enable a toolset when needed:
- "Enable scene editing" →
enable_toolset("scene_edit") - "Create a player node" →
godot_scene_edit_create_node
- "Enable scene editing" →
# Full install with dev dependencies
uv sync
# Run tests
uv run pytest # full suite (~304 tests)
uv run pytest tests/contract # contract tests (fake bridge)
uv run pytest tests/unit # unit tests (isolated logic)
# Lint and type check
uv run ruff check .
uv run mypy
# Run the server manually
uv run godot-mcp # stdio mode (default)
GODOT_MCP_TRANSPORT=http uv run godot-mcp # HTTP mode on 127.0.0.1:9090pip + venv fallback (no uv)
python3 -m venv .venv
source .venv/bin/activate # Windows: .venv\Scripts\activate
pip install -e '.[dev]'
pytestThe addon lives at godot/addons/godot_mcp/. You have two options:
Option A: Use the bundled project
Open the godot/ folder as a project in Godot 4.4+. Enable the plugin. This is a minimal project that exists only so the addon is loadable and testable.
Option B: Copy into your own project
cp -r godot/addons/godot_mcp /path/to/your/game/addons/Then enable the plugin in Project Settings.
What the addon provides:
- Status dock — read-only panel showing bridge state, project info, active scene, selected node, and recent commands
- WebSocket bridge — a client that connects out to the MCP server's listener at
ws://127.0.0.1:9080(configurable) and reconnects with backoff - Command router — handles 80+
cmd_*commands that call the Godot Editor API - Debugger plugin — captures the
godot_mcp:debugger channel for live game inspection - Runtime probe —
mcp_runtime_probe.gd, an autoload you add to your game for live input/profiling
The server exposes two transports:
| Transport | Use case | How to connect |
|---|---|---|
stdio |
A single local agent (Claude Code, OpenCode) | uv run godot-mcp |
http |
Shared service; remote or web-based clients | scripts/serve-http.sh |
stdio is the default and what most AI coding assistants expect: the client
spawns its own server subprocess and they speak JSON-RPC over stdin/stdout.
Service mode (one server, many clients). The bridge to the editor is a single connection — only one server process can own it at a time. So when you want several clients on the same live editor (e.g. Claude Code and the godot-agents project), run one HTTP service and have every client connect to it instead of each spawning its own:
scripts/serve-http.sh # http://127.0.0.1:9090/mcp + editor bridge :9080Clients then point at http://127.0.0.1:9090/mcp (FastMCP's Streamable HTTP
mount). Claude Code, via .mcp.json:
{ "mcpServers": { "godot": { "type": "http", "url": "http://127.0.0.1:9090/mcp" } } }With 175 tools, showing everything at once would overwhelm an agent's context window and degrade tool selection. So tools are grouped into toolsets and most are gated off by default.
Always exposed:
core— diagnostics, toolset management, safety introspectioninspection— read-only project/scene/node inspection
Gated off by default (27 toolsets):
scene_edit, scripts, resources_edit, project, editor, physics, animation, scene_3d, particles, navigation, audio, tilemap, theme_ui, shader, visual_shader, runtime, input, input_map, testing, profiling, batch, analysis, export, debugger, asset_import, project_scaffold, composite
Meta-tools (always available in core):
| Tool | Purpose |
|---|---|
godot_get_server_info |
Full capability snapshot: toolsets, prompts, resources, bridge state, troubleshooting |
godot_list_toolsets |
Discover toolsets, their enabled state, and version requirements |
godot_enable_toolset(category) |
Expose a toolset's tools (fires tools/list_changed) |
godot_disable_toolset(category) |
Hide a toolset to keep the surface small |
godot_list_tools_by_safety_class |
Report which tools are read_only / mutating / destructive / runtime |
Enable a toolset before using its tools:
Agent: godot_enable_toolset("scene_edit")
Server: { "name": "scene_edit", "enabled": true, "description": "...", "min_godot": "4.4" }
Agent: godot_scene_edit_create_node(parent_path=".", node_type="CharacterBody2D", node_name="Player")
Server: { "node_path": "./Player", "created": true }
Every tool carries a safety class that determines its risk and required parameters:
| Class | Risk | Extra params | Example |
|---|---|---|---|
read_only |
None | none | godot_inspection_get_scene_tree, godot_scripts_read |
mutating |
Reversible change | dry_run: bool = False |
godot_scene_edit_create_node, godot_scene_edit_set_node_property |
destructive |
May be irreversible | dry_run and confirm: bool = True |
godot_scene_edit_delete_node, godot_scene_edit_reload_scene |
runtime |
Controls execution | varies | godot_runtime_play_scene, godot_runtime_run_and_capture, godot_export_project |
dry_run=Trueruns preconditions and returns what would happen without sending any change.confirm=Trueis required for destructive tools. Without it, the tool returnsPRECONDITION_FAILED: ... [required=confirm].
All safety logic lives in mcp_server/safety.py — never in the addon.
Some toolsets depend on Godot editor APIs that are only reliable from 4.4 onward:
| Toolset | Min Godot | Why gated |
|---|---|---|
scene_edit |
4.4 | Scene session and PackedScene APIs validated on 4.4+ |
input_map |
4.4 | ProjectSettings.save() for input actions stable from 4.4+ |
tilemap |
4.4 | TileSet/AtlasSource APIs changed significantly |
scene_3d |
4.4 | MeshLibrary authoring uses ResourceSaver; validated on 4.4+ |
When the agent calls enable_toolset("input_map") on a 4.3 editor:
PRECONDITION_FAILED: Toolset 'input_map' requires Godot 4.4+ (connected editor is 4.3).
Upgrade the editor or enable a different toolset. [required=godot_version]
If the bridge is disconnected:
BRIDGE_DISCONNECTED: Toolset 'input_map' requires Godot 4.4+, but the Godot bridge
is not connected. Start the editor with the addon enabled and retry. [required=bridge_connected]
If the version query fails:
PRECONDITION_FAILED: Toolset 'input_map' requires Godot 4.4+, but the Godot version
could not be determined. Check the editor and addon status, then retry. [required=bridge_connected]
A typical agent session follows this pattern:
1. Discovery
get_server_info → capability snapshot: toolsets, bridge state, docs URLs
list_toolsets → see what's available
get_project_info → project name, Godot version, main scene, autoloads
get_active_scene → is a scene open? which one?
get_scene_tree → inspect the node hierarchy
get_selected_node → what the user is currently working on
2. Planning
list_tools_by_safety_class → know which tools are read-only vs. mutating
enable_toolset("scene_edit") → expose scene mutation tools
dry_run preview → preview changes before committing
3. Action (scene editing)
create_node → rename_node → set_node_property → attach_script
save_scene
4. Verification
debug_workflow(scene="res://main.tscn", timeout_seconds=10)
→ returns parse errors, scene tree, run results, findings, and suggestions in one call
run_and_capture(scene="res://main.tscn", timeout_seconds=10)
→ returns exit code, errors, warnings, output
5. Live testing (with probe)
enable_toolset("runtime")
play_scene()
get_game_scene_tree()
simulate_action("jump", pressed=true)
assert_node_state("Player", "position.y", expected=0, op="==")
stop_scene()
6. Export
enable_toolset("export")
list_export_presets()
export_project(preset="Web", output_path="builds/web")
Beyond the tool surface, two layers help an agent drive the server well:
- MCP prompts — step-numbered workflow recipes the server exposes over MCP. Clients that surface prompts (Claude Code, etc.) show them as slash commands, e.g.
/mcp__godot-mcp__build_scene. Shipped:toolset_discovery,build_scene,play_test,script_edit,debug_scene,troubleshoot,author_resource,export_build,batch_refactor. Discover withlist_prompts(); render withrender_prompt(name, arguments={...}). - Claude skills (
skills/) — optional, Claude-specific. Unlike prompts, a skill auto-triggers when the agent recognizes a matching task (no slash command), then routes to the prompts and tools. Copy a skill directory into~/.claude/skills/(personal) or your project's.claude/skills/(shared). Shipped:godot-mcp-getting-started,godot-mcp-build-a-scene,godot-mcp-playtest-and-debug.
Both stay pure to the generic Godot surface — no game-specific vocabulary.
All errors are structured — never Python tracebacks. The agent can parse them and recover:
{ "ok": false, "error": "PRECONDITION_FAILED", "hint": "No scene is open.", "required": "active_scene" }| Error code | Meaning | How to recover |
|---|---|---|
PRECONDITION_FAILED |
A required condition isn't met | Check required field and satisfy it |
RESOURCE_NOT_FOUND |
Node/scene/resource doesn't exist | Verify the path or create it first |
VALIDATION_ERROR |
Bad parameters | Check the schema and retry |
BRIDGE_DISCONNECTED |
Addon not reachable | Ensure Godot is running with the addon enabled |
TIMEOUT |
No response in time | Retry; check if Godot is frozen |
INTERNAL_ERROR |
Unexpected failure | Report as a bug |
When using MCP tools, errors surface as ToolError with the message in "<ERROR_CODE>: <hint> [required=<field>]" format.
Some tools inspect or drive a running game (not the editor). This requires the game to be launched from the editor so it connects to the editor's debugger. The addon captures the debugger channel, but it needs cooperation from the game side.
- In your game's project, add
res://addons/godot_mcp/mcp_runtime_probe.gdas an autoload:- Project → Project Settings → Globals/Autoload
- Path:
res://addons/godot_mcp/mcp_runtime_probe.gd - Name: any (e.g.,
MCPRuntimeProbe)
- The probe no-ops outside a debug session, so it's safe to leave enabled.
| Capability | Needs probe? | Without probe |
|---|---|---|
godot_runtime_play_scene / godot_runtime_stop_scene |
No | Works (editor play control) |
godot_runtime_get_game_scene_tree |
Yes | Returns connected: false + hint |
godot_input_simulate_key / godot_input_simulate_mouse / godot_input_simulate_action |
Yes | PRECONDITION_FAILED: required=runtime_probe |
godot_runtime_monitor_property / godot_runtime_get_property_samples |
Yes | PRECONDITION_FAILED: required=runtime_probe |
godot_runtime_find_ui_elements |
Yes | PRECONDITION_FAILED: required=runtime_probe |
godot_profiling_get_performance_monitors (live game) |
Yes | Returns connected: false + hint |
godot_input_record / godot_input_stop_recording |
Yes | PRECONDITION_FAILED: required=runtime_probe |
godot_runtime_run_and_capture |
No | Runs Godot headless subprocess directly |
godot_export_project |
No | Runs Godot headless subprocess directly |
The full surface is 175 tools across 29 categories (core + 28 toggleable toolsets). Below is a summary; the authoritative per-tool spec is in docs/tool-contracts.md.
godot_health_check— server version + bridge stategodot_get_server_info— full capability snapshot: toolsets, prompts, resources, bridge state, and common troubleshooting scenarios (call this first)godot_debug_workflow— one-call comprehensive debug check: parse errors, scene tree, headless run, and bridge stategodot_list_toolsets/godot_enable_toolset/godot_disable_toolset— toolset managementgodot_list_tools_by_safety_class— safety introspectiongodot_read_resource— fallback for clients without resource protocol support
godot_inspection_get_project_info— name, Godot version, main scene, autoloads, input actionsgodot_inspection_get_active_scene— is_open, path, namegodot_inspection_get_scene_tree— full node hierarchy withmax_depthcontrolgodot_inspection_get_selected_node— the currently selected node in the editorgodot_inspection_get_node_properties— type, script, properties, children for any node pathgodot_inspection_get_node_property— read a single property by name, including built-in Godot propertiesgodot_inspection_get_node_groups— a node's group memberships (for snapshot/rollback)
- Node creation:
godot_scene_edit_create_node,godot_scene_edit_instance_scene,godot_scene_edit_duplicate_node - Hierarchy:
godot_scene_edit_move_node,godot_scene_edit_rename_node,godot_scene_edit_delete_node(destructive, needsconfirm) - Properties:
godot_scene_edit_set_node_property(with Godot↔JSON type coercion) - Scripts:
godot_scene_edit_attach_script - Signals:
godot_scene_edit_connect_signal,godot_scene_edit_disconnect_signal,godot_scene_edit_list_signal_connections - Groups:
godot_scene_edit_add_to_group,godot_scene_edit_remove_from_group - Scene I/O:
godot_scene_edit_save_scene,godot_scene_edit_create_scene - Session:
godot_scene_edit_open_scene,godot_scene_edit_reload_scene(destructive),godot_scene_edit_save_all_scenes,godot_scene_edit_list_open_scenes,godot_scene_edit_select_nodes
godot_scripts_read,godot_scripts_list,godot_scripts_get_for_nodegodot_scripts_write,godot_scripts_patch(bothmutating, supportdry_run)godot_scripts_get_parse_errors— shells out togodot --check-only
godot_resources_edit_read_resource_file,godot_resources_edit_create_resource,godot_resources_edit_set_resource_propertygodot_resources_edit_register_autoload,godot_resources_edit_unregister_autoload
godot_project_get_filesystem_tree— recursive project treegodot_project_search_files— by name glob and/or content substringgodot_project_get_setting,godot_project_set_setting— project settingsgodot_project_resolve_uid— path ↔ uid:// resolutiongodot_project_delete_resource_file— delete ares://file (destructive; inverse of file-creating tools)
godot_editor_capture_screenshot— returns a PNG image for vision-capable clients
godot_physics_setup_body,godot_physics_setup_collision,godot_physics_set_layers,godot_physics_add_raycast
godot_animation_create,godot_animation_add_track,godot_animation_insert_keyframegodot_animation_create_tree,godot_animation_add_state_machine_state,godot_animation_set_blend_tree_nodegodot_animation_list_animations,godot_animation_get— read tracks/keyframes (for snapshot/rollback)
godot_scene_3d_add_mesh_instance,godot_scene_3d_setup_camera,godot_scene_3d_setup_lighting,godot_scene_3d_setup_environment,godot_scene_3d_gridmap_set_cell,godot_scene_3d_gridmap_get_cell- MeshLibrary authoring:
godot_scene_3d_create_mesh_library,godot_scene_3d_add_mesh_library_item
godot_particles_create,godot_particles_set_material,godot_particles_set_color_gradient,godot_particles_apply_preset,godot_particles_get_material
godot_navigation_setup_region,godot_navigation_setup_agent,godot_navigation_bake_mesh,godot_navigation_set_layers
godot_audio_add_player,godot_audio_get_bus_layout,godot_audio_add_bus,godot_audio_add_bus_effect,godot_audio_remove_bus(destructive),godot_audio_remove_bus_effect(destructive)
godot_tilemap_set_cell,godot_tilemap_fill_rect,godot_tilemap_get_cell,godot_tilemap_get_used_cells,godot_tilemap_clear,godot_tilemap_layers- TileSet authoring:
godot_tilemap_create_tileset,godot_tilemap_add_tileset_atlas_source,godot_tilemap_create_tile
godot_theme_ui_create,godot_theme_ui_set_color,godot_theme_ui_set_font_size,godot_theme_ui_set_stylebox,godot_theme_ui_get_node_overrides
godot_shader_create,godot_shader_read,godot_shader_assign_material,godot_shader_set_param
godot_runtime_run_and_capture— headless subprocessgodot_runtime_play_scene,godot_runtime_stop_scene,godot_runtime_is_playing,godot_runtime_get_game_scene_tree— editor play session
godot_input_simulate_key,godot_input_simulate_mouse,godot_input_simulate_action,godot_input_play_sequencegodot_input_get_stats,godot_input_record,godot_input_stop_recording
godot_testing_assert_node_state,godot_testing_run_test_scenario,godot_testing_run_stress_test,godot_testing_compare_screenshots
godot_profiling_get_editor_performance— editor process monitorsgodot_profiling_get_performance_monitors— live game monitors (via probe)
godot_batch_find_nodes_by_type,godot_batch_set_property,godot_batch_cross_scene_set_property,godot_batch_get_dependencies
godot_analysis_find_unused_resources,godot_analysis_analyze_signal_flow,godot_analysis_detect_circular_dependencies,godot_analysis_project_stats,godot_analysis_project_structure
godot_export_list_presets,godot_export_get_info,godot_export_project
godot_input_map_add_action,godot_input_map_remove_action(destructive),godot_input_map_add_event,godot_input_map_clear_action_events(destructive),godot_input_map_get_action_events(read_only)
godot_visual_shader_create,godot_visual_shader_add_node,godot_visual_shader_connect_nodes,godot_visual_shader_set_node_paramgodot_visual_shader_list_node_types,godot_visual_shader_read— node-graph introspection
- Breakpoints:
godot_debugger_set_breakpoint,godot_debugger_remove_breakpoint,godot_debugger_clear_breakpoints - Execution:
godot_debugger_force_break,godot_debugger_continue_execution,godot_debugger_step_into,godot_debugger_step_over,godot_debugger_step_out - Inspect paused state:
godot_debugger_get_stack_frames,godot_debugger_get_frame_variables,godot_debugger_evaluate_expression
godot_asset_import_asset,godot_asset_import_get_status— import external assets and poll statusgodot_asset_import_create_material_from_textures— build aStandardMaterial3Dfrom texture maps
godot_project_scaffold— generate a new project skeleton (directories,project.godot, starter scenes); destructive, needsconfirm
godot_composite_compose_node,godot_composite_batch_create_nodes,godot_composite_apply_node_edits,godot_composite_run_commands— one-call macros that fold several mutations into a single undo-tracked operation
Read-only snapshots refreshed on access:
godot://project/info— project infogodot://scene/current— active scenegodot://scene/tree— full scene treegodot://scene/tree/{max_depth}— tree limited to N levelsgodot://node/selected— selected node snapshot
All configuration is optional and passed via environment variables:
| Variable | Default | Description |
|---|---|---|
GODOT_MCP_TRANSPORT |
stdio |
stdio or http |
GODOT_MCP_HTTP_HOST |
127.0.0.1 |
HTTP bind host |
GODOT_MCP_HTTP_PORT |
9090 |
HTTP bind port |
GODOT_MCP_BRIDGE_URL |
ws://127.0.0.1:9080 |
Bridge endpoint — the server binds it (listener) and the addon connects to it; set the same value on both sides |
GODOT_MCP_GODOT_BIN |
auto-discovered | Godot executable for godot_runtime_run_and_capture / godot_export_project |
GODOT_MCP_PROJECT_DIR |
connected editor's project | Project directory for runner, export, and analysis |
GODOT_MCP_LOG_LEVEL |
INFO |
Log level (DEBUG, INFO, WARNING, ERROR) — JSON to stderr |
GODOT_MCP_APPROVAL_WEBHOOK |
unset | Optional human-in-the-loop approval webhook for destructive tools (ApprovalGate) |
- Ensure Godot is running with the godot_mcp addon enabled (status dock visible). The addon connects out to the server and reconnects automatically, so start order doesn't matter — give it a moment after either side starts.
- Check that nothing else is using port
9080(the server binds it; the addon dials in). - Check the Godot Output panel for WebSocket errors, and confirm both sides agree on
GODOT_MCP_BRIDGE_URLif you changed it.
- Upgrade to Godot 4.4 or newer. The addon checks version on enable.
- Open a
.tscnscene in the Godot editor before calling scene editing tools.
- Destructive tools (
godot_scene_edit_delete_node,godot_scene_edit_reload_scene, etc.) needconfirm=True. - Or use
dry_run=Trueto preview.
- Call
play_scene()before using live runtime/input/profiling tools.
- Add
addons/godot_mcp/mcp_runtime_probe.gdas an autoload in your game project.
- Set
GODOT_MCP_GODOT_BINto the full path, or ensuregodotis in yourPATH.
- The editor must have a display (not
--headless). The addon captures the viewport.
- Ensure export templates are installed for the target platform in Godot.
godot/
project.godot # minimal Godot project (addon is loadable here)
addons/godot_mcp/
plugin.cfg # addon manifest (name, version, Godot 4.4+)
godot_mcp.gd # EditorPlugin entry: dock, bridge, debugger
mcp_bridge.gd # WebSocketPeer client — connects out, reconnects, receives envelopes
command_router.gd # dispatches cmd_* → Godot API handlers
mcp_dock.gd # read-only status dock
scene_inspect.gd # JSON-safe scene tree / node serialization
type_coerce.gd # Godot ↔ JSON type coercion
mcp_debugger.gd # EditorDebuggerPlugin (captures godot_mcp channel)
mcp_runtime_probe.gd # game-side autoload for live runtime tools
mcp_server/ # FastMCP server (Python 3.11+)
main.py # stdio / Streamable-HTTP entrypoint
server.py # server factory: bridge + all tool registrations
bridge.py # async WebSocket listener (id correlation, timeout; the addon dials in)
toolsets.py # gated toolset system
categories.py # toolset tag constants
safety.py # safety classes, preconditions, dry_run/confirm
runtime.py # headless run / export subprocess
qa.py # screenshot diff, assertion evaluation
analysis.py # static analysis (unused resources, circular deps, stats)
tools/ # @mcp.tool() handlers (thin delegation)
resources/ # godot://… read-only resource handlers
models/ # Pydantic typed I/O models
prompts/ # @mcp.prompt() workflow recipes (slash commands)
skills/ # optional Claude skills (auto-trigger) — see skills/README.md
tests/
contract/ # envelope shapes + tool schemas (fake bridge)
integration/ # live headless-editor e2e (skipped if no Godot)
unit/ # isolated logic tests
docs/
architecture.md # bridge contract, JSON envelope, type coercion
tool-contracts.md # full per-tool spec
We follow an issue-driven workflow. Read CLAUDE.md and the path-scoped rules in .claude/rules/ before writing code.
The pipeline:
- Issue — open a GitHub issue describing the bug or feature
- Failing test — write a test that pins the desired behavior
- Green code — implement the minimum change to make the test pass
- Preflight — run the full suite, ruff, and mypy; confirm zero skips
- PR — open a PR with
closes #Nin the description - Merge — squash merge after review
Key rules:
- Tests come before implementation.
- The suite carries zero skips (no
@pytest.mark.skip, noxfail). - Safety logic lives in the server only (
mcp_server/safety.py), never in the addon. - The addon is the only layer that touches Godot.
- All errors are structured — never a Python traceback to the agent.
- Every mutation in the addon registers with
EditorUndoRedoManager. - Godot types are coerced in
type_coerce.gd, never inline.
MIT — see the LICENSE file for the full text.
- Model Context Protocol spec
- FastMCP docs
- Godot 4.4 docs
- Project issues
docs/tool-contracts.md— the authoritative per-tool referencedocs/architecture.md— the bridge and envelope contract