Files
server-deploy/windows-dev-stack/godot-mcp-pro-v1.14.1/server/build/tools/batch-tools.js
Joywayer dd3eb24d0f refactor: 拆分 claude-dev-stack 为 windows-dev-stack 和 wsl-dev-stack
将原 claude-dev-stack 目录拆分为独立的 Windows 和 WSL 部署栈,便于分别维护和使用。

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-05-29 01:11:20 +08:00

97 lines
6.3 KiB
JavaScript

import { z } from "zod";
import { formatErrorForMcp } from "../utils/errors.js";
export function registerBatchTools(server, godot) {
server.tool("find_nodes_by_type", "Find all nodes of a specific type in the current scene", {
type: z.string().describe("Node type/class to search for (e.g. 'Sprite2D', 'Label', 'CollisionShape2D')"),
recursive: z.boolean().optional().describe("Search recursively through children (default: true)"),
}, async (params) => {
try {
const result = await godot.sendCommand("find_nodes_by_type", params);
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
}
catch (e) {
return { content: [{ type: "text", text: formatErrorForMcp(e) }], isError: true };
}
});
server.tool("find_signal_connections", "Find all signal connections in the current scene, optionally filtered by signal name or node", {
signal_name: z.string().optional().describe("Filter by signal name (partial match)"),
node_path: z.string().optional().describe("Filter by node path (partial match)"),
}, async (params) => {
try {
const result = await godot.sendCommand("find_signal_connections", params);
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
}
catch (e) {
return { content: [{ type: "text", text: formatErrorForMcp(e) }], isError: true };
}
});
server.tool("batch_set_property", "Set a property on all nodes of a given type in the current scene", {
type: z.string().describe("Node type to target (e.g. 'Label', 'Sprite2D')"),
property: z.string().describe("Property name to set (e.g. 'visible', 'modulate')"),
value: z.union([z.string(), z.number(), z.boolean()]).describe("Value to set. Strings auto-parsed for Vector2, Color, etc."),
}, async (params) => {
try {
const result = await godot.sendCommand("batch_set_property", params);
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
}
catch (e) {
return { content: [{ type: "text", text: formatErrorForMcp(e) }], isError: true };
}
});
server.tool("batch_add_nodes", "Add multiple nodes in a single call. Supports building entire node trees at once — nodes added earlier can be referenced as parents by later entries. Much faster than calling add_node repeatedly.", {
nodes: z.array(z.object({
type: z.string().describe("Node type (e.g. 'Sprite2D', 'CharacterBody2D', 'Label')"),
parent_path: z.string().optional().describe("Parent node path (default: root '.'). Can reference nodes created earlier in this batch."),
name: z.string().optional().describe("Node name"),
properties: z.record(z.string(), z.any()).optional().describe("Properties to set (e.g. {\"position\": \"Vector2(100, 200)\"})"),
})).describe("Array of node definitions to add, processed in order"),
}, async (params) => {
try {
const result = await godot.sendCommand("batch_add_nodes", params);
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
}
catch (e) {
return { content: [{ type: "text", text: formatErrorForMcp(e) }], isError: true };
}
});
server.tool("find_node_references", "Search through project files (.tscn, .gd, .tres, .gdshader) for a text pattern", {
pattern: z.string().describe("Text pattern to search for"),
}, async (params) => {
try {
const result = await godot.sendCommand("find_node_references", params);
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
}
catch (e) {
return { content: [{ type: "text", text: formatErrorForMcp(e) }], isError: true };
}
});
server.tool("get_scene_dependencies", "Get all resource dependencies of a scene or resource file", {
path: z.string().describe("Path to the scene or resource file (e.g. 'res://scenes/player.tscn')"),
}, async (params) => {
try {
const result = await godot.sendCommand("get_scene_dependencies", params);
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
}
catch (e) {
return { content: [{ type: "text", text: formatErrorForMcp(e) }], isError: true };
}
});
server.tool("cross_scene_set_property", "Preview or apply a property change on all nodes of a given type across scene files in the project. Defaults to dry_run=true (returns the matching scenes and node paths without writing). To actually apply: pass force=true AND dry_run=false. Inactive open scenes are skipped and reported in skipped_open_scenes — open them as the active tab first to live-edit. The active open scene is live-edited via UndoRedo so changes are visible in the editor and undoable. Closed scenes are offline-saved. The response includes a per-scene `mode` field: dry_run / offline_saved / live_open_scene.", {
type: z.string().describe("Node type to target (e.g. 'Label', 'Sprite2D')"),
property: z.string().describe("Property name to set"),
value: z.union([z.string(), z.number(), z.boolean()]).describe("Value to set. Strings auto-parsed for Vector2, Color, etc."),
path_filter: z.string().optional().describe("Directory to search in (default: 'res://')"),
exclude_addons: z.boolean().optional().describe("Exclude addons/ directory (default: true)"),
dry_run: z.boolean().optional().describe("Preview only — list affected scenes and nodes without writing. Defaults to true unless force=true is set."),
force: z.boolean().optional().describe("Required (alongside dry_run=false) to actually write. Acknowledges that this can modify many scene files at once."),
}, async (params) => {
try {
const result = await godot.sendCommand("cross_scene_set_property", params);
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
}
catch (e) {
return { content: [{ type: "text", text: formatErrorForMcp(e) }], isError: true };
}
});
}
//# sourceMappingURL=batch-tools.js.map