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