godot-devtool-mcp-server
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseGodot Devtool MCP Server
Godot Devtool MCP 服务器
Skill by ara.so — Devtools Skills collection.
godot-devtool由 ara.so 开发的Skill — 开发工具Skill合集。
godot-devtoolArchitecture 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 build2. 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:
- : Path to Godot executable (optional if
GODOT_PATHis in PATH)godot - : WebSocket bridge port (default: 8766)
GODOT_DEVTOOL_WS_PORT
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可执行文件路径(若
GODOT_PATH已在PATH中则可选)godot - :WebSocket桥接端口(默认:8766)
GODOT_DEVTOOL_WS_PORT
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:
- Open your project
- Go to Project → Project Settings → Plugins
- 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中操作:
- 打开你的项目
- 进入 项目 → 项目设置 → 插件
- 启用 godot-devtool
对于运行时路由,插件还会注册:
autoload/DevtoolRuntime = *res://addons/godot_devtool/runtime_bridge.gdCore Concepts
核心概念
Sessions and Context
会话与上下文
Tools use , , , and to identify targets:
projectPathcontextsessionIdrunId- projectPath: Absolute path to Godot project directory
- context: or
editorruntime - sessionId: Disambiguate multiple editor/runtime connections
- runId: Track specific game instances from
run_project
工具通过、、和识别目标:
projectPathcontextsessionIdrunId- projectPath:Godot项目目录的绝对路径
- context:(编辑器)或
editor(运行时)runtime - sessionId:区分多个编辑器/运行时连接
- runId:跟踪启动的特定游戏实例
run_project
Tool Discovery
工具发现
Use to discover tools and filter by workflow:
get_capabilitiestypescript
// 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_setuplive_editorruntime_testmulti_instancerelease_verify使用发现工具并按工作流过滤:
get_capabilitiestypescript
// 轻量级目录(无模式)
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_setuplive_editorruntime_testmulti_instancerelease_verifyBridge Lifecycle
桥接生命周期
- Bridge port opens on demand when editor/runtime tools are called
- Port stays open while:
- is active
run_project - Editor or runtime client is connected
- Port releases after tool cleanup if no active sessions
- Use and
plugin_statusto inspect/manage the bridgeplugin_cleanup_port
- 当调用编辑器/运行时工具时,桥接端口会按需开启
- 端口在以下情况保持开启:
- 处于活跃状态
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
环境变量
- : Path to Godot executable (required if not in PATH)
GODOT_PATH - : WebSocket bridge port (default: 8766)
GODOT_DEVTOOL_WS_PORT
- :Godot可执行文件路径(若不在PATH中则必填)
GODOT_PATH - :WebSocket桥接端口(默认:8766)
GODOT_DEVTOOL_WS_PORT
Project Settings Integration
项目设置集成
The MCP server reads and writes using native Godot syntax:
project.godottypescript
// 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.godottypescript
// 添加自动加载
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
运行时桥接不可用
- Ensure the plugin is installed and enabled
- Verify autoload registration:
typescript
get_autoload({ projectPath: "E:/my-game", name: "DevtoolRuntime" }) - Run the project from Godot (or use )
run_project - Check bridge status:
typescript
plugin_status({ projectPath: "E:/my-game" })
- 确保插件已安装并启用
- 验证自动加载注册:
typescript
get_autoload({ projectPath: "E:/my-game", name: "DevtoolRuntime" }) - 从Godot运行项目(或使用)
run_project - 检查桥接状态:
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 requests:
get_capabilitiestypescript
// 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_capabilitiestypescript
// 不推荐:返回全部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:
- Always call first to discover available tools for your workflow
get_capabilities - Use for
dryRun: trueand other mutation operationsproject_update_settings - Filter by
get_capabilities,routeGroup, ortransportbefore requesting schemastoolNames - The WebSocket bridge opens on-demand and releases when idle (unless runtime is active)
- Use ,
projectPath,context, andsessionIdto disambiguate targetsrunId - Runtime routes require the project to be running with the autoload registered
- Editor routes require the Godot editor to be open with the plugin enabled
- 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 })重要说明:
- 始终先调用来发现适用于你工作流的可用工具
get_capabilities - 对及其他修改操作使用
project_update_settings进行试运行dryRun: true - 在请求模式前,先通过、
routeGroup或transport过滤toolNamesget_capabilities - WebSocket桥接按需开启,空闲时会释放(除非运行时处于活跃状态)
- 使用、
projectPath、context和sessionId区分不同目标runId - 运行时路由要求项目已运行且自动加载已注册
- 编辑器路由要求Godot编辑器已打开且插件已启用
- 生产环境使用时,在应用到主项目前,先在单独分支/备份中测试修改内容