{
  "type": "guide",
  "id": "drive-a-headless-godot-editor-over-mcp",
  "title": "Drive a headless Godot editor over MCP",
  "summary": "Run a Godot 4.7 editor with no display on a Linux box or CI runner and let a coding agent edit scenes and scripts through Beckett, Godot Editor MCP or Godot AI. Includes tested commands, a stdlib Python probe, and the security checks we ran.",
  "author": "Agentica Author",
  "tags": [
    "godot",
    "game-engine",
    "gamedev",
    "mcp",
    "headless",
    "ci",
    "testing",
    "editor-automation"
  ],
  "published": "2026-10-31",
  "last_verified": "2026-10-31",
  "difficulty": "intermediate",
  "time_estimate": "40 min",
  "entries": [
    "godot-engine",
    "beckett-godot-mcp",
    "godot-editor-mcp",
    "godot-ai",
    "model-context-protocol",
    "claude-code",
    "cursor"
  ],
  "links": {
    "html": "https://indexagentica.com/guides/drive-a-headless-godot-editor-over-mcp/",
    "markdown": "https://indexagentica.com/guides/drive-a-headless-godot-editor-over-mcp.md",
    "json": "https://indexagentica.com/api/longform/guides/drive-a-headless-godot-editor-over-mcp.json",
    "source": "https://github.com/Drudley/indexagentica/blob/main/content-long/guides/drive-a-headless-godot-editor-over-mcp.md"
  },
  "status": "published",
  "prerequisites": [
    "A Linux x86_64 machine (no display needed)",
    "Python 3.11+ for Godot Editor MCP and for the probe script",
    "uv, for Godot AI",
    "An MCP client, or the probe script below"
  ],
  "entries_detail": [
    {
      "id": "godot-engine",
      "name": "Godot Engine",
      "summary": "Free, open-source, multi-platform 2D and 3D game engine, scripted in GDScript or C#. Several community MCP servers let agents drive its editor.",
      "url": "https://indexagentica.com/entries/godot-engine/",
      "json": "https://indexagentica.com/api/entries/godot-engine.json"
    },
    {
      "id": "beckett-godot-mcp",
      "name": "Beckett (Godot MCP)",
      "summary": "Zero-sidecar MCP server that runs inside the Godot 4 editor as a GDScript plugin, letting agents inspect, author, run and screenshot a game in GDScript or C#.",
      "url": "https://indexagentica.com/entries/beckett-godot-mcp/",
      "json": "https://indexagentica.com/api/entries/beckett-godot-mcp.json"
    },
    {
      "id": "godot-editor-mcp",
      "name": "Godot Editor MCP (hybridindie/godot-mcp)",
      "summary": "Game-agnostic MCP server plus a Godot add-on that drives a live editor: inspect, edit scenes and scripts, run, simulate input, screenshot, profile and export.",
      "url": "https://indexagentica.com/entries/godot-editor-mcp/",
      "json": "https://indexagentica.com/api/entries/godot-editor-mcp.json"
    },
    {
      "id": "godot-ai",
      "name": "Godot AI",
      "summary": "Godot editor add-on plus a Python MCP server that connects Claude Code, Codex, Cursor and other clients to a live Godot editor through 46 tools.",
      "url": "https://indexagentica.com/entries/godot-ai/",
      "json": "https://indexagentica.com/api/entries/godot-ai.json"
    },
    {
      "id": "model-context-protocol",
      "name": "Model Context Protocol (MCP)",
      "summary": "Open protocol that standardizes how AI applications connect to external tools, data sources and prompts via MCP servers.",
      "url": "https://indexagentica.com/entries/model-context-protocol/",
      "json": "https://indexagentica.com/api/entries/model-context-protocol.json"
    },
    {
      "id": "claude-code",
      "name": "Claude Code",
      "summary": "Anthropic's agentic coding tool that reads your codebase, edits files, runs commands and integrates with dev tools; available in terminal, IDE, desktop and browser.",
      "url": "https://indexagentica.com/entries/claude-code/",
      "json": "https://indexagentica.com/api/entries/claude-code.json"
    },
    {
      "id": "cursor",
      "name": "Cursor",
      "summary": "AI code editor and coding agent with Agent mode, Rules, Skills, MCP servers and a CLI.",
      "url": "https://indexagentica.com/entries/cursor/",
      "json": "https://indexagentica.com/api/entries/cursor.json"
    }
  ],
  "related": [
    {
      "type": "comparison",
      "id": "game-engine-agent-tooling",
      "title": "Game engine agent tooling compared: Unreal, Unity, Godot, Roblox and Bevy",
      "url": "https://indexagentica.com/compare/game-engine-agent-tooling/",
      "json": "https://indexagentica.com/api/longform/compare/game-engine-agent-tooling.json"
    },
    {
      "type": "guide",
      "id": "test-your-mcp-server",
      "title": "Test your MCP server with in-process tests and Inspector CI checks",
      "url": "https://indexagentica.com/guides/test-your-mcp-server/",
      "json": "https://indexagentica.com/api/longform/guides/test-your-mcp-server.json"
    },
    {
      "type": "guide",
      "id": "add-mcp-servers-to-claude-code",
      "title": "Add MCP servers to Claude Code",
      "url": "https://indexagentica.com/guides/add-mcp-servers-to-claude-code/",
      "json": "https://indexagentica.com/api/longform/guides/add-mcp-servers-to-claude-code.json"
    },
    {
      "type": "guide",
      "id": "bridge-stdio-and-remote-mcp-servers",
      "title": "Bridge stdio and remote MCP servers: mcp-remote, Supergateway, mcp-proxy and mcpo",
      "url": "https://indexagentica.com/guides/bridge-stdio-and-remote-mcp-servers/",
      "json": "https://indexagentica.com/api/longform/guides/bridge-stdio-and-remote-mcp-servers.json"
    }
  ],
  "sources": [
    {
      "title": "Godot 4.7.2-stable release assets",
      "url": "https://github.com/godotengine/godot/releases/tag/4.7.2-stable",
      "accessed": "2026-10-31"
    },
    {
      "title": "beckettlab/beckett-godot-mcp README",
      "url": "https://github.com/beckettlab/beckett-godot-mcp",
      "accessed": "2026-10-31"
    },
    {
      "title": "Beckett v1.16.0 release",
      "url": "https://github.com/beckettlab/beckett-godot-mcp/releases/tag/v1.16.0",
      "accessed": "2026-10-31"
    },
    {
      "title": "hybridindie/godot-mcp README (Godot Editor MCP)",
      "url": "https://github.com/hybridindie/godot-mcp",
      "accessed": "2026-10-31"
    },
    {
      "title": "Godot Editor MCP environment variable reference",
      "url": "https://github.com/hybridindie/godot-mcp/blob/main/docs/site/reference-env-vars.md",
      "accessed": "2026-10-31"
    },
    {
      "title": "PyPI: godot-editor-mcp",
      "url": "https://pypi.org/project/godot-editor-mcp/",
      "accessed": "2026-10-31"
    },
    {
      "title": "hi-godot/godot-ai README",
      "url": "https://github.com/hi-godot/godot-ai",
      "accessed": "2026-10-31"
    },
    {
      "title": "Godot AI v4.3.1 release",
      "url": "https://github.com/hi-godot/godot-ai/releases/tag/v4.3.1",
      "accessed": "2026-10-31"
    },
    {
      "title": "Godot AI server lifecycle",
      "url": "https://github.com/hi-godot/godot-ai/blob/main/docs/server-lifecycle.md",
      "accessed": "2026-10-31"
    },
    {
      "title": "MCP specification: Streamable HTTP transport",
      "url": "https://modelcontextprotocol.io/specification/2025-06-18/basic/transports",
      "accessed": "2026-10-31"
    }
  ],
  "front_matter": {
    "id": "drive-a-headless-godot-editor-over-mcp",
    "type": "guide",
    "title": "Drive a headless Godot editor over MCP",
    "summary": "Run a Godot 4.7 editor with no display on a Linux box or CI runner and let a coding agent edit scenes and scripts through Beckett, Godot Editor MCP or Godot AI. Includes tested commands, a stdlib Python probe, and the security checks we ran.",
    "description": "Coding agents often run on machines with no screen: a CI runner, a container or a remote dev box. Godot's editor runs headless, and its MCP plugins mostly keep working. This guide installs Godot 4.7.2 on Linux, then connects three community MCP servers (Beckett, Godot Editor MCP and Godot AI) to a headless editor. For each one it gives the exact setup, the tool calls we made to create a node, write or attach a script and save the scene, what landed on disk, and how the server reacted to missing tokens and foreign Host or Origin headers. It also covers the settings that differ in headless mode and what not to commit.",
    "author": "Agentica Author",
    "difficulty": "intermediate",
    "time_estimate": "40 min",
    "prerequisites": [
      "A Linux x86_64 machine (no display needed)",
      "Python 3.11+ for Godot Editor MCP and for the probe script",
      "uv, for Godot AI",
      "An MCP client, or the probe script below"
    ],
    "tags": [
      "godot",
      "game-engine",
      "gamedev",
      "mcp",
      "headless",
      "ci",
      "testing",
      "editor-automation"
    ],
    "entries": [
      "godot-engine",
      "beckett-godot-mcp",
      "godot-editor-mcp",
      "godot-ai",
      "model-context-protocol",
      "claude-code",
      "cursor"
    ],
    "related": [
      "game-engine-agent-tooling",
      "test-your-mcp-server",
      "add-mcp-servers-to-claude-code",
      "bridge-stdio-and-remote-mcp-servers"
    ],
    "sources": [
      {
        "title": "Godot 4.7.2-stable release assets",
        "url": "https://github.com/godotengine/godot/releases/tag/4.7.2-stable",
        "accessed": "2026-10-31"
      },
      {
        "title": "beckettlab/beckett-godot-mcp README",
        "url": "https://github.com/beckettlab/beckett-godot-mcp",
        "accessed": "2026-10-31"
      },
      {
        "title": "Beckett v1.16.0 release",
        "url": "https://github.com/beckettlab/beckett-godot-mcp/releases/tag/v1.16.0",
        "accessed": "2026-10-31"
      },
      {
        "title": "hybridindie/godot-mcp README (Godot Editor MCP)",
        "url": "https://github.com/hybridindie/godot-mcp",
        "accessed": "2026-10-31"
      },
      {
        "title": "Godot Editor MCP environment variable reference",
        "url": "https://github.com/hybridindie/godot-mcp/blob/main/docs/site/reference-env-vars.md",
        "accessed": "2026-10-31"
      },
      {
        "title": "PyPI: godot-editor-mcp",
        "url": "https://pypi.org/project/godot-editor-mcp/",
        "accessed": "2026-10-31"
      },
      {
        "title": "hi-godot/godot-ai README",
        "url": "https://github.com/hi-godot/godot-ai",
        "accessed": "2026-10-31"
      },
      {
        "title": "Godot AI v4.3.1 release",
        "url": "https://github.com/hi-godot/godot-ai/releases/tag/v4.3.1",
        "accessed": "2026-10-31"
      },
      {
        "title": "Godot AI server lifecycle",
        "url": "https://github.com/hi-godot/godot-ai/blob/main/docs/server-lifecycle.md",
        "accessed": "2026-10-31"
      },
      {
        "title": "MCP specification: Streamable HTTP transport",
        "url": "https://modelcontextprotocol.io/specification/2025-06-18/basic/transports",
        "accessed": "2026-10-31"
      }
    ],
    "last_verified": "2026-10-31",
    "published": "2026-10-31"
  },
  "markdown": "\nA coding agent on a CI runner or a remote box has no screen, but Godot's editor does not need one. Start it with `--headless --editor` and its editor plugins still load, so an MCP server inside or beside the editor can open scenes, add nodes and write scripts. This guide sets that up with the three active community servers compared in [Game engine agent tooling compared](https://indexagentica.com/compare/game-engine-agent-tooling/): [Beckett](https://indexagentica.com/entries/beckett-godot-mcp/), [Godot Editor MCP](https://indexagentica.com/entries/godot-editor-mcp/) and [Godot AI](https://indexagentica.com/entries/godot-ai/).\n\nEverything below was run on 2026-10-31 on a Linux x86_64 box with no display, using Godot 4.7.2-stable, Beckett Lite 1.16.0, Godot Editor MCP 2026.10.20.1 and Godot AI 4.3.1.\n\n## 1. Install Godot and make a project\n\nDownload the official Linux build and check it against the release's SHA512 list:\n\n```bash\nmkdir -p ~/godot && cd ~/godot\ncurl -LO https://github.com/godotengine/godot/releases/download/4.7.2-stable/Godot_v4.7.2-stable_linux.x86_64.zip\ncurl -LO https://github.com/godotengine/godot/releases/download/4.7.2-stable/SHA512-SUMS.txt\ngrep 'Godot_v4.7.2-stable_linux.x86_64.zip' SHA512-SUMS.txt | sha512sum -c -\nunzip -q Godot_v4.7.2-stable_linux.x86_64.zip\nln -sf \"$PWD/Godot_v4.7.2-stable_linux.x86_64\" ~/godot/godot\n```\n\nEach server below gets its own small project. A project only needs `project.godot`, so you can create one without the project manager. The `[editor_plugins]` section is what the Plugins tab writes when you tick a plugin:\n\n```bash\nmkdir demo && cd demo\ncat > project.godot <<'CFG'\nconfig_version=5\n\n[application]\nconfig/name=\"demo\"\nconfig/features=PackedStringArray(\"4.7\")\n\n[editor_plugins]\nenabled=PackedStringArray(\"res://addons/PLUGIN/plugin.cfg\")\nCFG\nprintf '[gd_scene format=3]\\n\\n[node name=\"Main\" type=\"Node2D\"]\\n' > main.tscn\n```\n\nReplace `PLUGIN` with the addon folder: `beckett`, `godot_mcp` or `godot_ai`. Then start the editor in the background:\n\n```bash\n~/godot/godot --headless --editor --path . > editor.log 2>&1 &\n```\n\n## 2. A probe to drive any server\n\nMost clients can connect to these servers, but a small script gives you the same check in CI with no client installed. This one uses only the Python standard library. It speaks Streamable HTTP, handles both JSON and SSE replies, keeps the `Mcp-Session-Id`, lists the tools, then runs the calls you pass as `name={json}`:\n\n```python\n# mcp_probe.py: initialize, list tools, then call tools in one session\nimport json, sys, urllib.request, urllib.error\n\ndef rpc(url, method, params=None, id_=1, sid=None):\n    body = {\"jsonrpc\": \"2.0\", \"method\": method}\n    if id_ is not None:\n        body[\"id\"] = id_\n    if params is not None:\n        body[\"params\"] = params\n    h = {\"Content-Type\": \"application/json\", \"Accept\": \"application/json, text/event-stream\"}\n    if sid:\n        h[\"Mcp-Session-Id\"] = sid\n    req = urllib.request.Request(url, json.dumps(body).encode(), h)\n    try:\n        with urllib.request.urlopen(req, timeout=30) as r:\n            raw, sid, status = r.read().decode(), r.headers.get(\"Mcp-Session-Id\") or sid, r.status\n    except urllib.error.HTTPError as e:\n        return e.code, e.read().decode()[:200], sid\n    if raw.startswith((\"event:\", \"data:\")):\n        msgs = [json.loads(l[5:]) for l in raw.splitlines() if l.startswith(\"data:\") and l[5:].strip()]\n        match = [m for m in msgs if m.get(\"id\") == id_]\n        return status, (match or msgs or [None])[0], sid\n    return status, (json.loads(raw) if raw.strip() else None), sid\n\nurl = sys.argv[1]\nst, res, sid = rpc(url, \"initialize\", {\"protocolVersion\": \"2025-06-18\", \"capabilities\": {},\n                   \"clientInfo\": {\"name\": \"probe\", \"version\": \"0\"}})\nprint(\"initialize\", st, res if isinstance(res, str) else res[\"result\"][\"serverInfo\"])\nif st != 200:\n    sys.exit(1)\nrpc(url, \"notifications/initialized\", id_=None, sid=sid)\nst, res, sid = rpc(url, \"tools/list\", {}, 2, sid)\nprint(\"tools\", len(res[\"result\"][\"tools\"]))\nfor i, call in enumerate(sys.argv[2:], start=10):\n    name, _, args = call.partition(\"=\")\n    st, res, sid = rpc(url, \"tools/call\", {\"name\": name, \"arguments\": json.loads(args or \"{}\")}, i, sid)\n    print(name, json.dumps(res[\"result\"][\"content\"])[:300])\n```\n\nFor Godot AI, whose clients connect over stdio, the same loop works over a subprocess's stdin and stdout: write one JSON-RPC message per line and read lines until the reply with your `id` arrives.\n\n## 3. Beckett: a server inside the editor\n\nBeckett's free Lite edition is a pure GDScript plugin: the editor itself serves MCP, with no Python or Node process. Unzip the release into the project so it lands in `addons/beckett/`, set `PLUGIN` to `beckett`, and start the editor:\n\n```bash\ncurl -LO https://github.com/beckettlab/beckett-godot-mcp/releases/download/v1.16.0/beckett-godot-mcp-lite-v1.16.0.zip\nunzip -q beckett-godot-mcp-lite-v1.16.0.zip     # creates addons/beckett/\n~/godot/godot --headless --editor --path . > editor.log 2>&1 &\n```\n\nWithin about 20 seconds the plugin had started on `127.0.0.1:8770` and written three things to the project:\n\n- `.mcp.json` and `.cursor/mcp.json`, each with an `http` server whose URL is `http://127.0.0.1:8770/mcp/<token>`. The 32-hex-character token is part of the path.\n- `.beckett/port` and `.beckett/token`.\n- A `BeckettRuntime` autoload in `project.godot`.\n\nThe server reported itself as `beckett-godot-mcp` 1.16.0, advertised tools, resources and prompts, and listed 56 tools. This sequence built a scene:\n\n```bash\nTOKEN=$(cat .beckett/token)\npython3 mcp_probe.py \"http://127.0.0.1:8770/mcp/$TOKEN\" \\\n  'open_scene={\"path\":\"res://main.tscn\"}' \\\n  'create_node={\"type\":\"Sprite2D\",\"name\":\"Player\"}' \\\n  'write_script={\"path\":\"res://player.gd\",\"content\":\"extends Sprite2D\\nfunc _ready(:\\n\\tpass\\n\"}' \\\n  'write_script={\"path\":\"res://player.gd\",\"content\":\"extends Sprite2D\\n\\nfunc _ready():\\n\\tprint(\\\"ready\\\")\\n\"}' \\\n  'attach_script={\"target\":\"Player\",\"path\":\"res://player.gd\"}' \\\n  'save_scene={}'\n```\n\nThe first `write_script` has a syntax error on purpose. Beckett refused it with \"Refusing to write: script does not compile\", plus the engine's parse error, and wrote nothing. The second one returned `disk_verified: true`. After `save_scene`, `main.tscn` on disk had a `Player` Sprite2D with `player.gd` attached as an external resource. In headless mode, `save_scene` also reported an engine error from the dummy renderer's texture storage. The save still succeeded, so that error can be ignored.\n\nSecurity checks against the same server:\n\n| Request | Result |\n|---|---|\n| `POST /mcp` without the token in the path | 401 |\n| Correct URL, `Origin: http://evil.example` | 403 |\n| Correct URL, `Host: attacker.example:8770` | 403 |\n| Listening sockets | 127.0.0.1 only |\n\nFor a shared or CI machine, the README documents `BECKETT_READONLY=1` (inspection only), `BECKETT_ALLOWLIST` (limit the tools) and `BECKETT_CONFIRM_DESTRUCTIVE=1`, as well as `BECKETT_PORT` and `BECKETT_TOKEN`.\n\n## 4. Godot Editor MCP: a Python server the editor dials into\n\nGodot Editor MCP splits the work. A Python server talks MCP to the client, and an editor addon connects out to that server over a WebSocket on `127.0.0.1:9080`. Install the server, unzip the addon from the matching GitHub release, set `PLUGIN` to `godot_mcp`, and give both processes the same bridge token. The token is optional, but without it any local process could pose as the editor:\n\n```bash\npython3 -m venv .venv && .venv/bin/pip install godot-editor-mcp==2026.10.20.1\ncurl -LO https://github.com/hybridindie/godot-mcp/releases/download/2026.10.20.1/godot_mcp_addon.zip\nunzip -q godot_mcp_addon.zip                     # creates addons/godot_mcp/\nexport GODOT_MCP_BRIDGE_TOKEN=$(python3 -c 'import secrets; print(secrets.token_hex(16))')\nGODOT_MCP_TRANSPORT=http .venv/bin/godot-editor-mcp > server.log 2>&1 &\n~/godot/godot --headless --editor --path . > editor.log 2>&1 &\n```\n\nThe server log showed the bridge on `127.0.0.1:9080`, MCP on `http://127.0.0.1:9090/mcp`, and then \"bridge peer authenticated\" when the editor connected. For a desktop client, use stdio, which is the default transport, and let `godot-editor-mcp config --client <client> --write` write the client config. `godot-editor-mcp doctor --project <path>` checks a setup.\n\nOnly the core and inspection toolsets are on at first, so `tools/list` returned 24 tools. The agent enables more as it needs them:\n\n```bash\npython3 mcp_probe.py http://127.0.0.1:9090/mcp \\\n  'godot_enable_toolset={\"category\":\"scene_edit\"}' \\\n  'godot_scene_edit_open_scene={\"scene_path\":\"res://main.tscn\"}' \\\n  'godot_scene_edit_create_node={\"parent_path\":\".\",\"node_type\":\"Camera2D\",\"node_name\":\"Cam\",\"dry_run\":true}' \\\n  'godot_scene_edit_create_node={\"parent_path\":\".\",\"node_type\":\"Camera2D\",\"node_name\":\"Cam\"}' \\\n  'godot_scene_edit_save_scene={}'\n```\n\nAfter `scene_edit` was enabled, the list grew to 48 tools. The setting also persisted for a new session against the same server. The dry run returned `created: false`, the real call returned `created: true`, and the saved `main.tscn` contained the `Cam` Camera2D. With the default `GODOT_MCP_HTTP_HOST_ORIGIN_PROTECTION=auto`, a foreign `Host` header got 421 and a foreign `Origin` got 403. If you bind HTTP to a non-loopback address, the server refuses to start unless `GODOT_MCP_AUTH_TOKEN` is set.\n\nOne gotcha: `godot-editor-mcp --help` does not print help. It starts the server.\n\n## 5. Godot AI: set the headless opt-in\n\nGodot AI's plugin starts a Python server (through `uvx`) with authenticated HTTP on port 8000 and an authenticated WebSocket on port 9500. Clients connect through `godot-ai attach` over stdio. Unzip the release's `godot-ai-v4-plugin.zip` (it creates `addons/godot_ai/`) and set `PLUGIN` to `godot_ai`.\n\nStarted headless like the others, the editor log said `MCP | plugin disabled in headless mode` and nothing listened. The README's section on headless editors says normal headless launches skip the server, and to set `GODOT_AI_ALLOW_HEADLESS=1` only for intentional CI or editor sessions:\n\n```bash\ncurl -LO https://github.com/hi-godot/godot-ai/releases/download/v4.3.1/godot-ai-v4-plugin.zip\nunzip -q godot-ai-v4-plugin.zip                  # creates addons/godot_ai/\nGODOT_AI_ALLOW_HEADLESS=1 GODOT_AI_DISABLE_TELEMETRY=true \\\n  ~/godot/godot --headless --editor --path . > editor.log 2>&1 &\n```\n\nWith the variable set, the plugin started `godot-ai==4.3.1` with `--transport streamable-http --port 8000 --ws-port 9500`, connected and authenticated. Both ports listened on 127.0.0.1 only. It also added a `_mcp_game_helper` autoload to `project.godot`. `GODOT_AI_DISABLE_TELEMETRY=true` opts out of the anonymous telemetry that Godot AI otherwise sends.\n\nA bare `POST http://127.0.0.1:8000/mcp` got 401 with `TRANSPORT_AUTH_REQUIRED`, as the README warns. Through `attach`, which handles the authentication, a stdio session listed 47 tools and ran this sequence:\n\n```text\ncommand: uvx --from godot-ai==4.3.1 godot-ai attach --disable-telemetry\neditor_state         -> godot_version \"4.7.2-stable (official)\"\nscene_open           {\"path\": \"res://main.tscn\"}\nnode_create          {\"type\": \"Label\", \"name\": \"Hello\"}   -> path /Main/Hello, undoable true\nscene_save           {}                                   -> res://main.tscn\nscene_get_hierarchy  {}                                   -> Main (Node2D), Hello (Label)\n```\n\n`main.tscn` on disk then held the `Hello` Label. When we killed the editor, the plugin-started server was gone within 8 seconds, so you do not need to clean it up yourself.\n\n## 6. Use it from an agent\n\nOn a headless box, point the agent's MCP config at the same endpoints. For Claude Code (see [Add MCP servers to Claude Code](https://indexagentica.com/guides/add-mcp-servers-to-claude-code/)), Beckett's generated `.mcp.json` in the project root is picked up as a project-scoped server. For the others:\n\n```bash\nclaude mcp add --transport http godot-editor http://127.0.0.1:9090/mcp\nclaude mcp add godot-ai -- uvx --from godot-ai==4.3.1 godot-ai attach --disable-telemetry\n```\n\nStart the editor before the agent session, and in CI wait for the port (`8770`, `9090` or `8000`) to accept connections before the first call. All three need a running editor with the plugin loaded; Beckett and Godot AI have nothing to serve before that.\n\n## 7. Keep it safe\n\n- **Don't commit what the plugins generate.** Beckett's `.mcp.json`, `.cursor/mcp.json` and `.beckett/` hold the project token. Add them to `.gitignore` unless every collaborator should share that token.\n- **Review the autoloads.** Beckett and Godot AI both added an autoload to `project.godot`. Decide whether you want those runtime helpers in exported builds before you ship.\n- **Stay on loopback.** All three bound to 127.0.0.1 by default. If a container or VM boundary forces a non-loopback bind, set Godot Editor MCP's `GODOT_MCP_AUTH_TOKEN` and keep the port off public networks.\n- **Treat these tools as code execution.** Writing and attaching scripts and running the project all execute code as the user who runs the editor. On a CI runner, give that user nothing it doesn't need.\n- **Re-run the probe on upgrades.** The 401, 403 and 421 checks above are a quick regression test. [Test your MCP server](https://indexagentica.com/guides/test-your-mcp-server/) covers deeper checks.\n",
  "raw": "---\nid: drive-a-headless-godot-editor-over-mcp\ntype: guide\ntitle: Drive a headless Godot editor over MCP\nsummary: \"Run a Godot 4.7 editor with no display on a Linux box or CI runner and let a coding agent edit scenes and scripts through Beckett, Godot Editor MCP or Godot AI. Includes tested commands, a stdlib Python probe, and the security checks we ran.\"\ndescription: \"Coding agents often run on machines with no screen: a CI runner, a container or a remote dev box. Godot's editor runs headless, and its MCP plugins mostly keep working. This guide installs Godot 4.7.2 on Linux, then connects three community MCP servers (Beckett, Godot Editor MCP and Godot AI) to a headless editor. For each one it gives the exact setup, the tool calls we made to create a node, write or attach a script and save the scene, what landed on disk, and how the server reacted to missing tokens and foreign Host or Origin headers. It also covers the settings that differ in headless mode and what not to commit.\"\nauthor: Agentica Author\ndifficulty: intermediate\ntime_estimate: 40 min\nprerequisites:\n  - A Linux x86_64 machine (no display needed)\n  - Python 3.11+ for Godot Editor MCP and for the probe script\n  - uv, for Godot AI\n  - An MCP client, or the probe script below\ntags: [godot, game-engine, gamedev, mcp, headless, ci, testing, editor-automation]\nentries: [godot-engine, beckett-godot-mcp, godot-editor-mcp, godot-ai, model-context-protocol, claude-code, cursor]\nrelated: [game-engine-agent-tooling, test-your-mcp-server, add-mcp-servers-to-claude-code, bridge-stdio-and-remote-mcp-servers]\nsources:\n  - title: Godot 4.7.2-stable release assets\n    url: https://github.com/godotengine/godot/releases/tag/4.7.2-stable\n    accessed: 2026-10-31\n  - title: beckettlab/beckett-godot-mcp README\n    url: https://github.com/beckettlab/beckett-godot-mcp\n    accessed: 2026-10-31\n  - title: Beckett v1.16.0 release\n    url: https://github.com/beckettlab/beckett-godot-mcp/releases/tag/v1.16.0\n    accessed: 2026-10-31\n  - title: hybridindie/godot-mcp README (Godot Editor MCP)\n    url: https://github.com/hybridindie/godot-mcp\n    accessed: 2026-10-31\n  - title: Godot Editor MCP environment variable reference\n    url: https://github.com/hybridindie/godot-mcp/blob/main/docs/site/reference-env-vars.md\n    accessed: 2026-10-31\n  - title: \"PyPI: godot-editor-mcp\"\n    url: https://pypi.org/project/godot-editor-mcp/\n    accessed: 2026-10-31\n  - title: hi-godot/godot-ai README\n    url: https://github.com/hi-godot/godot-ai\n    accessed: 2026-10-31\n  - title: Godot AI v4.3.1 release\n    url: https://github.com/hi-godot/godot-ai/releases/tag/v4.3.1\n    accessed: 2026-10-31\n  - title: Godot AI server lifecycle\n    url: https://github.com/hi-godot/godot-ai/blob/main/docs/server-lifecycle.md\n    accessed: 2026-10-31\n  - title: \"MCP specification: Streamable HTTP transport\"\n    url: https://modelcontextprotocol.io/specification/2025-06-18/basic/transports\n    accessed: 2026-10-31\nlast_verified: 2026-10-31\npublished: 2026-10-31\n---\n\nA coding agent on a CI runner or a remote box has no screen, but Godot's editor does not need one. Start it with `--headless --editor` and its editor plugins still load, so an MCP server inside or beside the editor can open scenes, add nodes and write scripts. This guide sets that up with the three active community servers compared in [Game engine agent tooling compared](https://indexagentica.com/compare/game-engine-agent-tooling/): [Beckett](https://indexagentica.com/entries/beckett-godot-mcp/), [Godot Editor MCP](https://indexagentica.com/entries/godot-editor-mcp/) and [Godot AI](https://indexagentica.com/entries/godot-ai/).\n\nEverything below was run on 2026-10-31 on a Linux x86_64 box with no display, using Godot 4.7.2-stable, Beckett Lite 1.16.0, Godot Editor MCP 2026.10.20.1 and Godot AI 4.3.1.\n\n## 1. Install Godot and make a project\n\nDownload the official Linux build and check it against the release's SHA512 list:\n\n```bash\nmkdir -p ~/godot && cd ~/godot\ncurl -LO https://github.com/godotengine/godot/releases/download/4.7.2-stable/Godot_v4.7.2-stable_linux.x86_64.zip\ncurl -LO https://github.com/godotengine/godot/releases/download/4.7.2-stable/SHA512-SUMS.txt\ngrep 'Godot_v4.7.2-stable_linux.x86_64.zip' SHA512-SUMS.txt | sha512sum -c -\nunzip -q Godot_v4.7.2-stable_linux.x86_64.zip\nln -sf \"$PWD/Godot_v4.7.2-stable_linux.x86_64\" ~/godot/godot\n```\n\nEach server below gets its own small project. A project only needs `project.godot`, so you can create one without the project manager. The `[editor_plugins]` section is what the Plugins tab writes when you tick a plugin:\n\n```bash\nmkdir demo && cd demo\ncat > project.godot <<'CFG'\nconfig_version=5\n\n[application]\nconfig/name=\"demo\"\nconfig/features=PackedStringArray(\"4.7\")\n\n[editor_plugins]\nenabled=PackedStringArray(\"res://addons/PLUGIN/plugin.cfg\")\nCFG\nprintf '[gd_scene format=3]\\n\\n[node name=\"Main\" type=\"Node2D\"]\\n' > main.tscn\n```\n\nReplace `PLUGIN` with the addon folder: `beckett`, `godot_mcp` or `godot_ai`. Then start the editor in the background:\n\n```bash\n~/godot/godot --headless --editor --path . > editor.log 2>&1 &\n```\n\n## 2. A probe to drive any server\n\nMost clients can connect to these servers, but a small script gives you the same check in CI with no client installed. This one uses only the Python standard library. It speaks Streamable HTTP, handles both JSON and SSE replies, keeps the `Mcp-Session-Id`, lists the tools, then runs the calls you pass as `name={json}`:\n\n```python\n# mcp_probe.py: initialize, list tools, then call tools in one session\nimport json, sys, urllib.request, urllib.error\n\ndef rpc(url, method, params=None, id_=1, sid=None):\n    body = {\"jsonrpc\": \"2.0\", \"method\": method}\n    if id_ is not None:\n        body[\"id\"] = id_\n    if params is not None:\n        body[\"params\"] = params\n    h = {\"Content-Type\": \"application/json\", \"Accept\": \"application/json, text/event-stream\"}\n    if sid:\n        h[\"Mcp-Session-Id\"] = sid\n    req = urllib.request.Request(url, json.dumps(body).encode(), h)\n    try:\n        with urllib.request.urlopen(req, timeout=30) as r:\n            raw, sid, status = r.read().decode(), r.headers.get(\"Mcp-Session-Id\") or sid, r.status\n    except urllib.error.HTTPError as e:\n        return e.code, e.read().decode()[:200], sid\n    if raw.startswith((\"event:\", \"data:\")):\n        msgs = [json.loads(l[5:]) for l in raw.splitlines() if l.startswith(\"data:\") and l[5:].strip()]\n        match = [m for m in msgs if m.get(\"id\") == id_]\n        return status, (match or msgs or [None])[0], sid\n    return status, (json.loads(raw) if raw.strip() else None), sid\n\nurl = sys.argv[1]\nst, res, sid = rpc(url, \"initialize\", {\"protocolVersion\": \"2025-06-18\", \"capabilities\": {},\n                   \"clientInfo\": {\"name\": \"probe\", \"version\": \"0\"}})\nprint(\"initialize\", st, res if isinstance(res, str) else res[\"result\"][\"serverInfo\"])\nif st != 200:\n    sys.exit(1)\nrpc(url, \"notifications/initialized\", id_=None, sid=sid)\nst, res, sid = rpc(url, \"tools/list\", {}, 2, sid)\nprint(\"tools\", len(res[\"result\"][\"tools\"]))\nfor i, call in enumerate(sys.argv[2:], start=10):\n    name, _, args = call.partition(\"=\")\n    st, res, sid = rpc(url, \"tools/call\", {\"name\": name, \"arguments\": json.loads(args or \"{}\")}, i, sid)\n    print(name, json.dumps(res[\"result\"][\"content\"])[:300])\n```\n\nFor Godot AI, whose clients connect over stdio, the same loop works over a subprocess's stdin and stdout: write one JSON-RPC message per line and read lines until the reply with your `id` arrives.\n\n## 3. Beckett: a server inside the editor\n\nBeckett's free Lite edition is a pure GDScript plugin: the editor itself serves MCP, with no Python or Node process. Unzip the release into the project so it lands in `addons/beckett/`, set `PLUGIN` to `beckett`, and start the editor:\n\n```bash\ncurl -LO https://github.com/beckettlab/beckett-godot-mcp/releases/download/v1.16.0/beckett-godot-mcp-lite-v1.16.0.zip\nunzip -q beckett-godot-mcp-lite-v1.16.0.zip     # creates addons/beckett/\n~/godot/godot --headless --editor --path . > editor.log 2>&1 &\n```\n\nWithin about 20 seconds the plugin had started on `127.0.0.1:8770` and written three things to the project:\n\n- `.mcp.json` and `.cursor/mcp.json`, each with an `http` server whose URL is `http://127.0.0.1:8770/mcp/<token>`. The 32-hex-character token is part of the path.\n- `.beckett/port` and `.beckett/token`.\n- A `BeckettRuntime` autoload in `project.godot`.\n\nThe server reported itself as `beckett-godot-mcp` 1.16.0, advertised tools, resources and prompts, and listed 56 tools. This sequence built a scene:\n\n```bash\nTOKEN=$(cat .beckett/token)\npython3 mcp_probe.py \"http://127.0.0.1:8770/mcp/$TOKEN\" \\\n  'open_scene={\"path\":\"res://main.tscn\"}' \\\n  'create_node={\"type\":\"Sprite2D\",\"name\":\"Player\"}' \\\n  'write_script={\"path\":\"res://player.gd\",\"content\":\"extends Sprite2D\\nfunc _ready(:\\n\\tpass\\n\"}' \\\n  'write_script={\"path\":\"res://player.gd\",\"content\":\"extends Sprite2D\\n\\nfunc _ready():\\n\\tprint(\\\"ready\\\")\\n\"}' \\\n  'attach_script={\"target\":\"Player\",\"path\":\"res://player.gd\"}' \\\n  'save_scene={}'\n```\n\nThe first `write_script` has a syntax error on purpose. Beckett refused it with \"Refusing to write: script does not compile\", plus the engine's parse error, and wrote nothing. The second one returned `disk_verified: true`. After `save_scene`, `main.tscn` on disk had a `Player` Sprite2D with `player.gd` attached as an external resource. In headless mode, `save_scene` also reported an engine error from the dummy renderer's texture storage. The save still succeeded, so that error can be ignored.\n\nSecurity checks against the same server:\n\n| Request | Result |\n|---|---|\n| `POST /mcp` without the token in the path | 401 |\n| Correct URL, `Origin: http://evil.example` | 403 |\n| Correct URL, `Host: attacker.example:8770` | 403 |\n| Listening sockets | 127.0.0.1 only |\n\nFor a shared or CI machine, the README documents `BECKETT_READONLY=1` (inspection only), `BECKETT_ALLOWLIST` (limit the tools) and `BECKETT_CONFIRM_DESTRUCTIVE=1`, as well as `BECKETT_PORT` and `BECKETT_TOKEN`.\n\n## 4. Godot Editor MCP: a Python server the editor dials into\n\nGodot Editor MCP splits the work. A Python server talks MCP to the client, and an editor addon connects out to that server over a WebSocket on `127.0.0.1:9080`. Install the server, unzip the addon from the matching GitHub release, set `PLUGIN` to `godot_mcp`, and give both processes the same bridge token. The token is optional, but without it any local process could pose as the editor:\n\n```bash\npython3 -m venv .venv && .venv/bin/pip install godot-editor-mcp==2026.10.20.1\ncurl -LO https://github.com/hybridindie/godot-mcp/releases/download/2026.10.20.1/godot_mcp_addon.zip\nunzip -q godot_mcp_addon.zip                     # creates addons/godot_mcp/\nexport GODOT_MCP_BRIDGE_TOKEN=$(python3 -c 'import secrets; print(secrets.token_hex(16))')\nGODOT_MCP_TRANSPORT=http .venv/bin/godot-editor-mcp > server.log 2>&1 &\n~/godot/godot --headless --editor --path . > editor.log 2>&1 &\n```\n\nThe server log showed the bridge on `127.0.0.1:9080`, MCP on `http://127.0.0.1:9090/mcp`, and then \"bridge peer authenticated\" when the editor connected. For a desktop client, use stdio, which is the default transport, and let `godot-editor-mcp config --client <client> --write` write the client config. `godot-editor-mcp doctor --project <path>` checks a setup.\n\nOnly the core and inspection toolsets are on at first, so `tools/list` returned 24 tools. The agent enables more as it needs them:\n\n```bash\npython3 mcp_probe.py http://127.0.0.1:9090/mcp \\\n  'godot_enable_toolset={\"category\":\"scene_edit\"}' \\\n  'godot_scene_edit_open_scene={\"scene_path\":\"res://main.tscn\"}' \\\n  'godot_scene_edit_create_node={\"parent_path\":\".\",\"node_type\":\"Camera2D\",\"node_name\":\"Cam\",\"dry_run\":true}' \\\n  'godot_scene_edit_create_node={\"parent_path\":\".\",\"node_type\":\"Camera2D\",\"node_name\":\"Cam\"}' \\\n  'godot_scene_edit_save_scene={}'\n```\n\nAfter `scene_edit` was enabled, the list grew to 48 tools. The setting also persisted for a new session against the same server. The dry run returned `created: false`, the real call returned `created: true`, and the saved `main.tscn` contained the `Cam` Camera2D. With the default `GODOT_MCP_HTTP_HOST_ORIGIN_PROTECTION=auto`, a foreign `Host` header got 421 and a foreign `Origin` got 403. If you bind HTTP to a non-loopback address, the server refuses to start unless `GODOT_MCP_AUTH_TOKEN` is set.\n\nOne gotcha: `godot-editor-mcp --help` does not print help. It starts the server.\n\n## 5. Godot AI: set the headless opt-in\n\nGodot AI's plugin starts a Python server (through `uvx`) with authenticated HTTP on port 8000 and an authenticated WebSocket on port 9500. Clients connect through `godot-ai attach` over stdio. Unzip the release's `godot-ai-v4-plugin.zip` (it creates `addons/godot_ai/`) and set `PLUGIN` to `godot_ai`.\n\nStarted headless like the others, the editor log said `MCP | plugin disabled in headless mode` and nothing listened. The README's section on headless editors says normal headless launches skip the server, and to set `GODOT_AI_ALLOW_HEADLESS=1` only for intentional CI or editor sessions:\n\n```bash\ncurl -LO https://github.com/hi-godot/godot-ai/releases/download/v4.3.1/godot-ai-v4-plugin.zip\nunzip -q godot-ai-v4-plugin.zip                  # creates addons/godot_ai/\nGODOT_AI_ALLOW_HEADLESS=1 GODOT_AI_DISABLE_TELEMETRY=true \\\n  ~/godot/godot --headless --editor --path . > editor.log 2>&1 &\n```\n\nWith the variable set, the plugin started `godot-ai==4.3.1` with `--transport streamable-http --port 8000 --ws-port 9500`, connected and authenticated. Both ports listened on 127.0.0.1 only. It also added a `_mcp_game_helper` autoload to `project.godot`. `GODOT_AI_DISABLE_TELEMETRY=true` opts out of the anonymous telemetry that Godot AI otherwise sends.\n\nA bare `POST http://127.0.0.1:8000/mcp` got 401 with `TRANSPORT_AUTH_REQUIRED`, as the README warns. Through `attach`, which handles the authentication, a stdio session listed 47 tools and ran this sequence:\n\n```text\ncommand: uvx --from godot-ai==4.3.1 godot-ai attach --disable-telemetry\neditor_state         -> godot_version \"4.7.2-stable (official)\"\nscene_open           {\"path\": \"res://main.tscn\"}\nnode_create          {\"type\": \"Label\", \"name\": \"Hello\"}   -> path /Main/Hello, undoable true\nscene_save           {}                                   -> res://main.tscn\nscene_get_hierarchy  {}                                   -> Main (Node2D), Hello (Label)\n```\n\n`main.tscn` on disk then held the `Hello` Label. When we killed the editor, the plugin-started server was gone within 8 seconds, so you do not need to clean it up yourself.\n\n## 6. Use it from an agent\n\nOn a headless box, point the agent's MCP config at the same endpoints. For Claude Code (see [Add MCP servers to Claude Code](https://indexagentica.com/guides/add-mcp-servers-to-claude-code/)), Beckett's generated `.mcp.json` in the project root is picked up as a project-scoped server. For the others:\n\n```bash\nclaude mcp add --transport http godot-editor http://127.0.0.1:9090/mcp\nclaude mcp add godot-ai -- uvx --from godot-ai==4.3.1 godot-ai attach --disable-telemetry\n```\n\nStart the editor before the agent session, and in CI wait for the port (`8770`, `9090` or `8000`) to accept connections before the first call. All three need a running editor with the plugin loaded; Beckett and Godot AI have nothing to serve before that.\n\n## 7. Keep it safe\n\n- **Don't commit what the plugins generate.** Beckett's `.mcp.json`, `.cursor/mcp.json` and `.beckett/` hold the project token. Add them to `.gitignore` unless every collaborator should share that token.\n- **Review the autoloads.** Beckett and Godot AI both added an autoload to `project.godot`. Decide whether you want those runtime helpers in exported builds before you ship.\n- **Stay on loopback.** All three bound to 127.0.0.1 by default. If a container or VM boundary forces a non-loopback bind, set Godot Editor MCP's `GODOT_MCP_AUTH_TOKEN` and keep the port off public networks.\n- **Treat these tools as code execution.** Writing and attaching scripts and running the project all execute code as the user who runs the editor. On a CI runner, give that user nothing it doesn't need.\n- **Re-run the probe on upgrades.** The 401, 403 and 421 checks above are a quick regression test. [Test your MCP server](https://indexagentica.com/guides/test-your-mcp-server/) covers deeper checks.\n",
  "html": "<p>A coding agent on a CI runner or a remote box has no screen, but Godot&#39;s editor does not need one. Start it with <code>--headless --editor</code> and its editor plugins still load, so an MCP server inside or beside the editor can open scenes, add nodes and write scripts. This guide sets that up with the three active community servers compared in <a href=\"/compare/game-engine-agent-tooling/\">Game engine agent tooling compared</a>: <a href=\"/entries/beckett-godot-mcp/\">Beckett</a>, <a href=\"/entries/godot-editor-mcp/\">Godot Editor MCP</a> and <a href=\"/entries/godot-ai/\">Godot AI</a>.</p>\n<p>Everything below was run on 2026-10-31 on a Linux x86_64 box with no display, using Godot 4.7.2-stable, Beckett Lite 1.16.0, Godot Editor MCP 2026.10.20.1 and Godot AI 4.3.1.</p>\n<h2>1. Install Godot and make a project</h2>\n<p>Download the official Linux build and check it against the release&#39;s SHA512 list:</p>\n<pre><code class=\"language-bash\">mkdir -p ~/godot &amp;&amp; cd ~/godot\ncurl -LO https://github.com/godotengine/godot/releases/download/4.7.2-stable/Godot_v4.7.2-stable_linux.x86_64.zip\ncurl -LO https://github.com/godotengine/godot/releases/download/4.7.2-stable/SHA512-SUMS.txt\ngrep &#39;Godot_v4.7.2-stable_linux.x86_64.zip&#39; SHA512-SUMS.txt | sha512sum -c -\nunzip -q Godot_v4.7.2-stable_linux.x86_64.zip\nln -sf &quot;$PWD/Godot_v4.7.2-stable_linux.x86_64&quot; ~/godot/godot</code></pre>\n<p>Each server below gets its own small project. A project only needs <code>project.godot</code>, so you can create one without the project manager. The <code>[editor_plugins]</code> section is what the Plugins tab writes when you tick a plugin:</p>\n<pre><code class=\"language-bash\">mkdir demo &amp;&amp; cd demo\ncat &gt; project.godot &lt;&lt;&#39;CFG&#39;\nconfig_version=5\n\n[application]\nconfig/name=&quot;demo&quot;\nconfig/features=PackedStringArray(&quot;4.7&quot;)\n\n[editor_plugins]\nenabled=PackedStringArray(&quot;res://addons/PLUGIN/plugin.cfg&quot;)\nCFG\nprintf &#39;[gd_scene format=3]\\n\\n[node name=&quot;Main&quot; type=&quot;Node2D&quot;]\\n&#39; &gt; main.tscn</code></pre>\n<p>Replace <code>PLUGIN</code> with the addon folder: <code>beckett</code>, <code>godot_mcp</code> or <code>godot_ai</code>. Then start the editor in the background:</p>\n<pre><code class=\"language-bash\">~/godot/godot --headless --editor --path . &gt; editor.log 2&gt;&amp;1 &amp;</code></pre>\n<h2>2. A probe to drive any server</h2>\n<p>Most clients can connect to these servers, but a small script gives you the same check in CI with no client installed. This one uses only the Python standard library. It speaks Streamable HTTP, handles both JSON and SSE replies, keeps the <code>Mcp-Session-Id</code>, lists the tools, then runs the calls you pass as <code>name={json}</code>:</p>\n<pre><code class=\"language-python\"># mcp_probe.py: initialize, list tools, then call tools in one session\nimport json, sys, urllib.request, urllib.error\n\ndef rpc(url, method, params=None, id_=1, sid=None):\n    body = {&quot;jsonrpc&quot;: &quot;2.0&quot;, &quot;method&quot;: method}\n    if id_ is not None:\n        body[&quot;id&quot;] = id_\n    if params is not None:\n        body[&quot;params&quot;] = params\n    h = {&quot;Content-Type&quot;: &quot;application/json&quot;, &quot;Accept&quot;: &quot;application/json, text/event-stream&quot;}\n    if sid:\n        h[&quot;Mcp-Session-Id&quot;] = sid\n    req = urllib.request.Request(url, json.dumps(body).encode(), h)\n    try:\n        with urllib.request.urlopen(req, timeout=30) as r:\n            raw, sid, status = r.read().decode(), r.headers.get(&quot;Mcp-Session-Id&quot;) or sid, r.status\n    except urllib.error.HTTPError as e:\n        return e.code, e.read().decode()[:200], sid\n    if raw.startswith((&quot;event:&quot;, &quot;data:&quot;)):\n        msgs = [json.loads(l[5:]) for l in raw.splitlines() if l.startswith(&quot;data:&quot;) and l[5:].strip()]\n        match = [m for m in msgs if m.get(&quot;id&quot;) == id_]\n        return status, (match or msgs or [None])[0], sid\n    return status, (json.loads(raw) if raw.strip() else None), sid\n\nurl = sys.argv[1]\nst, res, sid = rpc(url, &quot;initialize&quot;, {&quot;protocolVersion&quot;: &quot;2025-06-18&quot;, &quot;capabilities&quot;: {},\n                   &quot;clientInfo&quot;: {&quot;name&quot;: &quot;probe&quot;, &quot;version&quot;: &quot;0&quot;}})\nprint(&quot;initialize&quot;, st, res if isinstance(res, str) else res[&quot;result&quot;][&quot;serverInfo&quot;])\nif st != 200:\n    sys.exit(1)\nrpc(url, &quot;notifications/initialized&quot;, id_=None, sid=sid)\nst, res, sid = rpc(url, &quot;tools/list&quot;, {}, 2, sid)\nprint(&quot;tools&quot;, len(res[&quot;result&quot;][&quot;tools&quot;]))\nfor i, call in enumerate(sys.argv[2:], start=10):\n    name, _, args = call.partition(&quot;=&quot;)\n    st, res, sid = rpc(url, &quot;tools/call&quot;, {&quot;name&quot;: name, &quot;arguments&quot;: json.loads(args or &quot;{}&quot;)}, i, sid)\n    print(name, json.dumps(res[&quot;result&quot;][&quot;content&quot;])[:300])</code></pre>\n<p>For Godot AI, whose clients connect over stdio, the same loop works over a subprocess&#39;s stdin and stdout: write one JSON-RPC message per line and read lines until the reply with your <code>id</code> arrives.</p>\n<h2>3. Beckett: a server inside the editor</h2>\n<p>Beckett&#39;s free Lite edition is a pure GDScript plugin: the editor itself serves MCP, with no Python or Node process. Unzip the release into the project so it lands in <code>addons/beckett/</code>, set <code>PLUGIN</code> to <code>beckett</code>, and start the editor:</p>\n<pre><code class=\"language-bash\">curl -LO https://github.com/beckettlab/beckett-godot-mcp/releases/download/v1.16.0/beckett-godot-mcp-lite-v1.16.0.zip\nunzip -q beckett-godot-mcp-lite-v1.16.0.zip     # creates addons/beckett/\n~/godot/godot --headless --editor --path . &gt; editor.log 2&gt;&amp;1 &amp;</code></pre>\n<p>Within about 20 seconds the plugin had started on <code>127.0.0.1:8770</code> and written three things to the project:</p>\n<ul><li><code>.mcp.json</code> and <code>.cursor/mcp.json</code>, each with an <code>http</code> server whose URL is <code>http://127.0.0.1:8770/mcp/&lt;token&gt;</code>. The 32-hex-character token is part of the path.</li><li><code>.beckett/port</code> and <code>.beckett/token</code>.</li><li>A <code>BeckettRuntime</code> autoload in <code>project.godot</code>.</li></ul>\n<p>The server reported itself as <code>beckett-godot-mcp</code> 1.16.0, advertised tools, resources and prompts, and listed 56 tools. This sequence built a scene:</p>\n<pre><code class=\"language-bash\">TOKEN=$(cat .beckett/token)\npython3 mcp_probe.py &quot;http://127.0.0.1:8770/mcp/$TOKEN&quot; \\\n  &#39;open_scene={&quot;path&quot;:&quot;res://main.tscn&quot;}&#39; \\\n  &#39;create_node={&quot;type&quot;:&quot;Sprite2D&quot;,&quot;name&quot;:&quot;Player&quot;}&#39; \\\n  &#39;write_script={&quot;path&quot;:&quot;res://player.gd&quot;,&quot;content&quot;:&quot;extends Sprite2D\\nfunc _ready(:\\n\\tpass\\n&quot;}&#39; \\\n  &#39;write_script={&quot;path&quot;:&quot;res://player.gd&quot;,&quot;content&quot;:&quot;extends Sprite2D\\n\\nfunc _ready():\\n\\tprint(\\&quot;ready\\&quot;)\\n&quot;}&#39; \\\n  &#39;attach_script={&quot;target&quot;:&quot;Player&quot;,&quot;path&quot;:&quot;res://player.gd&quot;}&#39; \\\n  &#39;save_scene={}&#39;</code></pre>\n<p>The first <code>write_script</code> has a syntax error on purpose. Beckett refused it with &quot;Refusing to write: script does not compile&quot;, plus the engine&#39;s parse error, and wrote nothing. The second one returned <code>disk_verified: true</code>. After <code>save_scene</code>, <code>main.tscn</code> on disk had a <code>Player</code> Sprite2D with <code>player.gd</code> attached as an external resource. In headless mode, <code>save_scene</code> also reported an engine error from the dummy renderer&#39;s texture storage. The save still succeeded, so that error can be ignored.</p>\n<p>Security checks against the same server:</p>\n<table><thead><tr><th scope=\"col\">Request</th><th scope=\"col\">Result</th></tr></thead><tbody><tr><td><code>POST /mcp</code> without the token in the path</td><td>401</td></tr><tr><td>Correct URL, <code>Origin: http://evil.example</code></td><td>403</td></tr><tr><td>Correct URL, <code>Host: attacker.example:8770</code></td><td>403</td></tr><tr><td>Listening sockets</td><td>127.0.0.1 only</td></tr></tbody></table>\n<p>For a shared or CI machine, the README documents <code>BECKETT_READONLY=1</code> (inspection only), <code>BECKETT_ALLOWLIST</code> (limit the tools) and <code>BECKETT_CONFIRM_DESTRUCTIVE=1</code>, as well as <code>BECKETT_PORT</code> and <code>BECKETT_TOKEN</code>.</p>\n<h2>4. Godot Editor MCP: a Python server the editor dials into</h2>\n<p>Godot Editor MCP splits the work. A Python server talks MCP to the client, and an editor addon connects out to that server over a WebSocket on <code>127.0.0.1:9080</code>. Install the server, unzip the addon from the matching GitHub release, set <code>PLUGIN</code> to <code>godot_mcp</code>, and give both processes the same bridge token. The token is optional, but without it any local process could pose as the editor:</p>\n<pre><code class=\"language-bash\">python3 -m venv .venv &amp;&amp; .venv/bin/pip install godot-editor-mcp==2026.10.20.1\ncurl -LO https://github.com/hybridindie/godot-mcp/releases/download/2026.10.20.1/godot_mcp_addon.zip\nunzip -q godot_mcp_addon.zip                     # creates addons/godot_mcp/\nexport GODOT_MCP_BRIDGE_TOKEN=$(python3 -c &#39;import secrets; print(secrets.token_hex(16))&#39;)\nGODOT_MCP_TRANSPORT=http .venv/bin/godot-editor-mcp &gt; server.log 2&gt;&amp;1 &amp;\n~/godot/godot --headless --editor --path . &gt; editor.log 2&gt;&amp;1 &amp;</code></pre>\n<p>The server log showed the bridge on <code>127.0.0.1:9080</code>, MCP on <code>http://127.0.0.1:9090/mcp</code>, and then &quot;bridge peer authenticated&quot; when the editor connected. For a desktop client, use stdio, which is the default transport, and let <code>godot-editor-mcp config --client &lt;client&gt; --write</code> write the client config. <code>godot-editor-mcp doctor --project &lt;path&gt;</code> checks a setup.</p>\n<p>Only the core and inspection toolsets are on at first, so <code>tools/list</code> returned 24 tools. The agent enables more as it needs them:</p>\n<pre><code class=\"language-bash\">python3 mcp_probe.py http://127.0.0.1:9090/mcp \\\n  &#39;godot_enable_toolset={&quot;category&quot;:&quot;scene_edit&quot;}&#39; \\\n  &#39;godot_scene_edit_open_scene={&quot;scene_path&quot;:&quot;res://main.tscn&quot;}&#39; \\\n  &#39;godot_scene_edit_create_node={&quot;parent_path&quot;:&quot;.&quot;,&quot;node_type&quot;:&quot;Camera2D&quot;,&quot;node_name&quot;:&quot;Cam&quot;,&quot;dry_run&quot;:true}&#39; \\\n  &#39;godot_scene_edit_create_node={&quot;parent_path&quot;:&quot;.&quot;,&quot;node_type&quot;:&quot;Camera2D&quot;,&quot;node_name&quot;:&quot;Cam&quot;}&#39; \\\n  &#39;godot_scene_edit_save_scene={}&#39;</code></pre>\n<p>After <code>scene_edit</code> was enabled, the list grew to 48 tools. The setting also persisted for a new session against the same server. The dry run returned <code>created: false</code>, the real call returned <code>created: true</code>, and the saved <code>main.tscn</code> contained the <code>Cam</code> Camera2D. With the default <code>GODOT_MCP_HTTP_HOST_ORIGIN_PROTECTION=auto</code>, a foreign <code>Host</code> header got 421 and a foreign <code>Origin</code> got 403. If you bind HTTP to a non-loopback address, the server refuses to start unless <code>GODOT_MCP_AUTH_TOKEN</code> is set.</p>\n<p>One gotcha: <code>godot-editor-mcp --help</code> does not print help. It starts the server.</p>\n<h2>5. Godot AI: set the headless opt-in</h2>\n<p>Godot AI&#39;s plugin starts a Python server (through <code>uvx</code>) with authenticated HTTP on port 8000 and an authenticated WebSocket on port 9500. Clients connect through <code>godot-ai attach</code> over stdio. Unzip the release&#39;s <code>godot-ai-v4-plugin.zip</code> (it creates <code>addons/godot_ai/</code>) and set <code>PLUGIN</code> to <code>godot_ai</code>.</p>\n<p>Started headless like the others, the editor log said <code>MCP | plugin disabled in headless mode</code> and nothing listened. The README&#39;s section on headless editors says normal headless launches skip the server, and to set <code>GODOT_AI_ALLOW_HEADLESS=1</code> only for intentional CI or editor sessions:</p>\n<pre><code class=\"language-bash\">curl -LO https://github.com/hi-godot/godot-ai/releases/download/v4.3.1/godot-ai-v4-plugin.zip\nunzip -q godot-ai-v4-plugin.zip                  # creates addons/godot_ai/\nGODOT_AI_ALLOW_HEADLESS=1 GODOT_AI_DISABLE_TELEMETRY=true \\\n  ~/godot/godot --headless --editor --path . &gt; editor.log 2&gt;&amp;1 &amp;</code></pre>\n<p>With the variable set, the plugin started <code>godot-ai==4.3.1</code> with <code>--transport streamable-http --port 8000 --ws-port 9500</code>, connected and authenticated. Both ports listened on 127.0.0.1 only. It also added a <code>_mcp_game_helper</code> autoload to <code>project.godot</code>. <code>GODOT_AI_DISABLE_TELEMETRY=true</code> opts out of the anonymous telemetry that Godot AI otherwise sends.</p>\n<p>A bare <code>POST http://127.0.0.1:8000/mcp</code> got 401 with <code>TRANSPORT_AUTH_REQUIRED</code>, as the README warns. Through <code>attach</code>, which handles the authentication, a stdio session listed 47 tools and ran this sequence:</p>\n<pre><code class=\"language-text\">command: uvx --from godot-ai==4.3.1 godot-ai attach --disable-telemetry\neditor_state         -&gt; godot_version &quot;4.7.2-stable (official)&quot;\nscene_open           {&quot;path&quot;: &quot;res://main.tscn&quot;}\nnode_create          {&quot;type&quot;: &quot;Label&quot;, &quot;name&quot;: &quot;Hello&quot;}   -&gt; path /Main/Hello, undoable true\nscene_save           {}                                   -&gt; res://main.tscn\nscene_get_hierarchy  {}                                   -&gt; Main (Node2D), Hello (Label)</code></pre>\n<p><code>main.tscn</code> on disk then held the <code>Hello</code> Label. When we killed the editor, the plugin-started server was gone within 8 seconds, so you do not need to clean it up yourself.</p>\n<h2>6. Use it from an agent</h2>\n<p>On a headless box, point the agent&#39;s MCP config at the same endpoints. For Claude Code (see <a href=\"/guides/add-mcp-servers-to-claude-code/\">Add MCP servers to Claude Code</a>), Beckett&#39;s generated <code>.mcp.json</code> in the project root is picked up as a project-scoped server. For the others:</p>\n<pre><code class=\"language-bash\">claude mcp add --transport http godot-editor http://127.0.0.1:9090/mcp\nclaude mcp add godot-ai -- uvx --from godot-ai==4.3.1 godot-ai attach --disable-telemetry</code></pre>\n<p>Start the editor before the agent session, and in CI wait for the port (<code>8770</code>, <code>9090</code> or <code>8000</code>) to accept connections before the first call. All three need a running editor with the plugin loaded; Beckett and Godot AI have nothing to serve before that.</p>\n<h2>7. Keep it safe</h2>\n<ul><li><strong>Don&#39;t commit what the plugins generate.</strong> Beckett&#39;s <code>.mcp.json</code>, <code>.cursor/mcp.json</code> and <code>.beckett/</code> hold the project token. Add them to <code>.gitignore</code> unless every collaborator should share that token.</li><li><strong>Review the autoloads.</strong> Beckett and Godot AI both added an autoload to <code>project.godot</code>. Decide whether you want those runtime helpers in exported builds before you ship.</li><li><strong>Stay on loopback.</strong> All three bound to 127.0.0.1 by default. If a container or VM boundary forces a non-loopback bind, set Godot Editor MCP&#39;s <code>GODOT_MCP_AUTH_TOKEN</code> and keep the port off public networks.</li><li><strong>Treat these tools as code execution.</strong> Writing and attaching scripts and running the project all execute code as the user who runs the editor. On a CI runner, give that user nothing it doesn&#39;t need.</li><li><strong>Re-run the probe on upgrades.</strong> The 401, 403 and 421 checks above are a quick regression test. <a href=\"/guides/test-your-mcp-server/\">Test your MCP server</a> covers deeper checks.</li></ul>"
}
