@npgamedev/godot-mcp-server 0.0.1 → 1.0.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/ATTRIBUTIONS.md +141 -0
- package/LICENSE +28 -0
- package/README.md +386 -4
- package/dist/extensions/extensionChanges.js +131 -0
- package/dist/extensions/extensionCommand.js +25 -0
- package/dist/extensions/extensionDiscovery.js +141 -0
- package/dist/extensions/extensionRegistrar.js +82 -0
- package/dist/extensions/extensions.js +33 -0
- package/dist/groups/builtinGroups.js +60 -0
- package/dist/groups/defs/3dTools.js +17 -0
- package/dist/groups/defs/animationAuthoring.js +16 -0
- package/dist/groups/defs/assetOps.js +6 -0
- package/dist/groups/defs/audio.js +6 -0
- package/dist/groups/defs/classdb.js +6 -0
- package/dist/groups/defs/cleanup.js +6 -0
- package/dist/groups/defs/debugger.js +6 -0
- package/dist/groups/defs/editorAdvanced.js +16 -0
- package/dist/groups/defs/inputMap.js +6 -0
- package/dist/groups/defs/layerNaming.js +6 -0
- package/dist/groups/defs/lspCodeAnalysis.js +23 -0
- package/dist/groups/defs/lspCodeNavigation.js +15 -0
- package/dist/groups/defs/navigation.js +17 -0
- package/dist/groups/defs/particles.js +21 -0
- package/dist/groups/defs/pathEditing.js +22 -0
- package/dist/groups/defs/placeholders.js +28 -0
- package/dist/groups/defs/procedural.js +6 -0
- package/dist/groups/defs/resourceIo.js +6 -0
- package/dist/groups/defs/runtimeAdvanced.js +17 -0
- package/dist/groups/defs/sceneAdvanced.js +6 -0
- package/dist/groups/defs/sceneInheritance.js +6 -0
- package/dist/groups/defs/signals.js +6 -0
- package/dist/groups/defs/spriteframes.js +16 -0
- package/dist/groups/defs/theme.js +6 -0
- package/dist/groups/defs/tilemap.js +6 -0
- package/dist/groups/defs/tileset.js +22 -0
- package/dist/groups/defs/tilesetEdit.js +21 -0
- package/dist/groups/defs/userData.js +6 -0
- package/dist/groups/extensionGroups.js +182 -0
- package/dist/groups/groupActivation.js +210 -0
- package/dist/groups/groupCatalogue.js +52 -0
- package/dist/groups/groupMatch.js +182 -0
- package/dist/groups/groupResult.js +16 -0
- package/dist/groups/groupState.js +15 -0
- package/dist/groups/groupToolHandlers.js +103 -0
- package/dist/groups/groupTypes.js +10 -0
- package/dist/groups/groups.js +205 -0
- package/dist/index.js +144 -0
- package/dist/lsp/lspClient.js +509 -0
- package/dist/lsp/lspLabels.js +105 -0
- package/dist/lsp/lspProjectScan.js +156 -0
- package/dist/lsp/lspSession.js +139 -0
- package/dist/lsp/lspStatusReporter.js +76 -0
- package/dist/lsp/lspUri.js +68 -0
- package/dist/mcp/prompts.js +59 -0
- package/dist/mcp/resources.js +113 -0
- package/dist/mcp/roots.js +30 -0
- package/dist/registration/catalogue.js +123 -0
- package/dist/registration/extensionCollision.js +38 -0
- package/dist/registration/operations.js +67 -0
- package/dist/registration/screenshotResponse.js +71 -0
- package/dist/registration/toolDispatch.js +76 -0
- package/dist/registration/toolMeta.js +104 -0
- package/dist/registration/toolRefs.js +48 -0
- package/dist/registration/toolRegistry.js +211 -0
- package/dist/registry.js +291 -0
- package/dist/registryLiveness.js +113 -0
- package/dist/security/pathGuard.js +97 -0
- package/dist/security/profiles.js +104 -0
- package/dist/security/untrusted.js +23 -0
- package/dist/shared/errorContract.js +154 -0
- package/dist/shared/errors.js +21 -0
- package/dist/shared/pagination.js +135 -0
- package/dist/shared/schemaCoercion.js +173 -0
- package/dist/shared/stableJson.js +27 -0
- package/dist/shared/types.js +1 -0
- package/dist/shared/version.js +82 -0
- package/dist/startup/cliArgs.js +103 -0
- package/dist/startup/configReload.js +57 -0
- package/dist/startup/hooks.js +89 -0
- package/dist/startup/lifecycle.js +22 -0
- package/dist/startup/portConfig.js +127 -0
- package/dist/startup/reconcile.js +81 -0
- package/dist/startup/registrars.js +59 -0
- package/dist/startup/serverMode.js +19 -0
- package/dist/startup/startupEnv.js +142 -0
- package/dist/tools/animation.js +88 -0
- package/dist/tools/asset.js +58 -0
- package/dist/tools/assetWrite.js +16 -0
- package/dist/tools/audio.js +40 -0
- package/dist/tools/classdb.js +43 -0
- package/dist/tools/collision.js +23 -0
- package/dist/tools/debug.js +46 -0
- package/dist/tools/diff.js +18 -0
- package/dist/tools/editor.js +222 -0
- package/dist/tools/file.js +38 -0
- package/dist/tools/folder.js +27 -0
- package/dist/tools/inputMap.js +54 -0
- package/dist/tools/layerNames.js +29 -0
- package/dist/tools/lsp.js +524 -0
- package/dist/tools/navigation.js +24 -0
- package/dist/tools/node.js +145 -0
- package/dist/tools/nodeManagement.js +82 -0
- package/dist/tools/particles.js +83 -0
- package/dist/tools/path.js +30 -0
- package/dist/tools/playtest.js +99 -0
- package/dist/tools/procedural.js +101 -0
- package/dist/tools/resource.js +47 -0
- package/dist/tools/runtime.js +338 -0
- package/dist/tools/save.js +64 -0
- package/dist/tools/scene.js +102 -0
- package/dist/tools/sceneInheritance.js +19 -0
- package/dist/tools/sceneQuery.js +38 -0
- package/dist/tools/script.js +75 -0
- package/dist/tools/signals.js +53 -0
- package/dist/tools/sound.js +31 -0
- package/dist/tools/spatial.js +41 -0
- package/dist/tools/spriteframes.js +94 -0
- package/dist/tools/texture.js +35 -0
- package/dist/tools/theme.js +35 -0
- package/dist/tools/threeD.js +116 -0
- package/dist/tools/tilemap.js +51 -0
- package/dist/tools/tileset.js +226 -0
- package/dist/transport/authHandshake.js +43 -0
- package/dist/transport/bridge.js +225 -0
- package/dist/transport/channel.js +352 -0
- package/dist/transport/heartbeat.js +54 -0
- package/dist/transport/runtimeConnection.js +239 -0
- package/dist/transport/tokenPath.js +98 -0
- package/package.json +97 -4
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { registerTools } from "../registration/toolRegistry.js";
|
|
3
|
+
import { coercedBoolean, jsonCoerce } from "../shared/schemaCoercion.js";
|
|
4
|
+
// signal_emit selects its channel: default routes to the editor-side
|
|
5
|
+
// edited scene; `channel: "runtime"` routes to the running game for
|
|
6
|
+
// emitting on live nodes. list / manage are editor-only.
|
|
7
|
+
export const signalTools = [
|
|
8
|
+
{
|
|
9
|
+
name: "signal_list",
|
|
10
|
+
method: "signal.list",
|
|
11
|
+
description: "List signals on a node. include_connections=true adds targets ({target_path, method_name, flags}). flags & 2 = CONNECT_PERSIST (saved in .tscn).",
|
|
12
|
+
inputSchema: {
|
|
13
|
+
node_path: z.string(),
|
|
14
|
+
include_connections: coercedBoolean().optional(),
|
|
15
|
+
},
|
|
16
|
+
annotations: { readOnlyHint: true, openWorldHint: false },
|
|
17
|
+
},
|
|
18
|
+
{
|
|
19
|
+
name: "signal_manage",
|
|
20
|
+
method: "signal.manage",
|
|
21
|
+
description: "Connect or disconnect a signal (editor-time, CONNECT_PERSIST — saved in .tscn, survives save/load). Idempotent connect (status 'returned' on collision).",
|
|
22
|
+
inputSchema: {
|
|
23
|
+
action: z.enum(["connect", "disconnect"]),
|
|
24
|
+
node_path: z.string(),
|
|
25
|
+
signal_name: z.string(),
|
|
26
|
+
target_path: z.string(),
|
|
27
|
+
method_name: z.string(),
|
|
28
|
+
},
|
|
29
|
+
annotations: { readOnlyHint: false, idempotentHint: true, openWorldHint: false, destructiveHint: false },
|
|
30
|
+
operationParam: "action",
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
name: "signal_emit",
|
|
34
|
+
method: "signal.emit",
|
|
35
|
+
description: "Emit signal_name on node with optional args. channel='editor' (default, edited scene) or channel='runtime' (the running game).",
|
|
36
|
+
inputSchema: {
|
|
37
|
+
node_path: z.string(),
|
|
38
|
+
signal_name: z.string(),
|
|
39
|
+
args: z.preprocess(jsonCoerce, z.array(z.unknown())).optional(),
|
|
40
|
+
// "game" is accepted as a hidden alias for "runtime" (mapped before the
|
|
41
|
+
// enum, not advertised) — z.toJSONSchema surfaces only the inner enum.
|
|
42
|
+
channel: z.preprocess((v) => (v === "game" ? "runtime" : v), z.enum(["editor", "runtime"])).optional(),
|
|
43
|
+
},
|
|
44
|
+
annotations: { readOnlyHint: false, openWorldHint: false, destructiveHint: false },
|
|
45
|
+
},
|
|
46
|
+
];
|
|
47
|
+
// NOTE: All signal tools are in the "signals" group (GROUP_TOOL_NAMES), so the
|
|
48
|
+
// group's activation path (groupActivation → createGroupToolHandler) builds the
|
|
49
|
+
// channel-routed signal_emit handler. This register() is unused on that path but
|
|
50
|
+
// remains as a fallback for direct-call scenarios.
|
|
51
|
+
export function register(server, bridge, allowedTools) {
|
|
52
|
+
registerTools(server, bridge, signalTools, allowedTools);
|
|
53
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { registerTools } from "../registration/toolRegistry.js";
|
|
3
|
+
import { assetWriteFields } from "./assetWrite.js";
|
|
4
|
+
export const soundTools = [
|
|
5
|
+
{
|
|
6
|
+
name: "sound_generate",
|
|
7
|
+
method: "sound.generate",
|
|
8
|
+
description: "Generate a placeholder sound effect (mono WAV): waveform sine/square/triangle/sawtooth/noise, frequency, duration <=5s, volume, optional pitch sweep + fade/decay envelope. SFX only, no music.",
|
|
9
|
+
inputSchema: {
|
|
10
|
+
file_path: z.string().describe("res:// destination ending in .wav"),
|
|
11
|
+
waveform: z.enum(["sine", "square", "triangle", "sawtooth", "noise"]).optional(),
|
|
12
|
+
frequency: z.coerce.number().optional().describe("Hz (default 440; ignored for noise)"),
|
|
13
|
+
end_frequency: z.coerce
|
|
14
|
+
.number()
|
|
15
|
+
.optional()
|
|
16
|
+
.describe("If set, pitch sweeps frequency -> end_frequency over the duration"),
|
|
17
|
+
duration: z.coerce.number().optional().describe("Seconds, max 5 (default 0.3)"),
|
|
18
|
+
volume: z.coerce.number().optional().describe("Peak amplitude 0-1 (default 0.8)"),
|
|
19
|
+
fade_in: z.coerce.number().optional().describe("Fade-in seconds (default ~0.003 de-click)"),
|
|
20
|
+
fade_out: z.coerce.number().optional().describe("Fade-out seconds (default ~0.003 de-click)"),
|
|
21
|
+
decay: z.coerce.number().optional().describe("Exponential decay time-constant in seconds (>0 = pluck/bell)"),
|
|
22
|
+
...assetWriteFields,
|
|
23
|
+
},
|
|
24
|
+
annotations: { readOnlyHint: false, idempotentHint: false, destructiveHint: false, openWorldHint: false },
|
|
25
|
+
successHint: "Assign the stream: node_set_property on AudioStreamPlayer / AudioStreamPlayer2D / AudioStreamPlayer3D .stream.",
|
|
26
|
+
pathParams: [{ param: "file_path", guard: "project" }],
|
|
27
|
+
},
|
|
28
|
+
];
|
|
29
|
+
export function register(server, bridge, allowedTools) {
|
|
30
|
+
registerTools(server, bridge, soundTools, allowedTools);
|
|
31
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { registerTools } from "../registration/toolRegistry.js";
|
|
3
|
+
import { jsonCoerce } from "../shared/schemaCoercion.js";
|
|
4
|
+
import { paginationDoc } from "../shared/pagination.js";
|
|
5
|
+
export const spatialTools = [
|
|
6
|
+
{
|
|
7
|
+
name: "scene_spatial_map",
|
|
8
|
+
method: "scene.spatial_map",
|
|
9
|
+
description: "Spatial layout of the current scene: per-node world position, bounds (2D Rect2 / 3D AABB), size, plus computed overlaps/gaps/containment. Call before placing or moving nodes to find clear space. " +
|
|
10
|
+
paginationDoc("nodes", {
|
|
11
|
+
resumable: false,
|
|
12
|
+
cursorlessNav: "narrow with subtree/class/region/radius or raise max_nodes",
|
|
13
|
+
}),
|
|
14
|
+
inputSchema: {
|
|
15
|
+
detail: z
|
|
16
|
+
.enum(["brief", "normal", "full"])
|
|
17
|
+
.optional()
|
|
18
|
+
.describe("brief = position/size only; normal = + bounds + overlaps; full = + containment + nearest-neighbour gaps"),
|
|
19
|
+
class: z.string().optional().describe("Only include nodes of this class (ancestry-aware)"),
|
|
20
|
+
subtree: z
|
|
21
|
+
.string()
|
|
22
|
+
.optional()
|
|
23
|
+
.describe("Map only this node and its descendants (node path relative to the scene root)"),
|
|
24
|
+
region: z
|
|
25
|
+
.preprocess(jsonCoerce, z.array(z.number()))
|
|
26
|
+
.optional()
|
|
27
|
+
.describe("Only nodes intersecting this box: [x,y,w,h] (2D) or [x,y,z,sx,sy,sz] (3D)"),
|
|
28
|
+
radius: z.coerce.number().optional().describe("Only nodes within this distance of center"),
|
|
29
|
+
center: z
|
|
30
|
+
.preprocess(jsonCoerce, z.array(z.number()))
|
|
31
|
+
.optional()
|
|
32
|
+
.describe("Center for radius filter: [x,y] (2D) or [x,y,z] (3D)"),
|
|
33
|
+
max_nodes: z.coerce.number().optional().describe("Response cap (default 200, max 1000)"),
|
|
34
|
+
},
|
|
35
|
+
annotations: { readOnlyHint: true, openWorldHint: false },
|
|
36
|
+
successHint: "Reason about a clear position from the overlaps/gaps, then place or move nodes with node_set_property (position / global_position).",
|
|
37
|
+
},
|
|
38
|
+
];
|
|
39
|
+
export function register(server, bridge, allowedTools) {
|
|
40
|
+
registerTools(server, bridge, spatialTools, allowedTools);
|
|
41
|
+
}
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { PROJECT_FILE_PATH } from "../security/pathGuard.js";
|
|
3
|
+
const frameSchema = z.object({
|
|
4
|
+
texture_path: z.string().describe("res:// path to frame texture"),
|
|
5
|
+
atlas: z
|
|
6
|
+
.object({
|
|
7
|
+
x: z.number().int(),
|
|
8
|
+
y: z.number().int(),
|
|
9
|
+
width: z.number().int(),
|
|
10
|
+
height: z.number().int(),
|
|
11
|
+
})
|
|
12
|
+
.optional()
|
|
13
|
+
.describe("Atlas region within the texture"),
|
|
14
|
+
duration: z.number().optional().describe("Per-frame duration multiplier (default 1.0)"),
|
|
15
|
+
});
|
|
16
|
+
const animationSchema = z.object({
|
|
17
|
+
name: z.string().describe("Animation name (e.g. 'idle', 'run')"),
|
|
18
|
+
fps: z.number().optional().describe("Frames per second (default 5.0)"),
|
|
19
|
+
loop: z.boolean().optional().describe("Loop animation (default true)"),
|
|
20
|
+
frames: z.array(frameSchema).describe("Frame textures"),
|
|
21
|
+
});
|
|
22
|
+
export const spriteframesTools = [
|
|
23
|
+
{
|
|
24
|
+
name: "spriteframes_create",
|
|
25
|
+
method: "spriteframes.create",
|
|
26
|
+
description: "Create a SpriteFrames resource (.tres) with named animations and frame textures. For AnimatedSprite2D character/effect animation.",
|
|
27
|
+
inputSchema: {
|
|
28
|
+
file_path: z.string().describe("Output .tres file path (res://)"),
|
|
29
|
+
animations: z.array(animationSchema).min(1).describe("Animations with their frames"),
|
|
30
|
+
},
|
|
31
|
+
annotations: { readOnlyHint: false, idempotentHint: true, openWorldHint: false, destructiveHint: false },
|
|
32
|
+
successHint: "Add/modify frames with spriteframes_edit. For spritesheets use spriteframes_from_spritesheet.",
|
|
33
|
+
pathParams: [PROJECT_FILE_PATH],
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
name: "spriteframes_edit",
|
|
37
|
+
method: "spriteframes.edit",
|
|
38
|
+
description: "Edit an existing SpriteFrames resource: add/remove animations, add/remove/reorder frames, adjust fps/loop. 'list' returns all animations.",
|
|
39
|
+
inputSchema: {
|
|
40
|
+
file_path: z.string().describe("Path to existing SpriteFrames .tres"),
|
|
41
|
+
action: z
|
|
42
|
+
.enum([
|
|
43
|
+
"add_animation",
|
|
44
|
+
"remove_animation",
|
|
45
|
+
"add_frame",
|
|
46
|
+
"remove_frame",
|
|
47
|
+
"set_fps",
|
|
48
|
+
"set_loop",
|
|
49
|
+
"reorder_frames",
|
|
50
|
+
"list",
|
|
51
|
+
])
|
|
52
|
+
.describe("Edit operation"),
|
|
53
|
+
animation_name: z.string().optional().describe("Target animation name"),
|
|
54
|
+
fps: z.number().optional().describe("New FPS value (for set_fps)"),
|
|
55
|
+
loop: z.boolean().optional().describe("New loop value (for set_loop)"),
|
|
56
|
+
frames: z.array(frameSchema).optional().describe("Frames to add"),
|
|
57
|
+
frame_index: z.number().int().optional().describe("Frame index (for remove/reorder)"),
|
|
58
|
+
new_index: z.number().int().optional().describe("New position (for reorder)"),
|
|
59
|
+
},
|
|
60
|
+
annotations: { readOnlyHint: false, openWorldHint: false, destructiveHint: false },
|
|
61
|
+
operationParam: "action",
|
|
62
|
+
pathParams: [PROJECT_FILE_PATH],
|
|
63
|
+
},
|
|
64
|
+
{
|
|
65
|
+
name: "spriteframes_from_spritesheet",
|
|
66
|
+
method: "spriteframes.from_spritesheet",
|
|
67
|
+
description: "Auto-slice a spritesheet into SpriteFrames animations by grid. Each animation maps to a row/column range in the sheet.",
|
|
68
|
+
inputSchema: {
|
|
69
|
+
file_path: z.string().describe("Output .tres file path"),
|
|
70
|
+
texture_path: z.string().describe("Spritesheet texture path (res://)"),
|
|
71
|
+
frame_size: z
|
|
72
|
+
.object({
|
|
73
|
+
x: z.number().int().describe("Frame width in pixels"),
|
|
74
|
+
y: z.number().int().describe("Frame height in pixels"),
|
|
75
|
+
})
|
|
76
|
+
.describe("Size of each frame in the grid"),
|
|
77
|
+
animations: z
|
|
78
|
+
.array(z.object({
|
|
79
|
+
name: z.string().describe("Animation name"),
|
|
80
|
+
row: z.number().int().optional().describe("Row in spritesheet (0-indexed, default 0)"),
|
|
81
|
+
start_col: z.number().int().optional().describe("Starting column (default 0)"),
|
|
82
|
+
frame_count: z.number().int().describe("Number of frames"),
|
|
83
|
+
fps: z.number().optional().describe("Frames per second"),
|
|
84
|
+
loop: z.boolean().optional().describe("Loop this animation"),
|
|
85
|
+
}))
|
|
86
|
+
.min(1)
|
|
87
|
+
.describe("Animation definitions mapping to spritesheet regions"),
|
|
88
|
+
},
|
|
89
|
+
annotations: { readOnlyHint: false, idempotentHint: true, openWorldHint: false, destructiveHint: false },
|
|
90
|
+
// file_path is guarded; texture_path is NOT (toolkit calls load(), which is
|
|
91
|
+
// res://-scoped — guarding it server-side could false-reject).
|
|
92
|
+
pathParams: [PROJECT_FILE_PATH],
|
|
93
|
+
},
|
|
94
|
+
];
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { registerTools } from "../registration/toolRegistry.js";
|
|
3
|
+
import { jsonCoerce } from "../shared/schemaCoercion.js";
|
|
4
|
+
import { assetWriteFields } from "./assetWrite.js";
|
|
5
|
+
/** A colour: a hex/named string ("#ff0000", "red") or an [r,g,b(,a)] array
|
|
6
|
+
* (0-1 or 0-255). Alpha 0 / omitted = that layer is absent. */
|
|
7
|
+
const colorField = z.preprocess(jsonCoerce, z.union([z.string(), z.array(z.number())]));
|
|
8
|
+
export const textureTools = [
|
|
9
|
+
{
|
|
10
|
+
name: "texture_generate",
|
|
11
|
+
method: "texture.generate",
|
|
12
|
+
description: "Generate a placeholder PNG (imports as Texture2D): a shape (solid/circle/triangle/diamond/arrow/checkerboard/grid) with fill/outline/background colours + an optional text label. Dimensions <=1024px.",
|
|
13
|
+
inputSchema: {
|
|
14
|
+
file_path: z.string().describe("res:// destination ending in .png"),
|
|
15
|
+
shape: z.enum(["solid", "circle", "triangle", "diamond", "arrow", "checkerboard", "grid"]).optional(),
|
|
16
|
+
width: z.coerce.number().optional().describe("Pixels, 1-1024 (default 64)"),
|
|
17
|
+
height: z.coerce.number().optional().describe("Pixels, 1-1024 (default 64)"),
|
|
18
|
+
fill_color: colorField.optional().describe("Interior colour; transparent = hollow shape"),
|
|
19
|
+
outline_color: colorField.optional().describe("Border colour; transparent/omitted = no border"),
|
|
20
|
+
outline_width: z.coerce.number().optional().describe("Border thickness in pixels (default 1)"),
|
|
21
|
+
background_color: colorField.optional().describe("Canvas colour behind the shape (default transparent)"),
|
|
22
|
+
label: z.string().optional().describe("Optional text overlaid centred on any shape"),
|
|
23
|
+
label_color: colorField.optional(),
|
|
24
|
+
direction: z.enum(["up", "down", "left", "right"]).optional().describe("Arrow direction"),
|
|
25
|
+
cell_size: z.coerce.number().optional().describe("Cell size for checkerboard/grid"),
|
|
26
|
+
...assetWriteFields,
|
|
27
|
+
},
|
|
28
|
+
annotations: { readOnlyHint: false, idempotentHint: false, destructiveHint: false, openWorldHint: false },
|
|
29
|
+
successHint: "Assign the texture: node_set_property on Sprite2D.texture / TextureRect.texture / Button.icon, or feed spriteframes_create.",
|
|
30
|
+
pathParams: [{ param: "file_path", guard: "project" }],
|
|
31
|
+
},
|
|
32
|
+
];
|
|
33
|
+
export function register(server, bridge, allowedTools) {
|
|
34
|
+
registerTools(server, bridge, textureTools, allowedTools);
|
|
35
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { registerTools } from "../registration/toolRegistry.js";
|
|
3
|
+
import { jsonCoerce } from "../shared/schemaCoercion.js";
|
|
4
|
+
import { PROJECT_FILE_PATH } from "../security/pathGuard.js";
|
|
5
|
+
export const themeTools = [
|
|
6
|
+
{
|
|
7
|
+
name: "theme_edit",
|
|
8
|
+
method: "theme.edit",
|
|
9
|
+
description: "Create or modify a Godot Theme resource (.tres). Batch-edit colors, constants, fonts, font sizes, icons, and styleboxes for any control type.",
|
|
10
|
+
inputSchema: {
|
|
11
|
+
file_path: z.string().describe("Theme resource path, e.g. 'res://themes/ui_theme.tres'. Created if missing."),
|
|
12
|
+
edits: z
|
|
13
|
+
.preprocess(jsonCoerce, z.array(z.object({
|
|
14
|
+
type_name: z.string().describe("Control type name, e.g. 'Button', 'Label', 'Panel'"),
|
|
15
|
+
property_type: z
|
|
16
|
+
.enum(["color", "constant", "font", "font_size", "icon", "stylebox"])
|
|
17
|
+
.describe("Theme property category"),
|
|
18
|
+
property: z.string().describe("Property name, e.g. 'font_color', 'font_size', 'panel'"),
|
|
19
|
+
value: z
|
|
20
|
+
.unknown()
|
|
21
|
+
.describe("Value — shape depends on property_type: " +
|
|
22
|
+
"color: {r,g,b,a?}; constant/font_size: number; " +
|
|
23
|
+
"font/icon: res:// path string; " +
|
|
24
|
+
"stylebox: {type:'StyleBoxFlat'|'StyleBoxTexture'|'StyleBoxLine', ...props}"),
|
|
25
|
+
})))
|
|
26
|
+
.describe("Array of theme property edits to apply"),
|
|
27
|
+
},
|
|
28
|
+
annotations: { readOnlyHint: false, openWorldHint: false, destructiveHint: false },
|
|
29
|
+
successHint: "Apply theme to Control via node_set_property (theme property with Resource type tag).",
|
|
30
|
+
pathParams: [PROJECT_FILE_PATH],
|
|
31
|
+
},
|
|
32
|
+
];
|
|
33
|
+
export function register(server, bridge, allowedTools) {
|
|
34
|
+
registerTools(server, bridge, themeTools, allowedTools);
|
|
35
|
+
}
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { registerTools } from "../registration/toolRegistry.js";
|
|
3
|
+
import { jsonCoerce } from "../shared/schemaCoercion.js";
|
|
4
|
+
const vec3Schema = z.object({
|
|
5
|
+
x: z.number().optional().describe("X component"),
|
|
6
|
+
y: z.number().optional().describe("Y component"),
|
|
7
|
+
z: z.number().optional().describe("Z component"),
|
|
8
|
+
});
|
|
9
|
+
const colorSchema = z.object({
|
|
10
|
+
r: z.number().optional().describe("Red 0-1"),
|
|
11
|
+
g: z.number().optional().describe("Green 0-1"),
|
|
12
|
+
b: z.number().optional().describe("Blue 0-1"),
|
|
13
|
+
a: z.number().optional().describe("Alpha 0-1"),
|
|
14
|
+
});
|
|
15
|
+
export const threeDTools = [
|
|
16
|
+
{
|
|
17
|
+
name: "3d_create_primitive",
|
|
18
|
+
method: "3d.create_primitive",
|
|
19
|
+
description: "Create a 3D mesh primitive (box, sphere, cylinder, capsule, plane, prism) as a MeshInstance3D node. Optionally set size, material, and position.",
|
|
20
|
+
inputSchema: {
|
|
21
|
+
parent_path: z.string().describe("Parent node path (e.g. '.' for scene root)"),
|
|
22
|
+
primitive: z.enum(["box", "sphere", "cylinder", "capsule", "plane", "prism"]).describe("Mesh primitive type"),
|
|
23
|
+
name: z.string().optional().describe("Node name (default: 'MeshInstance3D')"),
|
|
24
|
+
size: z
|
|
25
|
+
.preprocess(jsonCoerce, vec3Schema)
|
|
26
|
+
.optional()
|
|
27
|
+
.describe("Size as {x,y,z}. Interpretation depends on primitive: box→size, sphere→x=diameter/y=height, etc."),
|
|
28
|
+
material: z
|
|
29
|
+
.preprocess(jsonCoerce, z.object({
|
|
30
|
+
type: z.literal("StandardMaterial3D").optional().describe("Material type (only StandardMaterial3D)"),
|
|
31
|
+
albedo_color: z.preprocess(jsonCoerce, colorSchema).optional().describe("Base color {r,g,b,a?}"),
|
|
32
|
+
metallic: z.number().optional().describe("Metallic factor 0-1"),
|
|
33
|
+
roughness: z.number().optional().describe("Roughness factor 0-1"),
|
|
34
|
+
}))
|
|
35
|
+
.optional()
|
|
36
|
+
.describe("Material to apply: {type:'StandardMaterial3D', albedo_color?, metallic?, roughness?}"),
|
|
37
|
+
position: z.preprocess(jsonCoerce, vec3Schema).optional().describe("World position {x,y,z}"),
|
|
38
|
+
},
|
|
39
|
+
annotations: { readOnlyHint: false, openWorldHint: false, destructiveHint: false },
|
|
40
|
+
successHint: "Set material via node_set_property. Add lighting with 3d_create_light, camera with 3d_create_camera.",
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
name: "3d_setup_environment",
|
|
44
|
+
method: "3d.setup_environment",
|
|
45
|
+
description: "Create a WorldEnvironment node with sky, ambient light, tonemapping, and fog. Sets up a complete 3D rendering environment.",
|
|
46
|
+
inputSchema: {
|
|
47
|
+
parent_path: z.string().describe("Parent node path (e.g. '.' for scene root)"),
|
|
48
|
+
name: z.string().optional().describe("Node name (default: 'WorldEnvironment')"),
|
|
49
|
+
sky: z
|
|
50
|
+
.preprocess(jsonCoerce, z.object({
|
|
51
|
+
type: z.string().optional().describe("Sky material type (default: ProceduralSkyMaterial)"),
|
|
52
|
+
sky_top_color: z.preprocess(jsonCoerce, colorSchema).optional().describe("Sky top color {r,g,b}"),
|
|
53
|
+
sky_horizon_color: z.preprocess(jsonCoerce, colorSchema).optional().describe("Sky horizon color {r,g,b}"),
|
|
54
|
+
ground_bottom_color: z
|
|
55
|
+
.preprocess(jsonCoerce, colorSchema)
|
|
56
|
+
.optional()
|
|
57
|
+
.describe("Ground bottom color {r,g,b}"),
|
|
58
|
+
}))
|
|
59
|
+
.optional()
|
|
60
|
+
.describe("Sky configuration"),
|
|
61
|
+
ambient_light: z
|
|
62
|
+
.preprocess(jsonCoerce, z.object({
|
|
63
|
+
color: z.preprocess(jsonCoerce, colorSchema).optional().describe("Ambient light color {r,g,b}"),
|
|
64
|
+
energy: z.number().optional().describe("Ambient light energy"),
|
|
65
|
+
}))
|
|
66
|
+
.optional()
|
|
67
|
+
.describe("Ambient light: {color?, energy?}"),
|
|
68
|
+
tonemap: z.enum(["linear", "reinhardt", "filmic", "aces"]).optional().describe("Tonemapping mode"),
|
|
69
|
+
fog: z
|
|
70
|
+
.preprocess(jsonCoerce, z.object({
|
|
71
|
+
enabled: z.boolean().optional().describe("Enable fog (default true)"),
|
|
72
|
+
color: z.preprocess(jsonCoerce, colorSchema).optional().describe("Fog color {r,g,b}"),
|
|
73
|
+
density: z.number().optional().describe("Fog density"),
|
|
74
|
+
}))
|
|
75
|
+
.optional()
|
|
76
|
+
.describe("Fog settings: {enabled?, color?, density?}"),
|
|
77
|
+
},
|
|
78
|
+
annotations: { readOnlyHint: false, openWorldHint: false, destructiveHint: false },
|
|
79
|
+
successHint: "Add lights with 3d_create_light, camera with 3d_create_camera.",
|
|
80
|
+
},
|
|
81
|
+
{
|
|
82
|
+
name: "3d_create_light",
|
|
83
|
+
method: "3d.create_light",
|
|
84
|
+
description: "Create a 3D light node (DirectionalLight3D, OmniLight3D, or SpotLight3D). Optionally set color, energy, shadow, position, and rotation.",
|
|
85
|
+
inputSchema: {
|
|
86
|
+
parent_path: z.string().describe("Parent node path (e.g. '.' for scene root)"),
|
|
87
|
+
light_type: z.enum(["directional", "omni", "spot"]).describe("Light type"),
|
|
88
|
+
name: z.string().optional().describe("Node name (default: type-specific, e.g. 'DirectionalLight3D')"),
|
|
89
|
+
color: z.preprocess(jsonCoerce, colorSchema).optional().describe("Light color {r,g,b}"),
|
|
90
|
+
energy: z.number().optional().describe("Light energy/intensity"),
|
|
91
|
+
shadow: z.boolean().optional().describe("Enable shadow casting"),
|
|
92
|
+
position: z.preprocess(jsonCoerce, vec3Schema).optional().describe("World position {x,y,z}"),
|
|
93
|
+
rotation: z.preprocess(jsonCoerce, vec3Schema).optional().describe("Rotation in Euler degrees {x,y,z}"),
|
|
94
|
+
},
|
|
95
|
+
annotations: { readOnlyHint: false, openWorldHint: false, destructiveHint: false },
|
|
96
|
+
},
|
|
97
|
+
{
|
|
98
|
+
name: "3d_create_camera",
|
|
99
|
+
method: "3d.create_camera",
|
|
100
|
+
description: "Create a Camera3D node. Set projection mode (perspective/orthogonal), FOV, position, rotation, and whether it's the current camera.",
|
|
101
|
+
inputSchema: {
|
|
102
|
+
parent_path: z.string().describe("Parent node path (e.g. '.' for scene root)"),
|
|
103
|
+
name: z.string().optional().describe("Node name (default: 'Camera3D')"),
|
|
104
|
+
projection: z.enum(["perspective", "orthogonal"]).optional().describe("Projection mode (default: perspective)"),
|
|
105
|
+
fov: z.number().optional().describe("Field of view in degrees (perspective mode)"),
|
|
106
|
+
size: z.number().optional().describe("Viewport size (orthogonal mode)"),
|
|
107
|
+
position: z.preprocess(jsonCoerce, vec3Schema).optional().describe("World position {x,y,z}"),
|
|
108
|
+
rotation: z.preprocess(jsonCoerce, vec3Schema).optional().describe("Rotation in Euler degrees {x,y,z}"),
|
|
109
|
+
current: z.boolean().optional().describe("Set as the current active camera"),
|
|
110
|
+
},
|
|
111
|
+
annotations: { readOnlyHint: false, openWorldHint: false, destructiveHint: false },
|
|
112
|
+
},
|
|
113
|
+
];
|
|
114
|
+
export function register(server, bridge, allowedTools) {
|
|
115
|
+
registerTools(server, bridge, threeDTools, allowedTools);
|
|
116
|
+
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { registerTools } from "../registration/toolRegistry.js";
|
|
3
|
+
import { jsonCoerce } from "../shared/schemaCoercion.js";
|
|
4
|
+
import { paginationDoc } from "../shared/pagination.js";
|
|
5
|
+
export const tilemapTools = [
|
|
6
|
+
{
|
|
7
|
+
name: "tilemap_read_cells",
|
|
8
|
+
method: "tilemap.read_cells",
|
|
9
|
+
description: "Read placed tile data from a TileMapLayer (4.3+) or deprecated TileMap. Returns cell coords, source_id, atlas_coords. 500-cell cap. " +
|
|
10
|
+
paginationDoc("cells", { resumable: false, cursorlessNav: "narrow with region/source_id" }),
|
|
11
|
+
inputSchema: {
|
|
12
|
+
node_path: z.string().describe("Path to TileMapLayer or TileMap node"),
|
|
13
|
+
region: z
|
|
14
|
+
.object({
|
|
15
|
+
x: z.coerce.number().int(),
|
|
16
|
+
y: z.coerce.number().int(),
|
|
17
|
+
width: z.coerce.number().int().positive(),
|
|
18
|
+
height: z.coerce.number().int().positive(),
|
|
19
|
+
})
|
|
20
|
+
.optional()
|
|
21
|
+
.describe("Spatial filter: only cells within {x, y, width, height}"),
|
|
22
|
+
source_id: z.coerce.number().int().optional().describe("Filter to cells from this atlas source"),
|
|
23
|
+
layer: z.coerce.number().int().optional().describe("Layer index for deprecated TileMap (default 0)"),
|
|
24
|
+
},
|
|
25
|
+
annotations: { readOnlyHint: true, openWorldHint: false },
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
name: "tilemap_set_cells",
|
|
29
|
+
method: "tilemap.set_cells",
|
|
30
|
+
description: "Batch-set cells on TileMap or TileMapLayer. Returns cells_written + cells_unchanged. " +
|
|
31
|
+
"source_id:-1 clears a cell. Use 'regions' for bulk rectangular fills (far more efficient than listing individual cells).",
|
|
32
|
+
inputSchema: {
|
|
33
|
+
node_path: z.string(),
|
|
34
|
+
layer: z.coerce.number().optional(),
|
|
35
|
+
cells: z
|
|
36
|
+
.preprocess(jsonCoerce, z.array(z.record(z.string(), z.unknown())))
|
|
37
|
+
.optional()
|
|
38
|
+
.describe("Array of {x, y, source_id, atlas_x, atlas_y, alternative_tile?}. source_id:-1 clears."),
|
|
39
|
+
regions: z
|
|
40
|
+
.preprocess(jsonCoerce, z.array(z.record(z.string(), z.unknown())))
|
|
41
|
+
.optional()
|
|
42
|
+
.describe("Array of rectangular fills: [{x, y, width, height, source_id, atlas_x, atlas_y, alternative_tile?}]. " +
|
|
43
|
+
"Each region expands into width*height cells. Far more efficient than listing individual cells for room-scale fills. " +
|
|
44
|
+
"Can be combined with 'cells' — regions are appended to cells."),
|
|
45
|
+
},
|
|
46
|
+
annotations: { readOnlyHint: false, openWorldHint: false, destructiveHint: false },
|
|
47
|
+
},
|
|
48
|
+
];
|
|
49
|
+
export function register(server, bridge, allowedTools) {
|
|
50
|
+
registerTools(server, bridge, tilemapTools, allowedTools);
|
|
51
|
+
}
|