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