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>
This commit is contained in:
4
wsl-dev-stack/godot-mcp-pro-v1.14.1/server/build/tools/analysis-tools.d.ts
vendored
Normal file
4
wsl-dev-stack/godot-mcp-pro-v1.14.1/server/build/tools/analysis-tools.d.ts
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
||||
import { GodotConnection } from "../godot-connection.js";
|
||||
export declare function registerAnalysisTools(server: McpServer, godot: GodotConnection): void;
|
||||
//# sourceMappingURL=analysis-tools.d.ts.map
|
||||
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"analysis-tools.d.ts","sourceRoot":"","sources":["../../src/tools/analysis-tools.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAEpE,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAGzD,wBAAgB,qBAAqB,CACnC,MAAM,EAAE,SAAS,EACjB,KAAK,EAAE,eAAe,GACrB,IAAI,CAmGN"}
|
||||
@@ -0,0 +1,74 @@
|
||||
import { z } from "zod";
|
||||
import { formatErrorForMcp } from "../utils/errors.js";
|
||||
export function registerAnalysisTools(server, godot) {
|
||||
server.tool("find_unused_resources", "Scan the project for resource files (.tres, .tscn, .png, .wav, .ogg, .ttf, .gdshader, etc.) that are not referenced by any .tscn, .gd, or .tres file. Useful for cleaning up unused assets.", {
|
||||
path: z.string().optional().describe("Root path to scan (default: res://)"),
|
||||
include_addons: z.boolean().optional().describe("Include addons/ directory in scan (default: false)"),
|
||||
}, async (params) => {
|
||||
try {
|
||||
const result = await godot.sendCommand("find_unused_resources", params);
|
||||
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
||||
}
|
||||
catch (e) {
|
||||
return { content: [{ type: "text", text: formatErrorForMcp(e) }], isError: true };
|
||||
}
|
||||
});
|
||||
server.tool("analyze_signal_flow", "Map all signal connections in the currently edited scene. Returns a graph-like structure showing which nodes emit which signals and which nodes receive them.", {}, async () => {
|
||||
try {
|
||||
const result = await godot.sendCommand("analyze_signal_flow");
|
||||
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
||||
}
|
||||
catch (e) {
|
||||
return { content: [{ type: "text", text: formatErrorForMcp(e) }], isError: true };
|
||||
}
|
||||
});
|
||||
server.tool("analyze_scene_complexity", "Analyze a scene's complexity: total node count, max nesting depth, nodes grouped by type, attached scripts, and potential issues (too many nodes, deep nesting).", {
|
||||
path: z.string().optional().describe("Scene path to analyze (default: currently edited scene)"),
|
||||
}, async (params) => {
|
||||
try {
|
||||
const result = await godot.sendCommand("analyze_scene_complexity", 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_script_references", "Find all places where a given script path, class_name, or resource path is referenced across the project. Searches .tscn, .gd, and .tres files.", {
|
||||
query: z.string().describe("The script path, class_name, or resource path to search for (e.g. 'res://scripts/player.gd', 'PlayerController', 'res://assets/icon.png')"),
|
||||
path: z.string().optional().describe("Root path to search (default: res://)"),
|
||||
include_addons: z.boolean().optional().describe("Include addons/ directory in search (default: false)"),
|
||||
}, async (params) => {
|
||||
try {
|
||||
const result = await godot.sendCommand("find_script_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("detect_circular_dependencies", "Check for circular scene dependencies where Scene A instances Scene B which instances Scene A (directly or indirectly). Walks all .tscn files and builds a dependency graph.", {
|
||||
path: z.string().optional().describe("Root path to scan (default: res://)"),
|
||||
include_addons: z.boolean().optional().describe("Include addons/ directory in scan (default: false)"),
|
||||
}, async (params) => {
|
||||
try {
|
||||
const result = await godot.sendCommand("detect_circular_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("get_project_statistics", "Get overall project statistics: file counts by extension, total script lines, scene count, resource count, autoload list, and enabled plugins.", {
|
||||
path: z.string().optional().describe("Root path to scan (default: res://)"),
|
||||
include_addons: z.boolean().optional().describe("Include addons/ directory in statistics (default: false)"),
|
||||
}, async (params) => {
|
||||
try {
|
||||
const result = await godot.sendCommand("get_project_statistics", params);
|
||||
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
||||
}
|
||||
catch (e) {
|
||||
return { content: [{ type: "text", text: formatErrorForMcp(e) }], isError: true };
|
||||
}
|
||||
});
|
||||
}
|
||||
//# sourceMappingURL=analysis-tools.js.map
|
||||
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"analysis-tools.js","sourceRoot":"","sources":["../../src/tools/analysis-tools.ts"],"names":[],"mappings":"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"}
|
||||
4
wsl-dev-stack/godot-mcp-pro-v1.14.1/server/build/tools/android-tools.d.ts
vendored
Normal file
4
wsl-dev-stack/godot-mcp-pro-v1.14.1/server/build/tools/android-tools.d.ts
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
||||
import { GodotConnection } from "../godot-connection.js";
|
||||
export declare function registerAndroidTools(server: McpServer, godot: GodotConnection): void;
|
||||
//# sourceMappingURL=android-tools.d.ts.map
|
||||
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"android-tools.d.ts","sourceRoot":"","sources":["../../src/tools/android-tools.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAEpE,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAGzD,wBAAgB,oBAAoB,CAClC,MAAM,EAAE,SAAS,EACjB,KAAK,EAAE,eAAe,GACrB,IAAI,CAoDN"}
|
||||
@@ -0,0 +1,42 @@
|
||||
import { z } from "zod";
|
||||
import { formatErrorForMcp } from "../utils/errors.js";
|
||||
export function registerAndroidTools(server, godot) {
|
||||
server.tool("list_android_devices", "List Android devices visible to adb (parses 'adb devices -l'). Uses the path configured in Editor Settings > Export > Android > Adb, falls back to 'adb' on PATH.", {}, async () => {
|
||||
try {
|
||||
const result = await godot.sendCommand("list_android_devices");
|
||||
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
||||
}
|
||||
catch (e) {
|
||||
return { content: [{ type: "text", text: formatErrorForMcp(e) }], isError: true };
|
||||
}
|
||||
});
|
||||
server.tool("get_android_preset_info", "Read metadata (package name, export path, runnable flag) from an Android export preset in export_presets.cfg. If no preset is specified, returns the first Android preset.", {
|
||||
preset_name: z.string().optional().describe("Preset name as shown in Project > Export"),
|
||||
preset_index: z.number().optional().describe("Preset index (alternative to name)"),
|
||||
}, async (params) => {
|
||||
try {
|
||||
const result = await godot.sendCommand("get_android_preset_info", params);
|
||||
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
||||
}
|
||||
catch (e) {
|
||||
return { content: [{ type: "text", text: formatErrorForMcp(e) }], isError: true };
|
||||
}
|
||||
});
|
||||
server.tool("deploy_to_android", "Export APK via Godot CLI, install it on a connected Android device via adb, and optionally launch the main activity. Equivalent to Godot's Remote Deploy button. Requires a configured Android export preset and adb on PATH (or set in Editor Settings). This call is synchronous and may take tens of seconds to complete.", {
|
||||
preset_name: z.string().optional().describe("Android export preset name (defaults to first Android preset)"),
|
||||
preset_index: z.number().optional().describe("Preset index (alternative to name)"),
|
||||
device_serial: z.string().optional().describe("adb device serial (omit to use default device)"),
|
||||
debug: z.boolean().optional().describe("Debug export (default: true)"),
|
||||
launch: z.boolean().optional().describe("Launch the app after install (default: true)"),
|
||||
skip_export: z.boolean().optional().describe("Skip the export step and install the existing APK at the preset's export_path (default: false)"),
|
||||
}, async (params) => {
|
||||
try {
|
||||
const result = await godot.sendCommand("deploy_to_android", params);
|
||||
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
||||
}
|
||||
catch (e) {
|
||||
return { content: [{ type: "text", text: formatErrorForMcp(e) }], isError: true };
|
||||
}
|
||||
});
|
||||
}
|
||||
//# sourceMappingURL=android-tools.js.map
|
||||
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"android-tools.js","sourceRoot":"","sources":["../../src/tools/android-tools.ts"],"names":[],"mappings":"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"}
|
||||
4
wsl-dev-stack/godot-mcp-pro-v1.14.1/server/build/tools/animation-tools.d.ts
vendored
Normal file
4
wsl-dev-stack/godot-mcp-pro-v1.14.1/server/build/tools/animation-tools.d.ts
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
||||
import { GodotConnection } from "../godot-connection.js";
|
||||
export declare function registerAnimationTools(server: McpServer, godot: GodotConnection): void;
|
||||
//# sourceMappingURL=animation-tools.d.ts.map
|
||||
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"animation-tools.d.ts","sourceRoot":"","sources":["../../src/tools/animation-tools.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAEpE,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAGzD,wBAAgB,sBAAsB,CACpC,MAAM,EAAE,SAAS,EACjB,KAAK,EAAE,eAAe,GACrB,IAAI,CA8GN"}
|
||||
@@ -0,0 +1,85 @@
|
||||
import { z } from "zod";
|
||||
import { formatErrorForMcp } from "../utils/errors.js";
|
||||
export function registerAnimationTools(server, godot) {
|
||||
server.tool("list_animations", "List all animations in an AnimationPlayer node", {
|
||||
node_path: z.string().describe("Path to the AnimationPlayer node"),
|
||||
}, async (params) => {
|
||||
try {
|
||||
const result = await godot.sendCommand("list_animations", params);
|
||||
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
||||
}
|
||||
catch (e) {
|
||||
return { content: [{ type: "text", text: formatErrorForMcp(e) }], isError: true };
|
||||
}
|
||||
});
|
||||
server.tool("create_animation", "Create a new animation in an AnimationPlayer", {
|
||||
node_path: z.string().describe("Path to the AnimationPlayer node"),
|
||||
name: z.string().describe("Name for the new animation"),
|
||||
length: z.number().optional().describe("Animation length in seconds (default: 1.0)"),
|
||||
loop_mode: z.number().optional().describe("Loop mode: 0=none, 1=linear, 2=pingpong (default: 0)"),
|
||||
}, async (params) => {
|
||||
try {
|
||||
const result = await godot.sendCommand("create_animation", params);
|
||||
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
||||
}
|
||||
catch (e) {
|
||||
return { content: [{ type: "text", text: formatErrorForMcp(e) }], isError: true };
|
||||
}
|
||||
});
|
||||
server.tool("add_animation_track", "Add a track to an animation (value, position, rotation, scale, method, bezier)", {
|
||||
node_path: z.string().describe("Path to the AnimationPlayer node"),
|
||||
animation: z.string().describe("Animation name"),
|
||||
track_path: z.string().describe("Node path and property for the track (e.g. 'Sprite2D:position')"),
|
||||
track_type: z.string().optional().describe("Track type: value, position_2d, rotation_2d, scale_2d, method, bezier, blend_shape (default: value)"),
|
||||
update_mode: z.string().optional().describe("Update mode for value tracks: continuous, discrete, capture"),
|
||||
}, async (params) => {
|
||||
try {
|
||||
const result = await godot.sendCommand("add_animation_track", params);
|
||||
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
||||
}
|
||||
catch (e) {
|
||||
return { content: [{ type: "text", text: formatErrorForMcp(e) }], isError: true };
|
||||
}
|
||||
});
|
||||
server.tool("set_animation_keyframe", "Insert a keyframe into an animation track", {
|
||||
node_path: z.string().describe("Path to the AnimationPlayer node"),
|
||||
animation: z.string().describe("Animation name"),
|
||||
track_index: z.number().describe("Track index"),
|
||||
time: z.number().describe("Time position in seconds"),
|
||||
value: z.union([z.string(), z.number(), z.boolean()]).describe("Keyframe value. Strings auto-parsed for Vector2, Color, etc."),
|
||||
easing: z.number().optional().describe("Easing/transition value. 1.0=linear, <1.0=ease-in, >1.0=ease-out. Use negative for in-out variants. (default: 1.0)"),
|
||||
}, async (params) => {
|
||||
try {
|
||||
const result = await godot.sendCommand("set_animation_keyframe", 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_animation_info", "Get detailed info about an animation including all tracks and keyframes", {
|
||||
node_path: z.string().describe("Path to the AnimationPlayer node"),
|
||||
animation: z.string().describe("Animation name"),
|
||||
}, async (params) => {
|
||||
try {
|
||||
const result = await godot.sendCommand("get_animation_info", params);
|
||||
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
||||
}
|
||||
catch (e) {
|
||||
return { content: [{ type: "text", text: formatErrorForMcp(e) }], isError: true };
|
||||
}
|
||||
});
|
||||
server.tool("remove_animation", "Remove an animation from an AnimationPlayer", {
|
||||
node_path: z.string().describe("Path to the AnimationPlayer node"),
|
||||
name: z.string().describe("Name of the animation to remove"),
|
||||
}, async (params) => {
|
||||
try {
|
||||
const result = await godot.sendCommand("remove_animation", params);
|
||||
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
||||
}
|
||||
catch (e) {
|
||||
return { content: [{ type: "text", text: formatErrorForMcp(e) }], isError: true };
|
||||
}
|
||||
});
|
||||
}
|
||||
//# sourceMappingURL=animation-tools.js.map
|
||||
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"animation-tools.js","sourceRoot":"","sources":["../../src/tools/animation-tools.ts"],"names":[],"mappings":"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"}
|
||||
4
wsl-dev-stack/godot-mcp-pro-v1.14.1/server/build/tools/animation-tree-tools.d.ts
vendored
Normal file
4
wsl-dev-stack/godot-mcp-pro-v1.14.1/server/build/tools/animation-tree-tools.d.ts
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
||||
import { GodotConnection } from "../godot-connection.js";
|
||||
export declare function registerAnimationTreeTools(server: McpServer, godot: GodotConnection): void;
|
||||
//# sourceMappingURL=animation-tree-tools.d.ts.map
|
||||
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"animation-tree-tools.d.ts","sourceRoot":"","sources":["../../src/tools/animation-tree-tools.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAEpE,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAGzD,wBAAgB,0BAA0B,CACxC,MAAM,EAAE,SAAS,EACjB,KAAK,EAAE,eAAe,GACrB,IAAI,CA+JN"}
|
||||
@@ -0,0 +1,124 @@
|
||||
import { z } from "zod";
|
||||
import { formatErrorForMcp } from "../utils/errors.js";
|
||||
export function registerAnimationTreeTools(server, godot) {
|
||||
server.tool("create_animation_tree", "Create an AnimationTree node with an AnimationNodeStateMachine as root, optionally linked to an AnimationPlayer", {
|
||||
node_path: z.string().describe("Path to the parent node where the AnimationTree will be added"),
|
||||
anim_player: z.string().optional().describe("Relative path from the AnimationTree to the AnimationPlayer (e.g. '../AnimationPlayer')"),
|
||||
name: z.string().optional().describe("Name for the AnimationTree node (default: 'AnimationTree')"),
|
||||
}, async (params) => {
|
||||
try {
|
||||
const result = await godot.sendCommand("create_animation_tree", 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_animation_tree_structure", "Read the full structure of an AnimationTree including all states, transitions, and blend tree nodes", {
|
||||
node_path: z.string().describe("Path to the AnimationTree node"),
|
||||
}, async (params) => {
|
||||
try {
|
||||
const result = await godot.sendCommand("get_animation_tree_structure", params);
|
||||
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
||||
}
|
||||
catch (e) {
|
||||
return { content: [{ type: "text", text: formatErrorForMcp(e) }], isError: true };
|
||||
}
|
||||
});
|
||||
server.tool("add_state_machine_state", "Add a state to an AnimationNodeStateMachine (animation clip, blend tree, or nested state machine)", {
|
||||
node_path: z.string().describe("Path to the AnimationTree node"),
|
||||
state_name: z.string().describe("Name for the new state"),
|
||||
state_type: z.enum(["animation", "blend_tree", "state_machine"]).optional().describe("Type of state: 'animation' (default), 'blend_tree', or 'state_machine'"),
|
||||
animation: z.string().optional().describe("Animation name to play (only for state_type='animation')"),
|
||||
state_machine_path: z.string().optional().describe("Slash-separated path to a nested state machine (e.g. 'Run/SubState'). Empty or omit for root."),
|
||||
position_x: z.number().optional().describe("X position in the graph editor (default: 0)"),
|
||||
position_y: z.number().optional().describe("Y position in the graph editor (default: 0)"),
|
||||
}, async (params) => {
|
||||
try {
|
||||
const result = await godot.sendCommand("add_state_machine_state", params);
|
||||
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
||||
}
|
||||
catch (e) {
|
||||
return { content: [{ type: "text", text: formatErrorForMcp(e) }], isError: true };
|
||||
}
|
||||
});
|
||||
server.tool("remove_state_machine_state", "Remove a state from an AnimationNodeStateMachine (also removes connected transitions)", {
|
||||
node_path: z.string().describe("Path to the AnimationTree node"),
|
||||
state_name: z.string().describe("Name of the state to remove"),
|
||||
state_machine_path: z.string().optional().describe("Slash-separated path to a nested state machine. Empty or omit for root."),
|
||||
}, async (params) => {
|
||||
try {
|
||||
const result = await godot.sendCommand("remove_state_machine_state", params);
|
||||
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
||||
}
|
||||
catch (e) {
|
||||
return { content: [{ type: "text", text: formatErrorForMcp(e) }], isError: true };
|
||||
}
|
||||
});
|
||||
server.tool("add_state_machine_transition", "Add a transition between two states in an AnimationNodeStateMachine with configurable switch mode, advance mode, and expression conditions", {
|
||||
node_path: z.string().describe("Path to the AnimationTree node"),
|
||||
from_state: z.string().describe("Source state name (use 'Start' for the entry point)"),
|
||||
to_state: z.string().describe("Destination state name (use 'End' for the exit point)"),
|
||||
switch_mode: z.enum(["at_end", "immediate", "sync"]).optional().describe("When to switch: 'at_end' (wait for animation), 'immediate' (default), 'sync'"),
|
||||
advance_mode: z.enum(["disabled", "enabled", "auto"]).optional().describe("How to advance: 'disabled', 'enabled' (default, uses travel), 'auto' (automatic)"),
|
||||
advance_expression: z.string().optional().describe("GDScript expression that triggers this transition (e.g. 'is_running')"),
|
||||
xfade_time: z.number().optional().describe("Cross-fade time in seconds"),
|
||||
state_machine_path: z.string().optional().describe("Slash-separated path to a nested state machine. Empty or omit for root."),
|
||||
}, async (params) => {
|
||||
try {
|
||||
const result = await godot.sendCommand("add_state_machine_transition", params);
|
||||
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
||||
}
|
||||
catch (e) {
|
||||
return { content: [{ type: "text", text: formatErrorForMcp(e) }], isError: true };
|
||||
}
|
||||
});
|
||||
server.tool("remove_state_machine_transition", "Remove a transition between two states in an AnimationNodeStateMachine", {
|
||||
node_path: z.string().describe("Path to the AnimationTree node"),
|
||||
from_state: z.string().describe("Source state name"),
|
||||
to_state: z.string().describe("Destination state name"),
|
||||
state_machine_path: z.string().optional().describe("Slash-separated path to a nested state machine. Empty or omit for root."),
|
||||
}, async (params) => {
|
||||
try {
|
||||
const result = await godot.sendCommand("remove_state_machine_transition", params);
|
||||
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
||||
}
|
||||
catch (e) {
|
||||
return { content: [{ type: "text", text: formatErrorForMcp(e) }], isError: true };
|
||||
}
|
||||
});
|
||||
server.tool("set_blend_tree_node", "Add or replace a node inside an AnimationNodeBlendTree state (Add2, Blend2, TimeScale, Animation, etc.) with optional connection", {
|
||||
node_path: z.string().describe("Path to the AnimationTree node"),
|
||||
blend_tree_state: z.string().describe("Name of the BlendTree state in the state machine"),
|
||||
bt_node_name: z.string().describe("Name for the node inside the BlendTree"),
|
||||
bt_node_type: z.enum(["Animation", "Add2", "Blend2", "Add3", "Blend3", "TimeScale", "TimeSeek", "Transition", "OneShot", "Sub2"]).describe("Type of BlendTree node to create"),
|
||||
animation: z.string().optional().describe("Animation name (only for bt_node_type='Animation')"),
|
||||
connect_to: z.string().optional().describe("Name of another BlendTree node to connect this node's output to"),
|
||||
connect_port: z.number().optional().describe("Input port index on the target node (default: 0)"),
|
||||
state_machine_path: z.string().optional().describe("Slash-separated path to a nested state machine. Empty or omit for root."),
|
||||
position_x: z.number().optional().describe("X position in the graph editor (default: 0)"),
|
||||
position_y: z.number().optional().describe("Y position in the graph editor (default: 0)"),
|
||||
}, async (params) => {
|
||||
try {
|
||||
const result = await godot.sendCommand("set_blend_tree_node", params);
|
||||
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
||||
}
|
||||
catch (e) {
|
||||
return { content: [{ type: "text", text: formatErrorForMcp(e) }], isError: true };
|
||||
}
|
||||
});
|
||||
server.tool("set_tree_parameter", "Set an AnimationTree parameter value (conditions, blend amounts, time scale, etc.)", {
|
||||
node_path: z.string().describe("Path to the AnimationTree node"),
|
||||
parameter: z.string().describe("Parameter path (e.g. 'conditions/is_running', 'Blend2/blend_amount'). 'parameters/' prefix is auto-added if missing."),
|
||||
value: z.union([z.string(), z.number(), z.boolean()]).describe("Parameter value. Strings are auto-parsed for Vector2, Color, etc."),
|
||||
}, async (params) => {
|
||||
try {
|
||||
const result = await godot.sendCommand("set_tree_parameter", params);
|
||||
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
||||
}
|
||||
catch (e) {
|
||||
return { content: [{ type: "text", text: formatErrorForMcp(e) }], isError: true };
|
||||
}
|
||||
});
|
||||
}
|
||||
//# sourceMappingURL=animation-tree-tools.js.map
|
||||
File diff suppressed because one or more lines are too long
4
wsl-dev-stack/godot-mcp-pro-v1.14.1/server/build/tools/audio-tools.d.ts
vendored
Normal file
4
wsl-dev-stack/godot-mcp-pro-v1.14.1/server/build/tools/audio-tools.d.ts
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
||||
import { GodotConnection } from "../godot-connection.js";
|
||||
export declare function registerAudioTools(server: McpServer, godot: GodotConnection): void;
|
||||
//# sourceMappingURL=audio-tools.d.ts.map
|
||||
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"audio-tools.d.ts","sourceRoot":"","sources":["../../src/tools/audio-tools.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAEpE,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAGzD,wBAAgB,kBAAkB,CAChC,MAAM,EAAE,SAAS,EACjB,KAAK,EAAE,eAAe,GACrB,IAAI,CAsHN"}
|
||||
@@ -0,0 +1,93 @@
|
||||
import { z } from "zod";
|
||||
import { formatErrorForMcp } from "../utils/errors.js";
|
||||
export function registerAudioTools(server, godot) {
|
||||
server.tool("get_audio_bus_layout", "Get the entire audio bus layout: all buses with volumes, effects, send targets, solo/mute states", {}, async (params) => {
|
||||
try {
|
||||
const result = await godot.sendCommand("get_audio_bus_layout", params);
|
||||
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
||||
}
|
||||
catch (e) {
|
||||
return { content: [{ type: "text", text: formatErrorForMcp(e) }], isError: true };
|
||||
}
|
||||
});
|
||||
server.tool("add_audio_bus", "Add a new audio bus with name, volume, send target, solo, and mute settings", {
|
||||
name: z.string().describe("Name for the new audio bus"),
|
||||
volume_db: z.number().optional().describe("Volume in dB (default: 0)"),
|
||||
send: z.string().optional().describe("Name of the bus to send output to (e.g. 'Master')"),
|
||||
solo: z.boolean().optional().describe("Solo this bus (default: false)"),
|
||||
mute: z.boolean().optional().describe("Mute this bus (default: false)"),
|
||||
at_position: z.number().optional().describe("Bus index position to insert at (-1 = end)"),
|
||||
}, async (params) => {
|
||||
try {
|
||||
const result = await godot.sendCommand("add_audio_bus", params);
|
||||
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
||||
}
|
||||
catch (e) {
|
||||
return { content: [{ type: "text", text: formatErrorForMcp(e) }], isError: true };
|
||||
}
|
||||
});
|
||||
server.tool("set_audio_bus", "Modify an existing audio bus: volume, solo, mute, bypass_effects, send, or rename", {
|
||||
name: z.string().describe("Name of the audio bus to modify"),
|
||||
volume_db: z.number().optional().describe("Volume in dB"),
|
||||
solo: z.boolean().optional().describe("Solo state"),
|
||||
mute: z.boolean().optional().describe("Mute state"),
|
||||
bypass_effects: z.boolean().optional().describe("Bypass all effects on this bus"),
|
||||
send: z.string().optional().describe("Name of the bus to send output to"),
|
||||
rename: z.string().optional().describe("New name for the bus"),
|
||||
}, async (params) => {
|
||||
try {
|
||||
const result = await godot.sendCommand("set_audio_bus", params);
|
||||
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
||||
}
|
||||
catch (e) {
|
||||
return { content: [{ type: "text", text: formatErrorForMcp(e) }], isError: true };
|
||||
}
|
||||
});
|
||||
server.tool("add_audio_bus_effect", "Add an audio effect to a bus. Types: reverb, chorus, delay, compressor, limiter, phaser, distortion, lowpassfilter, highpassfilter, bandpassfilter, amplify, eq", {
|
||||
bus: z.string().describe("Name of the audio bus"),
|
||||
effect_type: z.string().describe("Effect type: reverb, chorus, delay, compressor, limiter, phaser, distortion, lowpassfilter (or lowpass), highpassfilter (or highpass), bandpassfilter (or bandpass), amplify, eq"),
|
||||
params: z.record(z.string(), z.union([z.string(), z.number(), z.boolean()])).optional().describe("Effect-specific parameters. E.g. for reverb: {room_size, damping, wet, dry, spread}; for compressor: {threshold, ratio, attack_us, release_ms}; for filters: {cutoff_hz, resonance}"),
|
||||
at_position: z.number().optional().describe("Effect index position (-1 = end)"),
|
||||
}, async (params) => {
|
||||
try {
|
||||
const result = await godot.sendCommand("add_audio_bus_effect", params);
|
||||
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
||||
}
|
||||
catch (e) {
|
||||
return { content: [{ type: "text", text: formatErrorForMcp(e) }], isError: true };
|
||||
}
|
||||
});
|
||||
server.tool("add_audio_player", "Add an AudioStreamPlayer, AudioStreamPlayer2D, or AudioStreamPlayer3D node to a parent node", {
|
||||
node_path: z.string().describe("Path to the parent node"),
|
||||
name: z.string().describe("Name for the new audio player node"),
|
||||
type: z.string().optional().describe("Player type: AudioStreamPlayer (default), AudioStreamPlayer2D, AudioStreamPlayer3D"),
|
||||
stream: z.string().optional().describe("Path to audio resource (e.g. 'res://audio/music.ogg')"),
|
||||
volume_db: z.number().optional().describe("Volume in dB (default: 0)"),
|
||||
bus: z.string().optional().describe("Audio bus name (default: 'Master')"),
|
||||
autoplay: z.boolean().optional().describe("Auto-play when scene starts (default: false)"),
|
||||
max_distance: z.number().optional().describe("Maximum hearing distance (for 2D/3D players)"),
|
||||
attenuation: z.number().optional().describe("Distance attenuation factor (for 2D players)"),
|
||||
attenuation_model: z.number().optional().describe("Attenuation model for 3D: 0=inverse_distance, 1=inverse_square, 2=logarithmic"),
|
||||
unit_size: z.number().optional().describe("Unit size for 3D player volume reference"),
|
||||
}, async (params) => {
|
||||
try {
|
||||
const result = await godot.sendCommand("add_audio_player", 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_audio_info", "Get audio setup for a node subtree: finds all AudioStreamPlayer nodes with their settings, streams, and bus assignments", {
|
||||
node_path: z.string().describe("Path to the root node to search within"),
|
||||
}, async (params) => {
|
||||
try {
|
||||
const result = await godot.sendCommand("get_audio_info", params);
|
||||
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
||||
}
|
||||
catch (e) {
|
||||
return { content: [{ type: "text", text: formatErrorForMcp(e) }], isError: true };
|
||||
}
|
||||
});
|
||||
}
|
||||
//# sourceMappingURL=audio-tools.js.map
|
||||
File diff suppressed because one or more lines are too long
4
wsl-dev-stack/godot-mcp-pro-v1.14.1/server/build/tools/batch-tools.d.ts
vendored
Normal file
4
wsl-dev-stack/godot-mcp-pro-v1.14.1/server/build/tools/batch-tools.d.ts
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
||||
import { GodotConnection } from "../godot-connection.js";
|
||||
export declare function registerBatchTools(server: McpServer, godot: GodotConnection): void;
|
||||
//# sourceMappingURL=batch-tools.d.ts.map
|
||||
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"batch-tools.d.ts","sourceRoot":"","sources":["../../src/tools/batch-tools.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAEpE,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAGzD,wBAAgB,kBAAkB,CAChC,MAAM,EAAE,SAAS,EACjB,KAAK,EAAE,eAAe,GACrB,IAAI,CA+HN"}
|
||||
@@ -0,0 +1,97 @@
|
||||
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
|
||||
File diff suppressed because one or more lines are too long
4
wsl-dev-stack/godot-mcp-pro-v1.14.1/server/build/tools/editor-tools.d.ts
vendored
Normal file
4
wsl-dev-stack/godot-mcp-pro-v1.14.1/server/build/tools/editor-tools.d.ts
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
||||
import { GodotConnection } from "../godot-connection.js";
|
||||
export declare function registerEditorTools(server: McpServer, godot: GodotConnection): void;
|
||||
//# sourceMappingURL=editor-tools.d.ts.map
|
||||
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"editor-tools.d.ts","sourceRoot":"","sources":["../../src/tools/editor-tools.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAEpE,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAGzD,wBAAgB,mBAAmB,CACjC,MAAM,EAAE,SAAS,EACjB,KAAK,EAAE,eAAe,GACrB,IAAI,CA2SN"}
|
||||
@@ -0,0 +1,231 @@
|
||||
import { z } from "zod";
|
||||
import { formatErrorForMcp } from "../utils/errors.js";
|
||||
export function registerEditorTools(server, godot) {
|
||||
server.tool("get_editor_errors", "Get recent errors and stack traces from the Godot editor log", {
|
||||
max_lines: z.number().optional().describe("Maximum log lines to scan for errors (default: 50)"),
|
||||
}, async (params) => {
|
||||
try {
|
||||
const result = await godot.sendCommand("get_editor_errors", 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_output_log", "Read the full Godot editor Output panel content. Unlike get_editor_errors which filters for errors only, this returns all output including print() statements and warnings.", {
|
||||
max_lines: z.number().optional().describe("Maximum number of lines to return from the end (default: 100)"),
|
||||
filter: z.string().optional().describe("Filter lines containing this substring (case-sensitive)"),
|
||||
}, async (params) => {
|
||||
try {
|
||||
const result = await godot.sendCommand("get_output_log", 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_editor_screenshot", "Capture a screenshot of the Godot editor's 2D/3D viewport", {
|
||||
save_path: z.string().optional().describe("Optional res:// or user:// path to save the screenshot as PNG file (e.g. 'res://screenshot.png'). When provided, the image is saved to disk and the file path is returned instead of base64 data."),
|
||||
}, async (params) => {
|
||||
try {
|
||||
const result = await godot.sendCommand("get_editor_screenshot", params);
|
||||
if (result && typeof result === "object" && "saved_path" in result) {
|
||||
return {
|
||||
content: [
|
||||
{
|
||||
type: "text",
|
||||
text: `Screenshot saved: ${result.saved_path} (${result.width}x${result.height})`,
|
||||
},
|
||||
],
|
||||
};
|
||||
}
|
||||
if (result && typeof result === "object" && "image_base64" in result) {
|
||||
return {
|
||||
content: [
|
||||
{
|
||||
type: "image",
|
||||
data: result.image_base64,
|
||||
mimeType: "image/png",
|
||||
},
|
||||
{
|
||||
type: "text",
|
||||
text: `Screenshot captured: ${result.width}x${result.height}`,
|
||||
},
|
||||
],
|
||||
};
|
||||
}
|
||||
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
||||
}
|
||||
catch (e) {
|
||||
return { content: [{ type: "text", text: formatErrorForMcp(e) }], isError: true };
|
||||
}
|
||||
});
|
||||
server.tool("get_game_screenshot", "Capture a single screenshot of the running game (requires a scene to be playing). Good for checking static visual state (UI layout, scene composition, colors). For verifying animations or movement, use capture_frames instead — a single screenshot cannot confirm whether an animation is playing.", {
|
||||
save_path: z.string().optional().describe("Optional res:// or user:// path to save the screenshot as PNG file (e.g. 'res://screenshot.png'). When provided, the image is saved to disk and the file path is returned instead of base64 data."),
|
||||
}, async (params) => {
|
||||
try {
|
||||
const result = await godot.sendCommand("get_game_screenshot", params);
|
||||
if (result && typeof result === "object" && "saved_path" in result) {
|
||||
return {
|
||||
content: [
|
||||
{
|
||||
type: "text",
|
||||
text: `Game screenshot saved: ${result.saved_path} (${result.width}x${result.height})${result.note ? ` (${result.note})` : ""}`,
|
||||
},
|
||||
],
|
||||
};
|
||||
}
|
||||
if (result && typeof result === "object" && "image_base64" in result) {
|
||||
return {
|
||||
content: [
|
||||
{
|
||||
type: "image",
|
||||
data: result.image_base64,
|
||||
mimeType: "image/png",
|
||||
},
|
||||
{
|
||||
type: "text",
|
||||
text: `Game screenshot: ${result.width}x${result.height}${result.note ? ` (${result.note})` : ""}`,
|
||||
},
|
||||
],
|
||||
};
|
||||
}
|
||||
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
||||
}
|
||||
catch (e) {
|
||||
return { content: [{ type: "text", text: formatErrorForMcp(e) }], isError: true };
|
||||
}
|
||||
});
|
||||
server.tool("execute_editor_script", "Execute arbitrary GDScript code inside the Godot editor. Use _mcp_print() to output values. By default refuses to execute code that contains direct file/resource write APIs (ResourceSaver.save, FileAccess WRITE, ProjectSettings.save, ConfigFile.save, DirAccess filesystem mutations) because those bypass the per-command open-resource guards. Use the dedicated MCP tools (save_scene, create_script, etc.) for those operations, or pass allow_unsafe_editor_io=true ONLY when you have verified no open editor resource will be overwritten.", {
|
||||
code: z.string().describe("GDScript code to execute. Use _mcp_print(value) to capture output. " +
|
||||
"The code runs inside a run() function with access to the full editor API."),
|
||||
allow_unsafe_editor_io: z.boolean().optional().describe("Override the file-write safety guard. Only set this when you are certain no open scene/script/shader will be overwritten by the script. Prefer the dedicated MCP tools for ordinary save flows."),
|
||||
}, async (params) => {
|
||||
try {
|
||||
const result = await godot.sendCommand("execute_editor_script", params);
|
||||
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
||||
}
|
||||
catch (e) {
|
||||
return { content: [{ type: "text", text: formatErrorForMcp(e) }], isError: true };
|
||||
}
|
||||
});
|
||||
server.tool("clear_output", "Clear the Godot editor output panel", {}, async () => {
|
||||
try {
|
||||
const result = await godot.sendCommand("clear_output");
|
||||
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
||||
}
|
||||
catch (e) {
|
||||
return { content: [{ type: "text", text: formatErrorForMcp(e) }], isError: true };
|
||||
}
|
||||
});
|
||||
server.tool("get_signals", "Get all signals of a node, including current connections", {
|
||||
node_path: z.string().describe("Path to the node to inspect"),
|
||||
}, async (params) => {
|
||||
try {
|
||||
const result = await godot.sendCommand("get_signals", params);
|
||||
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
||||
}
|
||||
catch (e) {
|
||||
return { content: [{ type: "text", text: formatErrorForMcp(e) }], isError: true };
|
||||
}
|
||||
});
|
||||
server.tool("reload_plugin", "Reload the Godot MCP Pro plugin (disable/re-enable). Connection will briefly drop and auto-reconnect. NOTE: This does NOT reload GDScript preload() caches. If you changed GDScript command files, use execute_editor_script with 'EditorInterface.restart_editor(true)' instead for a full editor restart.", {}, async () => {
|
||||
try {
|
||||
const result = await godot.sendCommand("reload_plugin");
|
||||
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
||||
}
|
||||
catch (e) {
|
||||
return { content: [{ type: "text", text: formatErrorForMcp(e) }], isError: true };
|
||||
}
|
||||
});
|
||||
server.tool("reload_project", "Rescan the Godot project filesystem and reload changed scripts (no reconnection needed)", {}, async () => {
|
||||
try {
|
||||
const result = await godot.sendCommand("reload_project");
|
||||
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
||||
}
|
||||
catch (e) {
|
||||
return { content: [{ type: "text", text: formatErrorForMcp(e) }], isError: true };
|
||||
}
|
||||
});
|
||||
server.tool("compare_screenshots", "Compare two screenshots pixel-by-pixel and return a diff analysis. Returns changed pixel count, diff percentage, and a highlighted diff image. Useful for visual regression testing. Accepts file paths (res://, user://) or base64 PNG strings.", {
|
||||
image_a: z.string().describe("First image: file path (e.g. 'user://screenshot_a.png') or base64 PNG string"),
|
||||
image_b: z.string().describe("Second image: file path (e.g. 'user://screenshot_b.png') or base64 PNG string"),
|
||||
threshold: z.number().optional().describe("Color difference threshold (0-255, default: 10). Pixels with max channel difference below this are considered identical."),
|
||||
}, async (params) => {
|
||||
try {
|
||||
const result = await godot.sendCommand("compare_screenshots", params);
|
||||
const content = [];
|
||||
// Add summary text
|
||||
content.push({
|
||||
type: "text",
|
||||
text: JSON.stringify({
|
||||
identical: result.identical,
|
||||
changed_pixels: result.changed_pixels,
|
||||
total_pixels: result.total_pixels,
|
||||
diff_percentage: result.diff_percentage,
|
||||
threshold: result.threshold,
|
||||
size: `${result.width}x${result.height}`,
|
||||
}, null, 2),
|
||||
});
|
||||
// Add diff image if there are differences
|
||||
if (result.diff_image_base64 && !result.identical) {
|
||||
content.push({
|
||||
type: "image",
|
||||
data: result.diff_image_base64,
|
||||
mimeType: "image/png",
|
||||
});
|
||||
}
|
||||
return { content };
|
||||
}
|
||||
catch (e) {
|
||||
return { content: [{ type: "text", text: formatErrorForMcp(e) }], isError: true };
|
||||
}
|
||||
});
|
||||
server.tool("set_auto_dismiss", "Enable or disable automatic dismissal of blocking editor dialogs (e.g. 'Reload from disk?', 'Save changes?'). Enable this before operations that modify files externally, and disable when done. Disabled by default.", {
|
||||
enabled: z.boolean().describe("true to enable auto-dismiss, false to disable"),
|
||||
}, async (params) => {
|
||||
try {
|
||||
const result = await godot.sendCommand("set_auto_dismiss", 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_editor_camera", "Get the current 3D editor viewport camera position, rotation, and FOV. Use this to understand the current view before taking editor screenshots.", {}, async () => {
|
||||
try {
|
||||
const result = await godot.sendCommand("get_editor_camera");
|
||||
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
||||
}
|
||||
catch (e) {
|
||||
return { content: [{ type: "text", text: formatErrorForMcp(e) }], isError: true };
|
||||
}
|
||||
});
|
||||
server.tool("set_editor_camera", "Move the 3D editor viewport camera to a specific position and orientation. Use this to frame a view before taking editor screenshots to validate changes visually.", {
|
||||
position: z.object({
|
||||
x: z.number().describe("X position"),
|
||||
y: z.number().describe("Y position"),
|
||||
z: z.number().describe("Z position"),
|
||||
}).optional().describe("Camera world position"),
|
||||
rotation_degrees: z.object({
|
||||
x: z.number().describe("Pitch (degrees)"),
|
||||
y: z.number().describe("Yaw (degrees)"),
|
||||
z: z.number().describe("Roll (degrees)"),
|
||||
}).optional().describe("Camera rotation in degrees"),
|
||||
look_at: z.object({
|
||||
x: z.number().describe("Target X"),
|
||||
y: z.number().describe("Target Y"),
|
||||
z: z.number().describe("Target Z"),
|
||||
}).optional().describe("Point to look at (overrides rotation_degrees if both set)"),
|
||||
fov: z.number().optional().describe("Field of view in degrees (default: 75)"),
|
||||
}, async (params) => {
|
||||
try {
|
||||
const result = await godot.sendCommand("set_editor_camera", params);
|
||||
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
||||
}
|
||||
catch (e) {
|
||||
return { content: [{ type: "text", text: formatErrorForMcp(e) }], isError: true };
|
||||
}
|
||||
});
|
||||
}
|
||||
//# sourceMappingURL=editor-tools.js.map
|
||||
File diff suppressed because one or more lines are too long
4
wsl-dev-stack/godot-mcp-pro-v1.14.1/server/build/tools/export-tools.d.ts
vendored
Normal file
4
wsl-dev-stack/godot-mcp-pro-v1.14.1/server/build/tools/export-tools.d.ts
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
||||
import { GodotConnection } from "../godot-connection.js";
|
||||
export declare function registerExportTools(server: McpServer, godot: GodotConnection): void;
|
||||
//# sourceMappingURL=export-tools.d.ts.map
|
||||
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"export-tools.d.ts","sourceRoot":"","sources":["../../src/tools/export-tools.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAEpE,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAGzD,wBAAgB,mBAAmB,CACjC,MAAM,EAAE,SAAS,EACjB,KAAK,EAAE,eAAe,GACrB,IAAI,CA8CN"}
|
||||
@@ -0,0 +1,36 @@
|
||||
import { z } from "zod";
|
||||
import { formatErrorForMcp } from "../utils/errors.js";
|
||||
export function registerExportTools(server, godot) {
|
||||
server.tool("list_export_presets", "List all export presets configured in export_presets.cfg", {}, async () => {
|
||||
try {
|
||||
const result = await godot.sendCommand("list_export_presets");
|
||||
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
||||
}
|
||||
catch (e) {
|
||||
return { content: [{ type: "text", text: formatErrorForMcp(e) }], isError: true };
|
||||
}
|
||||
});
|
||||
server.tool("export_project", "Get the export command for a preset (direct export from editor is not supported in Godot 4)", {
|
||||
preset_name: z.string().optional().describe("Export preset name"),
|
||||
preset_index: z.number().optional().describe("Export preset index (alternative to name)"),
|
||||
debug: z.boolean().optional().describe("Debug export (default: true)"),
|
||||
}, async (params) => {
|
||||
try {
|
||||
const result = await godot.sendCommand("export_project", 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_export_info", "Get export-related project info (executable path, templates, project path)", {}, async () => {
|
||||
try {
|
||||
const result = await godot.sendCommand("get_export_info");
|
||||
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
||||
}
|
||||
catch (e) {
|
||||
return { content: [{ type: "text", text: formatErrorForMcp(e) }], isError: true };
|
||||
}
|
||||
});
|
||||
}
|
||||
//# sourceMappingURL=export-tools.js.map
|
||||
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"export-tools.js","sourceRoot":"","sources":["../../src/tools/export-tools.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AAEvD,MAAM,UAAU,mBAAmB,CACjC,MAAiB,EACjB,KAAsB;IAEtB,MAAM,CAAC,IAAI,CACT,qBAAqB,EACrB,0DAA0D,EAC1D,EAAE,EACF,KAAK,IAAI,EAAE;QACT,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,MAAM,KAAK,CAAC,WAAW,CAAC,qBAAqB,CAAC,CAAC;YAC9D,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC;QAChF,CAAC;QAAC,OAAO,CAAC,EAAE,CAAC;YACX,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,iBAAiB,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;QACpF,CAAC;IACH,CAAC,CACF,CAAC;IAEF,MAAM,CAAC,IAAI,CACT,gBAAgB,EAChB,6FAA6F,EAC7F;QACE,WAAW,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,oBAAoB,CAAC;QACjE,YAAY,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,2CAA2C,CAAC;QACzF,KAAK,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,8BAA8B,CAAC;KACvE,EACD,KAAK,EAAE,MAAM,EAAE,EAAE;QACf,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,MAAM,KAAK,CAAC,WAAW,CAAC,gBAAgB,EAAE,MAAM,CAAC,CAAC;YACjE,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC;QAChF,CAAC;QAAC,OAAO,CAAC,EAAE,CAAC;YACX,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,iBAAiB,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;QACpF,CAAC;IACH,CAAC,CACF,CAAC;IAEF,MAAM,CAAC,IAAI,CACT,iBAAiB,EACjB,4EAA4E,EAC5E,EAAE,EACF,KAAK,IAAI,EAAE;QACT,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,MAAM,KAAK,CAAC,WAAW,CAAC,iBAAiB,CAAC,CAAC;YAC1D,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC;QAChF,CAAC;QAAC,OAAO,CAAC,EAAE,CAAC;YACX,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,iBAAiB,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;QACpF,CAAC;IACH,CAAC,CACF,CAAC;AACJ,CAAC"}
|
||||
4
wsl-dev-stack/godot-mcp-pro-v1.14.1/server/build/tools/input-map-tools.d.ts
vendored
Normal file
4
wsl-dev-stack/godot-mcp-pro-v1.14.1/server/build/tools/input-map-tools.d.ts
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
||||
import { GodotConnection } from "../godot-connection.js";
|
||||
export declare function registerInputMapTools(server: McpServer, godot: GodotConnection): void;
|
||||
//# sourceMappingURL=input-map-tools.d.ts.map
|
||||
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"input-map-tools.d.ts","sourceRoot":"","sources":["../../src/tools/input-map-tools.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAEpE,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAGzD,wBAAgB,qBAAqB,CACnC,MAAM,EAAE,SAAS,EACjB,KAAK,EAAE,eAAe,GACrB,IAAI,CA8CN"}
|
||||
@@ -0,0 +1,41 @@
|
||||
import { z } from "zod";
|
||||
import { formatErrorForMcp } from "../utils/errors.js";
|
||||
export function registerInputMapTools(server, godot) {
|
||||
server.tool("get_input_actions", "Get all input actions defined in the project's Input Map with their key/button bindings", {
|
||||
filter: z.string().optional().describe("Filter action names containing this substring"),
|
||||
include_builtin: z.boolean().optional().describe("Include built-in ui_* actions (default: false)"),
|
||||
}, async (params) => {
|
||||
try {
|
||||
const result = await godot.sendCommand("get_input_actions", params);
|
||||
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
||||
}
|
||||
catch (e) {
|
||||
return { content: [{ type: "text", text: formatErrorForMcp(e) }], isError: true };
|
||||
}
|
||||
});
|
||||
server.tool("set_input_action", "Create or update an input action with key/mouse/joypad bindings. Saves to project.godot and updates the runtime InputMap.", {
|
||||
action: z.string().describe("Action name (e.g. 'move_left', 'jump', 'attack')"),
|
||||
events: z.array(z.object({
|
||||
type: z.enum(["key", "mouse_button", "joypad_button", "joypad_motion"]).describe("Event type"),
|
||||
keycode: z.string().optional().describe("Key name for 'key' type (e.g. 'W', 'Space', 'Escape', 'Shift')"),
|
||||
physical_keycode: z.string().optional().describe("Physical key name for 'key' type"),
|
||||
ctrl: z.boolean().optional().describe("Ctrl modifier for 'key' type"),
|
||||
shift: z.boolean().optional().describe("Shift modifier for 'key' type"),
|
||||
alt: z.boolean().optional().describe("Alt modifier for 'key' type"),
|
||||
meta: z.boolean().optional().describe("Meta/Cmd modifier for 'key' type"),
|
||||
button_index: z.number().optional().describe("Button index for mouse/joypad button types"),
|
||||
axis: z.number().optional().describe("Axis index for joypad_motion type"),
|
||||
axis_value: z.number().optional().describe("Axis value (-1.0 or 1.0) for joypad_motion type"),
|
||||
})).describe("Array of input event bindings"),
|
||||
deadzone: z.number().optional().describe("Deadzone for analog inputs (default: 0.5)"),
|
||||
}, async (params) => {
|
||||
try {
|
||||
const result = await godot.sendCommand("set_input_action", params);
|
||||
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
||||
}
|
||||
catch (e) {
|
||||
return { content: [{ type: "text", text: formatErrorForMcp(e) }], isError: true };
|
||||
}
|
||||
});
|
||||
}
|
||||
//# sourceMappingURL=input-map-tools.js.map
|
||||
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"input-map-tools.js","sourceRoot":"","sources":["../../src/tools/input-map-tools.ts"],"names":[],"mappings":"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"}
|
||||
4
wsl-dev-stack/godot-mcp-pro-v1.14.1/server/build/tools/input-tools.d.ts
vendored
Normal file
4
wsl-dev-stack/godot-mcp-pro-v1.14.1/server/build/tools/input-tools.d.ts
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
||||
import { GodotConnection } from "../godot-connection.js";
|
||||
export declare function registerInputTools(server: McpServer, godot: GodotConnection): void;
|
||||
//# sourceMappingURL=input-tools.d.ts.map
|
||||
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"input-tools.d.ts","sourceRoot":"","sources":["../../src/tools/input-tools.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAEpE,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAIzD,wBAAgB,kBAAkB,CAChC,MAAM,EAAE,SAAS,EACjB,KAAK,EAAE,eAAe,GACrB,IAAI,CAgIN"}
|
||||
@@ -0,0 +1,109 @@
|
||||
import { z } from "zod";
|
||||
import { formatErrorForMcp } from "../utils/errors.js";
|
||||
import { coerceNumber } from "../utils/zod-coerce.js";
|
||||
export function registerInputTools(server, godot) {
|
||||
server.tool("simulate_key", "Simulate a keyboard key press or release in the running game. Use `duration` to hold a key for a set time (auto-releases after). Without duration: keys are NOT auto-released — you must explicitly call with pressed=false to release them.", {
|
||||
keycode: z.string().describe("Key constant (e.g. 'KEY_SPACE', 'KEY_W', 'KEY_ESCAPE')"),
|
||||
pressed: z.boolean().optional().describe("true for press, false for release (default: true)"),
|
||||
duration: coerceNumber().optional().describe("Hold duration in seconds (e.g. 1.5). Key is pressed, held for this duration, then auto-released. Cannot be used with pressed=false."),
|
||||
shift: z.boolean().optional().describe("Shift modifier (default: false)"),
|
||||
ctrl: z.boolean().optional().describe("Ctrl modifier (default: false)"),
|
||||
alt: z.boolean().optional().describe("Alt modifier (default: false)"),
|
||||
}, async (params) => {
|
||||
try {
|
||||
if (params.duration !== undefined && params.duration > 0) {
|
||||
const { duration, ...keyParams } = params;
|
||||
// Press
|
||||
await godot.sendCommand("simulate_key", { ...keyParams, pressed: true });
|
||||
// Hold
|
||||
await new Promise(resolve => setTimeout(resolve, duration * 1000));
|
||||
// Release
|
||||
await godot.sendCommand("simulate_key", { ...keyParams, pressed: false });
|
||||
return { content: [{ type: "text", text: JSON.stringify({
|
||||
event: { keycode: params.keycode, duration, shift: params.shift, ctrl: params.ctrl, alt: params.alt, auto_released: true },
|
||||
sent: true
|
||||
}, null, 2) }] };
|
||||
}
|
||||
const result = await godot.sendCommand("simulate_key", params);
|
||||
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
||||
}
|
||||
catch (e) {
|
||||
return { content: [{ type: "text", text: formatErrorForMcp(e) }], isError: true };
|
||||
}
|
||||
});
|
||||
server.tool("simulate_mouse_click", "Simulate a mouse button click at a position in the running game. By default sends both press and release (auto_release) so UI buttons work correctly.", {
|
||||
x: z.number().optional().describe("X position in viewport (default: 0)"),
|
||||
y: z.number().optional().describe("Y position in viewport (default: 0)"),
|
||||
button: z.number().optional().describe("Mouse button index: 1=left, 2=right, 3=middle (default: 1)"),
|
||||
pressed: z.boolean().optional().describe("true for press, false for release (default: true)"),
|
||||
double_click: z.boolean().optional().describe("Double click (default: false)"),
|
||||
auto_release: z.boolean().optional().describe("Auto-send release after press so buttons fire (default: true). Set false for drag operations."),
|
||||
}, async (params) => {
|
||||
try {
|
||||
const result = await godot.sendCommand("simulate_mouse_click", params);
|
||||
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
||||
}
|
||||
catch (e) {
|
||||
return { content: [{ type: "text", text: formatErrorForMcp(e) }], isError: true };
|
||||
}
|
||||
});
|
||||
server.tool("simulate_mouse_move", "Simulate mouse movement in the running game. Use x/y for absolute viewport positioning (UI interaction), or relative_x/relative_y for relative motion (camera rotation in 3D games, FPS-style look). For 3D camera rotation: relative_x rotates yaw (negative = look left, positive = look right), relative_y rotates pitch (negative = look up, positive = look down). Typical values: 200-400px for a ~90° turn. Use navigate_to tool to calculate exact relative_x needed to face a target.", {
|
||||
x: z.number().optional().describe("Absolute X position in viewport (for UI interaction)"),
|
||||
y: z.number().optional().describe("Absolute Y position in viewport (for UI interaction)"),
|
||||
relative_x: z.number().optional().describe("Relative X movement in pixels. For 3D camera: negative = look left, positive = look right. ~400px ≈ 180° turn"),
|
||||
relative_y: z.number().optional().describe("Relative Y movement in pixels. For 3D camera: negative = look up, positive = look down"),
|
||||
button_mask: z.number().optional().describe("Mouse button mask to simulate drag. 1=left button held, 2=right button held, 4=middle button held. Required for drag operations like camera pan. (default: 0)"),
|
||||
unhandled: z.boolean().optional().describe("Force event to bypass GUI layer and go directly to _unhandled_input(). Auto-enabled when button_mask > 0. Use for camera pan/drag when UI overlays consume mouse events. (default: false)"),
|
||||
}, async (params) => {
|
||||
try {
|
||||
const result = await godot.sendCommand("simulate_mouse_move", params);
|
||||
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
||||
}
|
||||
catch (e) {
|
||||
return { content: [{ type: "text", text: formatErrorForMcp(e) }], isError: true };
|
||||
}
|
||||
});
|
||||
server.tool("simulate_action", "Simulate a Godot Input Action (e.g. 'jump', 'move_left') in the running game", {
|
||||
action: z.string().describe("Action name as defined in Input Map (e.g. 'jump', 'move_left')"),
|
||||
pressed: z.boolean().optional().describe("true for press, false for release (default: true)"),
|
||||
strength: z.number().optional().describe("Action strength 0.0-1.0 (default: 1.0)"),
|
||||
}, async (params) => {
|
||||
try {
|
||||
const result = await godot.sendCommand("simulate_action", params);
|
||||
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
||||
}
|
||||
catch (e) {
|
||||
return { content: [{ type: "text", text: formatErrorForMcp(e) }], isError: true };
|
||||
}
|
||||
});
|
||||
server.tool("simulate_sequence", "Simulate a sequence of input events with optional frame delays between them. Useful for complex input patterns like press W → wait 30 frames → press Space → wait → release all. After the sequence, use capture_frames to verify the visual result.", {
|
||||
events: z.array(z.object({
|
||||
type: z.string().describe("Event type: 'key', 'mouse_button', 'mouse_motion', or 'action'"),
|
||||
keycode: z.string().optional().describe("For 'key': key constant (e.g. 'KEY_SPACE')"),
|
||||
action: z.string().optional().describe("For 'action': action name"),
|
||||
button: z.number().optional().describe("For 'mouse_button': button index"),
|
||||
pressed: z.boolean().optional().describe("Press state (default: true)"),
|
||||
x: z.number().optional().describe("X position for mouse events"),
|
||||
y: z.number().optional().describe("Y position for mouse events"),
|
||||
relative_x: z.number().optional().describe("Relative X for mouse_motion"),
|
||||
relative_y: z.number().optional().describe("Relative Y for mouse_motion"),
|
||||
button_mask: z.number().optional().describe("Mouse button mask for mouse_motion drag: 1=left, 2=right, 4=middle"),
|
||||
unhandled: z.boolean().optional().describe("Bypass GUI, send directly to _unhandled_input. Auto-enabled for mouse_motion with button_mask > 0"),
|
||||
shift: z.boolean().optional(),
|
||||
ctrl: z.boolean().optional(),
|
||||
alt: z.boolean().optional(),
|
||||
strength: z.number().optional(),
|
||||
double_click: z.boolean().optional(),
|
||||
})).describe("Array of input events to send"),
|
||||
frame_delay: z.number().optional().describe("Frames to wait between events (default: 1, 0 = all in one frame)"),
|
||||
}, async (params) => {
|
||||
try {
|
||||
const result = await godot.sendCommand("simulate_sequence", params);
|
||||
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
||||
}
|
||||
catch (e) {
|
||||
return { content: [{ type: "text", text: formatErrorForMcp(e) }], isError: true };
|
||||
}
|
||||
});
|
||||
}
|
||||
//# sourceMappingURL=input-tools.js.map
|
||||
File diff suppressed because one or more lines are too long
4
wsl-dev-stack/godot-mcp-pro-v1.14.1/server/build/tools/navigation-tools.d.ts
vendored
Normal file
4
wsl-dev-stack/godot-mcp-pro-v1.14.1/server/build/tools/navigation-tools.d.ts
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
||||
import { GodotConnection } from "../godot-connection.js";
|
||||
export declare function registerNavigationTools(server: McpServer, godot: GodotConnection): void;
|
||||
//# sourceMappingURL=navigation-tools.d.ts.map
|
||||
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"navigation-tools.d.ts","sourceRoot":"","sources":["../../src/tools/navigation-tools.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAEpE,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAGzD,wBAAgB,uBAAuB,CACrC,MAAM,EAAE,SAAS,EACjB,KAAK,EAAE,eAAe,GACrB,IAAI,CA2GN"}
|
||||
@@ -0,0 +1,87 @@
|
||||
import { z } from "zod";
|
||||
import { formatErrorForMcp } from "../utils/errors.js";
|
||||
export function registerNavigationTools(server, godot) {
|
||||
server.tool("setup_navigation_region", "Add a NavigationRegion2D/3D child to a node with auto-created NavigationPolygon or NavigationMesh. Auto-detects 2D/3D from parent context.", {
|
||||
node_path: z.string().describe("Path to the parent node to add the region to"),
|
||||
mode: z.string().optional().describe("Force '2d' or '3d' mode, or 'auto' to detect from parent (default: auto)"),
|
||||
name: z.string().optional().describe("Name for the NavigationRegion node"),
|
||||
navigation_layers: z.number().optional().describe("Navigation layers bitmask"),
|
||||
agent_radius: z.number().optional().describe("Agent radius for mesh generation (3D default: 0.5, 2D: from NavigationPolygon)"),
|
||||
agent_height: z.number().optional().describe("Agent height (3D only, default: 1.5)"),
|
||||
agent_max_climb: z.number().optional().describe("Max climb height (3D only, default: 0.25)"),
|
||||
agent_max_slope: z.number().optional().describe("Max slope angle in degrees (3D only, default: 45.0)"),
|
||||
cell_size: z.number().optional().describe("Cell size for navigation mesh (default: 0.25 for 3D)"),
|
||||
cell_height: z.number().optional().describe("Cell height (3D only, default: 0.25)"),
|
||||
source_geometry_mode: z.string().optional().describe("2D only: root_node, groups_with_children, or groups_explicit"),
|
||||
}, async (params) => {
|
||||
try {
|
||||
const result = await godot.sendCommand("setup_navigation_region", params);
|
||||
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
||||
}
|
||||
catch (e) {
|
||||
return { content: [{ type: "text", text: formatErrorForMcp(e) }], isError: true };
|
||||
}
|
||||
});
|
||||
server.tool("bake_navigation_mesh", "Bake navigation mesh for a NavigationRegion3D, or set outline vertices and generate polygons for a NavigationRegion2D.", {
|
||||
node_path: z.string().describe("Path to the NavigationRegion2D or NavigationRegion3D node"),
|
||||
outline: z.array(z.union([
|
||||
z.array(z.number()).describe("[x, y] coordinate pair"),
|
||||
z.object({ x: z.number(), y: z.number() }),
|
||||
])).optional().describe("2D only: Array of outline vertices as [x,y] pairs or {x,y} objects. At least 3 vertices required."),
|
||||
}, async (params) => {
|
||||
try {
|
||||
const result = await godot.sendCommand("bake_navigation_mesh", params);
|
||||
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
||||
}
|
||||
catch (e) {
|
||||
return { content: [{ type: "text", text: formatErrorForMcp(e) }], isError: true };
|
||||
}
|
||||
});
|
||||
server.tool("setup_navigation_agent", "Add a NavigationAgent2D/3D child to a node and configure pathfinding and avoidance properties. Auto-detects 2D/3D from parent context.", {
|
||||
node_path: z.string().describe("Path to the parent node to add the agent to"),
|
||||
mode: z.string().optional().describe("Force '2d' or '3d' mode, or 'auto' to detect from parent (default: auto)"),
|
||||
name: z.string().optional().describe("Name for the NavigationAgent node"),
|
||||
path_desired_distance: z.number().optional().describe("Distance threshold to advance to next path point"),
|
||||
target_desired_distance: z.number().optional().describe("Distance threshold to consider target reached"),
|
||||
radius: z.number().optional().describe("Agent radius for avoidance"),
|
||||
neighbor_distance: z.number().optional().describe("Max distance to consider other agents as neighbors"),
|
||||
max_neighbors: z.number().optional().describe("Max number of neighbors for avoidance"),
|
||||
max_speed: z.number().optional().describe("Maximum movement speed for avoidance"),
|
||||
avoidance_enabled: z.boolean().optional().describe("Enable avoidance behavior"),
|
||||
navigation_layers: z.number().optional().describe("Navigation layers bitmask for pathfinding queries"),
|
||||
}, async (params) => {
|
||||
try {
|
||||
const result = await godot.sendCommand("setup_navigation_agent", params);
|
||||
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
||||
}
|
||||
catch (e) {
|
||||
return { content: [{ type: "text", text: formatErrorForMcp(e) }], isError: true };
|
||||
}
|
||||
});
|
||||
server.tool("set_navigation_layers", "Set navigation layers for a NavigationRegion or NavigationAgent. Supports bitmask value, layer bit numbers, or named layers from ProjectSettings.", {
|
||||
node_path: z.string().describe("Path to a NavigationRegion2D/3D or NavigationAgent2D/3D node"),
|
||||
layers: z.number().optional().describe("Navigation layers as a bitmask value (e.g. 5 = layers 1 and 3)"),
|
||||
layer_bits: z.array(z.number()).optional().describe("Array of 1-based layer numbers to enable (e.g. [1, 3] = bitmask 5)"),
|
||||
layer_names: z.array(z.string()).optional().describe("Array of named layer names from ProjectSettings (layer_names/2d_navigation/layer_N or 3d)"),
|
||||
}, async (params) => {
|
||||
try {
|
||||
const result = await godot.sendCommand("set_navigation_layers", 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_navigation_info", "Get navigation setup info for a node and its subtree: all NavigationRegions, NavigationAgents, their layers, and mesh/polygon data.", {
|
||||
node_path: z.string().describe("Path to the root node to inspect"),
|
||||
}, async (params) => {
|
||||
try {
|
||||
const result = await godot.sendCommand("get_navigation_info", params);
|
||||
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
||||
}
|
||||
catch (e) {
|
||||
return { content: [{ type: "text", text: formatErrorForMcp(e) }], isError: true };
|
||||
}
|
||||
});
|
||||
}
|
||||
//# sourceMappingURL=navigation-tools.js.map
|
||||
File diff suppressed because one or more lines are too long
4
wsl-dev-stack/godot-mcp-pro-v1.14.1/server/build/tools/node-tools.d.ts
vendored
Normal file
4
wsl-dev-stack/godot-mcp-pro-v1.14.1/server/build/tools/node-tools.d.ts
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
||||
import { GodotConnection } from "../godot-connection.js";
|
||||
export declare function registerNodeTools(server: McpServer, godot: GodotConnection): void;
|
||||
//# sourceMappingURL=node-tools.d.ts.map
|
||||
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"node-tools.d.ts","sourceRoot":"","sources":["../../src/tools/node-tools.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAEpE,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAGzD,wBAAgB,iBAAiB,CAC/B,MAAM,EAAE,SAAS,EACjB,KAAK,EAAE,eAAe,GACrB,IAAI,CAqPN"}
|
||||
@@ -0,0 +1,180 @@
|
||||
import { z } from "zod";
|
||||
import { formatErrorForMcp } from "../utils/errors.js";
|
||||
export function registerNodeTools(server, godot) {
|
||||
server.tool("add_node", "Add a new node to the current scene. Supports built-in Godot types and script-defined classes (class_name).", {
|
||||
type: z.string().describe("Node type — built-in (e.g. 'Sprite2D', 'Camera2D') or script class_name (e.g. 'HoverDetector', 'StationBuilder')"),
|
||||
parent_path: z.string().optional().describe("Parent node path (default: root '.')"),
|
||||
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)\"})"),
|
||||
}, async (params) => {
|
||||
try {
|
||||
const result = await godot.sendCommand("add_node", params);
|
||||
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
||||
}
|
||||
catch (e) {
|
||||
return { content: [{ type: "text", text: formatErrorForMcp(e) }], isError: true };
|
||||
}
|
||||
});
|
||||
server.tool("delete_node", "Delete a node from the current scene (supports undo)", {
|
||||
node_path: z.string().describe("Path to the node to delete"),
|
||||
}, async (params) => {
|
||||
try {
|
||||
const result = await godot.sendCommand("delete_node", params);
|
||||
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
||||
}
|
||||
catch (e) {
|
||||
return { content: [{ type: "text", text: formatErrorForMcp(e) }], isError: true };
|
||||
}
|
||||
});
|
||||
server.tool("duplicate_node", "Duplicate a node and all its children in the current scene", {
|
||||
node_path: z.string().describe("Path to the node to duplicate"),
|
||||
name: z.string().optional().describe("Name for the duplicate (default: original_copy)"),
|
||||
}, async (params) => {
|
||||
try {
|
||||
const result = await godot.sendCommand("duplicate_node", params);
|
||||
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
||||
}
|
||||
catch (e) {
|
||||
return { content: [{ type: "text", text: formatErrorForMcp(e) }], isError: true };
|
||||
}
|
||||
});
|
||||
server.tool("move_node", "Move/reparent a node to a new parent in the scene tree", {
|
||||
node_path: z.string().describe("Path to the node to move"),
|
||||
new_parent_path: z.string().describe("Path to the new parent node"),
|
||||
}, async (params) => {
|
||||
try {
|
||||
const result = await godot.sendCommand("move_node", params);
|
||||
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
||||
}
|
||||
catch (e) {
|
||||
return { content: [{ type: "text", text: formatErrorForMcp(e) }], isError: true };
|
||||
}
|
||||
});
|
||||
server.tool("update_property", "Change a property on any node. Supports Vector2, Color, and other Godot types via string parsing.", {
|
||||
node_path: z.string().describe("Path to the target node"),
|
||||
property: z.string().describe("Property name (e.g. 'position', 'modulate', 'visible')"),
|
||||
value: z.any().describe("New value. Strings are auto-parsed: 'Vector2(10,20)', 'Color(1,0,0)', '#ff0000', etc."),
|
||||
}, async (params) => {
|
||||
try {
|
||||
const result = await godot.sendCommand("update_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("get_node_properties", "Get all editor-visible properties of a node with their current values", {
|
||||
node_path: z.string().describe("Path to the node"),
|
||||
category: z.string().optional().describe("Filter by property category prefix (e.g. 'transform', 'texture')"),
|
||||
}, async (params) => {
|
||||
try {
|
||||
const result = await godot.sendCommand("get_node_properties", params);
|
||||
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
||||
}
|
||||
catch (e) {
|
||||
return { content: [{ type: "text", text: formatErrorForMcp(e) }], isError: true };
|
||||
}
|
||||
});
|
||||
server.tool("add_resource", "Add a resource (Shape2D, Material, Texture, etc.) to a node's property", {
|
||||
node_path: z.string().describe("Path to the target node"),
|
||||
property: z.string().describe("Property to set the resource on (e.g. 'shape', 'material', 'texture')"),
|
||||
resource_type: z.string().describe("Resource class name (e.g. 'RectangleShape2D', 'CircleShape2D', 'StandardMaterial3D')"),
|
||||
resource_properties: z.record(z.string(), z.any()).optional().describe("Properties to set on the created resource"),
|
||||
}, async (params) => {
|
||||
try {
|
||||
const result = await godot.sendCommand("add_resource", params);
|
||||
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
||||
}
|
||||
catch (e) {
|
||||
return { content: [{ type: "text", text: formatErrorForMcp(e) }], isError: true };
|
||||
}
|
||||
});
|
||||
server.tool("set_anchor_preset", "Set a Control node's anchor preset (e.g. full_rect, center, top_left)", {
|
||||
node_path: z.string().describe("Path to the Control node"),
|
||||
preset: z.string().describe("Anchor preset name: top_left, top_right, bottom_left, bottom_right, center_left, center_top, center_right, center_bottom, center, left_wide, top_wide, right_wide, bottom_wide, vcenter_wide, hcenter_wide, full_rect"),
|
||||
keep_offsets: z.boolean().optional().describe("Keep current offsets (default: false)"),
|
||||
}, async (params) => {
|
||||
try {
|
||||
const result = await godot.sendCommand("set_anchor_preset", params);
|
||||
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
||||
}
|
||||
catch (e) {
|
||||
return { content: [{ type: "text", text: formatErrorForMcp(e) }], isError: true };
|
||||
}
|
||||
});
|
||||
server.tool("rename_node", "Rename a node in the current scene", {
|
||||
node_path: z.string().describe("Path to the node to rename"),
|
||||
new_name: z.string().describe("New name for the node"),
|
||||
}, async (params) => {
|
||||
try {
|
||||
const result = await godot.sendCommand("rename_node", params);
|
||||
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
||||
}
|
||||
catch (e) {
|
||||
return { content: [{ type: "text", text: formatErrorForMcp(e) }], isError: true };
|
||||
}
|
||||
});
|
||||
server.tool("connect_signal", "Connect a signal from one node to a method on another node", {
|
||||
source_path: z.string().describe("Path to the source node (emitter)"),
|
||||
signal_name: z.string().describe("Signal name to connect"),
|
||||
target_path: z.string().describe("Path to the target node (receiver)"),
|
||||
method_name: z.string().describe("Method name on target to call"),
|
||||
}, async (params) => {
|
||||
try {
|
||||
const result = await godot.sendCommand("connect_signal", params);
|
||||
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
||||
}
|
||||
catch (e) {
|
||||
return { content: [{ type: "text", text: formatErrorForMcp(e) }], isError: true };
|
||||
}
|
||||
});
|
||||
server.tool("disconnect_signal", "Disconnect a signal connection between two nodes", {
|
||||
source_path: z.string().describe("Path to the source node (emitter)"),
|
||||
signal_name: z.string().describe("Signal name to disconnect"),
|
||||
target_path: z.string().describe("Path to the target node (receiver)"),
|
||||
method_name: z.string().describe("Method name on target"),
|
||||
}, async (params) => {
|
||||
try {
|
||||
const result = await godot.sendCommand("disconnect_signal", 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_node_groups", "Get all groups a node belongs to (excludes internal groups starting with '_')", {
|
||||
node_path: z.string().describe("Path to the node"),
|
||||
}, async (params) => {
|
||||
try {
|
||||
const result = await godot.sendCommand("get_node_groups", params);
|
||||
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
||||
}
|
||||
catch (e) {
|
||||
return { content: [{ type: "text", text: formatErrorForMcp(e) }], isError: true };
|
||||
}
|
||||
});
|
||||
server.tool("set_node_groups", "Set the groups a node belongs to. Computes diff with current groups and adds/removes as needed.", {
|
||||
node_path: z.string().describe("Path to the node"),
|
||||
groups: z.array(z.string()).describe("Desired list of group names (replaces current groups)"),
|
||||
}, async (params) => {
|
||||
try {
|
||||
const result = await godot.sendCommand("set_node_groups", 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_nodes_in_group", "Find all nodes in the current scene that belong to a specific group", {
|
||||
group: z.string().describe("Group name to search for"),
|
||||
}, async (params) => {
|
||||
try {
|
||||
const result = await godot.sendCommand("find_nodes_in_group", params);
|
||||
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
||||
}
|
||||
catch (e) {
|
||||
return { content: [{ type: "text", text: formatErrorForMcp(e) }], isError: true };
|
||||
}
|
||||
});
|
||||
}
|
||||
//# sourceMappingURL=node-tools.js.map
|
||||
File diff suppressed because one or more lines are too long
4
wsl-dev-stack/godot-mcp-pro-v1.14.1/server/build/tools/particle-tools.d.ts
vendored
Normal file
4
wsl-dev-stack/godot-mcp-pro-v1.14.1/server/build/tools/particle-tools.d.ts
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
||||
import { GodotConnection } from "../godot-connection.js";
|
||||
export declare function registerParticleTools(server: McpServer, godot: GodotConnection): void;
|
||||
//# sourceMappingURL=particle-tools.d.ts.map
|
||||
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"particle-tools.d.ts","sourceRoot":"","sources":["../../src/tools/particle-tools.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAEpE,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAGzD,wBAAgB,qBAAqB,CACnC,MAAM,EAAE,SAAS,EACjB,KAAK,EAAE,eAAe,GACrB,IAAI,CA8HN"}
|
||||
@@ -0,0 +1,106 @@
|
||||
import { z } from "zod";
|
||||
import { formatErrorForMcp } from "../utils/errors.js";
|
||||
export function registerParticleTools(server, godot) {
|
||||
server.tool("create_particles", "Add a GPUParticles2D or GPUParticles3D node with a ParticleProcessMaterial. Configure amount, lifetime, one_shot, explosiveness, and randomness.", {
|
||||
parent_path: z.string().describe("Path to the parent node to add particles to"),
|
||||
name: z.string().optional().describe("Name for the particles node (default: 'Particles')"),
|
||||
is_3d: z.boolean().optional().describe("Create GPUParticles3D instead of GPUParticles2D (default: false)"),
|
||||
amount: z.number().optional().describe("Number of particles (default: 16)"),
|
||||
lifetime: z.number().optional().describe("Particle lifetime in seconds (default: 1.0)"),
|
||||
one_shot: z.boolean().optional().describe("Emit only once (default: false)"),
|
||||
explosiveness: z.number().optional().describe("Explosiveness ratio 0-1 (default: 0.0)"),
|
||||
randomness: z.number().optional().describe("Randomness ratio 0-1 (default: 0.0)"),
|
||||
emitting: z.boolean().optional().describe("Start emitting immediately (default: true)"),
|
||||
}, async (params) => {
|
||||
try {
|
||||
const result = await godot.sendCommand("create_particles", params);
|
||||
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
||||
}
|
||||
catch (e) {
|
||||
return { content: [{ type: "text", text: formatErrorForMcp(e) }], isError: true };
|
||||
}
|
||||
});
|
||||
server.tool("set_particle_material", "Configure ParticleProcessMaterial properties: direction, spread, velocity, gravity, scale, color, emission shape (point/sphere/box/ring), angular/orbit velocity, damping, and attractor interaction.", {
|
||||
node_path: z.string().describe("Path to the GPUParticles2D/3D node"),
|
||||
direction: z.object({
|
||||
x: z.number(),
|
||||
y: z.number(),
|
||||
z: z.number(),
|
||||
}).optional().describe("Emission direction vector"),
|
||||
spread: z.number().optional().describe("Spread angle in degrees (0-180)"),
|
||||
initial_velocity_min: z.number().optional().describe("Minimum initial velocity"),
|
||||
initial_velocity_max: z.number().optional().describe("Maximum initial velocity"),
|
||||
gravity: z.object({
|
||||
x: z.number(),
|
||||
y: z.number(),
|
||||
z: z.number(),
|
||||
}).optional().describe("Gravity vector"),
|
||||
scale_min: z.number().optional().describe("Minimum particle scale"),
|
||||
scale_max: z.number().optional().describe("Maximum particle scale"),
|
||||
color: z.string().optional().describe("Particle color (hex '#RRGGBB' or named color)"),
|
||||
emission_shape: z.string().optional().describe("Emission shape: point, sphere, sphere_surface, box, ring"),
|
||||
emission_sphere_radius: z.number().optional().describe("Sphere emission radius"),
|
||||
emission_box_extents: z.object({
|
||||
x: z.number(),
|
||||
y: z.number(),
|
||||
z: z.number(),
|
||||
}).optional().describe("Box emission extents"),
|
||||
emission_ring_radius: z.number().optional().describe("Ring outer radius"),
|
||||
emission_ring_inner_radius: z.number().optional().describe("Ring inner radius"),
|
||||
emission_ring_height: z.number().optional().describe("Ring height"),
|
||||
angular_velocity_min: z.number().optional().describe("Minimum angular velocity (degrees/sec)"),
|
||||
angular_velocity_max: z.number().optional().describe("Maximum angular velocity (degrees/sec)"),
|
||||
orbit_velocity_min: z.number().optional().describe("Minimum orbit velocity"),
|
||||
orbit_velocity_max: z.number().optional().describe("Maximum orbit velocity"),
|
||||
damping_min: z.number().optional().describe("Minimum damping"),
|
||||
damping_max: z.number().optional().describe("Maximum damping"),
|
||||
attractor_interaction_enabled: z.boolean().optional().describe("Enable attractor interaction"),
|
||||
}, async (params) => {
|
||||
try {
|
||||
const result = await godot.sendCommand("set_particle_material", params);
|
||||
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
||||
}
|
||||
catch (e) {
|
||||
return { content: [{ type: "text", text: formatErrorForMcp(e) }], isError: true };
|
||||
}
|
||||
});
|
||||
server.tool("set_particle_color_gradient", "Set a color ramp (gradient) on a particle system's material. Provide an array of color stops with offset (0-1) and color.", {
|
||||
node_path: z.string().describe("Path to the GPUParticles2D/3D node"),
|
||||
stops: z.array(z.object({
|
||||
offset: z.number().describe("Gradient position (0.0 to 1.0)"),
|
||||
color: z.string().describe("Color at this stop (hex '#RRGGBB' or named color)"),
|
||||
})).describe("Array of gradient color stops"),
|
||||
}, async (params) => {
|
||||
try {
|
||||
const result = await godot.sendCommand("set_particle_color_gradient", params);
|
||||
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
||||
}
|
||||
catch (e) {
|
||||
return { content: [{ type: "text", text: formatErrorForMcp(e) }], isError: true };
|
||||
}
|
||||
});
|
||||
server.tool("apply_particle_preset", "Apply a named particle preset. Available presets: explosion (burst, short life), fire (upward, orange gradient), smoke (slow upward, gray), sparks (burst, high velocity), rain (downward, blue), snow (slow downward, drift), magic (orbit, colorful), dust (ambient, subtle).", {
|
||||
node_path: z.string().describe("Path to the GPUParticles2D/3D node"),
|
||||
preset: z.string().describe("Preset name: explosion, fire, smoke, sparks, rain, snow, magic, dust"),
|
||||
}, async (params) => {
|
||||
try {
|
||||
const result = await godot.sendCommand("apply_particle_preset", 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_particle_info", "Get the full configuration of a particle system: node properties, material settings, emission shape, color gradient stops.", {
|
||||
node_path: z.string().describe("Path to the GPUParticles2D/3D node"),
|
||||
}, async (params) => {
|
||||
try {
|
||||
const result = await godot.sendCommand("get_particle_info", params);
|
||||
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
||||
}
|
||||
catch (e) {
|
||||
return { content: [{ type: "text", text: formatErrorForMcp(e) }], isError: true };
|
||||
}
|
||||
});
|
||||
}
|
||||
//# sourceMappingURL=particle-tools.js.map
|
||||
File diff suppressed because one or more lines are too long
4
wsl-dev-stack/godot-mcp-pro-v1.14.1/server/build/tools/physics-tools.d.ts
vendored
Normal file
4
wsl-dev-stack/godot-mcp-pro-v1.14.1/server/build/tools/physics-tools.d.ts
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
||||
import { GodotConnection } from "../godot-connection.js";
|
||||
export declare function registerPhysicsTools(server: McpServer, godot: GodotConnection): void;
|
||||
//# sourceMappingURL=physics-tools.d.ts.map
|
||||
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"physics-tools.d.ts","sourceRoot":"","sources":["../../src/tools/physics-tools.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAEpE,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAGzD,wBAAgB,oBAAoB,CAClC,MAAM,EAAE,SAAS,EACjB,KAAK,EAAE,eAAe,GACrB,IAAI,CA4IN"}
|
||||
@@ -0,0 +1,115 @@
|
||||
import { z } from "zod";
|
||||
import { formatErrorForMcp } from "../utils/errors.js";
|
||||
export function registerPhysicsTools(server, godot) {
|
||||
server.tool("setup_collision", "Add a CollisionShape2D/3D child to a physics body or area node with a specified shape. Auto-detects 2D/3D from the parent node type.", {
|
||||
node_path: z.string().describe("Path to the parent physics body or area node (e.g. CharacterBody2D, StaticBody3D, Area2D)"),
|
||||
shape: z.string().describe("Shape type: 'rectangle'/'rect', 'circle', 'capsule', 'segment' (2D only), 'cylinder' (3D only), 'custom'/'convex'. For 3D: 'box'/'sphere' also work."),
|
||||
width: z.number().optional().describe("Width for rectangle/box shape (default: 32 for 2D, 1 for 3D)"),
|
||||
height: z.number().optional().describe("Height for rectangle/box/capsule/cylinder shape"),
|
||||
depth: z.number().optional().describe("Depth for 3D box shape (default: 1)"),
|
||||
radius: z.number().optional().describe("Radius for circle/sphere/capsule/cylinder shape"),
|
||||
ax: z.number().optional().describe("Segment start X (2D segment only)"),
|
||||
ay: z.number().optional().describe("Segment start Y (2D segment only)"),
|
||||
bx: z.number().optional().describe("Segment end X (2D segment only)"),
|
||||
by: z.number().optional().describe("Segment end Y (2D segment only)"),
|
||||
points: z.array(z.array(z.number())).optional().describe("Convex polygon points as [[x,y],...] for 2D or [[x,y,z],...] for 3D"),
|
||||
disabled: z.boolean().optional().describe("Create the collision shape disabled (default: false)"),
|
||||
one_way_collision: z.boolean().optional().describe("Enable one-way collision (2D only, default: false)"),
|
||||
dimension: z.string().optional().describe("Force '2d' or '3d' if auto-detection fails"),
|
||||
}, async (params) => {
|
||||
try {
|
||||
const result = await godot.sendCommand("setup_collision", params);
|
||||
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
||||
}
|
||||
catch (e) {
|
||||
return { content: [{ type: "text", text: formatErrorForMcp(e) }], isError: true };
|
||||
}
|
||||
});
|
||||
server.tool("set_physics_layers", "Set collision layer and/or mask on a physics body or area node. Supports bitmask integers or arrays of layer numbers.", {
|
||||
node_path: z.string().describe("Path to the node with collision layers"),
|
||||
collision_layer: z.union([z.number(), z.array(z.number())]).optional().describe("Collision layer: bitmask integer or array of layer numbers [1,3,5]"),
|
||||
collision_mask: z.union([z.number(), z.array(z.number())]).optional().describe("Collision mask: bitmask integer or array of layer numbers [1,2,4]"),
|
||||
}, async (params) => {
|
||||
try {
|
||||
const result = await godot.sendCommand("set_physics_layers", 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_physics_layers", "Get the current collision layer and mask for a node, including named layer info from ProjectSettings.", {
|
||||
node_path: z.string().describe("Path to the node with collision layers"),
|
||||
}, async (params) => {
|
||||
try {
|
||||
const result = await godot.sendCommand("get_physics_layers", params);
|
||||
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
||||
}
|
||||
catch (e) {
|
||||
return { content: [{ type: "text", text: formatErrorForMcp(e) }], isError: true };
|
||||
}
|
||||
});
|
||||
server.tool("add_raycast", "Add a RayCast2D/3D child node for collision detection. Auto-detects 2D/3D from the parent node type.", {
|
||||
node_path: z.string().describe("Path to the parent node"),
|
||||
name: z.string().optional().describe("Name for the raycast node (default: 'RayCast')"),
|
||||
target_x: z.number().optional().describe("Target position X (default: 0)"),
|
||||
target_y: z.number().optional().describe("Target position Y (default: 50 for 2D, -1 for 3D)"),
|
||||
target_z: z.number().optional().describe("Target position Z (3D only, default: 0)"),
|
||||
collision_mask: z.number().optional().describe("Collision mask bitmask (default: 1)"),
|
||||
enabled: z.boolean().optional().describe("Enable the raycast (default: true)"),
|
||||
collide_with_areas: z.boolean().optional().describe("Collide with Area nodes (default: false)"),
|
||||
collide_with_bodies: z.boolean().optional().describe("Collide with physics bodies (default: true)"),
|
||||
hit_from_inside: z.boolean().optional().describe("Detect hits from inside shapes (default: false)"),
|
||||
dimension: z.string().optional().describe("Force '2d' or '3d' if auto-detection fails"),
|
||||
}, async (params) => {
|
||||
try {
|
||||
const result = await godot.sendCommand("add_raycast", params);
|
||||
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
||||
}
|
||||
catch (e) {
|
||||
return { content: [{ type: "text", text: formatErrorForMcp(e) }], isError: true };
|
||||
}
|
||||
});
|
||||
server.tool("setup_physics_body", "Configure physics body properties. For CharacterBody2D/3D: floor settings, motion mode, etc. For RigidBody2D/3D: mass, gravity, damping, etc.", {
|
||||
node_path: z.string().describe("Path to the physics body node"),
|
||||
// CharacterBody properties
|
||||
floor_stop_on_slope: z.boolean().optional().describe("CharacterBody: stop on slopes when not moving"),
|
||||
floor_max_angle: z.number().optional().describe("CharacterBody: maximum floor angle in radians (default ~0.785 = 45 degrees)"),
|
||||
floor_snap_length: z.number().optional().describe("CharacterBody: floor snap distance for sticking to the ground"),
|
||||
wall_min_slide_angle: z.number().optional().describe("CharacterBody: minimum angle for wall sliding in radians"),
|
||||
motion_mode: z.string().optional().describe("CharacterBody: 'grounded' or 'floating'"),
|
||||
max_slides: z.number().optional().describe("CharacterBody: maximum slide iterations (default: 6)"),
|
||||
slide_on_ceiling: z.boolean().optional().describe("CharacterBody: allow sliding on ceiling"),
|
||||
// RigidBody properties
|
||||
mass: z.number().optional().describe("RigidBody: mass in kg (default: 1)"),
|
||||
gravity_scale: z.number().optional().describe("RigidBody: gravity multiplier (default: 1, 0 = no gravity)"),
|
||||
linear_damp: z.number().optional().describe("RigidBody: linear velocity damping"),
|
||||
angular_damp: z.number().optional().describe("RigidBody: angular velocity damping"),
|
||||
freeze: z.boolean().optional().describe("RigidBody: freeze the body (stop physics simulation)"),
|
||||
freeze_mode: z.string().optional().describe("RigidBody: 'static' or 'kinematic' freeze behavior"),
|
||||
continuous_cd: z.union([z.string(), z.boolean()]).optional().describe("RigidBody: continuous collision detection. 2D: 'disabled'/'cast_ray'/'cast_shape'. 3D: true/false"),
|
||||
contact_monitor: z.boolean().optional().describe("RigidBody: enable contact monitoring for body_entered/body_exited signals"),
|
||||
max_contacts_reported: z.number().optional().describe("RigidBody: max contacts to report (requires contact_monitor)"),
|
||||
}, async (params) => {
|
||||
try {
|
||||
const result = await godot.sendCommand("setup_physics_body", 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_collision_info", "Get detailed collision information for a node: all collision shapes, layers/masks, raycasts, and physics body settings. Scans children by default.", {
|
||||
node_path: z.string().describe("Path to the node to inspect"),
|
||||
include_children: z.boolean().optional().describe("Include children in the scan (default: true)"),
|
||||
}, async (params) => {
|
||||
try {
|
||||
const result = await godot.sendCommand("get_collision_info", params);
|
||||
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
||||
}
|
||||
catch (e) {
|
||||
return { content: [{ type: "text", text: formatErrorForMcp(e) }], isError: true };
|
||||
}
|
||||
});
|
||||
}
|
||||
//# sourceMappingURL=physics-tools.js.map
|
||||
File diff suppressed because one or more lines are too long
4
wsl-dev-stack/godot-mcp-pro-v1.14.1/server/build/tools/profiling-tools.d.ts
vendored
Normal file
4
wsl-dev-stack/godot-mcp-pro-v1.14.1/server/build/tools/profiling-tools.d.ts
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
||||
import { GodotConnection } from "../godot-connection.js";
|
||||
export declare function registerProfilingTools(server: McpServer, godot: GodotConnection): void;
|
||||
//# sourceMappingURL=profiling-tools.d.ts.map
|
||||
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"profiling-tools.d.ts","sourceRoot":"","sources":["../../src/tools/profiling-tools.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAEpE,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAGzD,wBAAgB,sBAAsB,CACpC,MAAM,EAAE,SAAS,EACjB,KAAK,EAAE,eAAe,GACrB,IAAI,CA8BN"}
|
||||
@@ -0,0 +1,25 @@
|
||||
import { z } from "zod";
|
||||
import { formatErrorForMcp } from "../utils/errors.js";
|
||||
export function registerProfilingTools(server, godot) {
|
||||
server.tool("get_performance_monitors", "Get all Godot performance monitors (FPS, memory, draw calls, physics, navigation, etc.)", {
|
||||
category: z.string().optional().describe("Filter by category prefix: 'fps', 'memory', 'render', 'physics_2d', 'physics_3d', 'navigation'"),
|
||||
}, async (params) => {
|
||||
try {
|
||||
const result = await godot.sendCommand("get_performance_monitors", 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_editor_performance", "Get a quick performance summary (FPS, frame time, draw calls, memory usage)", {}, async () => {
|
||||
try {
|
||||
const result = await godot.sendCommand("get_editor_performance");
|
||||
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
||||
}
|
||||
catch (e) {
|
||||
return { content: [{ type: "text", text: formatErrorForMcp(e) }], isError: true };
|
||||
}
|
||||
});
|
||||
}
|
||||
//# sourceMappingURL=profiling-tools.js.map
|
||||
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"profiling-tools.js","sourceRoot":"","sources":["../../src/tools/profiling-tools.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AAEvD,MAAM,UAAU,sBAAsB,CACpC,MAAiB,EACjB,KAAsB;IAEtB,MAAM,CAAC,IAAI,CACT,0BAA0B,EAC1B,yFAAyF,EACzF;QACE,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,gGAAgG,CAAC;KAC3I,EACD,KAAK,EAAE,MAAM,EAAE,EAAE;QACf,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,MAAM,KAAK,CAAC,WAAW,CAAC,0BAA0B,EAAE,MAAM,CAAC,CAAC;YAC3E,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC;QAChF,CAAC;QAAC,OAAO,CAAC,EAAE,CAAC;YACX,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,iBAAiB,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;QACpF,CAAC;IACH,CAAC,CACF,CAAC;IAEF,MAAM,CAAC,IAAI,CACT,wBAAwB,EACxB,6EAA6E,EAC7E,EAAE,EACF,KAAK,IAAI,EAAE;QACT,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,MAAM,KAAK,CAAC,WAAW,CAAC,wBAAwB,CAAC,CAAC;YACjE,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC;QAChF,CAAC;QAAC,OAAO,CAAC,EAAE,CAAC;YACX,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,iBAAiB,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;QACpF,CAAC;IACH,CAAC,CACF,CAAC;AACJ,CAAC"}
|
||||
4
wsl-dev-stack/godot-mcp-pro-v1.14.1/server/build/tools/project-tools.d.ts
vendored
Normal file
4
wsl-dev-stack/godot-mcp-pro-v1.14.1/server/build/tools/project-tools.d.ts
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
||||
import { GodotConnection } from "../godot-connection.js";
|
||||
export declare function registerProjectTools(server: McpServer, godot: GodotConnection): void;
|
||||
//# sourceMappingURL=project-tools.d.ts.map
|
||||
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"project-tools.d.ts","sourceRoot":"","sources":["../../src/tools/project-tools.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAEpE,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAGzD,wBAAgB,oBAAoB,CAClC,MAAM,EAAE,SAAS,EACjB,KAAK,EAAE,eAAe,GACrB,IAAI,CA0KN"}
|
||||
@@ -0,0 +1,125 @@
|
||||
import { z } from "zod";
|
||||
import { formatErrorForMcp } from "../utils/errors.js";
|
||||
export function registerProjectTools(server, godot) {
|
||||
server.tool("get_project_info", "Get Godot project metadata including name, version, viewport settings, renderer, and autoloads", {}, async () => {
|
||||
try {
|
||||
const result = await godot.sendCommand("get_project_info");
|
||||
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
||||
}
|
||||
catch (e) {
|
||||
return { content: [{ type: "text", text: formatErrorForMcp(e) }], isError: true };
|
||||
}
|
||||
});
|
||||
server.tool("get_filesystem_tree", "Get the project's file/directory tree with optional filtering by extension (e.g. *.gd, *.tscn)", {
|
||||
path: z.string().optional().describe("Root path to scan (default: res://)"),
|
||||
filter: z.string().optional().describe("Glob filter pattern (e.g. '*.gd', '*.tscn')"),
|
||||
max_depth: z.number().optional().describe("Maximum directory depth to scan (default: 10)"),
|
||||
}, async (params) => {
|
||||
try {
|
||||
const result = await godot.sendCommand("get_filesystem_tree", params);
|
||||
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
||||
}
|
||||
catch (e) {
|
||||
return { content: [{ type: "text", text: formatErrorForMcp(e) }], isError: true };
|
||||
}
|
||||
});
|
||||
server.tool("search_files", "Search for files by name using fuzzy matching or glob patterns", {
|
||||
query: z.string().describe("Search query (fuzzy match or glob pattern)"),
|
||||
path: z.string().optional().describe("Root path to search (default: res://)"),
|
||||
file_type: z.string().optional().describe("Filter by file extension (e.g. 'gd', 'tscn')"),
|
||||
max_results: z.number().optional().describe("Maximum results to return (default: 50)"),
|
||||
}, async (params) => {
|
||||
try {
|
||||
const result = await godot.sendCommand("search_files", params);
|
||||
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
||||
}
|
||||
catch (e) {
|
||||
return { content: [{ type: "text", text: formatErrorForMcp(e) }], isError: true };
|
||||
}
|
||||
});
|
||||
server.tool("search_in_files", "Search for text content inside project files (grep-like). Searches through GDScript, scenes, resources, shaders, and other text files. Skips addons/ and .godot/ directories.", {
|
||||
query: z.string().describe("Text to search for (plain text or regex pattern)"),
|
||||
path: z.string().optional().describe("Root path to search (default: res://)"),
|
||||
regex: z.boolean().optional().describe("Use regex matching (default: false)"),
|
||||
file_type: z.string().optional().describe("Filter by file extension (e.g. 'gd', 'tscn'). Default: all text files"),
|
||||
max_results: z.number().optional().describe("Maximum results to return (default: 50)"),
|
||||
}, async (params) => {
|
||||
try {
|
||||
const result = await godot.sendCommand("search_in_files", 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_project_settings", "Read project.godot settings by section or specific key", {
|
||||
section: z.string().optional().describe("Settings section prefix (e.g. 'display/window')"),
|
||||
key: z.string().optional().describe("Specific setting key (e.g. 'display/window/size/viewport_width')"),
|
||||
}, async (params) => {
|
||||
try {
|
||||
const result = await godot.sendCommand("get_project_settings", params);
|
||||
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
||||
}
|
||||
catch (e) {
|
||||
return { content: [{ type: "text", text: formatErrorForMcp(e) }], isError: true };
|
||||
}
|
||||
});
|
||||
server.tool("set_project_setting", "Set a project setting value (e.g. viewport size, main scene). Saves to project.godot via the editor API.", {
|
||||
key: z.string().describe("Setting key (e.g. 'display/window/size/viewport_width', 'application/run/main_scene')"),
|
||||
value: z.union([z.string(), z.number(), z.boolean()]).describe("Value to set. Strings are auto-parsed for Vector2, bool, int, float."),
|
||||
}, async (params) => {
|
||||
try {
|
||||
const result = await godot.sendCommand("set_project_setting", params);
|
||||
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
||||
}
|
||||
catch (e) {
|
||||
return { content: [{ type: "text", text: formatErrorForMcp(e) }], isError: true };
|
||||
}
|
||||
});
|
||||
server.tool("uid_to_project_path", "Convert a Godot UID (uid://...) to a project resource path (res://...)", {
|
||||
uid: z.string().describe("The UID string (e.g. 'uid://abc123')"),
|
||||
}, async (params) => {
|
||||
try {
|
||||
const result = await godot.sendCommand("uid_to_project_path", params);
|
||||
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
||||
}
|
||||
catch (e) {
|
||||
return { content: [{ type: "text", text: formatErrorForMcp(e) }], isError: true };
|
||||
}
|
||||
});
|
||||
server.tool("project_path_to_uid", "Convert a project resource path (res://...) to its UID (uid://...)", {
|
||||
path: z.string().describe("The resource path (e.g. 'res://scenes/player.tscn')"),
|
||||
}, async (params) => {
|
||||
try {
|
||||
const result = await godot.sendCommand("project_path_to_uid", params);
|
||||
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
||||
}
|
||||
catch (e) {
|
||||
return { content: [{ type: "text", text: formatErrorForMcp(e) }], isError: true };
|
||||
}
|
||||
});
|
||||
server.tool("add_autoload", "Add an autoload (singleton) to the project. The script/scene will be auto-loaded when the project starts.", {
|
||||
name: z.string().describe("Autoload name (e.g. 'GameManager', 'AudioManager')"),
|
||||
path: z.string().describe("Path to the script or scene file (e.g. 'res://scripts/autoload/game_manager.gd')"),
|
||||
}, async (params) => {
|
||||
try {
|
||||
const result = await godot.sendCommand("add_autoload", params);
|
||||
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
||||
}
|
||||
catch (e) {
|
||||
return { content: [{ type: "text", text: formatErrorForMcp(e) }], isError: true };
|
||||
}
|
||||
});
|
||||
server.tool("remove_autoload", "Remove an autoload (singleton) from the project settings", {
|
||||
name: z.string().describe("Autoload name to remove (e.g. 'GameManager')"),
|
||||
}, async (params) => {
|
||||
try {
|
||||
const result = await godot.sendCommand("remove_autoload", params);
|
||||
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
||||
}
|
||||
catch (e) {
|
||||
return { content: [{ type: "text", text: formatErrorForMcp(e) }], isError: true };
|
||||
}
|
||||
});
|
||||
}
|
||||
//# sourceMappingURL=project-tools.js.map
|
||||
File diff suppressed because one or more lines are too long
4
wsl-dev-stack/godot-mcp-pro-v1.14.1/server/build/tools/resource-tools.d.ts
vendored
Normal file
4
wsl-dev-stack/godot-mcp-pro-v1.14.1/server/build/tools/resource-tools.d.ts
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
||||
import { GodotConnection } from "../godot-connection.js";
|
||||
export declare function registerResourceTools(server: McpServer, godot: GodotConnection): void;
|
||||
//# sourceMappingURL=resource-tools.d.ts.map
|
||||
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"resource-tools.d.ts","sourceRoot":"","sources":["../../src/tools/resource-tools.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAEpE,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAGzD,wBAAgB,qBAAqB,CACnC,MAAM,EAAE,SAAS,EACjB,KAAK,EAAE,eAAe,GACrB,IAAI,CAoFN"}
|
||||
@@ -0,0 +1,69 @@
|
||||
import { z } from "zod";
|
||||
import { formatErrorForMcp } from "../utils/errors.js";
|
||||
export function registerResourceTools(server, godot) {
|
||||
server.tool("read_resource", "Read a .tres resource file and return its properties. Works with any Godot Resource type (StyleBox, Font, Theme, Material, etc.)", {
|
||||
path: z.string().describe("Path to the resource file (e.g. 'res://themes/main_theme.tres')"),
|
||||
}, async (params) => {
|
||||
try {
|
||||
const result = await godot.sendCommand("read_resource", params);
|
||||
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
||||
}
|
||||
catch (e) {
|
||||
return { content: [{ type: "text", text: formatErrorForMcp(e) }], isError: true };
|
||||
}
|
||||
});
|
||||
server.tool("edit_resource", "Edit properties of an existing .tres resource file. Changes are saved to disk immediately.", {
|
||||
path: z.string().describe("Path to the resource file (e.g. 'res://themes/main_theme.tres')"),
|
||||
properties: z.record(z.string(), z.union([z.string(), z.number(), z.boolean()])).describe("Properties to set as key-value pairs. Values auto-parsed for Vector2, Color, etc."),
|
||||
}, async (params) => {
|
||||
try {
|
||||
const result = await godot.sendCommand("edit_resource", params);
|
||||
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
||||
}
|
||||
catch (e) {
|
||||
return { content: [{ type: "text", text: formatErrorForMcp(e) }], isError: true };
|
||||
}
|
||||
});
|
||||
server.tool("create_resource", "Create a new .tres resource file of a given type with optional initial properties", {
|
||||
path: z.string().describe("Path to save the resource (e.g. 'res://resources/player_stats.tres')"),
|
||||
type: z.string().describe("Resource type to create (e.g. 'StyleBoxFlat', 'LabelSettings', 'Environment')"),
|
||||
properties: z.record(z.string(), z.union([z.string(), z.number(), z.boolean()])).optional().describe("Initial properties to set"),
|
||||
overwrite: z.boolean().optional().describe("Overwrite if file exists (default: false)"),
|
||||
}, async (params) => {
|
||||
try {
|
||||
const result = await godot.sendCommand("create_resource", 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_resource_preview", "Get a visual preview of an image or texture resource as a PNG. Works with .png, .jpg, .webp, .svg image files and Texture2D resources.", {
|
||||
path: z.string().describe("Path to the resource (e.g. 'res://assets/player.png', 'res://icon.svg')"),
|
||||
max_size: z.number().optional().describe("Maximum width/height in pixels, preserving aspect ratio (default: 256)"),
|
||||
}, async (params) => {
|
||||
try {
|
||||
const result = await godot.sendCommand("get_resource_preview", params);
|
||||
if (result && typeof result === "object" && "image_base64" in result) {
|
||||
return {
|
||||
content: [
|
||||
{
|
||||
type: "image",
|
||||
data: result.image_base64,
|
||||
mimeType: "image/png",
|
||||
},
|
||||
{
|
||||
type: "text",
|
||||
text: `Preview of ${result.path}: ${result.width}x${result.height}`,
|
||||
},
|
||||
],
|
||||
};
|
||||
}
|
||||
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
||||
}
|
||||
catch (e) {
|
||||
return { content: [{ type: "text", text: formatErrorForMcp(e) }], isError: true };
|
||||
}
|
||||
});
|
||||
}
|
||||
//# sourceMappingURL=resource-tools.js.map
|
||||
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"resource-tools.js","sourceRoot":"","sources":["../../src/tools/resource-tools.ts"],"names":[],"mappings":"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"}
|
||||
4
wsl-dev-stack/godot-mcp-pro-v1.14.1/server/build/tools/runtime-tools.d.ts
vendored
Normal file
4
wsl-dev-stack/godot-mcp-pro-v1.14.1/server/build/tools/runtime-tools.d.ts
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
||||
import { GodotConnection } from "../godot-connection.js";
|
||||
export declare function registerRuntimeTools(server: McpServer, godot: GodotConnection): void;
|
||||
//# sourceMappingURL=runtime-tools.d.ts.map
|
||||
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"runtime-tools.d.ts","sourceRoot":"","sources":["../../src/tools/runtime-tools.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAEpE,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAIzD,wBAAgB,oBAAoB,CAClC,MAAM,EAAE,SAAS,EACjB,KAAK,EAAE,eAAe,GACrB,IAAI,CA6vBN"}
|
||||
@@ -0,0 +1,552 @@
|
||||
import { z } from "zod";
|
||||
import { formatErrorForMcp } from "../utils/errors.js";
|
||||
import { coerceStringArray, coerceNumber } from "../utils/zod-coerce.js";
|
||||
export function registerRuntimeTools(server, godot) {
|
||||
server.tool("get_game_scene_tree", "Get the scene tree of the currently running game (requires a scene to be playing). Supports filtering by script path, node type, or name.", {
|
||||
max_depth: z
|
||||
.number()
|
||||
.optional()
|
||||
.describe("Maximum tree depth (-1 for unlimited, default: -1)"),
|
||||
script_filter: z
|
||||
.string()
|
||||
.optional()
|
||||
.describe("Only include nodes whose script path contains this string (e.g. 'enemy' matches 'enemy.gd', 'enemy_drone.gd')"),
|
||||
type_filter: z
|
||||
.string()
|
||||
.optional()
|
||||
.describe("Only include nodes of this Godot class (e.g. 'CharacterBody2D', 'Area2D')"),
|
||||
named_only: z
|
||||
.boolean()
|
||||
.optional()
|
||||
.describe("If true, exclude nodes with auto-generated names (names starting with '@'). Default: false"),
|
||||
}, async (params) => {
|
||||
try {
|
||||
const result = await godot.sendCommand("get_game_scene_tree", 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_game_node_properties", "Get properties of a node in the running game (requires a scene to be playing)", {
|
||||
node_path: z
|
||||
.string()
|
||||
.describe("Absolute node path in the running game (e.g. '/root/Main/Player')"),
|
||||
properties: coerceStringArray()
|
||||
.optional()
|
||||
.describe("Specific property names to read (default: all editor-visible properties)"),
|
||||
}, async (params) => {
|
||||
try {
|
||||
const result = await godot.sendCommand("get_game_node_properties", params);
|
||||
return {
|
||||
content: [
|
||||
{ type: "text", text: JSON.stringify(result, null, 2) },
|
||||
],
|
||||
};
|
||||
}
|
||||
catch (e) {
|
||||
return {
|
||||
content: [{ type: "text", text: formatErrorForMcp(e) }],
|
||||
isError: true,
|
||||
};
|
||||
}
|
||||
});
|
||||
server.tool("set_game_node_property", "Set a property on a node in the running game (requires a scene to be playing). Useful for live-tweaking values like position, speed, health, etc.", {
|
||||
node_path: z
|
||||
.string()
|
||||
.describe("Absolute node path in the running game (e.g. '/root/Main/Player')"),
|
||||
property: z
|
||||
.string()
|
||||
.describe("Property name to set (e.g. 'position', 'speed', 'health')"),
|
||||
value: z
|
||||
.union([z.string(), z.number(), z.boolean(), z.record(z.string(), z.number())])
|
||||
.describe("Value to set. Accepts: strings with auto-parsing ('Vector2(100,200)', '#ff0000'), numbers, booleans, or JSON objects for vectors/colors ({\"x\":5,\"y\":3,\"z\":10} for Vector3, {\"x\":100,\"y\":200} for Vector2, {\"r\":1,\"g\":0,\"b\":0,\"a\":1} for Color)"),
|
||||
}, async (params) => {
|
||||
try {
|
||||
const result = await godot.sendCommand("set_game_node_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("execute_game_script", "Execute arbitrary GDScript code inside the running game process. Use _mcp_print() to output values. Has access to the live scene tree and all game nodes.", {
|
||||
code: z
|
||||
.string()
|
||||
.describe("GDScript code to execute in the running game. Use _mcp_print(value) to capture output. Code runs inside a run() function with access to the live game scene tree."),
|
||||
}, async (params) => {
|
||||
try {
|
||||
const result = await godot.sendCommand("execute_game_script", params);
|
||||
return {
|
||||
content: [
|
||||
{ type: "text", text: JSON.stringify(result, null, 2) },
|
||||
],
|
||||
};
|
||||
}
|
||||
catch (e) {
|
||||
return {
|
||||
content: [{ type: "text", text: formatErrorForMcp(e) }],
|
||||
isError: true,
|
||||
};
|
||||
}
|
||||
});
|
||||
server.tool("capture_frames", "Capture multiple screenshots at regular frame intervals from the running game. Returns base64 PNG images. Use this to verify animations are playing correctly — if character poses differ across frames, the animation is working; if all frames show the same pose (e.g. T-pose), animation loading failed. Also useful for verifying movement, physics, and any time-based behavior. Prefer this over get_game_screenshot when you need to confirm something is changing over time.", {
|
||||
count: coerceNumber()
|
||||
.optional()
|
||||
.describe("Number of frames to capture (1-30, default: 5)"),
|
||||
frame_interval: coerceNumber()
|
||||
.optional()
|
||||
.describe("Frames to wait between captures (default: 10, i.e. ~6 captures/sec at 60fps)"),
|
||||
half_resolution: z
|
||||
.boolean()
|
||||
.optional()
|
||||
.describe("Halve resolution to reduce data size (default: true)"),
|
||||
node_data: z
|
||||
.object({
|
||||
node_path: z.string().describe("Path to a node to track (e.g. '/root/Main/Player')"),
|
||||
properties: coerceStringArray().describe("Property names to capture per frame (e.g. ['global_position', 'velocity'])"),
|
||||
})
|
||||
.optional()
|
||||
.describe("Optional: capture node property data alongside each frame for debugging (position, velocity, etc.)"),
|
||||
}, async (params) => {
|
||||
try {
|
||||
const result = (await godot.sendCommand("capture_frames", params));
|
||||
if (result &&
|
||||
typeof result === "object" &&
|
||||
"frames" in result &&
|
||||
Array.isArray(result.frames)) {
|
||||
const content = [];
|
||||
const frameData = Array.isArray(result.frame_data) ? result.frame_data : null;
|
||||
for (let i = 0; i < result.frames.length; i++) {
|
||||
content.push({
|
||||
type: "image",
|
||||
data: result.frames[i],
|
||||
mimeType: "image/png",
|
||||
});
|
||||
if (frameData && frameData[i]) {
|
||||
content.push({
|
||||
type: "text",
|
||||
text: `Frame ${i + 1}: ${JSON.stringify(frameData[i])}`,
|
||||
});
|
||||
}
|
||||
}
|
||||
content.push({
|
||||
type: "text",
|
||||
text: `Captured ${result.count} frames (${result.width}x${result.height}${result.half_resolution ? ", half-res" : ""})`,
|
||||
});
|
||||
return { content };
|
||||
}
|
||||
return {
|
||||
content: [
|
||||
{ type: "text", text: JSON.stringify(result, null, 2) },
|
||||
],
|
||||
};
|
||||
}
|
||||
catch (e) {
|
||||
return {
|
||||
content: [{ type: "text", text: formatErrorForMcp(e) }],
|
||||
isError: true,
|
||||
};
|
||||
}
|
||||
});
|
||||
server.tool("record_frames", "Record many screenshots to files on disk for long-running debug observation. Unlike capture_frames (which returns base64 images directly), this saves PNG files to user://mcp_recorded_frames/ and returns file paths. Use this when you need more than 30 frames or want to observe behavior over a longer period without flooding the context with image data.", {
|
||||
count: coerceNumber()
|
||||
.optional()
|
||||
.describe("Number of frames to capture (1-600, default: 30)"),
|
||||
frame_interval: coerceNumber()
|
||||
.optional()
|
||||
.describe("Frames to wait between captures (default: 10, i.e. ~6 captures/sec at 60fps)"),
|
||||
half_resolution: z
|
||||
.boolean()
|
||||
.optional()
|
||||
.describe("Halve resolution to reduce file size (default: true)"),
|
||||
node_data: z
|
||||
.object({
|
||||
node_path: z.string().describe("Path to a node to track (e.g. '/root/Main/Player')"),
|
||||
properties: coerceStringArray().describe("Property names to capture per frame (e.g. ['global_position', 'velocity'])"),
|
||||
})
|
||||
.optional()
|
||||
.describe("Optional: capture node property data alongside each frame for debugging"),
|
||||
}, async (params) => {
|
||||
try {
|
||||
const result = (await godot.sendCommand("record_frames", params));
|
||||
const content = [];
|
||||
content.push({
|
||||
type: "text",
|
||||
text: `Recorded ${result.count} frames to ${result.directory}/ (${result.width}x${result.height}${result.half_resolution ? ", half-res" : ""})`,
|
||||
});
|
||||
if (Array.isArray(result.files)) {
|
||||
content.push({
|
||||
type: "text",
|
||||
text: `Files:\n${result.files.join("\n")}`,
|
||||
});
|
||||
}
|
||||
if (Array.isArray(result.frame_data) && result.frame_data.length > 0) {
|
||||
content.push({
|
||||
type: "text",
|
||||
text: `Node data:\n${JSON.stringify(result.frame_data, null, 2)}`,
|
||||
});
|
||||
}
|
||||
return { content };
|
||||
}
|
||||
catch (e) {
|
||||
return {
|
||||
content: [{ type: "text", text: formatErrorForMcp(e) }],
|
||||
isError: true,
|
||||
};
|
||||
}
|
||||
});
|
||||
server.tool("monitor_properties", "Record property values over multiple frames from the running game. Returns a timeline of samples. Great for verifying movement (position changing), animation state (current_animation property), physics behavior (velocity), and debugging time-dependent issues.", {
|
||||
node_path: z
|
||||
.string()
|
||||
.describe("Absolute node path in the running game (e.g. '/root/Main/Player')"),
|
||||
properties: coerceStringArray()
|
||||
.describe("Property names to monitor (e.g. ['position', 'velocity'])"),
|
||||
frame_count: coerceNumber()
|
||||
.optional()
|
||||
.describe("Number of samples to collect (1-600, default: 60)"),
|
||||
frame_interval: coerceNumber()
|
||||
.optional()
|
||||
.describe("Frames to wait between samples (default: 1, every frame)"),
|
||||
}, async (params) => {
|
||||
try {
|
||||
const result = await godot.sendCommand("monitor_properties", params);
|
||||
return {
|
||||
content: [
|
||||
{ type: "text", text: JSON.stringify(result, null, 2) },
|
||||
],
|
||||
};
|
||||
}
|
||||
catch (e) {
|
||||
return {
|
||||
content: [{ type: "text", text: formatErrorForMcp(e) }],
|
||||
isError: true,
|
||||
};
|
||||
}
|
||||
});
|
||||
server.tool("watch_signals", "Monitor signal emissions on specified nodes in the running game for a duration. Returns a timestamped log of every signal fired — great for debugging event flow, verifying signal connections, and understanding runtime behavior.", {
|
||||
node_paths: z
|
||||
.array(z.string())
|
||||
.describe("Absolute node paths to watch (e.g. ['/root/Main/Player', '/root/Main/Enemy'])"),
|
||||
signal_filter: z
|
||||
.array(z.string())
|
||||
.optional()
|
||||
.describe("Only watch signals containing these substrings (e.g. ['health', 'died']). Omit to watch all signals."),
|
||||
duration_ms: coerceNumber()
|
||||
.optional()
|
||||
.describe("How long to watch in milliseconds (500-30000, default: 5000)"),
|
||||
}, async (params) => {
|
||||
try {
|
||||
const result = await godot.sendCommand("watch_signals", params);
|
||||
return {
|
||||
content: [
|
||||
{ type: "text", text: JSON.stringify(result, null, 2) },
|
||||
],
|
||||
};
|
||||
}
|
||||
catch (e) {
|
||||
return {
|
||||
content: [{ type: "text", text: formatErrorForMcp(e) }],
|
||||
isError: true,
|
||||
};
|
||||
}
|
||||
});
|
||||
server.tool("start_recording", "Start recording all input events (keyboard, mouse, actions) in the running game. Use stop_recording to get the recorded events.", {}, async () => {
|
||||
try {
|
||||
const result = await godot.sendCommand("start_recording");
|
||||
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
||||
}
|
||||
catch (e) {
|
||||
return { content: [{ type: "text", text: formatErrorForMcp(e) }], isError: true };
|
||||
}
|
||||
});
|
||||
server.tool("stop_recording", "Stop recording input events and return the recorded event timeline. Events include timestamps for replay.", {}, async () => {
|
||||
try {
|
||||
const result = await godot.sendCommand("stop_recording");
|
||||
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
||||
}
|
||||
catch (e) {
|
||||
return { content: [{ type: "text", text: formatErrorForMcp(e) }], isError: true };
|
||||
}
|
||||
});
|
||||
server.tool("replay_recording", "Replay a previously recorded input event sequence in the running game. Useful for regression testing — record a test once, replay it after code changes.", {
|
||||
events: z.array(z.record(z.string(), z.unknown())).describe("Array of recorded event objects (from stop_recording output)"),
|
||||
speed: z.number().optional().describe("Playback speed multiplier (default: 1.0, 2.0 = double speed)"),
|
||||
}, async (params) => {
|
||||
try {
|
||||
const result = await godot.sendCommand("replay_recording", 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_nodes_by_script", "Find all nodes in the running game whose script path contains a given string. Returns matching nodes with their properties.", {
|
||||
script: z
|
||||
.string()
|
||||
.describe("Script path substring to search for (e.g. 'enemy', 'player.gd')"),
|
||||
properties: coerceStringArray()
|
||||
.optional()
|
||||
.describe("Specific property names to include for each match (default: all editor-visible properties)"),
|
||||
}, async (params) => {
|
||||
try {
|
||||
const result = await godot.sendCommand("find_nodes_by_script", 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_autoload", "Get properties of an autoload/singleton node in the running game. Quick access to global game state like GameManager, EventBus, etc.", {
|
||||
name: z
|
||||
.string()
|
||||
.describe("Autoload name (e.g. 'GameManager', 'EventBus', 'SaveManager')"),
|
||||
properties: coerceStringArray()
|
||||
.optional()
|
||||
.describe("Specific property names to read (default: all editor-visible properties)"),
|
||||
}, async (params) => {
|
||||
try {
|
||||
const result = await godot.sendCommand("get_autoload", 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_ui_elements", "Find all visible UI elements (Button, Label, LineEdit, CheckBox, Slider, etc.) in the running game. Returns each element's text, type, position, and center point for clicking.", {
|
||||
type_filter: z
|
||||
.string()
|
||||
.optional()
|
||||
.describe("Only return elements of this type (e.g. 'Button', 'Label', 'CheckBox'). Default: all types"),
|
||||
}, async (params) => {
|
||||
try {
|
||||
const result = await godot.sendCommand("find_ui_elements", params);
|
||||
return {
|
||||
content: [
|
||||
{ type: "text", text: JSON.stringify(result, null, 2) },
|
||||
],
|
||||
};
|
||||
}
|
||||
catch (e) {
|
||||
return {
|
||||
content: [{ type: "text", text: formatErrorForMcp(e) }],
|
||||
isError: true,
|
||||
};
|
||||
}
|
||||
});
|
||||
server.tool("click_button_by_text", "Click a button in the running game by its text label. Finds the button, calculates its center, and simulates a full click (press + release). Much easier than manual coordinate-based clicking.", {
|
||||
text: z
|
||||
.string()
|
||||
.describe("Button text to search for (e.g. 'New Game', 'Start', 'OK')"),
|
||||
partial: z
|
||||
.boolean()
|
||||
.optional()
|
||||
.describe("Allow partial text matching (default: true). If false, requires exact match."),
|
||||
}, async (params) => {
|
||||
try {
|
||||
const result = await godot.sendCommand("click_button_by_text", params);
|
||||
return {
|
||||
content: [
|
||||
{ type: "text", text: JSON.stringify(result, null, 2) },
|
||||
],
|
||||
};
|
||||
}
|
||||
catch (e) {
|
||||
return {
|
||||
content: [{ type: "text", text: formatErrorForMcp(e) }],
|
||||
isError: true,
|
||||
};
|
||||
}
|
||||
});
|
||||
server.tool("wait_for_node", "Wait until a node exists at the given path in the running game scene tree. Useful for waiting after scene transitions, node spawning, or UI state changes.", {
|
||||
node_path: z
|
||||
.string()
|
||||
.describe("Absolute node path to wait for (e.g. '/root/Main/Player', '/root/Dungeon')"),
|
||||
timeout: z
|
||||
.number()
|
||||
.optional()
|
||||
.describe("Maximum seconds to wait (default: 5.0)"),
|
||||
poll_frames: z
|
||||
.number()
|
||||
.optional()
|
||||
.describe("Frames between each check (default: 5, i.e. ~12 checks/sec at 60fps)"),
|
||||
}, async (params) => {
|
||||
try {
|
||||
const result = await godot.sendCommand("wait_for_node", 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_nearby_nodes", "Find all nodes within a radius of a position in the running game, sorted by distance. Useful for finding what's near the player (collectibles, enemies, interactables) without manually querying each node's position.", {
|
||||
position: z
|
||||
.union([z.string(), z.object({ x: z.number(), y: z.number(), z: z.number().optional() })])
|
||||
.describe("Origin position: either a node_path string (e.g. '/root/Main/Player') to use that node's global_position, or an {x, y, z} coordinate object"),
|
||||
radius: coerceNumber()
|
||||
.optional()
|
||||
.describe("Search radius in world units (default: 20.0)"),
|
||||
type_filter: z
|
||||
.string()
|
||||
.optional()
|
||||
.describe("Only include nodes of this Godot class (e.g. 'Area3D', 'CharacterBody3D')"),
|
||||
group_filter: z
|
||||
.string()
|
||||
.optional()
|
||||
.describe("Only include nodes in this group (e.g. 'enemies', 'collectibles')"),
|
||||
max_results: coerceNumber()
|
||||
.optional()
|
||||
.describe("Maximum number of results to return (default: 10)"),
|
||||
}, async (params) => {
|
||||
try {
|
||||
const result = await godot.sendCommand("find_nearby_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("navigate_to", "Calculate navigation info from the player to a target in the running 3D game. Returns the world direction, camera-relative suggested WASD keys to press, camera yaw rotation needed (as mouse relative_x pixels for simulate_mouse_move), and estimated walk duration. Use this to plan movement instead of manually calculating directions.", {
|
||||
target: z
|
||||
.union([z.string(), z.object({ x: z.number(), y: z.number(), z: z.number() })])
|
||||
.describe("Target: either a node_path string (e.g. '/root/Main/Crystal') or an {x, y, z} coordinate object"),
|
||||
player_path: z
|
||||
.string()
|
||||
.optional()
|
||||
.describe("Player node path (default: '/root/Main/Player')"),
|
||||
camera_path: z
|
||||
.string()
|
||||
.optional()
|
||||
.describe("Camera node path (default: auto-detect active Camera3D)"),
|
||||
move_speed: coerceNumber()
|
||||
.optional()
|
||||
.describe("Player movement speed in units/sec for duration estimation (default: 5.0)"),
|
||||
}, async (params) => {
|
||||
try {
|
||||
const result = await godot.sendCommand("navigate_to", params);
|
||||
return {
|
||||
content: [
|
||||
{ type: "text", text: JSON.stringify(result, null, 2) },
|
||||
],
|
||||
};
|
||||
}
|
||||
catch (e) {
|
||||
return {
|
||||
content: [{ type: "text", text: formatErrorForMcp(e) }],
|
||||
isError: true,
|
||||
};
|
||||
}
|
||||
});
|
||||
server.tool("move_to", "Autopilot the player character to walk to a target position in the running 3D game. Handles camera rotation and forward movement internally at 60fps — completes in a single call with no manual simulate_key/simulate_mouse_move loops needed. The player's camera pivot is directly rotated toward the target, and W key is injected to walk. Much more reliable and efficient than navigate_to + manual input simulation.", {
|
||||
target: z
|
||||
.union([z.string(), z.object({ x: z.number(), y: z.number(), z: z.number() })])
|
||||
.describe("Target: either a node_path string (e.g. '/root/Main/Crystal') or an {x, y, z} coordinate object"),
|
||||
player_path: z
|
||||
.string()
|
||||
.optional()
|
||||
.describe("Player node path (default: '/root/Main/Player')"),
|
||||
camera_path: z
|
||||
.string()
|
||||
.optional()
|
||||
.describe("Camera pivot node path (default: auto-detect SpringArm3D child of player, or active Camera3D parent)"),
|
||||
arrival_radius: coerceNumber()
|
||||
.optional()
|
||||
.describe("Stop when this close to target in world units (default: 1.5)"),
|
||||
timeout: coerceNumber()
|
||||
.optional()
|
||||
.describe("Maximum seconds before giving up (default: 15.0)"),
|
||||
run: z
|
||||
.boolean()
|
||||
.optional()
|
||||
.describe("Hold Shift for running speed (default: false)"),
|
||||
look_at_target: z
|
||||
.boolean()
|
||||
.optional()
|
||||
.describe("Rotate camera toward target while moving (default: true). Set false to walk forward without turning."),
|
||||
}, async (params) => {
|
||||
try {
|
||||
const result = await godot.sendCommand("move_to", 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_get_properties", "Get properties of multiple nodes at once in the running game. More efficient than calling get_game_node_properties multiple times.", {
|
||||
nodes: z
|
||||
.array(z.object({
|
||||
path: z
|
||||
.string()
|
||||
.describe("Absolute node path (e.g. '/root/Main/Player')"),
|
||||
properties: coerceStringArray()
|
||||
.optional()
|
||||
.describe("Specific properties to read (default: all editor-visible)"),
|
||||
}))
|
||||
.describe("Array of nodes to query"),
|
||||
}, async (params) => {
|
||||
try {
|
||||
const result = await godot.sendCommand("batch_get_properties", params);
|
||||
return {
|
||||
content: [
|
||||
{ type: "text", text: JSON.stringify(result, null, 2) },
|
||||
],
|
||||
};
|
||||
}
|
||||
catch (e) {
|
||||
return {
|
||||
content: [{ type: "text", text: formatErrorForMcp(e) }],
|
||||
isError: true,
|
||||
};
|
||||
}
|
||||
});
|
||||
}
|
||||
//# sourceMappingURL=runtime-tools.js.map
|
||||
File diff suppressed because one or more lines are too long
4
wsl-dev-stack/godot-mcp-pro-v1.14.1/server/build/tools/scene-3d-tools.d.ts
vendored
Normal file
4
wsl-dev-stack/godot-mcp-pro-v1.14.1/server/build/tools/scene-3d-tools.d.ts
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
||||
import { GodotConnection } from "../godot-connection.js";
|
||||
export declare function registerScene3DTools(server: McpServer, godot: GodotConnection): void;
|
||||
//# sourceMappingURL=scene-3d-tools.d.ts.map
|
||||
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"scene-3d-tools.d.ts","sourceRoot":"","sources":["../../src/tools/scene-3d-tools.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAEpE,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAGzD,wBAAgB,oBAAoB,CAClC,MAAM,EAAE,SAAS,EACjB,KAAK,EAAE,eAAe,GACrB,IAAI,CA4dN"}
|
||||
@@ -0,0 +1,405 @@
|
||||
import { z } from "zod";
|
||||
import { formatErrorForMcp } from "../utils/errors.js";
|
||||
export function registerScene3DTools(server, godot) {
|
||||
// ─── 1. add_mesh_instance ──────────────────────────────────────────────
|
||||
server.tool("add_mesh_instance", "Add a MeshInstance3D node with a primitive mesh (Box, Sphere, Cylinder, Capsule, Plane, Prism, Torus, Quad) or load a 3D model file (.glb/.gltf/.obj). Set position, rotation, scale, and mesh-specific properties.", {
|
||||
mesh_type: z
|
||||
.string()
|
||||
.optional()
|
||||
.describe("Primitive mesh type: BoxMesh, SphereMesh, CylinderMesh, CapsuleMesh, PlaneMesh, PrismMesh, TorusMesh, QuadMesh"),
|
||||
mesh_file: z
|
||||
.string()
|
||||
.optional()
|
||||
.describe("Path to a 3D model file (res://path/to/model.glb, .gltf, .obj). Use instead of mesh_type for imported models"),
|
||||
parent_path: z
|
||||
.string()
|
||||
.optional()
|
||||
.describe("Parent node path (default: root '.')"),
|
||||
name: z.string().optional().describe("Node name (default: MeshInstance3D)"),
|
||||
position: z
|
||||
.any()
|
||||
.optional()
|
||||
.describe("Position as Vector3 string 'Vector3(x,y,z)', object {x,y,z}, or array [x,y,z]"),
|
||||
rotation: z
|
||||
.any()
|
||||
.optional()
|
||||
.describe("Rotation in degrees as Vector3 string, object {x,y,z}, or array [x,y,z]"),
|
||||
scale: z
|
||||
.any()
|
||||
.optional()
|
||||
.describe("Scale as Vector3 string, object {x,y,z}, or array [x,y,z]"),
|
||||
mesh_properties: z
|
||||
.record(z.string(), z.any())
|
||||
.optional()
|
||||
.describe("Properties to set on the mesh resource (e.g. {\"size\": \"Vector3(2,1,2)\"} for BoxMesh)"),
|
||||
}, async (params) => {
|
||||
try {
|
||||
const result = await godot.sendCommand("add_mesh_instance", params);
|
||||
return {
|
||||
content: [{ type: "text", text: JSON.stringify(result, null, 2) }],
|
||||
};
|
||||
}
|
||||
catch (e) {
|
||||
return {
|
||||
content: [{ type: "text", text: formatErrorForMcp(e) }],
|
||||
isError: true,
|
||||
};
|
||||
}
|
||||
});
|
||||
// ─── 2. setup_lighting ─────────────────────────────────────────────────
|
||||
server.tool("setup_lighting", "Add a light node (DirectionalLight3D, OmniLight3D, SpotLight3D) to the scene. Supports preset configurations: 'sun' (directional with shadows), 'indoor' (warm omni), 'dramatic' (focused spot with shadows).", {
|
||||
light_type: z
|
||||
.string()
|
||||
.optional()
|
||||
.describe("Light type: DirectionalLight3D, OmniLight3D, SpotLight3D. Not needed if preset is specified"),
|
||||
preset: z
|
||||
.string()
|
||||
.optional()
|
||||
.describe("Preset configuration: 'sun' (directional, shadows, -45deg), 'indoor' (warm omni, range 8), 'dramatic' (spot, high energy, shadows)"),
|
||||
parent_path: z
|
||||
.string()
|
||||
.optional()
|
||||
.describe("Parent node path (default: root '.')"),
|
||||
name: z.string().optional().describe("Node name"),
|
||||
color: z
|
||||
.any()
|
||||
.optional()
|
||||
.describe("Light color as Color string or hex (default: white)"),
|
||||
energy: z
|
||||
.number()
|
||||
.optional()
|
||||
.describe("Light energy/intensity (default: 1.0)"),
|
||||
shadows: z
|
||||
.boolean()
|
||||
.optional()
|
||||
.describe("Enable shadow casting (default: false, true for sun/dramatic presets)"),
|
||||
range: z
|
||||
.number()
|
||||
.optional()
|
||||
.describe("Range for OmniLight3D/SpotLight3D (default: 5.0)"),
|
||||
attenuation: z
|
||||
.number()
|
||||
.optional()
|
||||
.describe("Attenuation for OmniLight3D/SpotLight3D (default: 1.0)"),
|
||||
spot_angle: z
|
||||
.number()
|
||||
.optional()
|
||||
.describe("Spot angle in degrees for SpotLight3D (default: 45.0)"),
|
||||
spot_angle_attenuation: z
|
||||
.number()
|
||||
.optional()
|
||||
.describe("Spot angle attenuation for SpotLight3D (default: 1.0)"),
|
||||
position: z
|
||||
.any()
|
||||
.optional()
|
||||
.describe("Position as Vector3 string, object {x,y,z}, or array [x,y,z]"),
|
||||
rotation: z
|
||||
.any()
|
||||
.optional()
|
||||
.describe("Rotation in degrees as Vector3 string, object {x,y,z}, or array [x,y,z]"),
|
||||
}, async (params) => {
|
||||
try {
|
||||
const result = await godot.sendCommand("setup_lighting", params);
|
||||
return {
|
||||
content: [{ type: "text", text: JSON.stringify(result, null, 2) }],
|
||||
};
|
||||
}
|
||||
catch (e) {
|
||||
return {
|
||||
content: [{ type: "text", text: formatErrorForMcp(e) }],
|
||||
isError: true,
|
||||
};
|
||||
}
|
||||
});
|
||||
// ─── 3. set_material_3d ────────────────────────────────────────────────
|
||||
server.tool("set_material_3d", "Create and apply a StandardMaterial3D to a MeshInstance3D. Configure PBR properties: albedo color/texture, metallic, roughness, emission, transparency, normal maps.", {
|
||||
node_path: z
|
||||
.string()
|
||||
.describe("Path to the MeshInstance3D node"),
|
||||
surface_index: z
|
||||
.number()
|
||||
.optional()
|
||||
.describe("Surface index to apply material to (default: 0)"),
|
||||
albedo_color: z
|
||||
.any()
|
||||
.optional()
|
||||
.describe("Albedo color as Color string 'Color(r,g,b,a)', hex '#ff0000', or object {r,g,b,a}"),
|
||||
albedo_texture: z
|
||||
.string()
|
||||
.optional()
|
||||
.describe("Path to albedo texture (res://path/to/texture.png)"),
|
||||
metallic: z
|
||||
.number()
|
||||
.optional()
|
||||
.describe("Metallic value 0.0-1.0 (default: 0.0)"),
|
||||
roughness: z
|
||||
.number()
|
||||
.optional()
|
||||
.describe("Roughness value 0.0-1.0 (default: 1.0)"),
|
||||
metallic_texture: z
|
||||
.string()
|
||||
.optional()
|
||||
.describe("Path to metallic texture"),
|
||||
roughness_texture: z
|
||||
.string()
|
||||
.optional()
|
||||
.describe("Path to roughness texture"),
|
||||
normal_texture: z
|
||||
.string()
|
||||
.optional()
|
||||
.describe("Path to normal map texture (auto-enables normal mapping)"),
|
||||
emission: z
|
||||
.any()
|
||||
.optional()
|
||||
.describe("Emission color (auto-enables emission). Color string or hex"),
|
||||
emission_color: z
|
||||
.any()
|
||||
.optional()
|
||||
.describe("Alias for emission"),
|
||||
emission_energy: z
|
||||
.number()
|
||||
.optional()
|
||||
.describe("Emission energy multiplier (default: 1.0)"),
|
||||
emission_texture: z
|
||||
.string()
|
||||
.optional()
|
||||
.describe("Path to emission texture"),
|
||||
transparency: z
|
||||
.string()
|
||||
.optional()
|
||||
.describe("Transparency mode: DISABLED, ALPHA, ALPHA_SCISSOR, ALPHA_HASH, ALPHA_DEPTH_PRE_PASS"),
|
||||
cull_mode: z
|
||||
.string()
|
||||
.optional()
|
||||
.describe("Cull mode: BACK, FRONT, DISABLED"),
|
||||
}, async (params) => {
|
||||
try {
|
||||
const result = await godot.sendCommand("set_material_3d", params);
|
||||
return {
|
||||
content: [{ type: "text", text: JSON.stringify(result, null, 2) }],
|
||||
};
|
||||
}
|
||||
catch (e) {
|
||||
return {
|
||||
content: [{ type: "text", text: formatErrorForMcp(e) }],
|
||||
isError: true,
|
||||
};
|
||||
}
|
||||
});
|
||||
// ─── 4. setup_environment ──────────────────────────────────────────────
|
||||
server.tool("setup_environment", "Add or configure a WorldEnvironment node with sky, ambient light, tonemap, fog, glow, SSAO, SSR, and SDFGI settings.", {
|
||||
parent_path: z
|
||||
.string()
|
||||
.optional()
|
||||
.describe("Parent node path (default: root '.')"),
|
||||
node_path: z
|
||||
.string()
|
||||
.optional()
|
||||
.describe("Path to an existing WorldEnvironment to modify instead of creating a new one"),
|
||||
name: z
|
||||
.string()
|
||||
.optional()
|
||||
.describe("Node name (default: WorldEnvironment)"),
|
||||
background_mode: z
|
||||
.string()
|
||||
.optional()
|
||||
.describe("Background mode: 'sky', 'color', 'canvas', 'clear_color' (default: sky)"),
|
||||
background_color: z
|
||||
.any()
|
||||
.optional()
|
||||
.describe("Background color when mode is 'color'"),
|
||||
sky: z
|
||||
.object({
|
||||
sky_top_color: z.any().optional().describe("Sky top color"),
|
||||
sky_horizon_color: z.any().optional().describe("Sky horizon color"),
|
||||
ground_bottom_color: z.any().optional().describe("Ground bottom color"),
|
||||
ground_horizon_color: z
|
||||
.any()
|
||||
.optional()
|
||||
.describe("Ground horizon color"),
|
||||
sun_angle_max: z
|
||||
.number()
|
||||
.optional()
|
||||
.describe("Maximum sun angle in degrees"),
|
||||
sky_curve: z
|
||||
.number()
|
||||
.optional()
|
||||
.describe("Sky color curve (0.0-1.0)"),
|
||||
})
|
||||
.optional()
|
||||
.describe("ProceduralSkyMaterial settings"),
|
||||
ambient_light_color: z.any().optional().describe("Ambient light color"),
|
||||
ambient_light_energy: z
|
||||
.number()
|
||||
.optional()
|
||||
.describe("Ambient light energy"),
|
||||
ambient_light_source: z
|
||||
.string()
|
||||
.optional()
|
||||
.describe("Ambient light source: BACKGROUND, DISABLED, COLOR, SKY"),
|
||||
tonemap_mode: z
|
||||
.string()
|
||||
.optional()
|
||||
.describe("Tonemap mode: LINEAR, REINHARDT, FILMIC, ACES"),
|
||||
tonemap_exposure: z.number().optional().describe("Tonemap exposure"),
|
||||
tonemap_white: z.number().optional().describe("Tonemap white point"),
|
||||
fog_enabled: z.boolean().optional().describe("Enable volumetric fog"),
|
||||
fog_light_color: z.any().optional().describe("Fog light color"),
|
||||
fog_density: z.number().optional().describe("Fog density"),
|
||||
fog_light_energy: z.number().optional().describe("Fog light energy"),
|
||||
glow_enabled: z.boolean().optional().describe("Enable glow/bloom"),
|
||||
glow_intensity: z.number().optional().describe("Glow intensity"),
|
||||
glow_strength: z.number().optional().describe("Glow strength"),
|
||||
glow_bloom: z.number().optional().describe("Glow bloom amount"),
|
||||
ssao_enabled: z
|
||||
.boolean()
|
||||
.optional()
|
||||
.describe("Enable Screen-Space Ambient Occlusion"),
|
||||
ssao_radius: z.number().optional().describe("SSAO radius"),
|
||||
ssao_intensity: z.number().optional().describe("SSAO intensity"),
|
||||
ssr_enabled: z
|
||||
.boolean()
|
||||
.optional()
|
||||
.describe("Enable Screen-Space Reflections"),
|
||||
ssr_max_steps: z.number().optional().describe("SSR max steps"),
|
||||
ssr_fade_in: z.number().optional().describe("SSR fade in"),
|
||||
ssr_fade_out: z.number().optional().describe("SSR fade out"),
|
||||
sdfgi_enabled: z
|
||||
.boolean()
|
||||
.optional()
|
||||
.describe("Enable Signed Distance Field Global Illumination"),
|
||||
}, async (params) => {
|
||||
try {
|
||||
const result = await godot.sendCommand("setup_environment", params);
|
||||
return {
|
||||
content: [{ type: "text", text: JSON.stringify(result, null, 2) }],
|
||||
};
|
||||
}
|
||||
catch (e) {
|
||||
return {
|
||||
content: [{ type: "text", text: formatErrorForMcp(e) }],
|
||||
isError: true,
|
||||
};
|
||||
}
|
||||
});
|
||||
// ─── 5. setup_camera_3d ────────────────────────────────────────────────
|
||||
server.tool("setup_camera_3d", "Add or configure a Camera3D node. Set projection mode, FOV, near/far planes, position, rotation, look-at target, and cull mask.", {
|
||||
parent_path: z
|
||||
.string()
|
||||
.optional()
|
||||
.describe("Parent node path (default: root '.')"),
|
||||
node_path: z
|
||||
.string()
|
||||
.optional()
|
||||
.describe("Path to an existing Camera3D to configure instead of creating a new one"),
|
||||
name: z.string().optional().describe("Node name (default: Camera3D)"),
|
||||
projection: z
|
||||
.string()
|
||||
.optional()
|
||||
.describe("Projection mode: 'perspective', 'orthogonal'/'orthographic', 'frustum'"),
|
||||
fov: z
|
||||
.number()
|
||||
.optional()
|
||||
.describe("Field of view in degrees for perspective (default: 75)"),
|
||||
size: z
|
||||
.number()
|
||||
.optional()
|
||||
.describe("View size for orthogonal projection"),
|
||||
near: z
|
||||
.number()
|
||||
.optional()
|
||||
.describe("Near clipping plane (default: 0.05)"),
|
||||
far: z
|
||||
.number()
|
||||
.optional()
|
||||
.describe("Far clipping plane (default: 4000)"),
|
||||
cull_mask: z
|
||||
.number()
|
||||
.optional()
|
||||
.describe("Cull mask as integer bitmask"),
|
||||
current: z
|
||||
.boolean()
|
||||
.optional()
|
||||
.describe("Make this the current/active camera (default: false)"),
|
||||
position: z
|
||||
.any()
|
||||
.optional()
|
||||
.describe("Position as Vector3 (default: (0, 1, 3) for new cameras)"),
|
||||
rotation: z
|
||||
.any()
|
||||
.optional()
|
||||
.describe("Rotation in degrees as Vector3"),
|
||||
look_at: z
|
||||
.any()
|
||||
.optional()
|
||||
.describe("Target position to look at as Vector3 (overrides rotation)"),
|
||||
environment_path: z
|
||||
.string()
|
||||
.optional()
|
||||
.describe("Path to an Environment resource for camera-specific environment override"),
|
||||
}, async (params) => {
|
||||
try {
|
||||
const result = await godot.sendCommand("setup_camera_3d", params);
|
||||
return {
|
||||
content: [{ type: "text", text: JSON.stringify(result, null, 2) }],
|
||||
};
|
||||
}
|
||||
catch (e) {
|
||||
return {
|
||||
content: [{ type: "text", text: formatErrorForMcp(e) }],
|
||||
isError: true,
|
||||
};
|
||||
}
|
||||
});
|
||||
// ─── 6. add_gridmap ────────────────────────────────────────────────────
|
||||
server.tool("add_gridmap", "Add or configure a GridMap node with a MeshLibrary. Optionally set cells at specific grid positions with item IDs and orientations.", {
|
||||
parent_path: z
|
||||
.string()
|
||||
.optional()
|
||||
.describe("Parent node path (default: root '.')"),
|
||||
node_path: z
|
||||
.string()
|
||||
.optional()
|
||||
.describe("Path to an existing GridMap to configure instead of creating a new one"),
|
||||
name: z.string().optional().describe("Node name (default: GridMap)"),
|
||||
mesh_library_path: z
|
||||
.string()
|
||||
.optional()
|
||||
.describe("Path to a MeshLibrary resource (res://path/to/library.meshlib or .tres)"),
|
||||
cell_size: z
|
||||
.any()
|
||||
.optional()
|
||||
.describe("Cell size as Vector3 (default: (2, 2, 2))"),
|
||||
position: z.any().optional().describe("GridMap position as Vector3"),
|
||||
cells: z
|
||||
.array(z.object({
|
||||
x: z.number().describe("Cell X coordinate"),
|
||||
y: z.number().describe("Cell Y coordinate"),
|
||||
z: z.number().describe("Cell Z coordinate"),
|
||||
item: z
|
||||
.number()
|
||||
.optional()
|
||||
.describe("MeshLibrary item index (default: 0)"),
|
||||
orientation: z
|
||||
.number()
|
||||
.optional()
|
||||
.describe("Cell orientation index (default: 0)"),
|
||||
}))
|
||||
.optional()
|
||||
.describe("Array of cells to set with grid positions and item IDs"),
|
||||
}, async (params) => {
|
||||
try {
|
||||
const result = await godot.sendCommand("add_gridmap", params);
|
||||
return {
|
||||
content: [{ type: "text", text: JSON.stringify(result, null, 2) }],
|
||||
};
|
||||
}
|
||||
catch (e) {
|
||||
return {
|
||||
content: [{ type: "text", text: formatErrorForMcp(e) }],
|
||||
isError: true,
|
||||
};
|
||||
}
|
||||
});
|
||||
}
|
||||
//# sourceMappingURL=scene-3d-tools.js.map
|
||||
File diff suppressed because one or more lines are too long
4
wsl-dev-stack/godot-mcp-pro-v1.14.1/server/build/tools/scene-tools.d.ts
vendored
Normal file
4
wsl-dev-stack/godot-mcp-pro-v1.14.1/server/build/tools/scene-tools.d.ts
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
||||
import { GodotConnection } from "../godot-connection.js";
|
||||
export declare function registerSceneTools(server: McpServer, godot: GodotConnection): void;
|
||||
//# sourceMappingURL=scene-tools.d.ts.map
|
||||
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"scene-tools.d.ts","sourceRoot":"","sources":["../../src/tools/scene-tools.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAEpE,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAGzD,wBAAgB,kBAAkB,CAChC,MAAM,EAAE,SAAS,EACjB,KAAK,EAAE,eAAe,GACrB,IAAI,CAkKN"}
|
||||
@@ -0,0 +1,117 @@
|
||||
import { z } from "zod";
|
||||
import { formatErrorForMcp } from "../utils/errors.js";
|
||||
export function registerSceneTools(server, godot) {
|
||||
server.tool("get_scene_tree", "Get the live scene tree of the currently edited scene, showing all nodes, types, and hierarchy", {
|
||||
max_depth: z.number().optional().describe("Max tree depth to return (-1 for unlimited)"),
|
||||
}, async (params) => {
|
||||
try {
|
||||
const result = await godot.sendCommand("get_scene_tree", 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_file_content", "Read the raw .tscn file content of a scene", {
|
||||
path: z.string().describe("Path to the scene file (e.g. 'res://scenes/main.tscn')"),
|
||||
}, async (params) => {
|
||||
try {
|
||||
const result = await godot.sendCommand("get_scene_file_content", params);
|
||||
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
||||
}
|
||||
catch (e) {
|
||||
return { content: [{ type: "text", text: formatErrorForMcp(e) }], isError: true };
|
||||
}
|
||||
});
|
||||
server.tool("create_scene", "Create a new scene file with a specified root node type", {
|
||||
path: z.string().describe("Path for the new scene (e.g. 'res://scenes/enemy.tscn')"),
|
||||
root_type: z.string().optional().describe("Root node type (default: Node2D). Examples: Node2D, Node3D, Control, CharacterBody2D"),
|
||||
root_name: z.string().optional().describe("Root node name (defaults to filename)"),
|
||||
}, async (params) => {
|
||||
try {
|
||||
const result = await godot.sendCommand("create_scene", params);
|
||||
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
||||
}
|
||||
catch (e) {
|
||||
return { content: [{ type: "text", text: formatErrorForMcp(e) }], isError: true };
|
||||
}
|
||||
});
|
||||
server.tool("open_scene", "Open a scene file in the Godot editor", {
|
||||
path: z.string().describe("Path to the scene file (e.g. 'res://scenes/main.tscn')"),
|
||||
}, async (params) => {
|
||||
try {
|
||||
const result = await godot.sendCommand("open_scene", params);
|
||||
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
||||
}
|
||||
catch (e) {
|
||||
return { content: [{ type: "text", text: formatErrorForMcp(e) }], isError: true };
|
||||
}
|
||||
});
|
||||
server.tool("delete_scene", "Delete a scene file from the project", {
|
||||
path: z.string().describe("Path to the scene file to delete"),
|
||||
}, async (params) => {
|
||||
try {
|
||||
const result = await godot.sendCommand("delete_scene", params);
|
||||
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
||||
}
|
||||
catch (e) {
|
||||
return { content: [{ type: "text", text: formatErrorForMcp(e) }], isError: true };
|
||||
}
|
||||
});
|
||||
server.tool("add_scene_instance", "Add an existing scene as a child node (instancing) in the current scene", {
|
||||
scene_path: z.string().describe("Path to the scene to instance (e.g. 'res://scenes/enemy.tscn')"),
|
||||
parent_path: z.string().optional().describe("Parent node path (default: root '.')"),
|
||||
name: z.string().optional().describe("Custom name for the instance"),
|
||||
}, async (params) => {
|
||||
try {
|
||||
const result = await godot.sendCommand("add_scene_instance", params);
|
||||
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
||||
}
|
||||
catch (e) {
|
||||
return { content: [{ type: "text", text: formatErrorForMcp(e) }], isError: true };
|
||||
}
|
||||
});
|
||||
server.tool("play_scene", "Run a scene in the Godot editor (main scene, current scene, or specific path)", {
|
||||
mode: z.string().optional().describe("'main' (default), 'current', or a scene file path"),
|
||||
}, async (params) => {
|
||||
try {
|
||||
const result = await godot.sendCommand("play_scene", params);
|
||||
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
||||
}
|
||||
catch (e) {
|
||||
return { content: [{ type: "text", text: formatErrorForMcp(e) }], isError: true };
|
||||
}
|
||||
});
|
||||
server.tool("stop_scene", "Stop the currently playing scene", {}, async () => {
|
||||
try {
|
||||
const result = await godot.sendCommand("stop_scene");
|
||||
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
||||
}
|
||||
catch (e) {
|
||||
return { content: [{ type: "text", text: formatErrorForMcp(e) }], isError: true };
|
||||
}
|
||||
});
|
||||
server.tool("save_scene", "Save the currently edited scene to disk", {
|
||||
path: z.string().optional().describe("Optional path to save to (defaults to current scene path)"),
|
||||
}, async (params) => {
|
||||
try {
|
||||
const result = await godot.sendCommand("save_scene", 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_exports", "Get all @export variables from all scripted nodes in a scene file. Useful for inspecting configurable parameters without opening the scene.", {
|
||||
path: z.string().describe("Path to the scene file (e.g. 'res://scenes/enemy.tscn')"),
|
||||
}, async (params) => {
|
||||
try {
|
||||
const result = await godot.sendCommand("get_scene_exports", params);
|
||||
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
||||
}
|
||||
catch (e) {
|
||||
return { content: [{ type: "text", text: formatErrorForMcp(e) }], isError: true };
|
||||
}
|
||||
});
|
||||
}
|
||||
//# sourceMappingURL=scene-tools.js.map
|
||||
File diff suppressed because one or more lines are too long
4
wsl-dev-stack/godot-mcp-pro-v1.14.1/server/build/tools/script-tools.d.ts
vendored
Normal file
4
wsl-dev-stack/godot-mcp-pro-v1.14.1/server/build/tools/script-tools.d.ts
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
||||
import { GodotConnection } from "../godot-connection.js";
|
||||
export declare function registerScriptTools(server: McpServer, godot: GodotConnection): void;
|
||||
//# sourceMappingURL=script-tools.d.ts.map
|
||||
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"script-tools.d.ts","sourceRoot":"","sources":["../../src/tools/script-tools.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAEpE,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAGzD,wBAAgB,mBAAmB,CACjC,MAAM,EAAE,SAAS,EACjB,KAAK,EAAE,eAAe,GACrB,IAAI,CAoIN"}
|
||||
@@ -0,0 +1,100 @@
|
||||
import { z } from "zod";
|
||||
import { formatErrorForMcp } from "../utils/errors.js";
|
||||
export function registerScriptTools(server, godot) {
|
||||
server.tool("list_scripts", "List all GDScript/C#/shader files in the project with class info", {
|
||||
path: z.string().optional().describe("Root path to search (default: res://)"),
|
||||
recursive: z.boolean().optional().describe("Search recursively (default: true)"),
|
||||
}, async (params) => {
|
||||
try {
|
||||
const result = await godot.sendCommand("list_scripts", params);
|
||||
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
||||
}
|
||||
catch (e) {
|
||||
return { content: [{ type: "text", text: formatErrorForMcp(e) }], isError: true };
|
||||
}
|
||||
});
|
||||
server.tool("read_script", "Read the full content of a GDScript file", {
|
||||
path: z.string().describe("Path to the script (e.g. 'res://scripts/player.gd')"),
|
||||
}, async (params) => {
|
||||
try {
|
||||
const result = await godot.sendCommand("read_script", params);
|
||||
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
||||
}
|
||||
catch (e) {
|
||||
return { content: [{ type: "text", text: formatErrorForMcp(e) }], isError: true };
|
||||
}
|
||||
});
|
||||
server.tool("create_script", "Create a new GDScript file with optional content or auto-generated template. Restricted to .gd/.cs paths. Refuses to overwrite a script that is currently open in Godot's script editor unless force=true is set.", {
|
||||
path: z.string().describe("Path for the new script (e.g. 'res://scripts/enemy_ai.gd'). Must be a .gd or .cs file."),
|
||||
content: z.string().optional().describe("Full script content. If empty, generates a template."),
|
||||
extends: z.string().optional().describe("Base class (default: 'Node'). Only used for template generation."),
|
||||
class_name: z.string().optional().describe("Class name to add. Only used for template generation."),
|
||||
force: z.boolean().optional().describe("Override the open-script-editor guard and write anyway. Use only when no editor buffer holds unsaved changes for the target path."),
|
||||
}, async (params) => {
|
||||
try {
|
||||
const result = await godot.sendCommand("create_script", params);
|
||||
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
||||
}
|
||||
catch (e) {
|
||||
return { content: [{ type: "text", text: formatErrorForMcp(e) }], isError: true };
|
||||
}
|
||||
});
|
||||
server.tool("edit_script", "Edit a script using search-and-replace, full content replacement, line insertion, or 1-based inclusive line-range replacement. Restricted to .gd/.cs paths. Refuses to write a script that is currently open in Godot's script editor unless force=true is set.", {
|
||||
path: z.string().describe("Path to the script to edit. Must be a .gd or .cs file."),
|
||||
replacements: z
|
||||
.array(z.object({
|
||||
search: z.string().describe("Text to find"),
|
||||
replace: z.string().describe("Replacement text"),
|
||||
regex: z.boolean().optional().describe("Use regex for search (default: false)"),
|
||||
}))
|
||||
.optional()
|
||||
.describe("Array of search-and-replace operations"),
|
||||
content: z.string().optional().describe("Full replacement content (replaces entire file), or replacement lines when combined with start_line/end_line"),
|
||||
insert_at_line: z.number().optional().describe("Line number to insert text at (0-indexed)"),
|
||||
text: z.string().optional().describe("Text to insert (used with insert_at_line)"),
|
||||
start_line: z.number().optional().describe("1-based inclusive starting line for range replacement (used with content)"),
|
||||
end_line: z.number().optional().describe("1-based inclusive ending line for range replacement (defaults to start_line)"),
|
||||
force: z.boolean().optional().describe("Override the open-script-editor guard and write anyway."),
|
||||
}, async (params) => {
|
||||
try {
|
||||
const result = await godot.sendCommand("edit_script", params);
|
||||
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
||||
}
|
||||
catch (e) {
|
||||
return { content: [{ type: "text", text: formatErrorForMcp(e) }], isError: true };
|
||||
}
|
||||
});
|
||||
server.tool("attach_script", "Attach a GDScript to a node in the current scene", {
|
||||
node_path: z.string().describe("Path to the target node"),
|
||||
script_path: z.string().describe("Path to the script file (e.g. 'res://scripts/player.gd')"),
|
||||
}, async (params) => {
|
||||
try {
|
||||
const result = await godot.sendCommand("attach_script", params);
|
||||
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
||||
}
|
||||
catch (e) {
|
||||
return { content: [{ type: "text", text: formatErrorForMcp(e) }], isError: true };
|
||||
}
|
||||
});
|
||||
server.tool("validate_script", "Validate a GDScript file by attempting to compile it. Returns whether the script is valid. Use get_output_log or get_editor_errors for detailed error messages on failure.", {
|
||||
path: z.string().describe("Path to the script to validate (e.g. 'res://scripts/player.gd')"),
|
||||
}, async (params) => {
|
||||
try {
|
||||
const result = await godot.sendCommand("validate_script", 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_open_scripts", "Get a list of scripts currently open in the Godot script editor", {}, async () => {
|
||||
try {
|
||||
const result = await godot.sendCommand("get_open_scripts");
|
||||
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
||||
}
|
||||
catch (e) {
|
||||
return { content: [{ type: "text", text: formatErrorForMcp(e) }], isError: true };
|
||||
}
|
||||
});
|
||||
}
|
||||
//# sourceMappingURL=script-tools.js.map
|
||||
File diff suppressed because one or more lines are too long
4
wsl-dev-stack/godot-mcp-pro-v1.14.1/server/build/tools/shader-tools.d.ts
vendored
Normal file
4
wsl-dev-stack/godot-mcp-pro-v1.14.1/server/build/tools/shader-tools.d.ts
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
||||
import { GodotConnection } from "../godot-connection.js";
|
||||
export declare function registerShaderTools(server: McpServer, godot: GodotConnection): void;
|
||||
//# sourceMappingURL=shader-tools.d.ts.map
|
||||
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"shader-tools.d.ts","sourceRoot":"","sources":["../../src/tools/shader-tools.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAEpE,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAGzD,wBAAgB,mBAAmB,CACjC,MAAM,EAAE,SAAS,EACjB,KAAK,EAAE,eAAe,GACrB,IAAI,CA4GN"}
|
||||
@@ -0,0 +1,83 @@
|
||||
import { z } from "zod";
|
||||
import { formatErrorForMcp } from "../utils/errors.js";
|
||||
export function registerShaderTools(server, godot) {
|
||||
server.tool("create_shader", "Create a new shader file with a template or custom content. Refuses to overwrite a shader that is currently loaded/open in the editor unless force=true.", {
|
||||
path: z.string().describe("Path for the shader file (e.g. 'res://shaders/dissolve.gdshader')"),
|
||||
shader_type: z.string().optional().describe("Shader type: spatial, canvas_item, particles, sky (default: spatial)"),
|
||||
content: z.string().optional().describe("Full shader code. If empty, generates a template."),
|
||||
force: z.boolean().optional().describe("Override the open/cached-shader guard and write anyway."),
|
||||
}, async (params) => {
|
||||
try {
|
||||
const result = await godot.sendCommand("create_shader", params);
|
||||
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
||||
}
|
||||
catch (e) {
|
||||
return { content: [{ type: "text", text: formatErrorForMcp(e) }], isError: true };
|
||||
}
|
||||
});
|
||||
server.tool("read_shader", "Read the content of a shader file", {
|
||||
path: z.string().describe("Path to the shader file"),
|
||||
}, async (params) => {
|
||||
try {
|
||||
const result = await godot.sendCommand("read_shader", params);
|
||||
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
||||
}
|
||||
catch (e) {
|
||||
return { content: [{ type: "text", text: formatErrorForMcp(e) }], isError: true };
|
||||
}
|
||||
});
|
||||
server.tool("edit_shader", "Edit a shader file using full replacement or search-and-replace. Refreshes any cached/loaded copy of the shader via take_over_path + emit_changed so live materials pick up changes. Refuses to write if the shader is currently loaded/open in the editor unless force=true.", {
|
||||
path: z.string().describe("Path to the shader file"),
|
||||
content: z.string().optional().describe("Full replacement content"),
|
||||
replacements: z.array(z.object({
|
||||
search: z.string().describe("Text to find"),
|
||||
replace: z.string().describe("Text to replace with"),
|
||||
})).optional().describe("Array of search-and-replace operations"),
|
||||
force: z.boolean().optional().describe("Override the open/cached-shader guard and write anyway."),
|
||||
}, async (params) => {
|
||||
try {
|
||||
const result = await godot.sendCommand("edit_shader", params);
|
||||
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
||||
}
|
||||
catch (e) {
|
||||
return { content: [{ type: "text", text: formatErrorForMcp(e) }], isError: true };
|
||||
}
|
||||
});
|
||||
server.tool("assign_shader_material", "Create a ShaderMaterial from a shader file and assign it to a node", {
|
||||
node_path: z.string().describe("Path to the target node (CanvasItem or MeshInstance3D)"),
|
||||
shader_path: z.string().describe("Path to the shader file"),
|
||||
}, async (params) => {
|
||||
try {
|
||||
const result = await godot.sendCommand("assign_shader_material", params);
|
||||
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
||||
}
|
||||
catch (e) {
|
||||
return { content: [{ type: "text", text: formatErrorForMcp(e) }], isError: true };
|
||||
}
|
||||
});
|
||||
server.tool("set_shader_param", "Set a shader parameter on a node's ShaderMaterial", {
|
||||
node_path: z.string().describe("Path to the node with a ShaderMaterial"),
|
||||
param: z.string().describe("Shader parameter name"),
|
||||
value: z.union([z.string(), z.number(), z.boolean()]).describe("Parameter value. Strings auto-parsed for Vector2, Color, etc."),
|
||||
}, async (params) => {
|
||||
try {
|
||||
const result = await godot.sendCommand("set_shader_param", 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_shader_params", "Get all shader parameters and their current values from a node's ShaderMaterial", {
|
||||
node_path: z.string().describe("Path to the node with a ShaderMaterial"),
|
||||
}, async (params) => {
|
||||
try {
|
||||
const result = await godot.sendCommand("get_shader_params", params);
|
||||
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
||||
}
|
||||
catch (e) {
|
||||
return { content: [{ type: "text", text: formatErrorForMcp(e) }], isError: true };
|
||||
}
|
||||
});
|
||||
}
|
||||
//# sourceMappingURL=shader-tools.js.map
|
||||
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"shader-tools.js","sourceRoot":"","sources":["../../src/tools/shader-tools.ts"],"names":[],"mappings":"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"}
|
||||
4
wsl-dev-stack/godot-mcp-pro-v1.14.1/server/build/tools/test-tools.d.ts
vendored
Normal file
4
wsl-dev-stack/godot-mcp-pro-v1.14.1/server/build/tools/test-tools.d.ts
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
||||
import { GodotConnection } from "../godot-connection.js";
|
||||
export declare function registerTestTools(server: McpServer, godot: GodotConnection): void;
|
||||
//# sourceMappingURL=test-tools.d.ts.map
|
||||
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"test-tools.d.ts","sourceRoot":"","sources":["../../src/tools/test-tools.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAEpE,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAGzD,wBAAgB,iBAAiB,CAC/B,MAAM,EAAE,SAAS,EACjB,KAAK,EAAE,eAAe,GACrB,IAAI,CA0LN"}
|
||||
@@ -0,0 +1,146 @@
|
||||
import { z } from "zod";
|
||||
import { formatErrorForMcp } from "../utils/errors.js";
|
||||
export function registerTestTools(server, godot) {
|
||||
server.tool("run_test_scenario", "Execute a test scenario in the running game. Optionally plays a scene, then runs a sequence of steps (input simulation, waits, assertions, screenshots). Returns pass/fail summary. Note: keep scenarios short (under 20 seconds total) to avoid timeout.", {
|
||||
scene_path: z
|
||||
.string()
|
||||
.optional()
|
||||
.describe("Scene to play before running steps. Use 'main' for main scene, 'current' for current scene, or a res:// path. If omitted, uses already-running scene."),
|
||||
steps: z
|
||||
.array(z.record(z.string(), z.unknown()))
|
||||
.describe("Array of test steps. Each step has a 'type' field: " +
|
||||
"'input' (action/keycode simulation), " +
|
||||
"'wait' (seconds or node_path to wait for), " +
|
||||
"'assert' (node_path+property+expected+operator, or text for screen text), " +
|
||||
"'screenshot' (capture a frame). " +
|
||||
"Examples: " +
|
||||
"{type:'input', action:'ui_accept'}, " +
|
||||
"{type:'wait', seconds:0.5}, " +
|
||||
"{type:'wait', node_path:'/root/Main/Player'}, " +
|
||||
"{type:'assert', node_path:'/root/Main/Player', property:'health', expected:100, operator:'eq'}, " +
|
||||
"{type:'assert', text:'Game Over'}, " +
|
||||
"{type:'screenshot'}"),
|
||||
}, async (params) => {
|
||||
try {
|
||||
const result = await godot.sendCommand("run_test_scenario", params);
|
||||
return {
|
||||
content: [
|
||||
{ type: "text", text: JSON.stringify(result, null, 2) },
|
||||
],
|
||||
};
|
||||
}
|
||||
catch (e) {
|
||||
return {
|
||||
content: [{ type: "text", text: formatErrorForMcp(e) }],
|
||||
isError: true,
|
||||
};
|
||||
}
|
||||
});
|
||||
server.tool("assert_node_state", "Assert a node's property value in the running game. Compares the actual property value against an expected value using the specified operator. Returns pass/fail with actual value for debugging.", {
|
||||
node_path: z
|
||||
.string()
|
||||
.describe("Absolute node path in the running game (e.g. '/root/Main/Player')"),
|
||||
property: z
|
||||
.string()
|
||||
.describe("Property name to check (e.g. 'health', 'position:x', 'visible')"),
|
||||
expected: z
|
||||
.union([z.string(), z.number(), z.boolean()])
|
||||
.describe("Expected value to compare against"),
|
||||
operator: z
|
||||
.enum(["eq", "neq", "gt", "lt", "gte", "lte", "contains", "type_is"])
|
||||
.optional()
|
||||
.describe("Comparison operator (default: 'eq'). " +
|
||||
"eq/neq: equality, gt/lt/gte/lte: numeric comparison, " +
|
||||
"contains: string/array contains, type_is: check Godot type name"),
|
||||
}, async (params) => {
|
||||
try {
|
||||
const result = await godot.sendCommand("assert_node_state", params);
|
||||
return {
|
||||
content: [
|
||||
{ type: "text", text: JSON.stringify(result, null, 2) },
|
||||
],
|
||||
};
|
||||
}
|
||||
catch (e) {
|
||||
return {
|
||||
content: [{ type: "text", text: formatErrorForMcp(e) }],
|
||||
isError: true,
|
||||
};
|
||||
}
|
||||
});
|
||||
server.tool("assert_screen_text", "Assert that specific text is visible on screen in the running game. Searches all visible UI elements (Button, Label, LineEdit, etc.) for matching text. Useful for verifying UI state, dialog content, or game messages.", {
|
||||
text: z
|
||||
.string()
|
||||
.describe("Text to search for on screen (e.g. 'Game Over', 'Score:', 'New Game')"),
|
||||
partial: z
|
||||
.boolean()
|
||||
.optional()
|
||||
.describe("Allow partial text matching (default: true). If false, requires exact match."),
|
||||
case_sensitive: z
|
||||
.boolean()
|
||||
.optional()
|
||||
.describe("Case-sensitive comparison (default: true)"),
|
||||
}, async (params) => {
|
||||
try {
|
||||
const result = await godot.sendCommand("assert_screen_text", params);
|
||||
return {
|
||||
content: [
|
||||
{ type: "text", text: JSON.stringify(result, null, 2) },
|
||||
],
|
||||
};
|
||||
}
|
||||
catch (e) {
|
||||
return {
|
||||
content: [{ type: "text", text: formatErrorForMcp(e) }],
|
||||
isError: true,
|
||||
};
|
||||
}
|
||||
});
|
||||
server.tool("run_stress_test", "Run rapid random input events for a specified duration and check if the game crashes. Sends random UI actions (up/down/left/right/accept/cancel) plus any custom actions. Returns whether the game survived, event count, and new errors.", {
|
||||
duration: z
|
||||
.number()
|
||||
.optional()
|
||||
.describe("Duration in seconds to run the stress test (1-60, default: 5)"),
|
||||
actions: z
|
||||
.array(z.string())
|
||||
.optional()
|
||||
.describe("Additional input action names to include in random input pool (e.g. ['jump', 'attack', 'dash'])"),
|
||||
}, async (params) => {
|
||||
try {
|
||||
const result = await godot.sendCommand("run_stress_test", 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_test_report", "Collect and format results from all assertions run so far (via assert_node_state, assert_screen_text, and run_test_scenario) into a summary test report. Shows pass/fail counts, pass rate, and detailed results.", {
|
||||
clear: z
|
||||
.boolean()
|
||||
.optional()
|
||||
.describe("Clear accumulated results after generating report (default: true)"),
|
||||
}, async (params) => {
|
||||
try {
|
||||
const result = await godot.sendCommand("get_test_report", params);
|
||||
return {
|
||||
content: [
|
||||
{ type: "text", text: JSON.stringify(result, null, 2) },
|
||||
],
|
||||
};
|
||||
}
|
||||
catch (e) {
|
||||
return {
|
||||
content: [{ type: "text", text: formatErrorForMcp(e) }],
|
||||
isError: true,
|
||||
};
|
||||
}
|
||||
});
|
||||
}
|
||||
//# sourceMappingURL=test-tools.js.map
|
||||
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"test-tools.js","sourceRoot":"","sources":["../../src/tools/test-tools.ts"],"names":[],"mappings":"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"}
|
||||
4
wsl-dev-stack/godot-mcp-pro-v1.14.1/server/build/tools/theme-tools.d.ts
vendored
Normal file
4
wsl-dev-stack/godot-mcp-pro-v1.14.1/server/build/tools/theme-tools.d.ts
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
||||
import { GodotConnection } from "../godot-connection.js";
|
||||
export declare function registerThemeTools(server: McpServer, godot: GodotConnection): void;
|
||||
//# sourceMappingURL=theme-tools.d.ts.map
|
||||
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"theme-tools.d.ts","sourceRoot":"","sources":["../../src/tools/theme-tools.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAEpE,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAGzD,wBAAgB,kBAAkB,CAChC,MAAM,EAAE,SAAS,EACjB,KAAK,EAAE,eAAe,GACrB,IAAI,CA2IN"}
|
||||
@@ -0,0 +1,109 @@
|
||||
import { z } from "zod";
|
||||
import { formatErrorForMcp } from "../utils/errors.js";
|
||||
export function registerThemeTools(server, godot) {
|
||||
server.tool("create_theme", "Create a new Theme resource file", {
|
||||
path: z.string().describe("Path to save the theme (e.g. 'res://themes/main.tres')"),
|
||||
default_font_size: z.number().optional().describe("Default font size"),
|
||||
}, async (params) => {
|
||||
try {
|
||||
const result = await godot.sendCommand("create_theme", params);
|
||||
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
||||
}
|
||||
catch (e) {
|
||||
return { content: [{ type: "text", text: formatErrorForMcp(e) }], isError: true };
|
||||
}
|
||||
});
|
||||
server.tool("set_theme_color", "Set a theme color override on a Control node", {
|
||||
node_path: z.string().describe("Path to the Control node"),
|
||||
name: z.string().describe("Color name (e.g. 'font_color', 'font_hover_color')"),
|
||||
color: z.string().describe("Color as hex string (e.g. '#ff0000') or name"),
|
||||
theme_type: z.string().optional().describe("Theme type (defaults to node's class)"),
|
||||
}, async (params) => {
|
||||
try {
|
||||
const result = await godot.sendCommand("set_theme_color", params);
|
||||
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
||||
}
|
||||
catch (e) {
|
||||
return { content: [{ type: "text", text: formatErrorForMcp(e) }], isError: true };
|
||||
}
|
||||
});
|
||||
server.tool("set_theme_constant", "Set a theme constant override on a Control node", {
|
||||
node_path: z.string().describe("Path to the Control node"),
|
||||
name: z.string().describe("Constant name (e.g. 'margin_left', 'separation')"),
|
||||
value: z.number().describe("Integer value"),
|
||||
}, async (params) => {
|
||||
try {
|
||||
const result = await godot.sendCommand("set_theme_constant", params);
|
||||
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
||||
}
|
||||
catch (e) {
|
||||
return { content: [{ type: "text", text: formatErrorForMcp(e) }], isError: true };
|
||||
}
|
||||
});
|
||||
server.tool("set_theme_font_size", "Set a theme font size override on a Control node", {
|
||||
node_path: z.string().describe("Path to the Control node"),
|
||||
name: z.string().describe("Font size name (e.g. 'font_size')"),
|
||||
size: z.number().describe("Font size in pixels"),
|
||||
}, async (params) => {
|
||||
try {
|
||||
const result = await godot.sendCommand("set_theme_font_size", params);
|
||||
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
||||
}
|
||||
catch (e) {
|
||||
return { content: [{ type: "text", text: formatErrorForMcp(e) }], isError: true };
|
||||
}
|
||||
});
|
||||
server.tool("set_theme_stylebox", "Set a StyleBoxFlat override on a Control node with customizable appearance", {
|
||||
node_path: z.string().describe("Path to the Control node"),
|
||||
name: z.string().describe("Style name (e.g. 'panel', 'normal', 'hover', 'pressed')"),
|
||||
bg_color: z.string().optional().describe("Background color (hex)"),
|
||||
border_color: z.string().optional().describe("Border color (hex)"),
|
||||
border_width: z.number().optional().describe("Border width in pixels"),
|
||||
corner_radius: z.number().optional().describe("Corner radius in pixels"),
|
||||
padding: z.number().optional().describe("Content padding in pixels"),
|
||||
}, async (params) => {
|
||||
try {
|
||||
const result = await godot.sendCommand("set_theme_stylebox", params);
|
||||
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
||||
}
|
||||
catch (e) {
|
||||
return { content: [{ type: "text", text: formatErrorForMcp(e) }], isError: true };
|
||||
}
|
||||
});
|
||||
server.tool("setup_control", "Configure a Control/Container node's layout properties in one call. Sets anchor preset, margins, min size, size flags, and container-specific properties like separation — much faster than multiple update_property calls.", {
|
||||
node_path: z.string().describe("Path to the Control node"),
|
||||
anchor_preset: z.string().optional().describe("Anchor preset: 'top_left', 'top_right', 'bottom_left', 'bottom_right', 'center_left', 'center_top', 'center_right', 'center_bottom', 'center', 'left_wide', 'top_wide', 'right_wide', 'bottom_wide', 'vcenter_wide', 'hcenter_wide', 'full_rect'"),
|
||||
min_size: z.string().optional().describe("Minimum size as 'Vector2(w, h)'"),
|
||||
size_flags_h: z.string().optional().describe("Horizontal size flags: 'fill', 'expand', 'fill_expand', 'shrink_center', 'shrink_end'"),
|
||||
size_flags_v: z.string().optional().describe("Vertical size flags: 'fill', 'expand', 'fill_expand', 'shrink_center', 'shrink_end'"),
|
||||
margins: z.object({
|
||||
left: z.number().optional(),
|
||||
top: z.number().optional(),
|
||||
right: z.number().optional(),
|
||||
bottom: z.number().optional(),
|
||||
}).optional().describe("Margin overrides for MarginContainer (sets theme constants margin_left/right/top/bottom)"),
|
||||
separation: z.number().optional().describe("Separation for VBoxContainer/HBoxContainer (theme constant override)"),
|
||||
grow_h: z.string().optional().describe("Horizontal grow direction: 'begin', 'end', 'both'"),
|
||||
grow_v: z.string().optional().describe("Vertical grow direction: 'begin', 'end', 'both'"),
|
||||
}, async (params) => {
|
||||
try {
|
||||
const result = await godot.sendCommand("setup_control", 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_theme_info", "Get theme information and overrides for a Control node", {
|
||||
node_path: z.string().describe("Path to the Control node"),
|
||||
}, async (params) => {
|
||||
try {
|
||||
const result = await godot.sendCommand("get_theme_info", params);
|
||||
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
||||
}
|
||||
catch (e) {
|
||||
return { content: [{ type: "text", text: formatErrorForMcp(e) }], isError: true };
|
||||
}
|
||||
});
|
||||
}
|
||||
//# sourceMappingURL=theme-tools.js.map
|
||||
File diff suppressed because one or more lines are too long
4
wsl-dev-stack/godot-mcp-pro-v1.14.1/server/build/tools/tilemap-tools.d.ts
vendored
Normal file
4
wsl-dev-stack/godot-mcp-pro-v1.14.1/server/build/tools/tilemap-tools.d.ts
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
||||
import { GodotConnection } from "../godot-connection.js";
|
||||
export declare function registerTilemapTools(server: McpServer, godot: GodotConnection): void;
|
||||
//# sourceMappingURL=tilemap-tools.d.ts.map
|
||||
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"tilemap-tools.d.ts","sourceRoot":"","sources":["../../src/tools/tilemap-tools.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAEpE,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAGzD,wBAAgB,oBAAoB,CAClC,MAAM,EAAE,SAAS,EACjB,KAAK,EAAE,eAAe,GACrB,IAAI,CAiHN"}
|
||||
@@ -0,0 +1,88 @@
|
||||
import { z } from "zod";
|
||||
import { formatErrorForMcp } from "../utils/errors.js";
|
||||
export function registerTilemapTools(server, godot) {
|
||||
server.tool("tilemap_set_cell", "Set a single cell in a TileMapLayer", {
|
||||
node_path: z.string().describe("Path to the TileMapLayer node"),
|
||||
x: z.number().describe("Cell X coordinate"),
|
||||
y: z.number().describe("Cell Y coordinate"),
|
||||
source_id: z.number().optional().describe("Tile source ID (default: 0)"),
|
||||
atlas_x: z.number().optional().describe("Atlas X coordinate (default: 0)"),
|
||||
atlas_y: z.number().optional().describe("Atlas Y coordinate (default: 0)"),
|
||||
alternative: z.number().optional().describe("Alternative tile ID (default: 0)"),
|
||||
}, async (params) => {
|
||||
try {
|
||||
const result = await godot.sendCommand("tilemap_set_cell", params);
|
||||
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
||||
}
|
||||
catch (e) {
|
||||
return { content: [{ type: "text", text: formatErrorForMcp(e) }], isError: true };
|
||||
}
|
||||
});
|
||||
server.tool("tilemap_fill_rect", "Fill a rectangular region of a TileMapLayer with tiles", {
|
||||
node_path: z.string().describe("Path to the TileMapLayer node"),
|
||||
x1: z.number().describe("Start X coordinate"),
|
||||
y1: z.number().describe("Start Y coordinate"),
|
||||
x2: z.number().describe("End X coordinate"),
|
||||
y2: z.number().describe("End Y coordinate"),
|
||||
source_id: z.number().optional().describe("Tile source ID (default: 0)"),
|
||||
atlas_x: z.number().optional().describe("Atlas X coordinate (default: 0)"),
|
||||
atlas_y: z.number().optional().describe("Atlas Y coordinate (default: 0)"),
|
||||
alternative: z.number().optional().describe("Alternative tile ID (default: 0)"),
|
||||
}, async (params) => {
|
||||
try {
|
||||
const result = await godot.sendCommand("tilemap_fill_rect", params);
|
||||
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
||||
}
|
||||
catch (e) {
|
||||
return { content: [{ type: "text", text: formatErrorForMcp(e) }], isError: true };
|
||||
}
|
||||
});
|
||||
server.tool("tilemap_get_cell", "Get tile data at a specific cell in a TileMapLayer", {
|
||||
node_path: z.string().describe("Path to the TileMapLayer node"),
|
||||
x: z.number().describe("Cell X coordinate"),
|
||||
y: z.number().describe("Cell Y coordinate"),
|
||||
}, async (params) => {
|
||||
try {
|
||||
const result = await godot.sendCommand("tilemap_get_cell", params);
|
||||
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
||||
}
|
||||
catch (e) {
|
||||
return { content: [{ type: "text", text: formatErrorForMcp(e) }], isError: true };
|
||||
}
|
||||
});
|
||||
server.tool("tilemap_clear", "Clear all cells in a TileMapLayer", {
|
||||
node_path: z.string().describe("Path to the TileMapLayer node"),
|
||||
}, async (params) => {
|
||||
try {
|
||||
const result = await godot.sendCommand("tilemap_clear", params);
|
||||
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
||||
}
|
||||
catch (e) {
|
||||
return { content: [{ type: "text", text: formatErrorForMcp(e) }], isError: true };
|
||||
}
|
||||
});
|
||||
server.tool("tilemap_get_info", "Get TileMapLayer info including tile set sources and cell count", {
|
||||
node_path: z.string().describe("Path to the TileMapLayer node"),
|
||||
}, async (params) => {
|
||||
try {
|
||||
const result = await godot.sendCommand("tilemap_get_info", params);
|
||||
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
||||
}
|
||||
catch (e) {
|
||||
return { content: [{ type: "text", text: formatErrorForMcp(e) }], isError: true };
|
||||
}
|
||||
});
|
||||
server.tool("tilemap_get_used_cells", "Get a list of used (non-empty) cells in a TileMapLayer", {
|
||||
node_path: z.string().describe("Path to the TileMapLayer node"),
|
||||
max_count: z.number().optional().describe("Maximum cells to return (default: 500)"),
|
||||
}, async (params) => {
|
||||
try {
|
||||
const result = await godot.sendCommand("tilemap_get_used_cells", params);
|
||||
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
||||
}
|
||||
catch (e) {
|
||||
return { content: [{ type: "text", text: formatErrorForMcp(e) }], isError: true };
|
||||
}
|
||||
});
|
||||
}
|
||||
//# sourceMappingURL=tilemap-tools.js.map
|
||||
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"tilemap-tools.js","sourceRoot":"","sources":["../../src/tools/tilemap-tools.ts"],"names":[],"mappings":"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"}
|
||||
Reference in New Issue
Block a user