sbox-mcp-server 1.20.0 → 2.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/dist/index.js +107 -82
- package/dist/tools/assets.js +5 -5
- package/dist/tools/audio.js +12 -19
- package/dist/tools/audit.d.ts +8 -0
- package/dist/tools/audit.js +65 -0
- package/dist/tools/batch.d.ts +8 -0
- package/dist/tools/batch.js +77 -0
- package/dist/tools/characters.js +6 -6
- package/dist/tools/cinematics.js +2 -2
- package/dist/tools/components.js +2 -2
- package/dist/tools/debugdraw.js +4 -4
- package/dist/tools/diagnostics.js +7 -5
- package/dist/tools/discovery.js +6 -6
- package/dist/tools/gameobjects.js +7 -7
- package/dist/tools/gameplay.js +4 -4
- package/dist/tools/inspection.js +6 -6
- package/dist/tools/leveltools.js +5 -5
- package/dist/tools/materials.js +4 -4
- package/dist/tools/moviemaker.js +1 -1
- package/dist/tools/networking.js +22 -22
- package/dist/tools/physics.js +4 -4
- package/dist/tools/playmode.js +5 -5
- package/dist/tools/playtest.js +2 -1
- package/dist/tools/prefabs.js +7 -3
- package/dist/tools/project.js +2 -2
- package/dist/tools/publishing.js +3 -3
- package/dist/tools/scenes.js +2 -2
- package/dist/tools/scripts.js +3 -3
- package/dist/tools/status.js +1 -1
- package/dist/tools/templates.js +7 -7
- package/dist/tools/ui.js +5 -5
- package/dist/tools/uifeedback.js +1 -1
- package/dist/tools/vehicles.d.ts +8 -0
- package/dist/tools/vehicles.js +98 -0
- package/dist/tools/visuals.js +8 -8
- package/dist/tools/workflow.d.ts +8 -0
- package/dist/tools/workflow.js +107 -0
- package/dist/tools/world.js +61 -58
- package/package.json +1 -1
package/dist/tools/physics.js
CHANGED
|
@@ -14,7 +14,7 @@ const Vector3Schema = z
|
|
|
14
14
|
.describe('3D vector — object {x,y,z} OR comma string "x,y,z"');
|
|
15
15
|
export function registerPhysicsTools(server, bridge) {
|
|
16
16
|
// ── add_physics ───────────────────────────────────────────────────
|
|
17
|
-
server.tool("add_physics", "Add a Rigidbody and collider to a GameObject, making it a dynamic physics object. Auto-selects BoxCollider if no collider type specified", {
|
|
17
|
+
server.tool("add_physics", "Add a Rigidbody and collider to a GameObject, making it a dynamic physics object. Auto-selects BoxCollider if no collider type specified. Returns { physicsAdded, id, components } listing exactly which components were added (e.g. Rigidbody + BoxCollider) — enter play mode (start_play) to see it simulate.", {
|
|
18
18
|
id: z.string().describe("GUID of the GameObject"),
|
|
19
19
|
collider: z
|
|
20
20
|
.enum(["box", "sphere", "capsule", "mesh"])
|
|
@@ -38,7 +38,7 @@ export function registerPhysicsTools(server, bridge) {
|
|
|
38
38
|
};
|
|
39
39
|
});
|
|
40
40
|
// ── add_collider ──────────────────────────────────────────────────
|
|
41
|
-
server.tool("add_collider", "Add a specific collider component to a GameObject.
|
|
41
|
+
server.tool("add_collider", "Add a specific collider component to a GameObject (no Rigidbody — use add_physics for a dynamic body). Can be configured as a trigger. Returns { added, id, collider, isTrigger } where collider is the actual component type added — note 'mesh' maps to HullCollider (s&box has no MeshCollider) and unrecognized types fall back to BoxCollider.", {
|
|
42
42
|
id: z.string().describe("GUID of the GameObject"),
|
|
43
43
|
type: z
|
|
44
44
|
.enum(["box", "sphere", "capsule", "mesh", "hull"])
|
|
@@ -68,7 +68,7 @@ export function registerPhysicsTools(server, bridge) {
|
|
|
68
68
|
};
|
|
69
69
|
});
|
|
70
70
|
// ── add_joint ─────────────────────────────────────────────────────
|
|
71
|
-
server.tool("add_joint", "Add a physics joint/constraint
|
|
71
|
+
server.tool("add_joint", "Add a physics joint/constraint component to a GameObject, optionally connected to a target body (targetId). Returns { added, id, joint, targetId } — joint is the component type added (FixedJoint/SpringJoint/SliderJoint). If targetId is omitted the joint is added unconnected; wire it later via set_property. Both objects need physics (add_physics) for the constraint to simulate in play mode.", {
|
|
72
72
|
id: z
|
|
73
73
|
.string()
|
|
74
74
|
.describe("GUID of the GameObject to add the joint to"),
|
|
@@ -97,7 +97,7 @@ export function registerPhysicsTools(server, bridge) {
|
|
|
97
97
|
};
|
|
98
98
|
});
|
|
99
99
|
// ── raycast ───────────────────────────────────────────────────────
|
|
100
|
-
server.tool("raycast", "Perform a physics raycast (Scene.Trace.Ray)
|
|
100
|
+
server.tool("raycast", "Perform a physics raycast (Scene.Trace.Ray) from start to end — pass both; the handler traces the start→end segment. Useful for line-of-sight checks, object placement, and collision detection. Returns { hit, hitPosition, normal, distance, gameObjectId, gameObjectName } — feed gameObjectId into get_all_properties/set_transform, or visualize the result with debug_draw_ray. A 'Default Surface not found' error is a known transient; call restart_editor and retry.", {
|
|
101
101
|
start: Vector3Schema
|
|
102
102
|
.describe('Ray start position (world space) — object {x,y,z} or comma string "x,y,z"'),
|
|
103
103
|
end: Vector3Schema
|
package/dist/tools/playmode.js
CHANGED
|
@@ -8,7 +8,7 @@ import { z } from "zod";
|
|
|
8
8
|
*/
|
|
9
9
|
export function registerPlayModeTools(server, bridge) {
|
|
10
10
|
// ── start_play ───────────────────────────────────────────────────
|
|
11
|
-
server.tool("start_play", "Enter play mode — starts running the game in the editor. Scripts execute, physics simulate, everything goes live", {}, async () => {
|
|
11
|
+
server.tool("start_play", "Enter play mode — starts running the game in the editor. Scripts execute, physics simulate, everything goes live. Returns { started, method } (method 'EditorScene.Play', or 'SetPlaying (fallback)' with editorErrorSkipped when the safe path failed). While playing, scene-mutating tools refuse — use get/set_runtime_property, capture_view, and playtest, then stop_play to edit again.", {}, async () => {
|
|
12
12
|
const res = await bridge.send("start_play");
|
|
13
13
|
if (!res.success) {
|
|
14
14
|
return { content: [{ type: "text", text: `Error: ${res.error}` }] };
|
|
@@ -41,7 +41,7 @@ export function registerPlayModeTools(server, bridge) {
|
|
|
41
41
|
};
|
|
42
42
|
});
|
|
43
43
|
// ── take_screenshot ──────────────────────────────────────────────
|
|
44
|
-
server.tool("take_screenshot", "Capture the
|
|
44
|
+
server.tool("take_screenshot", "Capture a 1920x1080 PNG from the scene's Main Camera (ONE fixed angle — the camera may not face what you changed; use screenshot_from to aim at a target object/point). Returns { taken, note, path }, but the engine saves to its default screenshots folder regardless of the path param (<sbox install>/screenshots/sbox.<timestamp>.png) — list the newest file there and READ the image to verify.", {
|
|
45
45
|
path: z
|
|
46
46
|
.string()
|
|
47
47
|
.optional()
|
|
@@ -56,7 +56,7 @@ export function registerPlayModeTools(server, bridge) {
|
|
|
56
56
|
};
|
|
57
57
|
});
|
|
58
58
|
// ── undo ─────────────────────────────────────────────────────────
|
|
59
|
-
server.tool("undo", "Undo the last editor action. Safety net for when a change goes wrong", {}, async () => {
|
|
59
|
+
server.tool("undo", "Undo the last editor action via the editor's UndoSystem. Safety net for when a change goes wrong. Returns { undone: true } — it does not report WHAT was undone, so re-check state with get_scene_hierarchy or get_all_properties. Reverse it with redo. Note: file writes (write_file/create_script) are not editor undo steps.", {}, async () => {
|
|
60
60
|
const res = await bridge.send("undo");
|
|
61
61
|
if (!res.success) {
|
|
62
62
|
return { content: [{ type: "text", text: `Error: ${res.error}` }] };
|
|
@@ -66,7 +66,7 @@ export function registerPlayModeTools(server, bridge) {
|
|
|
66
66
|
};
|
|
67
67
|
});
|
|
68
68
|
// ── redo ─────────────────────────────────────────────────────────
|
|
69
|
-
server.tool("redo", "
|
|
69
|
+
server.tool("redo", "Re-apply the editor action most recently reverted by undo (editor UndoSystem redo — the counterpart to the undo tool). Returns { redone: true } without details of what was redone, so verify the resulting state with get_scene_hierarchy or get_all_properties.", {}, async () => {
|
|
70
70
|
const res = await bridge.send("redo");
|
|
71
71
|
if (!res.success) {
|
|
72
72
|
return { content: [{ type: "text", text: `Error: ${res.error}` }] };
|
|
@@ -107,7 +107,7 @@ export function registerPlayModeTools(server, bridge) {
|
|
|
107
107
|
};
|
|
108
108
|
});
|
|
109
109
|
// ── set_runtime_property ─────────────────────────────────────────
|
|
110
|
-
server.tool("set_runtime_property", "Set a component property value during play mode — tweak values live while the game runs", {
|
|
110
|
+
server.tool("set_runtime_property", "Set a component property value during play mode — tweak values live while the game runs. Errors if the game is not playing (start_play first). Returns { set, id, component, property, value } like set_property; read it back with get_runtime_property. Runtime changes are DISCARDED when play mode stops — use set_property in edit mode to persist.", {
|
|
111
111
|
id: z.string().describe("GUID of the GameObject"),
|
|
112
112
|
component: z.string().describe("Component type name"),
|
|
113
113
|
property: z.string().describe("Property name to set"),
|
package/dist/tools/playtest.js
CHANGED
|
@@ -34,6 +34,7 @@ export function registerPlaytestTools(server, bridge) {
|
|
|
34
34
|
id: z.string().optional().describe("GUID of the player/controller GameObject. Omit to auto-resolve the first PlayerController."),
|
|
35
35
|
component: z.string().optional().describe("Controller component type to target (e.g. 'PlayerController'). Omit to auto-detect."),
|
|
36
36
|
}, async (p) => reply(await bridge.send("playtest", p)));
|
|
37
|
-
server.tool("playtest_status", "Poll the
|
|
37
|
+
server.tool("playtest_status", "Poll the playtest started by the playtest tool. While running: { active:true, step, totalSteps, passed, failed }. When done: { finished:true, reason, verdict:'PASS'|'FAIL', passed, failed, stepsRun, totalSteps, controller, controllerResolved, transcript:[...] } — the full per-step pass/fail record, including any capture PNG paths; the finished summary stays readable until the next playtest starts. If none has run yet: { active:false, finished:false }. Stop a stuck/wrong run early with playtest_abort.", {}, async () => reply(await bridge.send("playtest_status", {})));
|
|
38
|
+
server.tool("playtest_abort", "Stop the RUNNING playtest immediately: releases held input actions, restores UseInputControls, and finalizes the partial transcript (reason 'aborted'). Returns { aborted, stepsRun, passed, failed } — or aborted:false if no job is running. The partial transcript stays readable via playtest_status. Use when a step list is clearly stuck or targeting the wrong object", {}, async () => reply(await bridge.send("playtest_abort", {})));
|
|
38
39
|
}
|
|
39
40
|
//# sourceMappingURL=playtest.js.map
|
package/dist/tools/prefabs.js
CHANGED
|
@@ -5,7 +5,7 @@ import { z } from "zod";
|
|
|
5
5
|
*/
|
|
6
6
|
export function registerPrefabTools(server, bridge) {
|
|
7
7
|
// ── create_prefab ─────────────────────────────────────────────────
|
|
8
|
-
server.tool("create_prefab", "Save an existing GameObject as a
|
|
8
|
+
server.tool("create_prefab", "Save an existing GameObject as a real .prefab file — FULL engine serialization: every component with its property values, and all children, in the same JSON format the editor writes. Returns { created, path, sourceId, components, children } — pass path to instantiate_prefab to spawn copies or get_prefab_info to inspect. Errors if the source GameObject is missing; overwrites an existing file at path.", {
|
|
9
9
|
id: z.string().describe("GUID of the GameObject to save as prefab"),
|
|
10
10
|
path: z
|
|
11
11
|
.string()
|
|
@@ -20,10 +20,14 @@ export function registerPrefabTools(server, bridge) {
|
|
|
20
20
|
};
|
|
21
21
|
});
|
|
22
22
|
// ── instantiate_prefab ────────────────────────────────────────────
|
|
23
|
-
server.tool("instantiate_prefab", "Spawn a prefab instance into the active scene
|
|
23
|
+
server.tool("instantiate_prefab", "Spawn a FULL prefab instance into the active scene — components and children recreated. Uses the engine's GameObject.Clone for registered prefabs, with a guid-remapped deserialize fallback for freshly-written files (repeat instantiations never collide). Returns { instantiated, prefab, method, gameObject, components, childCount } — gameObject.id is the new GUID for set_transform/set_property follow-ups. Optional name/position/rotation override the spawned root.", {
|
|
24
24
|
path: z
|
|
25
25
|
.string()
|
|
26
26
|
.describe("Path to the .prefab file (e.g. 'prefabs/enemies/grunt.prefab')"),
|
|
27
|
+
name: z
|
|
28
|
+
.string()
|
|
29
|
+
.optional()
|
|
30
|
+
.describe("Rename the spawned root (defaults to the prefab's root name)"),
|
|
27
31
|
position: z
|
|
28
32
|
.union([
|
|
29
33
|
z.object({
|
|
@@ -80,7 +84,7 @@ export function registerPrefabTools(server, bridge) {
|
|
|
80
84
|
};
|
|
81
85
|
});
|
|
82
86
|
// ── get_prefab_info ───────────────────────────────────────────────
|
|
83
|
-
server.tool("get_prefab_info", "
|
|
87
|
+
server.tool("get_prefab_info", "Inspect a prefab file as a structured summary: { path, name, size, modified, totalObjects, maxDepth, referencedPrefabs, tree } — tree is the object hierarchy with per-node component type lists (children capped at 8 per node with a truncation count). referencedPrefabs lists other .prefab files this one links to. Use before instantiate_prefab; find prefabs with list_prefabs; raw JSON via read_file if needed.", {
|
|
84
88
|
path: z
|
|
85
89
|
.string()
|
|
86
90
|
.describe("Path to the .prefab file (e.g. 'prefabs/enemies/grunt.prefab')"),
|
package/dist/tools/project.js
CHANGED
|
@@ -21,7 +21,7 @@ export function registerProjectTools(server, bridge) {
|
|
|
21
21
|
};
|
|
22
22
|
});
|
|
23
23
|
// ── list_project_files ───────────────────────────────────────────
|
|
24
|
-
server.tool("list_project_files", "Browse the project file tree. Optionally filter by directory path and/or file extension (e.g. '.cs', '.scene')", {
|
|
24
|
+
server.tool("list_project_files", "Browse the project file tree. Optionally filter by directory path and/or file extension (e.g. '.cs', '.scene'). Returns { path, count, files } as project-root-relative paths — CAPPED AT 500 files (count reflects the truncated list, with no marker that more exist), so on large projects narrow with path/extension or use find_in_project. Recursive by default.", {
|
|
25
25
|
path: z
|
|
26
26
|
.string()
|
|
27
27
|
.optional()
|
|
@@ -67,7 +67,7 @@ export function registerProjectTools(server, bridge) {
|
|
|
67
67
|
};
|
|
68
68
|
});
|
|
69
69
|
// ── write_file ───────────────────────────────────────────────────
|
|
70
|
-
server.tool("write_file", "Write or overwrite a file in the s&box project. Creates parent directories as needed", {
|
|
70
|
+
server.tool("write_file", "Write or overwrite a file in the s&box project (SILENTLY replaces existing content — read_file first if you need to preserve it). Creates parent directories as needed; paths are confined to the project root (traversal outside it is denied). Returns a confirmation with the path — for C# follow with trigger_hotload so it compiles; for assets (.vmat etc.) follow with recompile_asset.", {
|
|
71
71
|
path: z
|
|
72
72
|
.string()
|
|
73
73
|
.describe("Relative path for the file (e.g. 'code/Components/Health.cs')"),
|
package/dist/tools/publishing.js
CHANGED
|
@@ -22,7 +22,7 @@ export function registerPublishingTools(server, bridge) {
|
|
|
22
22
|
};
|
|
23
23
|
});
|
|
24
24
|
// ── set_project_config ───────────────────────────────────────────
|
|
25
|
-
server.tool("set_project_config", "Update project configuration fields for publishing: title, description, version, type, package ident, summary, visibility. Only provided fields are changed", {
|
|
25
|
+
server.tool("set_project_config", "Update project configuration fields for publishing: title, description, version, type, package ident, summary, visibility. Only provided fields are changed — edits string values in the .sbproj file in place. Returns { updated, path } (the .sbproj path); read the result back with get_project_config to confirm what actually changed.", {
|
|
26
26
|
title: z.string().optional().describe("Project display title"),
|
|
27
27
|
description: z
|
|
28
28
|
.string()
|
|
@@ -58,7 +58,7 @@ export function registerPublishingTools(server, bridge) {
|
|
|
58
58
|
};
|
|
59
59
|
});
|
|
60
60
|
// ── validate_project ─────────────────────────────────────────────
|
|
61
|
-
server.tool("validate_project", "Validate that the project is ready for publishing.
|
|
61
|
+
server.tool("validate_project", "Validate that the project is ready for publishing. Runs four checks: .sbproj exists, at least one scene, project Ident set, project Title set. Returns { valid, issueCount, issues, checks } — issues are human-readable problems and each checks entry has { check, pass, detail }; fix metadata gaps with set_project_config (it does NOT check compile errors — use get_compile_errors for that).", {}, async (params) => {
|
|
62
62
|
const res = await bridge.send("validate_project", params);
|
|
63
63
|
if (!res.success) {
|
|
64
64
|
return { content: [{ type: "text", text: `Error: ${res.error}` }] };
|
|
@@ -93,7 +93,7 @@ export function registerPublishingTools(server, bridge) {
|
|
|
93
93
|
};
|
|
94
94
|
});
|
|
95
95
|
// ── get_package_details ──────────────────────────────────────────
|
|
96
|
-
server.tool("get_package_details", "Fetch
|
|
96
|
+
server.tool("get_package_details", "Fetch package information from the s&box package backend (Package.FetchAsync) by ident. Returns { fullIdent, title, summary, description, org } — no download/rating/dependency data is included. Use it to confirm a package exists and what it is before install_asset.", {
|
|
97
97
|
ident: z
|
|
98
98
|
.string()
|
|
99
99
|
.describe("Package identifier (e.g. 'facepunch.flatgrass', 'myorg.mygame')"),
|
package/dist/tools/scenes.js
CHANGED
|
@@ -33,7 +33,7 @@ export function registerSceneTools(server, bridge) {
|
|
|
33
33
|
};
|
|
34
34
|
});
|
|
35
35
|
// ── save_scene ───────────────────────────────────────────────────
|
|
36
|
-
server.tool("save_scene", "Save the currently open scene in the s&box editor", {
|
|
36
|
+
server.tool("save_scene", "Save the currently open scene in the s&box editor (EditorScene.SaveSession) to its existing .scene file — a provided path does NOT redirect the save. Returns a plain 'Scene saved' confirmation. Call after a batch of scene edits so work survives an editor restart.", {
|
|
37
37
|
path: z
|
|
38
38
|
.string()
|
|
39
39
|
.optional()
|
|
@@ -48,7 +48,7 @@ export function registerSceneTools(server, bridge) {
|
|
|
48
48
|
};
|
|
49
49
|
});
|
|
50
50
|
// ── create_scene ─────────────────────────────────────────────────
|
|
51
|
-
server.tool("create_scene", "Create a new
|
|
51
|
+
server.tool("create_scene", "Create a new EMPTY .scene file under the project's Assets folder and register it with the AssetSystem so load_scene works immediately. Errors if the scene already exists. NOTE: includeDefaults is not yet honored — the scene is always created empty, so after load_scene add a camera/light/ground yourself (create_gameobject, add_light). Returns a confirmation with the path — pass it to load_scene next.", {
|
|
52
52
|
path: z
|
|
53
53
|
.string()
|
|
54
54
|
.describe("Relative path for the new scene (e.g. 'scenes/level_01.scene')"),
|
package/dist/tools/scripts.js
CHANGED
|
@@ -6,7 +6,7 @@ import { z } from "zod";
|
|
|
6
6
|
*/
|
|
7
7
|
export function registerScriptTools(server, bridge) {
|
|
8
8
|
// ── create_script ────────────────────────────────────────────────
|
|
9
|
-
server.tool("create_script", "Create a new C# component script in the project
|
|
9
|
+
server.tool("create_script", "Create a new C# component script in the project — a minimal s&box Component class (name is sanitized to a valid identifier), or your exact code when content is provided. Errors if the file already exists. Returns { path, created, className } — the new type is NOT live until a recompile, so call trigger_hotload, then attach it with add_component_with_properties (component=className).", {
|
|
10
10
|
name: z
|
|
11
11
|
.string()
|
|
12
12
|
.describe("Class name for the component (e.g. 'PlayerController'). Will also be the filename"),
|
|
@@ -52,7 +52,7 @@ export function registerScriptTools(server, bridge) {
|
|
|
52
52
|
};
|
|
53
53
|
});
|
|
54
54
|
// ── edit_script ──────────────────────────────────────────────────
|
|
55
|
-
server.tool("edit_script", "Edit an existing C# script.
|
|
55
|
+
server.tool("edit_script", "Edit an existing C# script in place via exact-text find/replace or a full-content overwrite. Errors if the file or the find text isn't found (find/replace replaces ALL occurrences). Returns { path, edited, operation } where operation is 'find_replace' or 'overwrite' — follow with trigger_hotload so the change compiles, then get_compile_errors if in doubt.", {
|
|
56
56
|
path: z
|
|
57
57
|
.string()
|
|
58
58
|
.describe("Relative path to the script file (e.g. 'code/PlayerController.cs')"),
|
|
@@ -98,7 +98,7 @@ export function registerScriptTools(server, bridge) {
|
|
|
98
98
|
};
|
|
99
99
|
});
|
|
100
100
|
// ── delete_script ────────────────────────────────────────────────
|
|
101
|
-
server.tool("delete_script", "
|
|
101
|
+
server.tool("delete_script", "Permanently delete a file from the project by its project-relative path (built for C# scripts, but removes any file; no recycle bin, and editor undo cannot restore it). Errors if the file doesn't exist. Returns a confirmation with the path — follow with trigger_hotload so the removed class actually leaves the compiled assembly.", {
|
|
102
102
|
path: z
|
|
103
103
|
.string()
|
|
104
104
|
.describe("Relative path to the script file to delete"),
|
package/dist/tools/status.js
CHANGED
|
@@ -19,7 +19,7 @@ catch {
|
|
|
19
19
|
*/
|
|
20
20
|
export function registerStatusTools(server, bridge) {
|
|
21
21
|
// ── get_bridge_status ────────────────────────────────────────────
|
|
22
|
-
server.tool("get_bridge_status", "Check the connection
|
|
22
|
+
server.tool("get_bridge_status", "Check the s&box Bridge connection — call this FIRST in a session. Returns a human summary plus JSON: connected, roundTripOk (heartbeat can be fresh while the editor's request loop is stalled — trust roundTripOk), bridgeVersion vs mcpServerVersion + versionsAligned (a mismatch means restart Claude Code / republish the addon), handlerCount, heartbeatAgeMs, latencyMs, and ipcDir (transport is file IPC; host/port are legacy fields).", {}, async () => {
|
|
23
23
|
const connected = bridge.isConnected();
|
|
24
24
|
const ipcDir = bridge.getIpcDir();
|
|
25
25
|
const heartbeatAgeMs = bridge.getHeartbeatAgeMs();
|
package/dist/tools/templates.js
CHANGED
|
@@ -89,7 +89,7 @@ export function registerTemplateTools(server, bridge) {
|
|
|
89
89
|
};
|
|
90
90
|
});
|
|
91
91
|
// ── create_game_manager ───────────────────────────────────────────
|
|
92
|
-
server.tool("create_game_manager", "Generate a game
|
|
92
|
+
server.tool("create_game_manager", "Generate a minimal game-manager Component: a static Instance singleton, [Property] MaxPlayers / GameState, and a Component.INetworkListener OnActive hook that logs player connects. Writes <name>.cs and returns { created, path, className }. NOTE: the includeScore/includeTimer/includeSpawning params are not currently applied — the same minimal manager is always generated (for richer game-loop scaffolds see create_round_phase_machine / create_objective_system / create_economy_wallet). Follow with trigger_hotload, then get_compile_errors, then place via add_component_to_new_object", {
|
|
93
93
|
name: z
|
|
94
94
|
.string()
|
|
95
95
|
.optional()
|
|
@@ -101,15 +101,15 @@ export function registerTemplateTools(server, bridge) {
|
|
|
101
101
|
includeScore: z
|
|
102
102
|
.boolean()
|
|
103
103
|
.optional()
|
|
104
|
-
.describe("Include score tracking
|
|
104
|
+
.describe("Include score tracking (currently not applied by the handler)"),
|
|
105
105
|
includeTimer: z
|
|
106
106
|
.boolean()
|
|
107
107
|
.optional()
|
|
108
|
-
.describe("Include round timer with countdown
|
|
108
|
+
.describe("Include round timer with countdown (currently not applied by the handler)"),
|
|
109
109
|
includeSpawning: z
|
|
110
110
|
.boolean()
|
|
111
111
|
.optional()
|
|
112
|
-
.describe("Include player spawning from prefab at spawn point
|
|
112
|
+
.describe("Include player spawning from prefab at spawn point (currently not applied by the handler)"),
|
|
113
113
|
}, async (params) => {
|
|
114
114
|
const res = await bridge.send("create_game_manager", params);
|
|
115
115
|
if (!res.success) {
|
|
@@ -120,7 +120,7 @@ export function registerTemplateTools(server, bridge) {
|
|
|
120
120
|
};
|
|
121
121
|
});
|
|
122
122
|
// ── create_trigger_zone ───────────────────────────────────────────
|
|
123
|
-
server.tool("create_trigger_zone", "Generate a trigger
|
|
123
|
+
server.tool("create_trigger_zone", "Generate a trigger-zone Component (Component.ITriggerListener): auto-adds a trigger BoxCollider on start, filters entrants by a TriggerTag [Property] (default 'player'), and logs enter/exit via private OnPlayerEnter/OnPlayerExit extension points you fill in. Writes <name>.cs and returns { created, path, className }. NOTE: the action/filterTag params are not currently applied at generation time — the zone always logs; implement teleport/damage/spawn in the generated methods (edit_script). Follow with trigger_hotload, then get_compile_errors", {
|
|
124
124
|
name: z
|
|
125
125
|
.string()
|
|
126
126
|
.optional()
|
|
@@ -132,11 +132,11 @@ export function registerTemplateTools(server, bridge) {
|
|
|
132
132
|
action: z
|
|
133
133
|
.enum(["log", "teleport", "damage", "spawn"])
|
|
134
134
|
.optional()
|
|
135
|
-
.describe("What happens on trigger
|
|
135
|
+
.describe("What happens on trigger (currently not applied by the handler — the generated zone always logs; implement the effect in OnPlayerEnter yourself)"),
|
|
136
136
|
filterTag: z
|
|
137
137
|
.string()
|
|
138
138
|
.optional()
|
|
139
|
-
.describe("Only trigger for objects with this tag
|
|
139
|
+
.describe("Only trigger for objects with this tag (currently not applied at generation — the generated TriggerTag [Property] defaults to 'player'; change it per-instance with set_property)"),
|
|
140
140
|
}, async (params) => {
|
|
141
141
|
const res = await bridge.send("create_trigger_zone", params);
|
|
142
142
|
if (!res.success) {
|
package/dist/tools/ui.js
CHANGED
|
@@ -5,7 +5,7 @@ import { z } from "zod";
|
|
|
5
5
|
*/
|
|
6
6
|
export function registerUITools(server, bridge) {
|
|
7
7
|
// ── create_razor_ui ───────────────────────────────────────────────
|
|
8
|
-
server.tool("create_razor_ui", "Create a Razor UI component file (.razor)
|
|
8
|
+
server.tool("create_razor_ui", "Create a Razor UI component file (.razor). Returns { created, path, componentName }; errors if the file already exists. NOTE: the current handler generates one fixed basic panel (a root div + label bound to a Title [Property]) from name+directory only — panelType/content/styles/includeStyles are not applied and no .scss is written; for custom markup or a PanelComponent you can host via add_screen_panel, write the files with write_file and check them with razor_lint. Follow with trigger_hotload, then get_compile_errors", {
|
|
9
9
|
name: z
|
|
10
10
|
.string()
|
|
11
11
|
.describe("Component name (e.g. 'GameHud', 'MainMenu')"),
|
|
@@ -43,11 +43,11 @@ export function registerUITools(server, bridge) {
|
|
|
43
43
|
};
|
|
44
44
|
});
|
|
45
45
|
// ── add_screen_panel ──────────────────────────────────────────────
|
|
46
|
-
server.tool("add_screen_panel", "Create a new GameObject with a ScreenPanel component for full-screen UI overlay (HUD, menus, etc.)", {
|
|
46
|
+
server.tool("add_screen_panel", "Create a new GameObject with a ScreenPanel component for full-screen UI overlay (HUD, menus, etc.). Returns { created, gameObject:{ id, name, components, ... } }. NOTE: panelComponent is looked up in the TypeLibrary and SILENTLY skipped if the type isn't loaded (freshly generated panels need trigger_hotload first) — check gameObject.components to confirm it attached", {
|
|
47
47
|
name: z
|
|
48
48
|
.string()
|
|
49
49
|
.optional()
|
|
50
|
-
.describe("Name for the UI GameObject. Defaults to 'Screen
|
|
50
|
+
.describe("Name for the UI GameObject. Defaults to 'Screen Panel'"),
|
|
51
51
|
zIndex: z
|
|
52
52
|
.number()
|
|
53
53
|
.optional()
|
|
@@ -70,11 +70,11 @@ export function registerUITools(server, bridge) {
|
|
|
70
70
|
};
|
|
71
71
|
});
|
|
72
72
|
// ── add_world_panel ───────────────────────────────────────────────
|
|
73
|
-
server.tool("add_world_panel", "Create a new GameObject with a WorldPanel component for in-world 3D UI (health bars, signs, nameplates)", {
|
|
73
|
+
server.tool("add_world_panel", "Create a new GameObject with a WorldPanel component for in-world 3D UI (health bars, signs, nameplates). Returns { created, gameObject:{ id, name, components, ... } }. As with add_screen_panel, panelComponent is SILENTLY skipped if the type isn't in the TypeLibrary (trigger_hotload first, then verify via gameObject.components). For CLICKABLE world UI the scene also needs a Sandbox.WorldInput (see create_worldpanel_ui)", {
|
|
74
74
|
name: z
|
|
75
75
|
.string()
|
|
76
76
|
.optional()
|
|
77
|
-
.describe("Name for the UI GameObject. Defaults to 'World
|
|
77
|
+
.describe("Name for the UI GameObject. Defaults to 'World Panel'"),
|
|
78
78
|
position: z
|
|
79
79
|
.union([
|
|
80
80
|
z.object({ x: z.number(), y: z.number(), z: z.number() }),
|
package/dist/tools/uifeedback.js
CHANGED
|
@@ -34,7 +34,7 @@ export function registerUiFeedbackTools(server, bridge) {
|
|
|
34
34
|
return { content: [{ type: "text", text: JSON.stringify(res.data, null, 2) }] };
|
|
35
35
|
});
|
|
36
36
|
// ── create_proxy_nametag ──────────────────────────────────────────
|
|
37
|
-
server.tool("create_proxy_nametag", "Generate a sealed Component that floats the OWNER'S display name above a networked player. TextRenderer-based (not WorldPanel): a nametag is one short string with a distance fade, so a TextRenderer on a managed child object is far simpler than a WorldPanel + Razor + WorldInput stack — no UI assets, no panel host, per-frame alpha is a one-liner (mirrors create_floating_combat_text). Reads GameObject.Network.Owner.DisplayName (Owner and OwnerConnection are the same Connection on this SDK; falls back to the object name offline). Visibility is the INVERSE of the usual proxy guard: it renders only when GameObject.Network.IsProxy is true — i.e. on OTHER clients' copies of the player — so you never see a tag over your own head (offline / no networking => IsProxy false everywhere => no tags, expected). Spawns a CHILD GameObject for the text so billboarding never rotates the player model; cleaned up on disable. [Property] MaxDistance fades the tag out with distance, HeightOffset floats it above the head, FontSize sizes it. Attach to the ROOT of your networked player object. Pairs with create_networked_player (add it to the generated player prefab so every remote player is labeled).", {
|
|
37
|
+
server.tool("create_proxy_nametag", "Generate a sealed Component that floats the OWNER'S display name above a networked player. TextRenderer-based (not WorldPanel): a nametag is one short string with a distance fade, so a TextRenderer on a managed child object is far simpler than a WorldPanel + Razor + WorldInput stack — no UI assets, no panel host, per-frame alpha is a one-liner (mirrors create_floating_combat_text). Reads GameObject.Network.Owner.DisplayName (Owner and OwnerConnection are the same Connection on this SDK; falls back to the object name offline). Visibility is the INVERSE of the usual proxy guard: it renders only when GameObject.Network.IsProxy is true — i.e. on OTHER clients' copies of the player — so you never see a tag over your own head (offline / no networking => IsProxy false everywhere => no tags, expected). Spawns a CHILD GameObject for the text so billboarding never rotates the player model; cleaned up on disable. [Property] MaxDistance fades the tag out with distance, HeightOffset floats it above the head, FontSize sizes it. Attach to the ROOT of your networked player object. Pairs with create_networked_player (add it to the generated player prefab so every remote player is labeled). Returns { created, path, className, maxDistance, heightOffset, note, nextSteps }. Follow with trigger_hotload, then get_compile_errors, then attach via add_component_with_properties (component=className).", {
|
|
38
38
|
name: z
|
|
39
39
|
.string()
|
|
40
40
|
.optional()
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
2
|
+
import { BridgeClient } from "../transport/bridge-client.js";
|
|
3
|
+
/**
|
|
4
|
+
* Vehicle tools (Batch 54): create_vehicle_controller, create_seat_system,
|
|
5
|
+
* tune_vehicle, create_physics_grab_tool — the corpus vehicles theme.
|
|
6
|
+
*/
|
|
7
|
+
export declare function registerVehicleTools(server: McpServer, bridge: BridgeClient): void;
|
|
8
|
+
//# sourceMappingURL=vehicles.d.ts.map
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
/**
|
|
3
|
+
* Vehicle tools (Batch 54): create_vehicle_controller, create_seat_system,
|
|
4
|
+
* tune_vehicle, create_physics_grab_tool — the corpus vehicles theme.
|
|
5
|
+
*/
|
|
6
|
+
export function registerVehicleTools(server, bridge) {
|
|
7
|
+
// ── create_vehicle_controller ────────────────────────────────────
|
|
8
|
+
server.tool("create_vehicle_controller", "Generate a drivable raycast-car component: 4-corner spring/damper suspension, mass-scaled engine force, speed-scaled yaw steering, lateral grip (lower = drift), and a BUILT-IN driver seat (press E to enter — the driver is hidden while driving so their controller can't fight the vehicle transform, the host assigns them ownership, and a chase camera follows the car — E to exit). Attach it plus a Rigidbody and collider to any prop and it drives. Returns { created, path, className, nextSteps } — follow with trigger_hotload + compile_status, then batch_add_component the parts. Apply handling presets with tune_vehicle. HONEST LIMIT: compiles + runs is verified; driving FEEL needs a human playtest — tune from the inspector while playing", {
|
|
9
|
+
name: z
|
|
10
|
+
.string()
|
|
11
|
+
.optional()
|
|
12
|
+
.describe("Class/file name (default 'VehicleController' -> Code/VehicleController.cs). Errors if the file exists"),
|
|
13
|
+
directory: z
|
|
14
|
+
.string()
|
|
15
|
+
.optional()
|
|
16
|
+
.describe("Directory for the .cs file. Default 'Code'"),
|
|
17
|
+
engineForce: z
|
|
18
|
+
.number()
|
|
19
|
+
.optional()
|
|
20
|
+
.describe("Engine force (mass-scaled). Default 900"),
|
|
21
|
+
steerStrength: z
|
|
22
|
+
.number()
|
|
23
|
+
.optional()
|
|
24
|
+
.describe("Yaw rate in rad/s at full speed factor. Default 2.0"),
|
|
25
|
+
grip: z
|
|
26
|
+
.number()
|
|
27
|
+
.optional()
|
|
28
|
+
.describe("Lateral grip 0-1 — fraction of sideways velocity killed per tick; lower = drift. Default 0.85"),
|
|
29
|
+
}, async (params) => {
|
|
30
|
+
const res = await bridge.send("create_vehicle_controller", params);
|
|
31
|
+
if (!res.success) {
|
|
32
|
+
return { content: [{ type: "text", text: `Error: ${res.error}` }] };
|
|
33
|
+
}
|
|
34
|
+
return {
|
|
35
|
+
content: [{ type: "text", text: JSON.stringify(res.data, null, 2) }],
|
|
36
|
+
};
|
|
37
|
+
});
|
|
38
|
+
// ── create_seat_system ───────────────────────────────────────────
|
|
39
|
+
server.tool("create_seat_system", "Generate a standalone networked one-occupant seat component: press E (use) to sit — claims route through the host so seats can't be shared — E to stand; the occupant parents to the seat with their controller input disabled and restored on exit, which tries each ExitOffsets entry and takes the first spot with clearance. Static OnOccupantChanged event for camera/UI. For chairs, benches, turret mounts; vehicles get a seat built into create_vehicle_controller. Returns { created, path, className, nextSteps } — trigger_hotload + compile_status, then attach to any prop", {
|
|
40
|
+
name: z
|
|
41
|
+
.string()
|
|
42
|
+
.optional()
|
|
43
|
+
.describe("Class/file name (default 'Seat' -> Code/Seat.cs). Errors if the file exists"),
|
|
44
|
+
directory: z
|
|
45
|
+
.string()
|
|
46
|
+
.optional()
|
|
47
|
+
.describe("Directory for the .cs file. Default 'Code'"),
|
|
48
|
+
}, async (params) => {
|
|
49
|
+
const res = await bridge.send("create_seat_system", params);
|
|
50
|
+
if (!res.success) {
|
|
51
|
+
return { content: [{ type: "text", text: `Error: ${res.error}` }] };
|
|
52
|
+
}
|
|
53
|
+
return {
|
|
54
|
+
content: [{ type: "text", text: JSON.stringify(res.data, null, 2) }],
|
|
55
|
+
};
|
|
56
|
+
});
|
|
57
|
+
// ── tune_vehicle ─────────────────────────────────────────────────
|
|
58
|
+
server.tool("tune_vehicle", "Apply a handling preset to a vehicle component on a GameObject: arcade (forgiving), drift (low grip, sharp steering), offroad (soft long-travel suspension), or race (fast, planted). Sets EngineForce/MaxSpeed/SteerStrength/GripFactor/SuspensionStrength/SuspensionDamping by name via reflection — targets create_vehicle_controller scaffolds out of the box, partially tunes anything exposing those property names. Returns { tuned, preset, component, applied, missing } — missing lists properties the component lacks. Auto-finds the first component with 'Vehicle' in its type name; pass component to target explicitly. Scene-mutating: refused during play mode (use set_property on runtime objects while playing)", {
|
|
59
|
+
id: z
|
|
60
|
+
.string()
|
|
61
|
+
.describe("GUID of the GameObject carrying the vehicle component (from find_objects)"),
|
|
62
|
+
preset: z
|
|
63
|
+
.enum(["arcade", "drift", "offroad", "race"])
|
|
64
|
+
.describe("Handling preset to apply"),
|
|
65
|
+
component: z
|
|
66
|
+
.string()
|
|
67
|
+
.optional()
|
|
68
|
+
.describe("Component type name to tune. Default: first component with 'Vehicle' in its name"),
|
|
69
|
+
}, async (params) => {
|
|
70
|
+
const res = await bridge.send("tune_vehicle", params);
|
|
71
|
+
if (!res.success) {
|
|
72
|
+
return { content: [{ type: "text", text: `Error: ${res.error}` }] };
|
|
73
|
+
}
|
|
74
|
+
return {
|
|
75
|
+
content: [{ type: "text", text: JSON.stringify(res.data, null, 2) }],
|
|
76
|
+
};
|
|
77
|
+
});
|
|
78
|
+
// ── create_physics_grab_tool ─────────────────────────────────────
|
|
79
|
+
server.tool("create_physics_grab_tool", "Generate a physgun-lite player component: hold attack2 while looking at a Rigidbody prop within Range to grab it — it spring-follows a point in front of your view with physics LIVE (collides and swings, unlike the parented create_carry_system) — attack1 throws it, release lets go. Grab requests route through the host, which assigns the grabber network ownership. Returns { created, path, className, nextSteps } — trigger_hotload + compile_status, attach to the player object; ensure_input_action if attack1/attack2 aren't bound", {
|
|
80
|
+
name: z
|
|
81
|
+
.string()
|
|
82
|
+
.optional()
|
|
83
|
+
.describe("Class/file name (default 'PhysicsGrabTool' -> Code/PhysicsGrabTool.cs). Errors if the file exists"),
|
|
84
|
+
directory: z
|
|
85
|
+
.string()
|
|
86
|
+
.optional()
|
|
87
|
+
.describe("Directory for the .cs file. Default 'Code'"),
|
|
88
|
+
}, async (params) => {
|
|
89
|
+
const res = await bridge.send("create_physics_grab_tool", params);
|
|
90
|
+
if (!res.success) {
|
|
91
|
+
return { content: [{ type: "text", text: `Error: ${res.error}` }] };
|
|
92
|
+
}
|
|
93
|
+
return {
|
|
94
|
+
content: [{ type: "text", text: JSON.stringify(res.data, null, 2) }],
|
|
95
|
+
};
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
//# sourceMappingURL=vehicles.js.map
|
package/dist/tools/visuals.js
CHANGED
|
@@ -72,7 +72,7 @@ export function registerVisualTools(server, bridge) {
|
|
|
72
72
|
};
|
|
73
73
|
});
|
|
74
74
|
// ── set_fog ────────────────────────────────────────────────────────
|
|
75
|
-
server.tool("set_fog", "Add or update fog in the active scene. Types: 'gradient' (distance haze — great for mood/horror), 'cubemap' (sky-tinted distance fog), 'volumetric' (a localized fog volume). Re-running
|
|
75
|
+
server.tool("set_fog", "Add or update fog in the active scene. Types: 'gradient' (distance haze — great for mood/horror), 'cubemap' (sky-tinted distance fog), 'volumetric' (a localized fog volume). Re-running with the same targetId updates it rather than duplicating; without targetId each call creates a new fog object. Returns { created, type, gameObject } — gameObject.id addresses the fog object for later set_property/delete_gameobject; screenshot to verify the look.", {
|
|
76
76
|
type: z
|
|
77
77
|
.enum(["gradient", "cubemap", "volumetric"])
|
|
78
78
|
.optional()
|
|
@@ -127,7 +127,7 @@ export function registerVisualTools(server, bridge) {
|
|
|
127
127
|
};
|
|
128
128
|
});
|
|
129
129
|
// ── set_skybox ───────────────────────────────────────────────────────
|
|
130
|
-
server.tool("set_skybox", "Set the scene's 2D skybox tint / indirect lighting (re-uses an existing SkyBox2D or creates one). Darken the tint for night/dusk. Optionally point it at a .vmat sky material.", {
|
|
130
|
+
server.tool("set_skybox", "Set the scene's 2D skybox tint / indirect lighting (re-uses an existing SkyBox2D or creates one). Darken the tint for night/dusk. Optionally point it at a .vmat sky material (silently kept as-is if the material fails to load). Returns { created, gameObject } — gameObject.id is the sky object; screenshot to verify the change.", {
|
|
131
131
|
tint: ColorSchema.optional().describe("Sky tint colour"),
|
|
132
132
|
indirectLighting: z
|
|
133
133
|
.boolean()
|
|
@@ -145,7 +145,7 @@ export function registerVisualTools(server, bridge) {
|
|
|
145
145
|
};
|
|
146
146
|
});
|
|
147
147
|
// ── apply_atmosphere (preset) ─────────────────────────────────────────
|
|
148
|
-
server.tool("apply_atmosphere", "One-call scene mood: composes ambient + directional light, gradient fog, and a camera post-fx stack (tonemap + colour grade + vignette) tuned for the chosen mood. Idempotent — re-runs update the same 'Atmosphere *' objects.", {
|
|
148
|
+
server.tool("apply_atmosphere", "One-call scene mood: composes ambient + directional light, gradient fog, and a camera post-fx stack (tonemap + colour grade + vignette) tuned for the chosen mood. Idempotent — re-runs update the same 'Atmosphere *' objects. Returns { applied, mood, components, postFxCamera } — the post-fx stack is only applied when a camera exists (postFxCamera is null otherwise; add a camera and re-run). Screenshot to verify.", {
|
|
149
149
|
mood: z
|
|
150
150
|
.enum(["horror-night", "foggy-dawn", "overcast", "warm-interior"])
|
|
151
151
|
.describe("Atmosphere preset"),
|
|
@@ -159,7 +159,7 @@ export function registerVisualTools(server, bridge) {
|
|
|
159
159
|
};
|
|
160
160
|
});
|
|
161
161
|
// ── apply_post_fx_look (preset) ───────────────────────────────────────
|
|
162
|
-
server.tool("apply_post_fx_look", "Apply just a camera post-processing look (no lights/fog): cinematic (tonemap + bloom + soft vignette), filmic-horror (desaturated, high-contrast, heavy vignette, film grain), or clean (tonemap only).", {
|
|
162
|
+
server.tool("apply_post_fx_look", "Apply just a camera post-processing look (no lights/fog): cinematic (tonemap + bloom + soft vignette), filmic-horror (desaturated, high-contrast, heavy vignette, film grain), or clean (tonemap only). Errors if the scene has no CameraComponent. Returns { applied, look, components, camera } listing the effect components added to the main camera — tune them individually afterwards with add_post_process.", {
|
|
163
163
|
look: z
|
|
164
164
|
.enum(["cinematic", "filmic-horror", "clean"])
|
|
165
165
|
.describe("Post-fx look preset"),
|
|
@@ -173,7 +173,7 @@ export function registerVisualTools(server, bridge) {
|
|
|
173
173
|
};
|
|
174
174
|
});
|
|
175
175
|
// ── add_envmap_probe ─────────────────────────────────────────────────
|
|
176
|
-
server.tool("add_envmap_probe", "Add an environment reflection/ambient probe (EnvmapProbe) at a position with a cubic influence volume — captures local reflections and indirect light for nearby surfaces.", {
|
|
176
|
+
server.tool("add_envmap_probe", "Add an environment reflection/ambient probe (EnvmapProbe) at a position with a cubic influence volume — captures local reflections and indirect light for nearby surfaces. IMPORTANT: a placed probe captures NOTHING until baked — follow with bake_reflections. Returns { created, gameObject } — gameObject.id is the probe object's GUID.", {
|
|
177
177
|
name: z.string().optional().describe("GameObject name"),
|
|
178
178
|
position: Vector3Schema.optional().describe("World position (centre of the probe)"),
|
|
179
179
|
size: z.number().optional().describe("Cubic influence size in units (default 1024)"),
|
|
@@ -192,7 +192,7 @@ export function registerVisualTools(server, bridge) {
|
|
|
192
192
|
};
|
|
193
193
|
});
|
|
194
194
|
// ── spawn_particle (Batch 18: VFX) ───────────────────────────────────
|
|
195
|
-
server.tool("spawn_particle", "
|
|
195
|
+
server.tool("spawn_particle", "EXPERIMENTAL — build an additive runtime ParticleEffect (no texture asset needed): kind = fire, embers, sparks, magic, dust, blood, or snow ('smoke' returns an error). Returns { created, kind, gameObject } — the component graph is created, but this runtime particle path has NOT been verified to render through the bridge; for particles you can actually see, prefer spawn_vpcf.", {
|
|
196
196
|
kind: z
|
|
197
197
|
.enum(["fire", "embers", "sparks", "magic", "dust", "blood", "snow"])
|
|
198
198
|
.describe("Particle preset"),
|
|
@@ -226,7 +226,7 @@ export function registerVisualTools(server, bridge) {
|
|
|
226
226
|
};
|
|
227
227
|
});
|
|
228
228
|
// ── add_beam ─────────────────────────────────────────────────────────
|
|
229
|
-
server.tool("add_beam", "
|
|
229
|
+
server.tool("add_beam", "EXPERIMENTAL — create an energy/laser beam (BeamEffect) from a position to a target point (default: 128u straight up) — additive, tintable. Returns { created, gameObject } — gameObject.id is the beam object's GUID. Like the other runtime particle tools, rendering through the bridge is unverified; use spawn_vpcf when you need a guaranteed-visible effect.", {
|
|
230
230
|
position: Vector3Schema.optional().describe("Beam start (world position of the beam object)"),
|
|
231
231
|
target: Vector3Schema.optional().describe("Beam end point in world space (default: 128u up)"),
|
|
232
232
|
width: z.number().optional().describe("Beam width/scale (default 4)"),
|
|
@@ -286,7 +286,7 @@ export function registerVisualTools(server, bridge) {
|
|
|
286
286
|
};
|
|
287
287
|
});
|
|
288
288
|
// ── bake_reflections ────────────────────────────────────────────────
|
|
289
|
-
server.tool("bake_reflections", "Bake all EnvmapProbe reflection probes in the scene (EnvmapProbe.BakeAll) so they actually capture their surroundings — placing a probe with add_envmap_probe does nothing visible until it's baked. This is a real editor compute step, not a component setter. Runs async; re-screenshot after a moment to see reflections appear
|
|
289
|
+
server.tool("bake_reflections", "Bake all EnvmapProbe reflection probes in the scene (EnvmapProbe.BakeAll) so they actually capture their surroundings — placing a probe with add_envmap_probe does nothing visible until it's baked. This is a real editor compute step, not a component setter. Runs async — returns { baking, count, note, probes } immediately (each probe: id, name, mode, hasBaked), or { baked: false, count: 0 } when the scene has no probes; re-screenshot after a moment to see reflections appear.", {}, async (params) => {
|
|
290
290
|
const res = await bridge.send("bake_reflections", params);
|
|
291
291
|
if (!res.success) {
|
|
292
292
|
return { content: [{ type: "text", text: `Error: ${res.error}` }] };
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
2
|
+
import { BridgeClient } from "../transport/bridge-client.js";
|
|
3
|
+
/**
|
|
4
|
+
* Workflow tools (Batch 53): scene checkpoints (the agent-side undo safety net),
|
|
5
|
+
* describe_scene orientation, and the team-assigner / idle-income scaffolds.
|
|
6
|
+
*/
|
|
7
|
+
export declare function registerWorkflowTools(server: McpServer, bridge: BridgeClient): void;
|
|
8
|
+
//# sourceMappingURL=workflow.d.ts.map
|