breakpoint-mcp 1.0.0 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/config.js +6 -30
- package/dist/index.js +3 -3
- package/dist/tools/editor/animation.js +162 -0
- package/dist/tools/editor/audio.js +109 -0
- package/dist/tools/editor/common.js +31 -0
- package/dist/tools/editor/core.js +49 -0
- package/dist/tools/editor/filesystem.js +35 -0
- package/dist/tools/editor/introspection.js +73 -0
- package/dist/tools/editor/node.js +171 -0
- package/dist/tools/editor/particles.js +96 -0
- package/dist/tools/editor/physics.js +236 -0
- package/dist/tools/editor/project_input_test.js +187 -0
- package/dist/tools/editor/resource.js +104 -0
- package/dist/tools/editor/scene.js +95 -0
- package/dist/tools/editor/shader.js +59 -0
- package/dist/tools/editor/signal.js +67 -0
- package/dist/tools/editor/spatial.js +185 -0
- package/dist/tools/editor/tiles.js +160 -0
- package/dist/tools/editor/ui.js +175 -0
- package/dist/tools/editor.js +39 -1914
- package/package.json +1 -1
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { gate } from "../../confirm.js";
|
|
3
|
+
/** InputMap, extended project config (autoloads / export presets / main scene / settings), editor settings, and test-framework detection. */
|
|
4
|
+
export function registerProjectInputTestTools(server, call) {
|
|
5
|
+
server.registerTool("inputmap_add_action", {
|
|
6
|
+
title: "Add input action",
|
|
7
|
+
description: "Define a project input action (ProjectSettings input/<name>) with an empty event list and a deadzone. Set save=true to persist to project.godot. DESTRUCTIVE (project-wide input map) — gated by confirmation.",
|
|
8
|
+
inputSchema: {
|
|
9
|
+
name: z.string().describe("Action name (without the input/ prefix)"),
|
|
10
|
+
deadzone: z.number().optional().describe("Analog deadzone 0..1 (default 0.5)"),
|
|
11
|
+
save: z.boolean().optional().describe("Persist to project.godot (default false)"),
|
|
12
|
+
confirm: z.boolean().optional().describe("Auto-approve this destructive action (skip the confirmation prompt)"),
|
|
13
|
+
},
|
|
14
|
+
}, async ({ name, deadzone, save, confirm }) => {
|
|
15
|
+
const blocked = await gate(server, confirm, `Add input action "${name}"${save ? " and save project.godot" : ""}`);
|
|
16
|
+
if (blocked)
|
|
17
|
+
return blocked;
|
|
18
|
+
const params = { name };
|
|
19
|
+
if (deadzone !== undefined)
|
|
20
|
+
params.deadzone = deadzone;
|
|
21
|
+
if (save !== undefined)
|
|
22
|
+
params.save = save;
|
|
23
|
+
return call("inputmap.add_action", params);
|
|
24
|
+
});
|
|
25
|
+
server.registerTool("inputmap_add_event", {
|
|
26
|
+
title: "Add input event to action",
|
|
27
|
+
description: "Append an input event to an existing project input action. 'event' is { type: key|mouse_button|joy_button|joy_motion, ... } — key: keycode or physical_keycode as a name like \"A\"/\"Space\" or an int; mouse_button/joy_button: button_index; joy_motion: axis + axis_value. Set save=true to persist. DESTRUCTIVE — gated by confirmation.",
|
|
28
|
+
inputSchema: {
|
|
29
|
+
name: z.string().describe("Existing action name (without the input/ prefix)"),
|
|
30
|
+
event: z
|
|
31
|
+
.object({
|
|
32
|
+
type: z.enum(["key", "mouse_button", "joy_button", "joy_motion"]).describe("Event type"),
|
|
33
|
+
keycode: z.union([z.string(), z.number()]).optional().describe("Key name or code (type=key)"),
|
|
34
|
+
physical_keycode: z.union([z.string(), z.number()]).optional().describe("Physical key name or code (type=key)"),
|
|
35
|
+
button_index: z.number().optional().describe("Button index (mouse_button/joy_button)"),
|
|
36
|
+
axis: z.number().optional().describe("Joypad axis (joy_motion)"),
|
|
37
|
+
axis_value: z.number().optional().describe("Joypad axis value (joy_motion)"),
|
|
38
|
+
})
|
|
39
|
+
.describe("Input event descriptor"),
|
|
40
|
+
save: z.boolean().optional().describe("Persist to project.godot (default false)"),
|
|
41
|
+
confirm: z.boolean().optional().describe("Auto-approve this destructive action (skip the confirmation prompt)"),
|
|
42
|
+
},
|
|
43
|
+
}, async ({ name, event, save, confirm }) => {
|
|
44
|
+
const blocked = await gate(server, confirm, `Add input event to "${name}"`);
|
|
45
|
+
if (blocked)
|
|
46
|
+
return blocked;
|
|
47
|
+
const params = { name, event };
|
|
48
|
+
if (save !== undefined)
|
|
49
|
+
params.save = save;
|
|
50
|
+
return call("inputmap.add_event", params);
|
|
51
|
+
});
|
|
52
|
+
server.registerTool("inputmap_list", {
|
|
53
|
+
title: "List input actions",
|
|
54
|
+
description: "List all project-defined input actions (ProjectSettings input/*) with their deadzone and events (class + human-readable text). Read-only.",
|
|
55
|
+
inputSchema: {},
|
|
56
|
+
}, async () => call("inputmap.list"));
|
|
57
|
+
server.registerTool("inputmap_erase_action", {
|
|
58
|
+
title: "Erase input action",
|
|
59
|
+
description: "Remove a project input action (ProjectSettings input/<name>). Set save=true to persist to project.godot. DESTRUCTIVE — gated by confirmation.",
|
|
60
|
+
inputSchema: {
|
|
61
|
+
name: z.string().describe("Action name (without the input/ prefix)"),
|
|
62
|
+
save: z.boolean().optional().describe("Persist to project.godot (default false)"),
|
|
63
|
+
confirm: z.boolean().optional().describe("Auto-approve this destructive action (skip the confirmation prompt)"),
|
|
64
|
+
},
|
|
65
|
+
}, async ({ name, save, confirm }) => {
|
|
66
|
+
const blocked = await gate(server, confirm, `Erase input action "${name}"${save ? " and save project.godot" : ""}`);
|
|
67
|
+
if (blocked)
|
|
68
|
+
return blocked;
|
|
69
|
+
const params = { name };
|
|
70
|
+
if (save !== undefined)
|
|
71
|
+
params.save = save;
|
|
72
|
+
return call("inputmap.erase_action", params);
|
|
73
|
+
});
|
|
74
|
+
server.registerTool("project_add_autoload", {
|
|
75
|
+
title: "Add autoload singleton",
|
|
76
|
+
description: "Register an autoload (ProjectSettings autoload/<name>) pointing at a res:// script or scene, enabled as a global singleton by default. Set save=true to persist to project.godot. DESTRUCTIVE — gated by confirmation.",
|
|
77
|
+
inputSchema: {
|
|
78
|
+
name: z.string().describe("Autoload / singleton name"),
|
|
79
|
+
path: z.string().describe("res:// path to a .gd script or .tscn scene"),
|
|
80
|
+
enabled: z.boolean().optional().describe("Enable as a global singleton (default true)"),
|
|
81
|
+
save: z.boolean().optional().describe("Persist to project.godot (default false)"),
|
|
82
|
+
confirm: z.boolean().optional().describe("Auto-approve this destructive action (skip the confirmation prompt)"),
|
|
83
|
+
},
|
|
84
|
+
}, async ({ name, path, enabled, save, confirm }) => {
|
|
85
|
+
const blocked = await gate(server, confirm, `Add autoload "${name}" -> ${path}${save ? " and save project.godot" : ""}`);
|
|
86
|
+
if (blocked)
|
|
87
|
+
return blocked;
|
|
88
|
+
const params = { name, path };
|
|
89
|
+
if (enabled !== undefined)
|
|
90
|
+
params.enabled = enabled;
|
|
91
|
+
if (save !== undefined)
|
|
92
|
+
params.save = save;
|
|
93
|
+
return call("project.add_autoload", params);
|
|
94
|
+
});
|
|
95
|
+
server.registerTool("project_remove_autoload", {
|
|
96
|
+
title: "Remove autoload singleton",
|
|
97
|
+
description: "Remove an autoload (ProjectSettings autoload/<name>). Set save=true to persist to project.godot. DESTRUCTIVE — gated by confirmation.",
|
|
98
|
+
inputSchema: {
|
|
99
|
+
name: z.string().describe("Autoload / singleton name"),
|
|
100
|
+
save: z.boolean().optional().describe("Persist to project.godot (default false)"),
|
|
101
|
+
confirm: z.boolean().optional().describe("Auto-approve this destructive action (skip the confirmation prompt)"),
|
|
102
|
+
},
|
|
103
|
+
}, async ({ name, save, confirm }) => {
|
|
104
|
+
const blocked = await gate(server, confirm, `Remove autoload "${name}"${save ? " and save project.godot" : ""}`);
|
|
105
|
+
if (blocked)
|
|
106
|
+
return blocked;
|
|
107
|
+
const params = { name };
|
|
108
|
+
if (save !== undefined)
|
|
109
|
+
params.save = save;
|
|
110
|
+
return call("project.remove_autoload", params);
|
|
111
|
+
});
|
|
112
|
+
server.registerTool("project_add_export_preset", {
|
|
113
|
+
title: "Add export preset",
|
|
114
|
+
description: "Append an export preset to res://export_presets.cfg for a platform (e.g. \"Windows Desktop\", \"Web\", \"Linux/X11\", \"macOS\"). Returns the preset's index. DESTRUCTIVE (writes export_presets.cfg) — gated by confirmation.",
|
|
115
|
+
inputSchema: {
|
|
116
|
+
name: z.string().describe("Preset display name"),
|
|
117
|
+
platform: z.string().describe("Export platform name as shown in the editor"),
|
|
118
|
+
runnable: z.boolean().optional().describe("Mark the preset runnable (default true)"),
|
|
119
|
+
export_path: z.string().optional().describe("Default export output path"),
|
|
120
|
+
confirm: z.boolean().optional().describe("Auto-approve this destructive action (skip the confirmation prompt)"),
|
|
121
|
+
},
|
|
122
|
+
}, async ({ name, platform, runnable, export_path, confirm }) => {
|
|
123
|
+
const blocked = await gate(server, confirm, `Add export preset "${name}" (${platform})`);
|
|
124
|
+
if (blocked)
|
|
125
|
+
return blocked;
|
|
126
|
+
const params = { name, platform };
|
|
127
|
+
if (runnable !== undefined)
|
|
128
|
+
params.runnable = runnable;
|
|
129
|
+
if (export_path !== undefined)
|
|
130
|
+
params.export_path = export_path;
|
|
131
|
+
return call("project.add_export_preset", params);
|
|
132
|
+
});
|
|
133
|
+
server.registerTool("project_set_main_scene", {
|
|
134
|
+
title: "Set main scene",
|
|
135
|
+
description: "Set the project's main scene (ProjectSettings application/run/main_scene) to an existing res:// .tscn/.scn. Set save=true to persist to project.godot. DESTRUCTIVE — gated by confirmation.",
|
|
136
|
+
inputSchema: {
|
|
137
|
+
path: z.string().describe("res:// path to the scene to run first"),
|
|
138
|
+
save: z.boolean().optional().describe("Persist to project.godot (default false)"),
|
|
139
|
+
confirm: z.boolean().optional().describe("Auto-approve this destructive action (skip the confirmation prompt)"),
|
|
140
|
+
},
|
|
141
|
+
}, async ({ path, save, confirm }) => {
|
|
142
|
+
const blocked = await gate(server, confirm, `Set main scene to ${path}${save ? " and save project.godot" : ""}`);
|
|
143
|
+
if (blocked)
|
|
144
|
+
return blocked;
|
|
145
|
+
const params = { path };
|
|
146
|
+
if (save !== undefined)
|
|
147
|
+
params.save = save;
|
|
148
|
+
return call("project.set_main_scene", params);
|
|
149
|
+
});
|
|
150
|
+
server.registerTool("project_list_settings", {
|
|
151
|
+
title: "List project settings",
|
|
152
|
+
description: "List ProjectSettings keys and values, optionally filtered by a dotted-key prefix (e.g. \"input/\", \"autoload/\", \"application/\"). Read-only.",
|
|
153
|
+
inputSchema: {
|
|
154
|
+
prefix: z.string().optional().describe("Only return keys starting with this prefix (default: all)"),
|
|
155
|
+
},
|
|
156
|
+
}, async ({ prefix }) => call("project.list_settings", prefix !== undefined ? { prefix } : {}));
|
|
157
|
+
server.registerTool("editorsettings_get_set", {
|
|
158
|
+
title: "Get or set an editor setting",
|
|
159
|
+
description: "Read an EditorSettings value by name; if 'value' is provided, write it instead (persists to the editor's global config). Reading is read-only; writing is DESTRUCTIVE (mutates the editor config) — gated by confirmation.",
|
|
160
|
+
inputSchema: {
|
|
161
|
+
name: z.string().describe("EditorSettings key, e.g. interface/editor/code_font_size"),
|
|
162
|
+
value: z.any().optional().describe("If provided, set this value (rich types use the {\"__type__\":...} tagging convention)"),
|
|
163
|
+
confirm: z.boolean().optional().describe("Auto-approve the write (skip the confirmation prompt)"),
|
|
164
|
+
},
|
|
165
|
+
}, async ({ name, value, confirm }) => {
|
|
166
|
+
if (value !== undefined) {
|
|
167
|
+
const blocked = await gate(server, confirm, `Set editor setting "${name}"`);
|
|
168
|
+
if (blocked)
|
|
169
|
+
return blocked;
|
|
170
|
+
return call("editorsettings.get_set", { name, value });
|
|
171
|
+
}
|
|
172
|
+
return call("editorsettings.get_set", { name });
|
|
173
|
+
});
|
|
174
|
+
server.registerTool("test_detect", {
|
|
175
|
+
title: "Detect test framework",
|
|
176
|
+
description: "Detect an installed GDScript test framework (GUT or GdUnit4) in the project. Returns { framework: gut|gdunit4|none, path, version }. Read-only.",
|
|
177
|
+
inputSchema: {},
|
|
178
|
+
}, async () => call("test.detect"));
|
|
179
|
+
server.registerTool("test_list", {
|
|
180
|
+
title: "List test scripts",
|
|
181
|
+
description: "List GDScript test scripts (files named test_*.gd or *_test.gd) under a directory (default res://test), searched recursively. Read-only.",
|
|
182
|
+
inputSchema: {
|
|
183
|
+
dir: z.string().optional().describe("Directory to search (default res://test)"),
|
|
184
|
+
},
|
|
185
|
+
}, async ({ dir }) => call("test.list", dir !== undefined ? { dir } : {}));
|
|
186
|
+
}
|
|
187
|
+
//# sourceMappingURL=project_input_test.js.map
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { gate } from "../../confirm.js";
|
|
3
|
+
/** Resource (.tres/.res) create / load / save / property / import ops. */
|
|
4
|
+
export function registerResourceTools(server, call) {
|
|
5
|
+
server.registerTool("resource_create", {
|
|
6
|
+
title: "Create resource",
|
|
7
|
+
description: "Instantiate a Resource subclass and save it as a new file. DESTRUCTIVE (writes a file) — gated by confirmation. Optional initial properties use the tagged-Variant convention.",
|
|
8
|
+
inputSchema: {
|
|
9
|
+
class_name: z.string().describe("Resource subclass to instantiate, e.g. StyleBoxFlat, Theme, GDScript"),
|
|
10
|
+
to_path: z.string().describe("Destination res:// path, e.g. res://styles/panel.tres"),
|
|
11
|
+
properties: z.record(z.any()).optional().describe("Initial property values (JSON scalars or __type__-tagged Variants)"),
|
|
12
|
+
confirm: z.boolean().optional().describe("Auto-approve this destructive action (skip the confirmation prompt)"),
|
|
13
|
+
},
|
|
14
|
+
}, async ({ class_name, to_path, properties, confirm }) => {
|
|
15
|
+
const blocked = await gate(server, confirm, `Create ${class_name} resource at ${to_path}`);
|
|
16
|
+
if (blocked)
|
|
17
|
+
return blocked;
|
|
18
|
+
return call("resource.create", properties !== undefined ? { class_name, to_path, properties } : { class_name, to_path });
|
|
19
|
+
});
|
|
20
|
+
server.registerTool("resource_load", {
|
|
21
|
+
title: "Load resource",
|
|
22
|
+
description: "Load a resource file and return its class, resource_name, and inspector-visible property list. Read-only.",
|
|
23
|
+
inputSchema: { path: z.string().describe("Resource res:// path") },
|
|
24
|
+
}, async ({ path }) => call("resource.load", { path }));
|
|
25
|
+
server.registerTool("resource_save", {
|
|
26
|
+
title: "Save resource",
|
|
27
|
+
description: "Load a resource and (re-)save it, optionally to a new path and with ResourceSaver flags. DESTRUCTIVE (writes a file) — gated by confirmation. Shares subresources by reference; use resource_duplicate for an independent copy.",
|
|
28
|
+
inputSchema: {
|
|
29
|
+
from_path: z.string().describe("Source resource res:// path"),
|
|
30
|
+
to_path: z.string().optional().describe("Destination res:// path (default: overwrite from_path)"),
|
|
31
|
+
flags: z.number().int().optional().describe("ResourceSaver.SaverFlags bitmask (e.g. 32 = FLAG_COMPRESS)"),
|
|
32
|
+
confirm: z.boolean().optional().describe("Auto-approve this destructive action (skip the confirmation prompt)"),
|
|
33
|
+
},
|
|
34
|
+
}, async ({ from_path, to_path, flags, confirm }) => {
|
|
35
|
+
const blocked = await gate(server, confirm, `Save resource ${from_path}${to_path ? ` to ${to_path}` : ""}`);
|
|
36
|
+
if (blocked)
|
|
37
|
+
return blocked;
|
|
38
|
+
const params = { from_path };
|
|
39
|
+
if (to_path !== undefined)
|
|
40
|
+
params.to_path = to_path;
|
|
41
|
+
if (flags !== undefined)
|
|
42
|
+
params.flags = flags;
|
|
43
|
+
return call("resource.save", params);
|
|
44
|
+
});
|
|
45
|
+
server.registerTool("resource_duplicate", {
|
|
46
|
+
title: "Duplicate resource",
|
|
47
|
+
description: "Load a resource, duplicate it (optionally deep, cloning subresources), and save the copy to a new path. DESTRUCTIVE (writes a file) — gated by confirmation.",
|
|
48
|
+
inputSchema: {
|
|
49
|
+
path: z.string().describe("Source resource res:// path"),
|
|
50
|
+
to_path: z.string().describe("Destination res:// path for the copy"),
|
|
51
|
+
deep: z.boolean().optional().describe("Deep-duplicate subresources (default false)"),
|
|
52
|
+
confirm: z.boolean().optional().describe("Auto-approve this destructive action (skip the confirmation prompt)"),
|
|
53
|
+
},
|
|
54
|
+
}, async ({ path, to_path, deep, confirm }) => {
|
|
55
|
+
const blocked = await gate(server, confirm, `Duplicate resource ${path} to ${to_path}`);
|
|
56
|
+
if (blocked)
|
|
57
|
+
return blocked;
|
|
58
|
+
return call("resource.duplicate", deep !== undefined ? { path, to_path, deep } : { path, to_path });
|
|
59
|
+
});
|
|
60
|
+
server.registerTool("resource_get_property", {
|
|
61
|
+
title: "Get resource property",
|
|
62
|
+
description: "Read a single property of a resource file by name. Read-only. The value comes back tagged (Variant convention).",
|
|
63
|
+
inputSchema: {
|
|
64
|
+
path: z.string().describe("Resource res:// path"),
|
|
65
|
+
property: z.string().describe("Property name"),
|
|
66
|
+
},
|
|
67
|
+
}, async ({ path, property }) => call("resource.get_property", { path, property }));
|
|
68
|
+
server.registerTool("resource_set_property", {
|
|
69
|
+
title: "Set resource property",
|
|
70
|
+
description: "Set a single property on a resource file and save it. DESTRUCTIVE (writes a file) — gated by confirmation. The value uses the tagged-Variant convention.",
|
|
71
|
+
inputSchema: {
|
|
72
|
+
path: z.string().describe("Resource res:// path"),
|
|
73
|
+
property: z.string().describe("Property name"),
|
|
74
|
+
value: z.any().describe("New value (JSON scalar or __type__-tagged Variant)"),
|
|
75
|
+
confirm: z.boolean().optional().describe("Auto-approve this destructive action (skip the confirmation prompt)"),
|
|
76
|
+
},
|
|
77
|
+
}, async ({ path, property, value, confirm }) => {
|
|
78
|
+
const blocked = await gate(server, confirm, `Set ${property} on ${path}`);
|
|
79
|
+
if (blocked)
|
|
80
|
+
return blocked;
|
|
81
|
+
return call("resource.set_property", { path, property, value });
|
|
82
|
+
});
|
|
83
|
+
server.registerTool("resource_get_import_settings", {
|
|
84
|
+
title: "Get import settings",
|
|
85
|
+
description: "Read an asset's import metadata (.import): the importer and its parameters. Read-only. Returns imported=false when the asset has no .import sidecar.",
|
|
86
|
+
inputSchema: { path: z.string().describe("Asset res:// path (e.g. res://icon.png)") },
|
|
87
|
+
}, async ({ path }) => call("resource.get_import_settings", { path }));
|
|
88
|
+
server.registerTool("resource_set_import_settings", {
|
|
89
|
+
title: "Set import settings",
|
|
90
|
+
description: "Update import parameters in an asset's .import metadata and trigger a reimport. DESTRUCTIVE (rewrites metadata + reimports) — gated by confirmation. Errors if the asset has no .import sidecar.",
|
|
91
|
+
inputSchema: {
|
|
92
|
+
path: z.string().describe("Asset res:// path"),
|
|
93
|
+
settings: z.record(z.any()).describe("Import params to set (name -> JSON scalar or __type__-tagged Variant)"),
|
|
94
|
+
reimport: z.boolean().optional().describe("Reimport after writing (default true)"),
|
|
95
|
+
confirm: z.boolean().optional().describe("Auto-approve this destructive action (skip the confirmation prompt)"),
|
|
96
|
+
},
|
|
97
|
+
}, async ({ path, settings, reimport, confirm }) => {
|
|
98
|
+
const blocked = await gate(server, confirm, `Set import settings on ${path} and reimport`);
|
|
99
|
+
if (blocked)
|
|
100
|
+
return blocked;
|
|
101
|
+
return call("resource.set_import_settings", reimport !== undefined ? { path, settings, reimport } : { path, settings });
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
//# sourceMappingURL=resource.js.map
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { gate } from "../../confirm.js";
|
|
3
|
+
/** Scene lifecycle: open / save / new / reload / pack / dependencies. */
|
|
4
|
+
export function registerSceneTools(server, call) {
|
|
5
|
+
server.registerTool("scene_get_tree", {
|
|
6
|
+
title: "Get scene tree",
|
|
7
|
+
description: "Return the node tree of the currently edited scene (name, type, path, script, children).",
|
|
8
|
+
inputSchema: { max_depth: z.number().int().positive().optional().describe("Max recursion depth (default 64)") },
|
|
9
|
+
}, async ({ max_depth }) => call("scene.get_tree", max_depth ? { max_depth } : {}));
|
|
10
|
+
server.registerTool("scene_open", {
|
|
11
|
+
title: "Open scene",
|
|
12
|
+
description: "Open an existing scene in the editor by res:// path.",
|
|
13
|
+
inputSchema: { path: z.string().describe("Scene path, e.g. res://scenes/main.tscn") },
|
|
14
|
+
}, async ({ path }) => call("scene.open", { path }));
|
|
15
|
+
server.registerTool("scene_save", { title: "Save scene", description: "Save the currently edited scene to its existing path.", inputSchema: {} }, async () => call("scene.save"));
|
|
16
|
+
server.registerTool("scene_new", {
|
|
17
|
+
title: "New scene",
|
|
18
|
+
description: "Create a new scene with the given root class, save it to a path, and open it. DESTRUCTIVE (writes a file) — gated by confirmation.",
|
|
19
|
+
inputSchema: {
|
|
20
|
+
root_type: z.string().describe("Root node class, e.g. Node2D, Node3D, Control"),
|
|
21
|
+
path: z.string().describe("Where to save, e.g. res://scenes/new.tscn"),
|
|
22
|
+
name: z.string().optional().describe("Root node name (defaults to the class name)"),
|
|
23
|
+
confirm: z.boolean().optional().describe("Auto-approve this destructive action (skip the confirmation prompt)"),
|
|
24
|
+
},
|
|
25
|
+
}, async ({ root_type, path, name, confirm }) => {
|
|
26
|
+
const blocked = await gate(server, confirm, `Create and overwrite scene file "${path}"`);
|
|
27
|
+
if (blocked)
|
|
28
|
+
return blocked;
|
|
29
|
+
return call("scene.new", { root_type, path, name });
|
|
30
|
+
});
|
|
31
|
+
server.registerTool("scene_list_open", {
|
|
32
|
+
title: "List open scenes",
|
|
33
|
+
description: "List the res:// paths of all scenes open in the editor, which one is current, and which have unsaved changes. Read-only.",
|
|
34
|
+
inputSchema: {},
|
|
35
|
+
}, async () => call("scene.list_open"));
|
|
36
|
+
server.registerTool("scene_reload", {
|
|
37
|
+
title: "Reload scene from disk",
|
|
38
|
+
description: "Reload a scene from disk, discarding unsaved changes to it. DESTRUCTIVE — gated by confirmation. Defaults to the current scene.",
|
|
39
|
+
inputSchema: {
|
|
40
|
+
path: z.string().optional().describe("Scene res:// path; omitted = the current edited scene"),
|
|
41
|
+
confirm: z.boolean().optional().describe("Auto-approve this destructive action (skip the confirmation prompt)"),
|
|
42
|
+
},
|
|
43
|
+
}, async ({ path, confirm }) => {
|
|
44
|
+
const blocked = await gate(server, confirm, `Reload scene ${path ?? "(current)"} from disk, discarding unsaved changes`);
|
|
45
|
+
if (blocked)
|
|
46
|
+
return blocked;
|
|
47
|
+
return call("scene.reload", path !== undefined ? { path } : {});
|
|
48
|
+
});
|
|
49
|
+
server.registerTool("scene_close", {
|
|
50
|
+
title: "Close current scene",
|
|
51
|
+
description: "Close the current scene tab, discarding unsaved changes. DESTRUCTIVE — gated by confirmation. Only the current scene can be closed; pass its path to assert which one.",
|
|
52
|
+
inputSchema: {
|
|
53
|
+
path: z.string().optional().describe("Optional assertion: must equal the current edited scene's path"),
|
|
54
|
+
confirm: z.boolean().optional().describe("Auto-approve this destructive action (skip the confirmation prompt)"),
|
|
55
|
+
},
|
|
56
|
+
}, async ({ path, confirm }) => {
|
|
57
|
+
const blocked = await gate(server, confirm, "Close the current scene, discarding unsaved changes");
|
|
58
|
+
if (blocked)
|
|
59
|
+
return blocked;
|
|
60
|
+
return call("scene.close", path !== undefined ? { path } : {});
|
|
61
|
+
});
|
|
62
|
+
server.registerTool("scene_pack", {
|
|
63
|
+
title: "Pack branch as scene",
|
|
64
|
+
description: "Save a node branch (the node and its subtree) as a new PackedScene file. DESTRUCTIVE (writes a file) — gated by confirmation. Does not modify the edited scene.",
|
|
65
|
+
inputSchema: {
|
|
66
|
+
path: z.string().describe("Branch root node path relative to the scene root"),
|
|
67
|
+
to_path: z.string().describe("Where to save the PackedScene, e.g. res://scenes/branch.tscn"),
|
|
68
|
+
confirm: z.boolean().optional().describe("Auto-approve this destructive action (skip the confirmation prompt)"),
|
|
69
|
+
},
|
|
70
|
+
}, async ({ path, to_path, confirm }) => {
|
|
71
|
+
const blocked = await gate(server, confirm, `Pack branch "${path}" to ${to_path}`);
|
|
72
|
+
if (blocked)
|
|
73
|
+
return blocked;
|
|
74
|
+
return call("scene.pack", { path, to_path });
|
|
75
|
+
});
|
|
76
|
+
server.registerTool("scene_get_dependencies", {
|
|
77
|
+
title: "Scene dependencies",
|
|
78
|
+
description: "List the external resource dependencies of a scene file. Read-only. Defaults to the current scene.",
|
|
79
|
+
inputSchema: { path: z.string().optional().describe("Scene res:// path; omitted = the current edited scene") },
|
|
80
|
+
}, async ({ path }) => call("scene.get_dependencies", path !== undefined ? { path } : {}));
|
|
81
|
+
server.registerTool("scene_save_as", {
|
|
82
|
+
title: "Save scene as",
|
|
83
|
+
description: "Save the current scene to a new res:// path (Save As). DESTRUCTIVE (writes a file) — gated by confirmation.",
|
|
84
|
+
inputSchema: {
|
|
85
|
+
path: z.string().describe("Destination path, e.g. res://scenes/copy.tscn"),
|
|
86
|
+
confirm: z.boolean().optional().describe("Auto-approve this destructive action (skip the confirmation prompt)"),
|
|
87
|
+
},
|
|
88
|
+
}, async ({ path, confirm }) => {
|
|
89
|
+
const blocked = await gate(server, confirm, `Save the current scene to ${path}`);
|
|
90
|
+
if (blocked)
|
|
91
|
+
return blocked;
|
|
92
|
+
return call("scene.save_as", { path });
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
//# sourceMappingURL=scene.js.map
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { gate } from "../../confirm.js";
|
|
3
|
+
/** Shader + ShaderMaterial authoring. */
|
|
4
|
+
export function registerShaderTools(server, call) {
|
|
5
|
+
server.registerTool("shader_create", {
|
|
6
|
+
title: "Create shader",
|
|
7
|
+
description: "Create a Shader resource with optional initial code and save it as a .gdshader file. DESTRUCTIVE (writes a file) — gated by confirmation.",
|
|
8
|
+
inputSchema: {
|
|
9
|
+
to_path: z.string().describe("Destination res:// path, e.g. res://shaders/glow.gdshader"),
|
|
10
|
+
code: z.string().optional().describe("Initial GDShader source (e.g. \"shader_type canvas_item; ...\")"),
|
|
11
|
+
confirm: z.boolean().optional().describe("Auto-approve this destructive action (skip the confirmation prompt)"),
|
|
12
|
+
},
|
|
13
|
+
}, async ({ to_path, code, confirm }) => {
|
|
14
|
+
const blocked = await gate(server, confirm, `Create shader at ${to_path}`);
|
|
15
|
+
if (blocked)
|
|
16
|
+
return blocked;
|
|
17
|
+
return call("shader.create", code !== undefined ? { to_path, code } : { to_path });
|
|
18
|
+
});
|
|
19
|
+
server.registerTool("shader_set_code", {
|
|
20
|
+
title: "Set shader code",
|
|
21
|
+
description: "Replace the source code of an existing .gdshader resource and save it. DESTRUCTIVE (writes a file) — gated by confirmation.",
|
|
22
|
+
inputSchema: {
|
|
23
|
+
path: z.string().describe("Shader res:// path"),
|
|
24
|
+
code: z.string().describe("New GDShader source"),
|
|
25
|
+
confirm: z.boolean().optional().describe("Auto-approve this destructive action (skip the confirmation prompt)"),
|
|
26
|
+
},
|
|
27
|
+
}, async ({ path, code, confirm }) => {
|
|
28
|
+
const blocked = await gate(server, confirm, `Overwrite shader code at ${path}`);
|
|
29
|
+
if (blocked)
|
|
30
|
+
return blocked;
|
|
31
|
+
return call("shader.set_code", { path, code });
|
|
32
|
+
});
|
|
33
|
+
server.registerTool("shadermaterial_create", {
|
|
34
|
+
title: "Create shader material",
|
|
35
|
+
description: "Create a ShaderMaterial and assign it to a node's material slot in the edited scene (undoable). Targets CanvasItem.material (2D / Control) or GeometryInstance3D.material_override (3D); other node types return unsupported. Optionally assign a Shader loaded from a res:// path. In-scene and undoable — not gated.",
|
|
36
|
+
inputSchema: {
|
|
37
|
+
path: z.string().describe("Node path relative to the scene root (a CanvasItem or GeometryInstance3D)"),
|
|
38
|
+
shader_path: z.string().optional().describe("res:// path to a Shader to assign to the new material"),
|
|
39
|
+
},
|
|
40
|
+
}, async ({ path, shader_path }) => call("shadermaterial.create", shader_path !== undefined ? { path, shader_path } : { path }));
|
|
41
|
+
server.registerTool("shadermaterial_set_shader", {
|
|
42
|
+
title: "Set shader material shader",
|
|
43
|
+
description: "Load a Shader from a res:// path and assign it to the ShaderMaterial on a node's material slot in the edited scene (undoable). The node must already have a ShaderMaterial. In-scene and undoable — not gated.",
|
|
44
|
+
inputSchema: {
|
|
45
|
+
path: z.string().describe("Node path relative to the scene root"),
|
|
46
|
+
shader_path: z.string().describe("res:// path to a Shader resource"),
|
|
47
|
+
},
|
|
48
|
+
}, async ({ path, shader_path }) => call("shadermaterial.set_shader", { path, shader_path }));
|
|
49
|
+
server.registerTool("shadermaterial_set_param", {
|
|
50
|
+
title: "Set shader material parameter",
|
|
51
|
+
description: "Set a shader uniform parameter on the ShaderMaterial of a node's material slot in the edited scene (undoable). The node must already have a ShaderMaterial. The value uses the tagged-Variant convention. In-scene and undoable — not gated.",
|
|
52
|
+
inputSchema: {
|
|
53
|
+
path: z.string().describe("Node path relative to the scene root"),
|
|
54
|
+
param: z.string().describe("Shader uniform name"),
|
|
55
|
+
value: z.any().describe("New value (JSON scalar or __type__-tagged Variant)"),
|
|
56
|
+
},
|
|
57
|
+
}, async ({ path, param, value }) => call("shadermaterial.set_param", { path, param, value }));
|
|
58
|
+
}
|
|
59
|
+
//# sourceMappingURL=shader.js.map
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { gate } from "../../confirm.js";
|
|
3
|
+
/** Signal introspection and (dis)connection on nodes. */
|
|
4
|
+
export function registerSignalTools(server, call) {
|
|
5
|
+
server.registerTool("signal_list", {
|
|
6
|
+
title: "List node signals",
|
|
7
|
+
description: "List the signals a node declares (name and argument names), including user signals. Read-only.",
|
|
8
|
+
inputSchema: { path: z.string().describe("Node path relative to the scene root") },
|
|
9
|
+
}, async ({ path }) => call("signal.list", { path }));
|
|
10
|
+
server.registerTool("signal_list_connections", {
|
|
11
|
+
title: "List signal connections",
|
|
12
|
+
description: "List a node's outgoing signal connections (signal, target node path, method, flags). Optionally filter to one signal. Read-only.",
|
|
13
|
+
inputSchema: {
|
|
14
|
+
path: z.string().describe("Node path relative to the scene root"),
|
|
15
|
+
signal: z.string().optional().describe("Only list connections for this signal"),
|
|
16
|
+
},
|
|
17
|
+
}, async ({ path, signal }) => call("signal.list_connections", signal !== undefined ? { path, signal } : { path }));
|
|
18
|
+
server.registerTool("signal_connect", {
|
|
19
|
+
title: "Connect signal",
|
|
20
|
+
description: "Connect a source node's signal to a target node's method (undoable). Persistent by default (flags=2, CONNECT_PERSIST) so it saves into the scene. No-op if already connected.",
|
|
21
|
+
inputSchema: {
|
|
22
|
+
path: z.string().describe("Source node path (emitter)"),
|
|
23
|
+
signal: z.string().describe("Signal name on the source"),
|
|
24
|
+
target_path: z.string().describe("Target node path (receiver)"),
|
|
25
|
+
method: z.string().describe("Method to call on the target"),
|
|
26
|
+
flags: z.number().int().optional().describe("Object.ConnectFlags bitmask (default 2 = CONNECT_PERSIST)"),
|
|
27
|
+
},
|
|
28
|
+
}, async ({ path, signal, target_path, method, flags }) => call("signal.connect", flags !== undefined ? { path, signal, target_path, method, flags } : { path, signal, target_path, method }));
|
|
29
|
+
server.registerTool("signal_disconnect", {
|
|
30
|
+
title: "Disconnect signal",
|
|
31
|
+
description: "Disconnect a source node's signal from a target node's method (undoable). No-op if not connected.",
|
|
32
|
+
inputSchema: {
|
|
33
|
+
path: z.string().describe("Source node path (emitter)"),
|
|
34
|
+
signal: z.string().describe("Signal name on the source"),
|
|
35
|
+
target_path: z.string().describe("Target node path (receiver)"),
|
|
36
|
+
method: z.string().describe("Connected method on the target"),
|
|
37
|
+
},
|
|
38
|
+
}, async ({ path, signal, target_path, method }) => call("signal.disconnect", { path, signal, target_path, method }));
|
|
39
|
+
server.registerTool("signal_add_user_signal", {
|
|
40
|
+
title: "Add user signal",
|
|
41
|
+
description: "Declare a new user signal on a node (undoable). Optional typed arguments. Errors if the signal already exists.",
|
|
42
|
+
inputSchema: {
|
|
43
|
+
path: z.string().describe("Node path relative to the scene root"),
|
|
44
|
+
signal: z.string().describe("New signal name"),
|
|
45
|
+
args: z
|
|
46
|
+
.array(z.object({ name: z.string(), type: z.number().int().optional() }))
|
|
47
|
+
.optional()
|
|
48
|
+
.describe("Signal parameters (name + Variant type int)"),
|
|
49
|
+
},
|
|
50
|
+
}, async ({ path, signal, args }) => call("signal.add_user_signal", args !== undefined ? { path, signal, args } : { path, signal }));
|
|
51
|
+
server.registerTool("signal_emit", {
|
|
52
|
+
title: "Emit signal (edit-time)",
|
|
53
|
+
description: "Emit a signal from a node in the EDITED scene, firing its connected callables now. DESTRUCTIVE (edit-time side effects) — gated by confirmation. Args use the tagged-Variant convention.",
|
|
54
|
+
inputSchema: {
|
|
55
|
+
path: z.string().describe("Node path relative to the scene root"),
|
|
56
|
+
signal: z.string().describe("Signal name"),
|
|
57
|
+
args: z.array(z.any()).optional().describe("Signal arguments (JSON scalars or __type__-tagged Variants)"),
|
|
58
|
+
confirm: z.boolean().optional().describe("Auto-approve this destructive action (skip the confirmation prompt)"),
|
|
59
|
+
},
|
|
60
|
+
}, async ({ path, signal, args, confirm }) => {
|
|
61
|
+
const blocked = await gate(server, confirm, `Emit signal "${signal}" from ${path} in the edited scene`);
|
|
62
|
+
if (blocked)
|
|
63
|
+
return blocked;
|
|
64
|
+
return call("signal.emit", { path, signal, args: args ?? [] });
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
//# sourceMappingURL=signal.js.map
|