godot-devtool-mcp-server

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Godot Devtool MCP Server

Godot Devtool MCP 服务器

Skill by ara.so — Devtools Skills collection.
godot-devtool
is an MCP (Model Context Protocol) server that enables AI-assisted inspection, editing, validation, and runtime automation for Godot 4 projects. It provides 234 tools across project management, scene/node manipulation, script handling, editor integration, and live runtime control.
ara.so 开发的Skill — 开发工具Skill合集。
godot-devtool
是一款MCP(Model Context Protocol)服务器,可为Godot 4项目提供AI辅助的检查、编辑、验证及运行时自动化功能。它提供了234个工具,覆盖项目管理、场景/节点操作、脚本处理、编辑器集成以及实时运行时控制等领域。

Architecture Overview

架构概述

MCP Client (Claude Code, Cursor, Cline, etc.)
  ↓ stdio
Node.js MCP Server (build/index.js)
├─ Native routes (file inspection/editing)
├─ Headless Godot routes (scene/resource ops)
├─ WebSocket bridge (ws://127.0.0.1:8766)
│   ├─ Editor plugin (live scene editing, Inspector, UndoRedo)
│   └─ Runtime autoload (running game inspection, input simulation)
└─ Browser visualizer (local HTTP dashboard)
  • stdio MCP server: Always runs over stdin/stdout, no exclusive port binding
  • Native routes: Inspect/edit project files without opening Godot editor
  • Headless routes: Call Godot CLI for scene/resource/script operations
  • Editor routes: Live editing via bundled WebSocket plugin
  • Runtime routes: Running-game scene tree, properties, input simulation, screenshots
  • Shared bridge: Multiple MCP clients can use the same WebSocket port
MCP Client (Claude Code, Cursor, Cline, etc.)
  ↓ stdio
Node.js MCP Server (build/index.js)
├─ Native routes (file inspection/editing)
├─ Headless Godot routes (scene/resource ops)
├─ WebSocket bridge (ws://127.0.0.1:8766)
│   ├─ Editor plugin (live scene editing, Inspector, UndoRedo)
│   └─ Runtime autoload (running game inspection, input simulation)
└─ Browser visualizer (local HTTP dashboard)
  • stdio MCP服务器:始终通过标准输入/输出运行,不占用专属端口
  • Native路由:无需打开Godot编辑器即可检查/编辑项目文件
  • Headless路由:调用Godot CLI执行场景/资源/脚本操作
  • Editor路由:通过内置WebSocket插件实现实时编辑
  • Runtime路由:运行中游戏的场景树、属性、输入模拟、截图功能
  • 共享桥接:多个MCP客户端可共用同一个WebSocket端口

Installation

安装步骤

1. Install the MCP Server

1. 安装MCP服务器

Extract the release build or build from source:
bash
git clone https://github.com/wangdiandao/godot-devtool.git
cd godot-devtool
npm install
npm run build
解压发布版本或从源码构建:
bash
git clone https://github.com/wangdiandao/godot-devtool.git
cd godot-devtool
npm install
npm run build

2. Configure Your MCP Client

2. 配置MCP客户端

Claude Desktop / VS Code (JSON):
json
{
  "mcpServers": {
    "godot-devtool": {
      "command": "node",
      "args": ["E:/godot-devtool/build/index.js"],
      "env": {
        "GODOT_PATH": "D:/Program Files/Godot/Godot_v4.x.exe",
        "GODOT_DEVTOOL_WS_PORT": "8766"
      }
    }
  }
}
Codex Desktop (TOML):
toml
[mcp_servers.godot-devtool]
command = "node"
args = ["E:/godot-devtool/build/index.js"]
env = { GODOT_PATH = "D:/Program Files/Godot/Godot_v4.x.exe", GODOT_DEVTOOL_WS_PORT = "8766" }
Environment variables:
  • GODOT_PATH
    : Path to Godot executable (optional if
    godot
    is in PATH)
  • GODOT_DEVTOOL_WS_PORT
    : WebSocket bridge port (default: 8766)
Claude Desktop / VS Code(JSON格式)
json
{
  "mcpServers": {
    "godot-devtool": {
      "command": "node",
      "args": ["E:/godot-devtool/build/index.js"],
      "env": {
        "GODOT_PATH": "D:/Program Files/Godot/Godot_v4.x.exe",
        "GODOT_DEVTOOL_WS_PORT": "8766"
      }
    }
  }
}
Codex Desktop(TOML格式)
toml
[mcp_servers.godot-devtool]
command = "node"
args = ["E:/godot-devtool/build/index.js"]
env = { GODOT_PATH = "D:/Program Files/Godot/Godot_v4.x.exe", GODOT_DEVTOOL_WS_PORT = "8766" }
环境变量说明:
  • GODOT_PATH
    :Godot可执行文件路径(若
    godot
    已在PATH中则可选)
  • GODOT_DEVTOOL_WS_PORT
    :WebSocket桥接端口(默认:8766)

3. Install the Godot Plugin

3. 安装Godot插件

The plugin enables live editor and runtime routes. Install via MCP tools:
typescript
// Call from MCP client
plugin_install({
  projectPath: "E:/my-godot-project",
  overwrite: true,
  websocketPort: 8766
})
Then in Godot:
  1. Open your project
  2. Go to Project → Project Settings → Plugins
  3. Enable godot-devtool
For runtime routes, the plugin also registers:
autoload/DevtoolRuntime = *res://addons/godot_devtool/runtime_bridge.gd
该插件支持实时编辑器和运行时路由,通过MCP工具安装:
typescript
// 从MCP客户端调用
plugin_install({
  projectPath: "E:/my-godot-project",
  overwrite: true,
  websocketPort: 8766
})
随后在Godot中操作:
  1. 打开你的项目
  2. 进入 项目 → 项目设置 → 插件
  3. 启用 godot-devtool
对于运行时路由,插件还会注册:
autoload/DevtoolRuntime = *res://addons/godot_devtool/runtime_bridge.gd

Core Concepts

核心概念

Sessions and Context

会话与上下文

Tools use
projectPath
,
context
,
sessionId
, and
runId
to identify targets:
  • projectPath: Absolute path to Godot project directory
  • context:
    editor
    or
    runtime
  • sessionId: Disambiguate multiple editor/runtime connections
  • runId: Track specific game instances from
    run_project
工具通过
projectPath
context
sessionId
runId
识别目标:
  • projectPath:Godot项目目录的绝对路径
  • context
    editor
    (编辑器)或
    runtime
    (运行时)
  • sessionId:区分多个编辑器/运行时连接
  • runId:跟踪
    run_project
    启动的特定游戏实例

Tool Discovery

工具发现

Use
get_capabilities
to discover tools and filter by workflow:
typescript
// Lightweight catalog (no schemas)
get_capabilities()

// Focused workflow with schemas
get_capabilities({
  toolNames: ["plugin_install", "plugin_status", "scene_tree_inspect"],
  includeSchemas: true
})

// Filter by route group
get_capabilities({
  routeGroup: "scene",
  includeSchemas: true
})

// Filter by transport
get_capabilities({
  transport: "editor_ws",
  includeSchemas: true
})
Workflow filters:
project_setup
,
live_editor
,
runtime_test
,
multi_instance
,
release_verify
使用
get_capabilities
发现工具并按工作流过滤:
typescript
// 轻量级目录(无模式)
get_capabilities()

// 带模式的聚焦工作流
get_capabilities({
  toolNames: ["plugin_install", "plugin_status", "scene_tree_inspect"],
  includeSchemas: true
})

// 按路由组过滤
get_capabilities({
  routeGroup: "scene",
  includeSchemas: true
})

// 按传输方式过滤
get_capabilities({
  transport: "editor_ws",
  includeSchemas: true
})
工作流过滤器:
project_setup
live_editor
runtime_test
multi_instance
release_verify

Bridge Lifecycle

桥接生命周期

  • Bridge port opens on demand when editor/runtime tools are called
  • Port stays open while:
    • run_project
      is active
    • Editor or runtime client is connected
  • Port releases after tool cleanup if no active sessions
  • Use
    plugin_status
    and
    plugin_cleanup_port
    to inspect/manage the bridge
  • 当调用编辑器/运行时工具时,桥接端口会按需开启
  • 端口在以下情况保持开启:
    • run_project
      处于活跃状态
    • 编辑器或运行时客户端已连接
  • 若没有活跃会话,工具清理后端口会释放
  • 使用
    plugin_status
    plugin_cleanup_port
    检查/管理桥接

Key Tool Categories

核心工具分类

Project Management

项目管理

typescript
// Get project metadata
get_project_info({
  projectPath: "E:/my-godot-project"
})

// Read project settings
project_get_settings({
  projectPath: "E:/my-godot-project",
  sections: ["application/config", "display/window"]
})

// Update project settings (dry run first)
project_update_settings({
  projectPath: "E:/my-godot-project",
  settings: {
    "application/config/name": "My Game",
    "display/window/size/viewport_width": 1920
  },
  dryRun: true
})

// Configure input actions
project_input_action({
  projectPath: "E:/my-godot-project",
  action: "jump",
  events: [
    { type: "InputEventKey", keycode: "KEY_SPACE" },
    { type: "InputEventJoypadButton", button_index: 0 }
  ]
})

// Run project
run_project({
  projectPath: "E:/my-godot-project",
  scene: "res://levels/level_01.tscn",
  debugCollisions: true,
  position: [100, 100],
  size: [1280, 720]
})

// List running instances
list_run_instances({
  projectPath: "E:/my-godot-project"
})

// Stop specific instance
stop_run_instance({
  projectPath: "E:/my-godot-project",
  runId: "run_12345"
})
typescript
// 获取项目元数据
get_project_info({
  projectPath: "E:/my-godot-project"
})

// 读取项目设置
project_get_settings({
  projectPath: "E:/my-godot-project",
  sections: ["application/config", "display/window"]
})

// 更新项目设置(先执行试运行)
project_update_settings({
  projectPath: "E:/my-godot-project",
  settings: {
    "application/config/name": "My Game",
    "display/window/size/viewport_width": 1920
  },
  dryRun: true
})

// 配置输入动作
project_input_action({
  projectPath: "E:/my-godot-project",
  action: "jump",
  events: [
    { type: "InputEventKey", keycode: "KEY_SPACE" },
    { type: "InputEventJoypadButton", button_index: 0 }
  ]
})

// 运行项目
run_project({
  projectPath: "E:/my-godot-project",
  scene: "res://levels/level_01.tscn",
  debugCollisions: true,
  position: [100, 100],
  size: [1280, 720]
})

// 列出运行中的实例
list_run_instances({
  projectPath: "E:/my-godot-project"
})

// 停止特定实例
stop_run_instance({
  projectPath: "E:/my-godot-project",
  runId: "run_12345"
})

Scene and Node Operations

场景与节点操作

typescript
// Inspect scene tree (native)
scene_tree_inspect({
  projectPath: "E:/my-godot-project",
  scenePath: "res://player.tscn",
  maxDepth: 3
})

// Inspect live editor scene (WebSocket)
editor_ws_scene_tree_inspect({
  projectPath: "E:/my-godot-project",
  maxDepth: 5
})

// Add node to live scene
editor_ws_node_add({
  projectPath: "E:/my-godot-project",
  parentPath: "Player/Body",
  nodeType: "Sprite2D",
  nodeName: "WeaponSprite",
  position: 1
})

// Update node property
editor_ws_node_set_property({
  projectPath: "E:/my-godot-project",
  nodePath: "Player/WeaponSprite",
  property: "texture",
  value: { type: "Resource", path: "res://sprites/sword.png" }
})

// Delete node with undo
editor_ws_node_delete({
  projectPath: "E:/my-godot-project",
  nodePath: "Player/OldSprite",
  undoable: true
})

// Save scene
editor_ws_scene_save({
  projectPath: "E:/my-godot-project"
})
typescript
// 检查场景树(原生)
scene_tree_inspect({
  projectPath: "E:/my-godot-project",
  scenePath: "res://player.tscn",
  maxDepth: 3
})

// 检查实时编辑器场景(WebSocket)
editor_ws_scene_tree_inspect({
  projectPath: "E:/my-godot-project",
  maxDepth: 5
})

// 向实时场景添加节点
editor_ws_node_add({
  projectPath: "E:/my-godot-project",
  parentPath: "Player/Body",
  nodeType: "Sprite2D",
  nodeName: "WeaponSprite",
  position: 1
})

// 更新节点属性
editor_ws_node_set_property({
  projectPath: "E:/my-godot-project",
  nodePath: "Player/WeaponSprite",
  property: "texture",
  value: { type: "Resource", path: "res://sprites/sword.png" }
})

// 带撤销功能的节点删除
editor_ws_node_delete({
  projectPath: "E:/my-godot-project",
  nodePath: "Player/OldSprite",
  undoable: true
})

// 保存场景
editor_ws_scene_save({
  projectPath: "E:/my-godot-project"
})

Script Management

脚本管理

typescript
// List GDScript files
script_index({
  projectPath: "E:/my-godot-project",
  includeTests: true
})

// Read script
script_read({
  projectPath: "E:/my-godot-project",
  scriptPath: "res://player.gd"
})

// Write script
script_write({
  projectPath: "E:/my-godot-project",
  scriptPath: "res://enemy.gd",
  content: `extends CharacterBody2D

var speed = 200.0

func _physics_process(delta):
    var direction = Vector2.ZERO
    if Input.is_action_pressed("move_right"):
        direction.x += 1
    velocity = direction * speed
    move_and_slide()
`
})

// Check syntax
script_check_syntax({
  projectPath: "E:/my-godot-project",
  scriptPath: "res://player.gd"
})

// Create and attach script
script_create({
  projectPath: "E:/my-godot-project",
  scriptPath: "res://powerup.gd",
  template: "Node2D",
  attachTo: "res://scenes/powerup.tscn"
})
typescript
// 列出GDScript文件
script_index({
  projectPath: "E:/my-godot-project",
  includeTests: true
})

// 读取脚本
script_read({
  projectPath: "E:/my-godot-project",
  scriptPath: "res://player.gd"
})

// 写入脚本
script_write({
  projectPath: "E:/my-godot-project",
  scriptPath: "res://enemy.gd",
  content: `extends CharacterBody2D

var speed = 200.0

func _physics_process(delta):
    var direction = Vector2.ZERO
    if Input.is_action_pressed("move_right"):
        direction.x += 1
    velocity = direction * speed
    move_and_slide()
`
})

// 检查语法
script_check_syntax({
  projectPath: "E:/my-godot-project",
  scriptPath: "res://player.gd"
})

// 创建并附加脚本
script_create({
  projectPath: "E:/my-godot-project",
  scriptPath: "res://powerup.gd",
  template: "Node2D",
  attachTo: "res://scenes/powerup.tscn"
})

Runtime Inspection & Automation

运行时检查与自动化

typescript
// Inspect running game scene tree
runtime_ws_scene_tree_inspect({
  projectPath: "E:/my-godot-project",
  rootPath: "/root/Game",
  maxDepth: 4
})

// Get runtime node property
runtime_ws_node_get_property({
  projectPath: "E:/my-godot-project",
  nodePath: "/root/Game/Player",
  property: "position"
})

// Set runtime property
runtime_ws_node_set_property({
  projectPath: "E:/my-godot-project",
  nodePath: "/root/Game/Player",
  property: "health",
  value: { type: "int", value: 100 }
})

// Simulate input action
runtime_ws_input_action({
  projectPath: "E:/my-godot-project",
  action: "jump",
  pressed: true,
  strength: 1.0
})

// Capture screenshot
runtime_ws_screenshot({
  projectPath: "E:/my-godot-project",
  outputPath: "E:/screenshots/test_jump.png"
})

// Wait for node to appear
runtime_ws_wait_for_node({
  projectPath: "E:/my-godot-project",
  nodePath: "/root/Game/VictoryScreen",
  timeout: 5000
})

// Run QA assertion
runtime_ws_qa_assert({
  projectPath: "E:/my-godot-project",
  nodePath: "/root/Game/Player",
  property: "health",
  expected: { type: "int", value: 100 },
  operator: "greater_than",
  message: "Player should have full health at start"
})
typescript
// 检查运行中游戏的场景树
runtime_ws_scene_tree_inspect({
  projectPath: "E:/my-godot-project",
  rootPath: "/root/Game",
  maxDepth: 4
})

// 获取运行时节点属性
runtime_ws_node_get_property({
  projectPath: "E:/my-godot-project",
  nodePath: "/root/Game/Player",
  property: "position"
})

// 设置运行时属性
runtime_ws_node_set_property({
  projectPath: "E:/my-godot-project",
  nodePath: "/root/Game/Player",
  property: "health",
  value: { type: "int", value: 100 }
})

// 模拟输入动作
runtime_ws_input_action({
  projectPath: "E:/my-godot-project",
  action: "jump",
  pressed: true,
  strength: 1.0
})

// 捕获截图
runtime_ws_screenshot({
  projectPath: "E:/my-godot-project",
  outputPath: "E:/screenshots/test_jump.png"
})

// 等待节点出现
runtime_ws_wait_for_node({
  projectPath: "E:/my-godot-project",
  nodePath: "/root/Game/VictoryScreen",
  timeout: 5000
})

// 运行QA断言
runtime_ws_qa_assert({
  projectPath: "E:/my-godot-project",
  nodePath: "/root/Game/Player",
  property: "health",
  expected: { type: "int", value: 100 },
  operator: "greater_than",
  message: "Player should have full health at start"
})

File & Resource Operations

文件与资源操作

typescript
// List project files
file_list({
  projectPath: "E:/my-godot-project",
  directory: "res://sprites",
  pattern: "*.png",
  recursive: true
})

// Search in files
file_search({
  projectPath: "E:/my-godot-project",
  query: "extends CharacterBody2D",
  paths: ["res://scripts"],
  filePattern: "*.gd"
})

// Load resource metadata
resource_load({
  projectPath: "E:/my-godot-project",
  resourcePath: "res://player.tscn",
  shallow: true
})

// Build dependency graph
resource_dependency_graph({
  projectPath: "E:/my-godot-project",
  resourcePath: "res://levels/level_01.tscn",
  direction: "forward",
  maxDepth: 3
})
typescript
// 列出项目文件
file_list({
  projectPath: "E:/my-godot-project",
  directory: "res://sprites",
  pattern: "*.png",
  recursive: true
})

// 在文件中搜索
file_search({
  projectPath: "E:/my-godot-project",
  query: "extends CharacterBody2D",
  paths: ["res://scripts"],
  filePattern: "*.gd"
})

// 加载资源元数据
resource_load({
  projectPath: "E:/my-godot-project",
  resourcePath: "res://player.tscn",
  shallow: true
})

// 构建依赖图
resource_dependency_graph({
  projectPath: "E:/my-godot-project",
  resourcePath: "res://levels/level_01.tscn",
  direction: "forward",
  maxDepth: 3
})

Common Workflows

常见工作流

1. Project Setup & Inspection

1. 项目设置与检查

typescript
// Verify Godot installation
get_godot_version()

// Discover available tools
get_capabilities({
  routeGroup: "project",
  includeSchemas: true
})

// Get project info
get_project_info({ projectPath: "E:/my-game" })

// Check project settings
project_get_settings({
  projectPath: "E:/my-game",
  sections: ["application", "display", "input"]
})

// Install plugin for live editing
plugin_install({
  projectPath: "E:/my-game",
  overwrite: true,
  websocketPort: 8766
})

// Verify plugin installation
plugin_status({ projectPath: "E:/my-game" })
typescript
// 验证Godot安装
get_godot_version()

// 发现可用工具
get_capabilities({
  routeGroup: "project",
  includeSchemas: true
})

// 获取项目信息
get_project_info({ projectPath: "E:/my-game" })

// 检查项目设置
project_get_settings({
  projectPath: "E:/my-game",
  sections: ["application", "display", "input"]
})

// 安装实时编辑插件
plugin_install({
  projectPath: "E:/my-game",
  overwrite: true,
  websocketPort: 8766
})

// 验证插件安装状态
plugin_status({ projectPath: "E:/my-game" })

2. Live Scene Editing

2. 实时场景编辑

typescript
// 1. Ensure editor is open with plugin enabled

// 2. Get current editor selection
editor_ws_selection_get({ projectPath: "E:/my-game" })

// 3. Inspect current scene
editor_ws_scene_tree_inspect({
  projectPath: "E:/my-game",
  maxDepth: 5
})

// 4. Add a new node
editor_ws_node_add({
  projectPath: "E:/my-game",
  parentPath: "Player",
  nodeType: "Area2D",
  nodeName: "HitBox"
})

// 5. Configure the node
editor_ws_node_set_property({
  projectPath: "E:/my-game",
  nodePath: "Player/HitBox",
  property: "collision_layer",
  value: { type: "int", value: 2 }
})

// 6. Add collision shape
editor_ws_node_add({
  projectPath: "E:/my-game",
  parentPath: "Player/HitBox",
  nodeType: "CollisionShape2D",
  nodeName: "Shape"
})

// 7. Save the scene
editor_ws_scene_save({ projectPath: "E:/my-game" })
typescript
// 1. 确保编辑器已打开且插件已启用

// 2. 获取当前编辑器选中内容
editor_ws_selection_get({ projectPath: "E:/my-game" })

// 3. 检查当前场景
editor_ws_scene_tree_inspect({
  projectPath: "E:/my-game",
  maxDepth: 5
})

// 4. 添加新节点
editor_ws_node_add({
  projectPath: "E:/my-game",
  parentPath: "Player",
  nodeType: "Area2D",
  nodeName: "HitBox"
})

// 5. 配置节点
editor_ws_node_set_property({
  projectPath: "E:/my-game",
  nodePath: "Player/HitBox",
  property: "collision_layer",
  value: { type: "int", value: 2 }
})

// 6. 添加碰撞形状
editor_ws_node_add({
  projectPath: "E:/my-game",
  parentPath: "Player/HitBox",
  nodeType: "CollisionShape2D",
  nodeName: "Shape"
})

// 7. 保存场景
editor_ws_scene_save({ projectPath: "E:/my-game" })

3. Runtime Testing & QA

3. 运行时测试与QA

typescript
// 1. Run the project
run_project({
  projectPath: "E:/my-game",
  scene: "res://test_level.tscn",
  debugCollisions: true
})

// 2. Wait for game to load
await sleep(2000)

// 3. Inspect runtime scene tree
runtime_ws_scene_tree_inspect({
  projectPath: "E:/my-game",
  rootPath: "/root"
})

// 4. Check initial state
runtime_ws_node_get_property({
  projectPath: "E:/my-game",
  nodePath: "/root/Game/Player",
  property: "position"
})

// 5. Simulate input
runtime_ws_input_action({
  projectPath: "E:/my-game",
  action: "move_right",
  pressed: true
})

await sleep(1000)

runtime_ws_input_action({
  projectPath: "E:/my-game",
  action: "move_right",
  pressed: false
})

// 6. Verify movement
runtime_ws_qa_assert({
  projectPath: "E:/my-game",
  nodePath: "/root/Game/Player",
  property: "position.x",
  expected: { type: "float", value: 0 },
  operator: "greater_than",
  message: "Player should move right"
})

// 7. Capture screenshot
runtime_ws_screenshot({
  projectPath: "E:/my-game",
  outputPath: "E:/test_results/player_moved.png"
})

// 8. Stop the test
stop_project({ projectPath: "E:/my-game" })
typescript
// 1. 运行项目
run_project({
  projectPath: "E:/my-game",
  scene: "res://test_level.tscn",
  debugCollisions: true
})

// 2. 等待游戏加载
await sleep(2000)

// 3. 检查运行时场景树
runtime_ws_scene_tree_inspect({
  projectPath: "E:/my-game",
  rootPath: "/root"
})

// 4. 检查初始状态
runtime_ws_node_get_property({
  projectPath: "E:/my-game",
  nodePath: "/root/Game/Player",
  property: "position"
})

// 5. 模拟输入
runtime_ws_input_action({
  projectPath: "E:/my-game",
  action: "move_right",
  pressed: true
})

await sleep(1000)

runtime_ws_input_action({
  projectPath: "E:/my-game",
  action: "move_right",
  pressed: false
})

// 6. 验证移动结果
runtime_ws_qa_assert({
  projectPath: "E:/my-game",
  nodePath: "/root/Game/Player",
  property: "position.x",
  expected: { type: "float", value: 0 },
  operator: "greater_than",
  message: "Player should move right"
})

// 7. 捕获截图
runtime_ws_screenshot({
  projectPath: "E:/my-game",
  outputPath: "E:/test_results/player_moved.png"
})

// 8. 停止测试
stop_project({ projectPath: "E:/my-game" })

4. Batch Scene Validation

4. 批量场景验证

typescript
// List all scenes
const scenes = await file_list({
  projectPath: "E:/my-game",
  directory: "res://",
  pattern: "*.tscn",
  recursive: true
})

// Check each scene for common issues
for (const scene of scenes.files) {
  // Inspect scene tree
  const tree = await scene_tree_inspect({
    projectPath: "E:/my-game",
    scenePath: scene.path,
    maxDepth: 10
  })
  
  // Check for orphan nodes (no parent reference)
  // Check for missing scripts
  // Check for invalid resource paths
  
  // Run syntax check on attached scripts
  const scriptsToCheck = tree.nodes
    .filter(n => n.script)
    .map(n => n.script)
  
  for (const scriptPath of scriptsToCheck) {
    await script_check_syntax({
      projectPath: "E:/my-game",
      scriptPath: scriptPath
    })
  }
}
typescript
// 列出所有场景
const scenes = await file_list({
  projectPath: "E:/my-game",
  directory: "res://",
  pattern: "*.tscn",
  recursive: true
})

// 检查每个场景的常见问题
for (const scene of scenes.files) {
  // 检查场景树
  const tree = await scene_tree_inspect({
    projectPath: "E:/my-game",
    scenePath: scene.path,
    maxDepth: 10
  })
  
  // 检查孤立节点(无父节点引用)
  // 检查缺失脚本
  // 检查无效资源路径
  
  // 对附加脚本执行语法检查
  const scriptsToCheck = tree.nodes
    .filter(n => n.script)
    .map(n => n.script)
  
  for (const scriptPath of scriptsToCheck) {
    await script_check_syntax({
      projectPath: "E:/my-game",
      scriptPath: scriptPath
    })
  }
}

Configuration

配置说明

Environment Variables

环境变量

  • GODOT_PATH
    : Path to Godot executable (required if not in PATH)
  • GODOT_DEVTOOL_WS_PORT
    : WebSocket bridge port (default: 8766)
  • GODOT_PATH
    :Godot可执行文件路径(若不在PATH中则必填)
  • GODOT_DEVTOOL_WS_PORT
    :WebSocket桥接端口(默认:8766)

Project Settings Integration

项目设置集成

The MCP server reads and writes
project.godot
using native Godot syntax:
typescript
// Add autoload
add_autoload({
  projectPath: "E:/my-game",
  name: "GameManager",
  path: "res://singletons/game_manager.gd",
  enabled: true
})

// Configure display settings
project_update_settings({
  projectPath: "E:/my-game",
  settings: {
    "display/window/size/viewport_width": 1920,
    "display/window/size/viewport_height": 1080,
    "display/window/size/mode": 3, // fullscreen
    "display/window/vsync/vsync_mode": 1
  }
})
MCP服务器使用原生Godot语法读取和写入
project.godot
typescript
// 添加自动加载
add_autoload({
  projectPath: "E:/my-game",
  name: "GameManager",
  path: "res://singletons/game_manager.gd",
  enabled: true
})

// 配置显示设置
project_update_settings({
  projectPath: "E:/my-game",
  settings: {
    "display/window/size/viewport_width": 1920,
    "display/window/size/viewport_height": 1080,
    "display/window/size/mode": 3, // 全屏
    "display/window/vsync/vsync_mode": 1
  }
})

Input Actions

输入动作

Use native Godot event syntax:
typescript
project_input_action({
  projectPath: "E:/my-game",
  action: "attack",
  events: [
    {
      type: "InputEventKey",
      keycode: "KEY_CTRL"
    },
    {
      type: "InputEventMouseButton",
      button_index: 1 // MOUSE_BUTTON_LEFT
    },
    {
      type: "InputEventJoypadButton",
      button_index: 0, // BUTTON_A
      device: -1 // any gamepad
    }
  ],
  deadzone: 0.5
})
使用原生Godot事件语法:
typescript
project_input_action({
  projectPath: "E:/my-game",
  action: "attack",
  events: [
    {
      type: "InputEventKey",
      keycode: "KEY_CTRL"
    },
    {
      type: "InputEventMouseButton",
      button_index: 1 // MOUSE_BUTTON_LEFT
    },
    {
      type: "InputEventJoypadButton",
      button_index: 0, // BUTTON_A
      device: -1 // 任意游戏手柄
    }
  ],
  deadzone: 0.5
})

Property Value Syntax

属性值语法

Use structured Variant types for node properties:
typescript
// Basic types
{ type: "int", value: 42 }
{ type: "float", value: 3.14 }
{ type: "bool", value: true }
{ type: "String", value: "Hello" }

// Vector types
{ type: "Vector2", value: [10, 20] }
{ type: "Vector3", value: [1, 2, 3] }
{ type: "Color", value: [1.0, 0.5, 0.0, 1.0] } // RGBA

// Resources
{ type: "Resource", path: "res://sprites/player.png" }

// NodePath
{ type: "NodePath", value: "../OtherNode" }

// Arrays
{ type: "Array", value: [1, 2, 3] }

// Dictionaries
{ type: "Dictionary", value: { "key1": "value1", "key2": 42 } }
使用结构化Variant类型设置节点属性:
typescript
// 基础类型
{ type: "int", value: 42 }
{ type: "float", value: 3.14 }
{ type: "bool", value: true }
{ type: "String", value: "Hello" }

// 向量类型
{ type: "Vector2", value: [10, 20] }
{ type: "Vector3", value: [1, 2, 3] }
{ type: "Color", value: [1.0, 0.5, 0.0, 1.0] } // RGBA

// 资源
{ type: "Resource", path: "res://sprites/player.png" }

// NodePath
{ type: "NodePath", value: "../OtherNode" }

// 数组
{ type: "Array", value: [1, 2, 3] }

// 字典
{ type: "Dictionary", value: { "key1": "value1", "key2": 42 } }

Troubleshooting

故障排除

Plugin Not Connecting

插件无法连接

typescript
// 1. Check plugin status
plugin_status({ projectPath: "E:/my-game" })

// 2. Check if port is blocked
plugin_cleanup_port({
  projectPath: "E:/my-game",
  websocketPort: 8766,
  kill: false // inspect only
})

// 3. If stale, kill and reinstall
plugin_cleanup_port({
  projectPath: "E:/my-game",
  websocketPort: 8766,
  kill: true
})

plugin_reload({ projectPath: "E:/my-game" })
typescript
// 1. 检查插件状态
plugin_status({ projectPath: "E:/my-game" })

// 2. 检查端口是否被占用
plugin_cleanup_port({
  projectPath: "E:/my-game",
  websocketPort: 8766,
  kill: false // 仅检查
})

// 3. 若端口已失效,终止并重新安装
plugin_cleanup_port({
  projectPath: "E:/my-game",
  websocketPort: 8766,
  kill: true
})

plugin_reload({ projectPath: "E:/my-game" })

Runtime Bridge Not Available

运行时桥接不可用

  1. Ensure the plugin is installed and enabled
  2. Verify autoload registration:
    typescript
    get_autoload({
      projectPath: "E:/my-game",
      name: "DevtoolRuntime"
    })
  3. Run the project from Godot (or use
    run_project
    )
  4. Check bridge status:
    typescript
    plugin_status({ projectPath: "E:/my-game" })
  1. 确保插件已安装并启用
  2. 验证自动加载注册:
    typescript
    get_autoload({
      projectPath: "E:/my-game",
      name: "DevtoolRuntime"
    })
  3. 从Godot运行项目(或使用
    run_project
  4. 检查桥接状态:
    typescript
    plugin_status({ projectPath: "E:/my-game" })

Multiple Game Instances

多游戏实例

typescript
// List all running instances
list_run_instances({ projectPath: "E:/my-game" })

// Use runId for specific instance operations
runtime_ws_scene_tree_inspect({
  projectPath: "E:/my-game",
  runId: "run_12345"
})

// Stop specific instance
stop_run_instance({
  projectPath: "E:/my-game",
  runId: "run_12345"
})
typescript
// 列出所有运行中的实例
list_run_instances({ projectPath: "E:/my-game" })

// 使用runId操作特定实例
runtime_ws_scene_tree_inspect({
  projectPath: "E:/my-game",
  runId: "run_12345"
})

// 停止特定实例
stop_run_instance({
  projectPath: "E:/my-game",
  runId: "run_12345"
})

Schema Too Large

模式过大

Filter
get_capabilities
requests:
typescript
// Bad: returns all 234 tool schemas
get_capabilities({ includeSchemas: true }) // REJECTED

// Good: filter first
get_capabilities({
  routeGroup: "scene",
  transport: "editor_ws",
  includeSchemas: true
})

// Or specify exact tools
get_capabilities({
  toolNames: ["editor_ws_scene_tree_inspect", "editor_ws_node_add"],
  includeSchemas: true
})
过滤
get_capabilities
请求:
typescript
// 不推荐:返回全部234个工具模式
get_capabilities({ includeSchemas: true }) // 会被拒绝

// 推荐:先过滤
get_capabilities({
  routeGroup: "scene",
  transport: "editor_ws",
  includeSchemas: true
})

// 或指定具体工具
get_capabilities({
  toolNames: ["editor_ws_scene_tree_inspect", "editor_ws_node_add"],
  includeSchemas: true
})

Editor Changes Not Saving

编辑器修改未保存

typescript
// Explicit save after edits
editor_ws_scene_save({ projectPath: "E:/my-game" })

// Check if scene is modified
editor_ws_selection_get({ projectPath: "E:/my-game" })
// Returns: { sceneModified: true, ... }
typescript
// 编辑后显式保存
editor_ws_scene_save({ projectPath: "E:/my-game" })

// 检查场景是否已修改
editor_ws_selection_get({ projectPath: "E:/my-game" })
// 返回结果:{ sceneModified: true, ... }

Browser Visualizer

浏览器可视化工具

Start a local dashboard to monitor bridge status:
typescript
// Start visualizer on port 3456
browser_visualizer_start({
  projectPath: "E:/my-game",
  port: 3456
})

// Open http://127.0.0.1:3456/ in browser
// Shows:
// - Bridge connection status
// - Connected editor/runtime clients
// - Active sessions and run IDs
// - Available screenshot/scene/input routes
// - Pending command queue

// Stop visualizer
browser_visualizer_stop({
  projectPath: "E:/my-game"
})
启动本地仪表盘监控桥接状态:
typescript
// 在3456端口启动可视化工具
browser_visualizer_start({
  projectPath: "E:/my-game",
  port: 3456
})

// 在浏览器中打开 http://127.0.0.1:3456/
// 显示内容:
// - 桥接连接状态
// - 已连接的编辑器/运行时客户端
// - 活跃会话和运行ID
// - 可用的截图/场景/输入路由
// - 待处理命令队列

// 停止可视化工具
browser_visualizer_stop({
  projectPath: "E:/my-game"
})

Example: Full Integration Test

示例:完整集成测试

typescript
// 1. Setup
const projectPath = "E:/my-game"

await plugin_install({
  projectPath,
  overwrite: true,
  websocketPort: 8766
})

// 2. Configure input
await project_input_action({
  projectPath,
  action: "test_jump",
  events: [{ type: "InputEventKey", keycode: "KEY_J" }]
})

// 3. Create test scene
await scene_create({
  projectPath,
  scenePath: "res://test_scenes/jump_test.tscn",
  rootType: "Node2D"
})

// 4. Add player node (assuming editor is open)
await editor_ws_node_add({
  projectPath,
  parentPath: ".",
  nodeType: "CharacterBody2D",
  nodeName: "Player"
})

await editor_ws_node_set_property({
  projectPath,
  nodePath: "Player",
  property: "position",
  value: { type: "Vector2", value: [100, 100] }
})

await editor_ws_scene_save({ projectPath })

// 5. Run test
const runResult = await run_project({
  projectPath,
  scene: "res://test_scenes/jump_test.tscn"
})

await sleep(1000)

// 6. Simulate jump
await runtime_ws_input_action({
  projectPath,
  action: "test_jump",
  pressed: true
})

await sleep(100)

await runtime_ws_input_action({
  projectPath,
  action: "test_jump",
  pressed: false
})

// 7. Verify result
const finalPos = await runtime_ws_node_get_property({
  projectPath,
  nodePath: "/root/Node2D/Player",
  property: "position.y"
})

await runtime_ws_qa_assert({
  projectPath,
  nodePath: "/root/Node2D/Player",
  property: "position.y",
  expected: { type: "float", value: 100 },
  operator: "less_than",
  message: "Player should have moved up after jump"
})

// 8. Cleanup
await stop_project({ projectPath })
typescript
// 1. 初始化设置
const projectPath = "E:/my-game"

await plugin_install({
  projectPath,
  overwrite: true,
  websocketPort: 8766
})

// 2. 配置输入
await project_input_action({
  projectPath,
  action: "test_jump",
  events: [{ type: "InputEventKey", keycode: "KEY_J" }]
})

// 3. 创建测试场景
await scene_create({
  projectPath,
  scenePath: "res://test_scenes/jump_test.tscn",
  rootType: "Node2D"
})

// 4. 添加玩家节点(假设编辑器已打开)
await editor_ws_node_add({
  projectPath,
  parentPath: ".",
  nodeType: "CharacterBody2D",
  nodeName: "Player"
})

await editor_ws_node_set_property({
  projectPath,
  nodePath: "Player",
  property: "position",
  value: { type: "Vector2", value: [100, 100] }
})

await editor_ws_scene_save({ projectPath })

// 5. 运行测试
const runResult = await run_project({
  projectPath,
  scene: "res://test_scenes/jump_test.tscn"
})

await sleep(1000)

// 6. 模拟跳跃
await runtime_ws_input_action({
  projectPath,
  action: "test_jump",
  pressed: true
})

await sleep(100)

await runtime_ws_input_action({
  projectPath,
  action: "test_jump",
  pressed: false
})

// 7. 验证结果
const finalPos = await runtime_ws_node_get_property({
  projectPath,
  nodePath: "/root/Node2D/Player",
  property: "position.y"
})

await runtime_ws_qa_assert({
  projectPath,
  nodePath: "/root/Node2D/Player",
  property: "position.y",
  expected: { type: "float", value: 100 },
  operator: "less_than",
  message: "Player should have moved up after jump"
})

// 8. 清理
await stop_project({ projectPath })

Advanced: Multi-Instance Testing

进阶:多实例测试

typescript
// Run multiple instances for multiplayer testing
const run1 = await run_project({
  projectPath: "E:/my-game",
  scene: "res://multiplayer_test.tscn",
  position: [0, 0]
})

const run2 = await run_project({
  projectPath: "E:/my-game",
  scene: "res://multiplayer_test.tscn",
  position: [800, 0]
})

// Control each instance separately
await runtime_ws_input_action({
  projectPath: "E:/my-game",
  runId: run1.runId,
  action: "move_right",
  pressed: true
})

await runtime_ws_input_action({
  projectPath: "E:/my-game",
  runId: run2.runId,
  action: "move_left",
  pressed: true
})

// Monitor both
const pos1 = await runtime_ws_node_get_property({
  projectPath: "E:/my-game",
  runId: run1.runId,
  nodePath: "/root/Game/Player",
  property: "position"
})

const pos2 = await runtime_ws_node_get_property({
  projectPath: "E:/my-game",
  runId: run2.runId,
  nodePath: "/root/Game/Player",
  property: "position"
})

// Cleanup
await stop_run_instance({ projectPath: "E:/my-game", runId: run1.runId })
await stop_run_instance({ projectPath: "E:/my-game", runId: run2.runId })

Important Notes:
  1. Always call
    get_capabilities
    first to discover available tools for your workflow
  2. Use
    dryRun: true
    for
    project_update_settings
    and other mutation operations
  3. Filter
    get_capabilities
    by
    routeGroup
    ,
    transport
    , or
    toolNames
    before requesting schemas
  4. The WebSocket bridge opens on-demand and releases when idle (unless runtime is active)
  5. Use
    projectPath
    ,
    context
    ,
    sessionId
    , and
    runId
    to disambiguate targets
  6. Runtime routes require the project to be running with the autoload registered
  7. Editor routes require the Godot editor to be open with the plugin enabled
  8. For production use, test changes in a separate branch/backup before applying to main project
typescript
// 运行多个实例进行多人游戏测试
const run1 = await run_project({
  projectPath: "E:/my-game",
  scene: "res://multiplayer_test.tscn",
  position: [0, 0]
})

const run2 = await run_project({
  projectPath: "E:/my-game",
  scene: "res://multiplayer_test.tscn",
  position: [800, 0]
})

// 分别控制每个实例
await runtime_ws_input_action({
  projectPath: "E:/my-game",
  runId: run1.runId,
  action: "move_right",
  pressed: true
})

await runtime_ws_input_action({
  projectPath: "E:/my-game",
  runId: run2.runId,
  action: "move_left",
  pressed: true
})

// 监控两个实例
const pos1 = await runtime_ws_node_get_property({
  projectPath: "E:/my-game",
  runId: run1.runId,
  nodePath: "/root/Game/Player",
  property: "position"
})

const pos2 = await runtime_ws_node_get_property({
  projectPath: "E:/my-game",
  runId: run2.runId,
  nodePath: "/root/Game/Player",
  property: "position"
})

// 清理
await stop_run_instance({ projectPath: "E:/my-game", runId: run1.runId })
await stop_run_instance({ projectPath: "E:/my-game", runId: run2.runId })

重要说明
  1. 始终先调用
    get_capabilities
    来发现适用于你工作流的可用工具
  2. project_update_settings
    及其他修改操作使用
    dryRun: true
    进行试运行
  3. 在请求模式前,先通过
    routeGroup
    transport
    toolNames
    过滤
    get_capabilities
  4. WebSocket桥接按需开启,空闲时会释放(除非运行时处于活跃状态)
  5. 使用
    projectPath
    context
    sessionId
    runId
    区分不同目标
  6. 运行时路由要求项目已运行且自动加载已注册
  7. 编辑器路由要求Godot编辑器已打开且插件已启用
  8. 生产环境使用时,在应用到主项目前,先在单独分支/备份中测试修改内容