sbox-mcp-server 1.2.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/LICENSE +21 -0
- package/README.md +90 -0
- package/dist/index.d.ts +13 -0
- package/dist/index.js +155 -0
- package/dist/tools/assets.d.ts +8 -0
- package/dist/tools/assets.js +80 -0
- package/dist/tools/audio.d.ts +8 -0
- package/dist/tools/audio.js +101 -0
- package/dist/tools/components.d.ts +11 -0
- package/dist/tools/components.js +78 -0
- package/dist/tools/console.d.ts +8 -0
- package/dist/tools/console.js +59 -0
- package/dist/tools/discovery.d.ts +13 -0
- package/dist/tools/discovery.js +58 -0
- package/dist/tools/gameobjects.d.ts +4 -0
- package/dist/tools/gameobjects.js +197 -0
- package/dist/tools/materials.d.ts +8 -0
- package/dist/tools/materials.js +82 -0
- package/dist/tools/networking.d.ts +11 -0
- package/dist/tools/networking.js +227 -0
- package/dist/tools/physics.d.ts +8 -0
- package/dist/tools/physics.js +130 -0
- package/dist/tools/playmode.d.ts +11 -0
- package/dist/tools/playmode.js +140 -0
- package/dist/tools/prefabs.d.ts +8 -0
- package/dist/tools/prefabs.js +94 -0
- package/dist/tools/project.d.ts +12 -0
- package/dist/tools/project.js +90 -0
- package/dist/tools/publishing.d.ts +11 -0
- package/dist/tools/publishing.js +168 -0
- package/dist/tools/scenes.d.ts +8 -0
- package/dist/tools/scenes.js +75 -0
- package/dist/tools/scripts.d.ts +9 -0
- package/dist/tools/scripts.js +132 -0
- package/dist/tools/status.d.ts +8 -0
- package/dist/tools/status.js +49 -0
- package/dist/tools/templates.d.ts +11 -0
- package/dist/tools/templates.js +135 -0
- package/dist/tools/ui.d.ts +8 -0
- package/dist/tools/ui.js +116 -0
- package/dist/tools/world.d.ts +20 -0
- package/dist/tools/world.js +272 -0
- package/dist/transport/bridge-client.d.ts +60 -0
- package/dist/transport/bridge-client.js +239 -0
- package/package.json +54 -0
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
/**
|
|
3
|
+
* Publishing tools: get_project_config, set_project_config, validate_project,
|
|
4
|
+
* build_project, get_build_status, clean_build, export_project,
|
|
5
|
+
* set_project_thumbnail, get_package_details, prepare_publish.
|
|
6
|
+
*
|
|
7
|
+
* Manages project configuration, building, exporting, and publishing preparation.
|
|
8
|
+
*/
|
|
9
|
+
export function registerPublishingTools(server, bridge) {
|
|
10
|
+
// ── get_project_config ───────────────────────────────────────────
|
|
11
|
+
server.tool("get_project_config", "Read the full project configuration from the .sbproj file including title, description, version, type, package references, metadata, and raw JSON", {}, async (params) => {
|
|
12
|
+
const res = await bridge.send("get_project_config", params);
|
|
13
|
+
if (!res.success) {
|
|
14
|
+
return { content: [{ type: "text", text: `Error: ${res.error}` }] };
|
|
15
|
+
}
|
|
16
|
+
return {
|
|
17
|
+
content: [{ type: "text", text: JSON.stringify(res.data, null, 2) }],
|
|
18
|
+
};
|
|
19
|
+
});
|
|
20
|
+
// ── set_project_config ───────────────────────────────────────────
|
|
21
|
+
server.tool("set_project_config", "Update project configuration fields for publishing: title, description, version, type, package ident, summary, visibility. Only provided fields are changed", {
|
|
22
|
+
title: z.string().optional().describe("Project display title"),
|
|
23
|
+
description: z
|
|
24
|
+
.string()
|
|
25
|
+
.optional()
|
|
26
|
+
.describe("Project description for publishing"),
|
|
27
|
+
version: z
|
|
28
|
+
.string()
|
|
29
|
+
.optional()
|
|
30
|
+
.describe("Version string (e.g. '1.0.0', '2.1.3')"),
|
|
31
|
+
type: z
|
|
32
|
+
.string()
|
|
33
|
+
.optional()
|
|
34
|
+
.describe("Project type: 'game', 'addon', 'library', or 'template'"),
|
|
35
|
+
packageIdent: z
|
|
36
|
+
.string()
|
|
37
|
+
.optional()
|
|
38
|
+
.describe("Package identifier (e.g. 'myorg.mygame')"),
|
|
39
|
+
summary: z
|
|
40
|
+
.string()
|
|
41
|
+
.optional()
|
|
42
|
+
.describe("Short summary for asset.party listing"),
|
|
43
|
+
isPublic: z
|
|
44
|
+
.boolean()
|
|
45
|
+
.optional()
|
|
46
|
+
.describe("Whether the project is publicly visible"),
|
|
47
|
+
}, async (params) => {
|
|
48
|
+
const res = await bridge.send("set_project_config", params);
|
|
49
|
+
if (!res.success) {
|
|
50
|
+
return { content: [{ type: "text", text: `Error: ${res.error}` }] };
|
|
51
|
+
}
|
|
52
|
+
return {
|
|
53
|
+
content: [{ type: "text", text: JSON.stringify(res.data, null, 2) }],
|
|
54
|
+
};
|
|
55
|
+
});
|
|
56
|
+
// ── validate_project ─────────────────────────────────────────────
|
|
57
|
+
server.tool("validate_project", "Validate that the project is ready for publishing. Checks: compile errors, metadata completeness, scenes, scripts, thumbnail, and project type", {}, async (params) => {
|
|
58
|
+
const res = await bridge.send("validate_project", params);
|
|
59
|
+
if (!res.success) {
|
|
60
|
+
return { content: [{ type: "text", text: `Error: ${res.error}` }] };
|
|
61
|
+
}
|
|
62
|
+
return {
|
|
63
|
+
content: [{ type: "text", text: JSON.stringify(res.data, null, 2) }],
|
|
64
|
+
};
|
|
65
|
+
});
|
|
66
|
+
// ── build_project ────────────────────────────────────────────────
|
|
67
|
+
server.tool("build_project", "Trigger a full project build/recompilation. Returns build result with error and warning counts", {
|
|
68
|
+
configuration: z
|
|
69
|
+
.enum(["Debug", "Release"])
|
|
70
|
+
.optional()
|
|
71
|
+
.describe("Build configuration. Defaults to 'Release'"),
|
|
72
|
+
}, async (params) => {
|
|
73
|
+
const res = await bridge.send("build_project", params);
|
|
74
|
+
if (!res.success) {
|
|
75
|
+
return { content: [{ type: "text", text: `Error: ${res.error}` }] };
|
|
76
|
+
}
|
|
77
|
+
return {
|
|
78
|
+
content: [{ type: "text", text: JSON.stringify(res.data, null, 2) }],
|
|
79
|
+
};
|
|
80
|
+
});
|
|
81
|
+
// ── get_build_status ─────────────────────────────────────────────
|
|
82
|
+
server.tool("get_build_status", "Get the current build/compilation status: is compiling, errors, warnings, and full diagnostics list", {}, async (params) => {
|
|
83
|
+
const res = await bridge.send("get_build_status", params);
|
|
84
|
+
if (!res.success) {
|
|
85
|
+
return { content: [{ type: "text", text: `Error: ${res.error}` }] };
|
|
86
|
+
}
|
|
87
|
+
return {
|
|
88
|
+
content: [{ type: "text", text: JSON.stringify(res.data, null, 2) }],
|
|
89
|
+
};
|
|
90
|
+
});
|
|
91
|
+
// ── clean_build ──────────────────────────────────────────────────
|
|
92
|
+
server.tool("clean_build", "Clean all compiled output (bin, obj) and trigger a fresh rebuild from scratch", {}, async (params) => {
|
|
93
|
+
const res = await bridge.send("clean_build", params);
|
|
94
|
+
if (!res.success) {
|
|
95
|
+
return { content: [{ type: "text", text: `Error: ${res.error}` }] };
|
|
96
|
+
}
|
|
97
|
+
return {
|
|
98
|
+
content: [{ type: "text", text: JSON.stringify(res.data, null, 2) }],
|
|
99
|
+
};
|
|
100
|
+
});
|
|
101
|
+
// ── export_project ───────────────────────────────────────────────
|
|
102
|
+
server.tool("export_project", "Export the project as a standalone game. Copies assemblies, assets, and scenes to an output directory for distribution", {
|
|
103
|
+
outputPath: z
|
|
104
|
+
.string()
|
|
105
|
+
.optional()
|
|
106
|
+
.describe("Relative output directory within the project. Defaults to 'export'"),
|
|
107
|
+
configuration: z
|
|
108
|
+
.enum(["Debug", "Release"])
|
|
109
|
+
.optional()
|
|
110
|
+
.describe("Build configuration for export. Defaults to 'Release'"),
|
|
111
|
+
}, async (params) => {
|
|
112
|
+
const res = await bridge.send("export_project", params);
|
|
113
|
+
if (!res.success) {
|
|
114
|
+
return { content: [{ type: "text", text: `Error: ${res.error}` }] };
|
|
115
|
+
}
|
|
116
|
+
return {
|
|
117
|
+
content: [{ type: "text", text: JSON.stringify(res.data, null, 2) }],
|
|
118
|
+
};
|
|
119
|
+
});
|
|
120
|
+
// ── set_project_thumbnail ────────────────────────────────────────
|
|
121
|
+
server.tool("set_project_thumbnail", "Set or update the project thumbnail image (thumb.png) used for publishing. Provide either a source path or base64 image data", {
|
|
122
|
+
sourcePath: z
|
|
123
|
+
.string()
|
|
124
|
+
.optional()
|
|
125
|
+
.describe("Relative path to an image file within the project to use as thumbnail"),
|
|
126
|
+
base64: z
|
|
127
|
+
.string()
|
|
128
|
+
.optional()
|
|
129
|
+
.describe("Base64-encoded image data to write as thumbnail"),
|
|
130
|
+
format: z
|
|
131
|
+
.enum(["png", "jpg"])
|
|
132
|
+
.optional()
|
|
133
|
+
.describe("Image format when using base64 mode. Defaults to 'png'"),
|
|
134
|
+
}, async (params) => {
|
|
135
|
+
const res = await bridge.send("set_project_thumbnail", params);
|
|
136
|
+
if (!res.success) {
|
|
137
|
+
return { content: [{ type: "text", text: `Error: ${res.error}` }] };
|
|
138
|
+
}
|
|
139
|
+
return {
|
|
140
|
+
content: [{ type: "text", text: JSON.stringify(res.data, null, 2) }],
|
|
141
|
+
};
|
|
142
|
+
});
|
|
143
|
+
// ── get_package_details ──────────────────────────────────────────
|
|
144
|
+
server.tool("get_package_details", "Fetch detailed package information from the s&box asset library (asset.party) including title, author, version, downloads, ratings, and dependencies", {
|
|
145
|
+
ident: z
|
|
146
|
+
.string()
|
|
147
|
+
.describe("Package identifier (e.g. 'facepunch.flatgrass', 'myorg.mygame')"),
|
|
148
|
+
}, async (params) => {
|
|
149
|
+
const res = await bridge.send("get_package_details", params);
|
|
150
|
+
if (!res.success) {
|
|
151
|
+
return { content: [{ type: "text", text: `Error: ${res.error}` }] };
|
|
152
|
+
}
|
|
153
|
+
return {
|
|
154
|
+
content: [{ type: "text", text: JSON.stringify(res.data, null, 2) }],
|
|
155
|
+
};
|
|
156
|
+
});
|
|
157
|
+
// ── prepare_publish ──────────────────────────────────────────────
|
|
158
|
+
server.tool("prepare_publish", "Comprehensive publish preparation: validates project, compiles, checks metadata, and generates a detailed readiness report with issues, warnings, and next steps", {}, async (params) => {
|
|
159
|
+
const res = await bridge.send("prepare_publish", params);
|
|
160
|
+
if (!res.success) {
|
|
161
|
+
return { content: [{ type: "text", text: `Error: ${res.error}` }] };
|
|
162
|
+
}
|
|
163
|
+
return {
|
|
164
|
+
content: [{ type: "text", text: JSON.stringify(res.data, null, 2) }],
|
|
165
|
+
};
|
|
166
|
+
});
|
|
167
|
+
}
|
|
168
|
+
//# sourceMappingURL=publishing.js.map
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
2
|
+
import { BridgeClient } from "../transport/bridge-client.js";
|
|
3
|
+
/**
|
|
4
|
+
* Scene management tools: list_scenes, load_scene, save_scene, create_scene.
|
|
5
|
+
* create_scene generates .scene JSON with optional default objects (camera, light, ground).
|
|
6
|
+
*/
|
|
7
|
+
export declare function registerSceneTools(server: McpServer, bridge: BridgeClient): void;
|
|
8
|
+
//# sourceMappingURL=scenes.d.ts.map
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
/**
|
|
3
|
+
* Scene management tools: list_scenes, load_scene, save_scene, create_scene.
|
|
4
|
+
* create_scene generates .scene JSON with optional default objects (camera, light, ground).
|
|
5
|
+
*/
|
|
6
|
+
export function registerSceneTools(server, bridge) {
|
|
7
|
+
// ── list_scenes ──────────────────────────────────────────────────
|
|
8
|
+
server.tool("list_scenes", "List all .scene files in the project with their paths and basic metadata", {}, async () => {
|
|
9
|
+
const res = await bridge.send("list_scenes");
|
|
10
|
+
if (!res.success) {
|
|
11
|
+
return { content: [{ type: "text", text: `Error: ${res.error}` }] };
|
|
12
|
+
}
|
|
13
|
+
return {
|
|
14
|
+
content: [
|
|
15
|
+
{ type: "text", text: JSON.stringify(res.data, null, 2) },
|
|
16
|
+
],
|
|
17
|
+
};
|
|
18
|
+
});
|
|
19
|
+
// ── load_scene ───────────────────────────────────────────────────
|
|
20
|
+
server.tool("load_scene", "Open a scene in the s&box editor by its path", {
|
|
21
|
+
path: z
|
|
22
|
+
.string()
|
|
23
|
+
.describe("Relative path to the .scene file (e.g. 'scenes/main.scene')"),
|
|
24
|
+
}, async (params) => {
|
|
25
|
+
const res = await bridge.send("load_scene", params);
|
|
26
|
+
if (!res.success) {
|
|
27
|
+
return { content: [{ type: "text", text: `Error: ${res.error}` }] };
|
|
28
|
+
}
|
|
29
|
+
return {
|
|
30
|
+
content: [
|
|
31
|
+
{ type: "text", text: `Scene loaded: ${params.path}` },
|
|
32
|
+
],
|
|
33
|
+
};
|
|
34
|
+
});
|
|
35
|
+
// ── save_scene ───────────────────────────────────────────────────
|
|
36
|
+
server.tool("save_scene", "Save the currently open scene in the s&box editor", {
|
|
37
|
+
path: z
|
|
38
|
+
.string()
|
|
39
|
+
.optional()
|
|
40
|
+
.describe("Path to save to. If omitted, saves to the current scene's path"),
|
|
41
|
+
}, async (params) => {
|
|
42
|
+
const res = await bridge.send("save_scene", params);
|
|
43
|
+
if (!res.success) {
|
|
44
|
+
return { content: [{ type: "text", text: `Error: ${res.error}` }] };
|
|
45
|
+
}
|
|
46
|
+
return {
|
|
47
|
+
content: [{ type: "text", text: "Scene saved" }],
|
|
48
|
+
};
|
|
49
|
+
});
|
|
50
|
+
// ── create_scene ─────────────────────────────────────────────────
|
|
51
|
+
server.tool("create_scene", "Create a new empty scene file. Optionally include basic objects like a camera, directional light, and ground plane", {
|
|
52
|
+
path: z
|
|
53
|
+
.string()
|
|
54
|
+
.describe("Relative path for the new scene (e.g. 'scenes/level_01.scene')"),
|
|
55
|
+
name: z.string().optional().describe("Display name for the scene"),
|
|
56
|
+
includeDefaults: z
|
|
57
|
+
.boolean()
|
|
58
|
+
.optional()
|
|
59
|
+
.describe("If true, includes a Camera, Directional Light, and ground plane. Defaults to true"),
|
|
60
|
+
}, async (params) => {
|
|
61
|
+
const res = await bridge.send("create_scene", params);
|
|
62
|
+
if (!res.success) {
|
|
63
|
+
return { content: [{ type: "text", text: `Error: ${res.error}` }] };
|
|
64
|
+
}
|
|
65
|
+
return {
|
|
66
|
+
content: [
|
|
67
|
+
{
|
|
68
|
+
type: "text",
|
|
69
|
+
text: `Scene created: ${params.path}`,
|
|
70
|
+
},
|
|
71
|
+
],
|
|
72
|
+
};
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
//# sourceMappingURL=scenes.js.map
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
2
|
+
import { BridgeClient } from "../transport/bridge-client.js";
|
|
3
|
+
/**
|
|
4
|
+
* Script management tools: create_script, edit_script, delete_script, trigger_hotload.
|
|
5
|
+
* create_script generates boilerplate from parameters or writes raw C# content.
|
|
6
|
+
* edit_script supports find/replace, line insert, append, and line deletion operations.
|
|
7
|
+
*/
|
|
8
|
+
export declare function registerScriptTools(server: McpServer, bridge: BridgeClient): void;
|
|
9
|
+
//# sourceMappingURL=scripts.d.ts.map
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
/**
|
|
3
|
+
* Script management tools: create_script, edit_script, delete_script, trigger_hotload.
|
|
4
|
+
* create_script generates boilerplate from parameters or writes raw C# content.
|
|
5
|
+
* edit_script supports find/replace, line insert, append, and line deletion operations.
|
|
6
|
+
*/
|
|
7
|
+
export function registerScriptTools(server, bridge) {
|
|
8
|
+
// ── create_script ────────────────────────────────────────────────
|
|
9
|
+
server.tool("create_script", "Create a new C# component script in the project. Generates proper s&box component boilerplate with the specified class name, namespace, and optional properties", {
|
|
10
|
+
name: z
|
|
11
|
+
.string()
|
|
12
|
+
.describe("Class name for the component (e.g. 'PlayerController'). Will also be the filename"),
|
|
13
|
+
directory: z
|
|
14
|
+
.string()
|
|
15
|
+
.optional()
|
|
16
|
+
.describe("Subdirectory under code/ to place the script (e.g. 'Components'). Defaults to 'code/'"),
|
|
17
|
+
description: z
|
|
18
|
+
.string()
|
|
19
|
+
.optional()
|
|
20
|
+
.describe("Description of what this component does — used to generate appropriate code"),
|
|
21
|
+
properties: z
|
|
22
|
+
.array(z.object({
|
|
23
|
+
name: z.string().describe("Property name"),
|
|
24
|
+
type: z.string().describe("C# type (e.g. 'float', 'Vector3', 'GameObject')"),
|
|
25
|
+
default: z
|
|
26
|
+
.string()
|
|
27
|
+
.optional()
|
|
28
|
+
.describe("Default value as a string"),
|
|
29
|
+
description: z
|
|
30
|
+
.string()
|
|
31
|
+
.optional()
|
|
32
|
+
.describe("Property description for the editor tooltip"),
|
|
33
|
+
}))
|
|
34
|
+
.optional()
|
|
35
|
+
.describe("List of [Property] fields to include in the component"),
|
|
36
|
+
content: z
|
|
37
|
+
.string()
|
|
38
|
+
.optional()
|
|
39
|
+
.describe("Full C# file content. If provided, ignores name/properties and writes this directly"),
|
|
40
|
+
}, async (params) => {
|
|
41
|
+
const res = await bridge.send("create_script", params);
|
|
42
|
+
if (!res.success) {
|
|
43
|
+
return { content: [{ type: "text", text: `Error: ${res.error}` }] };
|
|
44
|
+
}
|
|
45
|
+
return {
|
|
46
|
+
content: [
|
|
47
|
+
{
|
|
48
|
+
type: "text",
|
|
49
|
+
text: JSON.stringify(res.data, null, 2),
|
|
50
|
+
},
|
|
51
|
+
],
|
|
52
|
+
};
|
|
53
|
+
});
|
|
54
|
+
// ── edit_script ──────────────────────────────────────────────────
|
|
55
|
+
server.tool("edit_script", "Edit an existing C# script. Supports find/replace, inserting code at a line number, or appending code to the class body", {
|
|
56
|
+
path: z
|
|
57
|
+
.string()
|
|
58
|
+
.describe("Relative path to the script file (e.g. 'code/PlayerController.cs')"),
|
|
59
|
+
operations: z
|
|
60
|
+
.array(z.object({
|
|
61
|
+
type: z
|
|
62
|
+
.enum(["replace", "insert", "append", "delete_lines"])
|
|
63
|
+
.describe("Type of edit operation"),
|
|
64
|
+
find: z
|
|
65
|
+
.string()
|
|
66
|
+
.optional()
|
|
67
|
+
.describe("Text to find (for 'replace' operation)"),
|
|
68
|
+
replacement: z
|
|
69
|
+
.string()
|
|
70
|
+
.optional()
|
|
71
|
+
.describe("Replacement text (for 'replace' and 'insert' operations)"),
|
|
72
|
+
line: z
|
|
73
|
+
.number()
|
|
74
|
+
.optional()
|
|
75
|
+
.describe("Line number (for 'insert' and 'delete_lines' operations)"),
|
|
76
|
+
endLine: z
|
|
77
|
+
.number()
|
|
78
|
+
.optional()
|
|
79
|
+
.describe("End line number (for 'delete_lines' operation)"),
|
|
80
|
+
content: z
|
|
81
|
+
.string()
|
|
82
|
+
.optional()
|
|
83
|
+
.describe("Content to append (for 'append' operation)"),
|
|
84
|
+
}))
|
|
85
|
+
.describe("List of edit operations to apply in order"),
|
|
86
|
+
}, async (params) => {
|
|
87
|
+
const res = await bridge.send("edit_script", params);
|
|
88
|
+
if (!res.success) {
|
|
89
|
+
return { content: [{ type: "text", text: `Error: ${res.error}` }] };
|
|
90
|
+
}
|
|
91
|
+
return {
|
|
92
|
+
content: [
|
|
93
|
+
{
|
|
94
|
+
type: "text",
|
|
95
|
+
text: JSON.stringify(res.data, null, 2),
|
|
96
|
+
},
|
|
97
|
+
],
|
|
98
|
+
};
|
|
99
|
+
});
|
|
100
|
+
// ── delete_script ────────────────────────────────────────────────
|
|
101
|
+
server.tool("delete_script", "Delete a C# script from the project", {
|
|
102
|
+
path: z
|
|
103
|
+
.string()
|
|
104
|
+
.describe("Relative path to the script file to delete"),
|
|
105
|
+
}, async (params) => {
|
|
106
|
+
const res = await bridge.send("delete_script", params);
|
|
107
|
+
if (!res.success) {
|
|
108
|
+
return { content: [{ type: "text", text: `Error: ${res.error}` }] };
|
|
109
|
+
}
|
|
110
|
+
return {
|
|
111
|
+
content: [
|
|
112
|
+
{ type: "text", text: `Script deleted: ${params.path}` },
|
|
113
|
+
],
|
|
114
|
+
};
|
|
115
|
+
});
|
|
116
|
+
// ── trigger_hotload ──────────────────────────────────────────────
|
|
117
|
+
server.tool("trigger_hotload", "Force s&box to recompile and hotload all C# scripts immediately. Use after creating or editing scripts to see changes in real-time", {}, async () => {
|
|
118
|
+
const res = await bridge.send("trigger_hotload");
|
|
119
|
+
if (!res.success) {
|
|
120
|
+
return { content: [{ type: "text", text: `Error: ${res.error}` }] };
|
|
121
|
+
}
|
|
122
|
+
return {
|
|
123
|
+
content: [
|
|
124
|
+
{
|
|
125
|
+
type: "text",
|
|
126
|
+
text: "Hotload triggered — s&box is recompiling scripts",
|
|
127
|
+
},
|
|
128
|
+
],
|
|
129
|
+
};
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
//# sourceMappingURL=scripts.js.map
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
2
|
+
import { BridgeClient } from "../transport/bridge-client.js";
|
|
3
|
+
/**
|
|
4
|
+
* Diagnostic and health-check tool (get_bridge_status).
|
|
5
|
+
* Reports connection state, latency, host/port, and editor version.
|
|
6
|
+
*/
|
|
7
|
+
export declare function registerStatusTools(server: McpServer, bridge: BridgeClient): void;
|
|
8
|
+
//# sourceMappingURL=status.d.ts.map
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Diagnostic and health-check tool (get_bridge_status).
|
|
3
|
+
* Reports connection state, latency, host/port, and editor version.
|
|
4
|
+
*/
|
|
5
|
+
export function registerStatusTools(server, bridge) {
|
|
6
|
+
// ── get_bridge_status ────────────────────────────────────────────
|
|
7
|
+
server.tool("get_bridge_status", "Check the connection status to the s&box Bridge — whether it's connected, latency, host/port, and editor info. Useful for debugging", {}, async () => {
|
|
8
|
+
const connected = bridge.isConnected();
|
|
9
|
+
let latencyMs = -1;
|
|
10
|
+
let editorVersion = null;
|
|
11
|
+
if (connected) {
|
|
12
|
+
// Measure round-trip ping
|
|
13
|
+
latencyMs = await bridge.ping();
|
|
14
|
+
// Try to get editor version via project info
|
|
15
|
+
try {
|
|
16
|
+
const res = await bridge.send("get_project_info", {}, 5000);
|
|
17
|
+
if (res.success && res.data) {
|
|
18
|
+
const data = res.data;
|
|
19
|
+
editorVersion = data.editorVersion ?? null;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
catch {
|
|
23
|
+
// Non-fatal
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
const status = {
|
|
27
|
+
connected,
|
|
28
|
+
host: bridge.getHost(),
|
|
29
|
+
port: bridge.getPort(),
|
|
30
|
+
latencyMs: connected ? latencyMs : null,
|
|
31
|
+
lastPong: connected
|
|
32
|
+
? new Date(bridge.getLastPongTime()).toISOString()
|
|
33
|
+
: null,
|
|
34
|
+
editorVersion,
|
|
35
|
+
};
|
|
36
|
+
const text = connected
|
|
37
|
+
? `Bridge connected (${bridge.getHost()}:${bridge.getPort()}, ${latencyMs}ms latency)`
|
|
38
|
+
: `Bridge NOT connected (${bridge.getHost()}:${bridge.getPort()}). Is s&box running?`;
|
|
39
|
+
return {
|
|
40
|
+
content: [
|
|
41
|
+
{
|
|
42
|
+
type: "text",
|
|
43
|
+
text: `${text}\n\n${JSON.stringify(status, null, 2)}`,
|
|
44
|
+
},
|
|
45
|
+
],
|
|
46
|
+
};
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
//# sourceMappingURL=status.js.map
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
2
|
+
import { BridgeClient } from "../transport/bridge-client.js";
|
|
3
|
+
/**
|
|
4
|
+
* Game logic template tools: create_player_controller, create_npc_controller,
|
|
5
|
+
* create_game_manager, create_trigger_zone.
|
|
6
|
+
*
|
|
7
|
+
* These generate fully functional C# scripts with configurable boilerplate,
|
|
8
|
+
* saving non-coders from writing game logic from scratch.
|
|
9
|
+
*/
|
|
10
|
+
export declare function registerTemplateTools(server: McpServer, bridge: BridgeClient): void;
|
|
11
|
+
//# sourceMappingURL=templates.d.ts.map
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
/**
|
|
3
|
+
* Game logic template tools: create_player_controller, create_npc_controller,
|
|
4
|
+
* create_game_manager, create_trigger_zone.
|
|
5
|
+
*
|
|
6
|
+
* These generate fully functional C# scripts with configurable boilerplate,
|
|
7
|
+
* saving non-coders from writing game logic from scratch.
|
|
8
|
+
*/
|
|
9
|
+
export function registerTemplateTools(server, bridge) {
|
|
10
|
+
// ── create_player_controller ──────────────────────────────────────
|
|
11
|
+
server.tool("create_player_controller", "Generate a player controller script with WASD movement, mouse look, jumping, and sprint. Supports first-person and third-person camera modes", {
|
|
12
|
+
name: z
|
|
13
|
+
.string()
|
|
14
|
+
.optional()
|
|
15
|
+
.describe("Class name. Defaults to 'PlayerController'"),
|
|
16
|
+
directory: z
|
|
17
|
+
.string()
|
|
18
|
+
.optional()
|
|
19
|
+
.describe("Subdirectory under code/ for the file"),
|
|
20
|
+
type: z
|
|
21
|
+
.enum(["first_person", "third_person"])
|
|
22
|
+
.optional()
|
|
23
|
+
.describe("Camera mode: 'first_person' or 'third_person'. Defaults to 'first_person'"),
|
|
24
|
+
moveSpeed: z
|
|
25
|
+
.number()
|
|
26
|
+
.optional()
|
|
27
|
+
.describe("Movement speed in units/sec. Defaults to 300"),
|
|
28
|
+
jumpForce: z
|
|
29
|
+
.number()
|
|
30
|
+
.optional()
|
|
31
|
+
.describe("Jump force. Defaults to 350"),
|
|
32
|
+
sprintMultiplier: z
|
|
33
|
+
.number()
|
|
34
|
+
.optional()
|
|
35
|
+
.describe("Sprint speed multiplier. Defaults to 1.5"),
|
|
36
|
+
}, async (params) => {
|
|
37
|
+
const res = await bridge.send("create_player_controller", params);
|
|
38
|
+
if (!res.success) {
|
|
39
|
+
return { content: [{ type: "text", text: `Error: ${res.error}` }] };
|
|
40
|
+
}
|
|
41
|
+
return {
|
|
42
|
+
content: [{ type: "text", text: JSON.stringify(res.data, null, 2) }],
|
|
43
|
+
};
|
|
44
|
+
});
|
|
45
|
+
// ── create_npc_controller ─────────────────────────────────────────
|
|
46
|
+
server.tool("create_npc_controller", "Generate an NPC controller script with NavMeshAgent pathfinding. Supports patrol, chase, and patrol-chase behaviors", {
|
|
47
|
+
name: z
|
|
48
|
+
.string()
|
|
49
|
+
.optional()
|
|
50
|
+
.describe("Class name. Defaults to 'NpcController'"),
|
|
51
|
+
directory: z
|
|
52
|
+
.string()
|
|
53
|
+
.optional()
|
|
54
|
+
.describe("Subdirectory under code/ for the file"),
|
|
55
|
+
behavior: z
|
|
56
|
+
.enum(["patrol", "chase", "patrol_chase"])
|
|
57
|
+
.optional()
|
|
58
|
+
.describe("AI behavior: 'patrol' (follow waypoints), 'chase' (follow player), 'patrol_chase' (patrol until player nearby). Defaults to 'patrol'"),
|
|
59
|
+
moveSpeed: z
|
|
60
|
+
.number()
|
|
61
|
+
.optional()
|
|
62
|
+
.describe("Movement speed. Defaults to 150"),
|
|
63
|
+
chaseRange: z
|
|
64
|
+
.number()
|
|
65
|
+
.optional()
|
|
66
|
+
.describe("Detection range for chase behavior. Defaults to 500"),
|
|
67
|
+
}, async (params) => {
|
|
68
|
+
const res = await bridge.send("create_npc_controller", params);
|
|
69
|
+
if (!res.success) {
|
|
70
|
+
return { content: [{ type: "text", text: `Error: ${res.error}` }] };
|
|
71
|
+
}
|
|
72
|
+
return {
|
|
73
|
+
content: [{ type: "text", text: JSON.stringify(res.data, null, 2) }],
|
|
74
|
+
};
|
|
75
|
+
});
|
|
76
|
+
// ── create_game_manager ───────────────────────────────────────────
|
|
77
|
+
server.tool("create_game_manager", "Generate a game manager script with configurable game loop features: score tracking, round timer, player spawning, and game state machine", {
|
|
78
|
+
name: z
|
|
79
|
+
.string()
|
|
80
|
+
.optional()
|
|
81
|
+
.describe("Class name. Defaults to 'GameManager'"),
|
|
82
|
+
directory: z
|
|
83
|
+
.string()
|
|
84
|
+
.optional()
|
|
85
|
+
.describe("Subdirectory under code/ for the file"),
|
|
86
|
+
includeScore: z
|
|
87
|
+
.boolean()
|
|
88
|
+
.optional()
|
|
89
|
+
.describe("Include score tracking. Defaults to true"),
|
|
90
|
+
includeTimer: z
|
|
91
|
+
.boolean()
|
|
92
|
+
.optional()
|
|
93
|
+
.describe("Include round timer with countdown. Defaults to false"),
|
|
94
|
+
includeSpawning: z
|
|
95
|
+
.boolean()
|
|
96
|
+
.optional()
|
|
97
|
+
.describe("Include player spawning from prefab at spawn point. Defaults to false"),
|
|
98
|
+
}, async (params) => {
|
|
99
|
+
const res = await bridge.send("create_game_manager", params);
|
|
100
|
+
if (!res.success) {
|
|
101
|
+
return { content: [{ type: "text", text: `Error: ${res.error}` }] };
|
|
102
|
+
}
|
|
103
|
+
return {
|
|
104
|
+
content: [{ type: "text", text: JSON.stringify(res.data, null, 2) }],
|
|
105
|
+
};
|
|
106
|
+
});
|
|
107
|
+
// ── create_trigger_zone ───────────────────────────────────────────
|
|
108
|
+
server.tool("create_trigger_zone", "Generate a trigger zone script that detects when GameObjects enter/exit a collider volume. Supports teleport, damage, spawn, and log actions", {
|
|
109
|
+
name: z
|
|
110
|
+
.string()
|
|
111
|
+
.optional()
|
|
112
|
+
.describe("Class name. Defaults to 'TriggerZone'"),
|
|
113
|
+
directory: z
|
|
114
|
+
.string()
|
|
115
|
+
.optional()
|
|
116
|
+
.describe("Subdirectory under code/ for the file"),
|
|
117
|
+
action: z
|
|
118
|
+
.enum(["log", "teleport", "damage", "spawn"])
|
|
119
|
+
.optional()
|
|
120
|
+
.describe("What happens on trigger: 'log' (print message), 'teleport' (move to destination), 'damage' (apply damage), 'spawn' (create prefab). Defaults to 'log'"),
|
|
121
|
+
filterTag: z
|
|
122
|
+
.string()
|
|
123
|
+
.optional()
|
|
124
|
+
.describe("Only trigger for objects with this tag. Defaults to 'player'"),
|
|
125
|
+
}, async (params) => {
|
|
126
|
+
const res = await bridge.send("create_trigger_zone", params);
|
|
127
|
+
if (!res.success) {
|
|
128
|
+
return { content: [{ type: "text", text: `Error: ${res.error}` }] };
|
|
129
|
+
}
|
|
130
|
+
return {
|
|
131
|
+
content: [{ type: "text", text: JSON.stringify(res.data, null, 2) }],
|
|
132
|
+
};
|
|
133
|
+
});
|
|
134
|
+
}
|
|
135
|
+
//# sourceMappingURL=templates.js.map
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
2
|
+
import { BridgeClient } from "../transport/bridge-client.js";
|
|
3
|
+
/**
|
|
4
|
+
* UI tools: create_razor_ui, add_screen_panel, add_world_panel.
|
|
5
|
+
* Manages s&box's Razor-based UI system — .razor component files, ScreenPanel, and WorldPanel.
|
|
6
|
+
*/
|
|
7
|
+
export declare function registerUITools(server: McpServer, bridge: BridgeClient): void;
|
|
8
|
+
//# sourceMappingURL=ui.d.ts.map
|