sbox-mcp-server 1.2.0 → 1.3.1

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/README.md CHANGED
@@ -1,55 +1,60 @@
1
1
  # sbox-mcp-server
2
2
 
3
- MCP Server for the s&box game engine. Lets Claude Code build s&box games through conversation — 78 working tools for scenes, scripts, GameObjects, components, assets, materials, audio, physics, UI, networking, publishing, and more.
3
+ MCP Server for the s&box game engine. Lets Claude Code build s&box games through conversation — 99 working tools for scenes, scripts, GameObjects, components, assets, materials, audio, physics, UI, networking, publishing, world-gen, and type discovery.
4
4
 
5
- ## Quick Start
5
+ ## Fastest install — the Claude Code plugin
6
6
 
7
- ### 1. Install the Bridge Addon in s&box
7
+ If you use Claude Code, the easiest install is the companion plugin. It registers this MCP server automatically, ships a workflow skill, and includes the `sbox-game-dev` specialist agent.
8
8
 
9
- The Bridge Addon runs inside the s&box editor and receives commands from this MCP server.
10
-
11
- **From source:**
12
- ```bash
13
- git clone https://github.com/lousputthole/sbox-claude.git
9
+ ```
10
+ /plugin marketplace add LouSputthole/Sbox-Claude
11
+ /plugin install sbox-claude
14
12
  ```
15
13
 
16
- Then in s&box:
17
- 1. Open your project in the s&box editor
18
- 2. Go to **Library Manager** and create a new library called **"claudebridge"**
19
- 3. Copy `sbox-bridge-addon/Editor/MyEditorMenu.cs` into the library's `Editor/` folder
20
- 4. Restart s&box
14
+ You still need to install the s&box-side **bridge addon** into your project's `Libraries/` folder (see step 1 below). The plugin handles the Claude side; the addon handles the s&box side.
21
15
 
22
- ### 2. Build the MCP Server
16
+ ## Manual install three steps
23
17
 
24
- ```bash
25
- cd sbox-claude/sbox-mcp-server
26
- npm install
27
- npm run build
18
+ ### 1. Install the bridge addon in s&box
19
+
20
+ The bridge addon runs inside the s&box editor and receives commands from this MCP server. It MUST live inside a project's `Libraries/` folder — putting it in s&box's global `addons/` will silently fail to compile.
21
+
22
+ ```powershell
23
+ git clone https://github.com/LouSputthole/Sbox-Claude.git
24
+ cd Sbox-Claude
25
+ .\install.ps1 -RemoveStaleAddons # Windows, auto-detects your s&box project
26
+ ./install.sh --remove-stale # Linux/Mac/WSL
28
27
  ```
29
28
 
30
- ### 3. Connect to Claude Code
29
+ See [INSTALL.md](https://github.com/LouSputthole/Sbox-Claude/blob/main/INSTALL.md) for the full guide and manual fallback.
30
+
31
+ ### 2. Register the MCP server with Claude Code
31
32
 
32
33
  ```bash
33
- claude mcp add sbox -- node /path/to/sbox-mcp-server/dist/index.js
34
+ claude mcp add sbox -- npx sbox-mcp-server
34
35
  ```
35
36
 
36
- ### 4. Open the Bridge Dock
37
-
38
- In s&box, go to **View > Claude Bridge** to open the dock panel. The dock **must be visible** for commands to be processed.
37
+ This is the bare command — equivalent to what the plugin's `.mcp.json` does for you.
39
38
 
40
- That's it. Start Claude Code and start building.
39
+ ### 3. Open s&box
41
40
 
42
- ## How It Works
41
+ Open your project. The bridge starts automatically. Verify with:
43
42
 
44
43
  ```
45
- Claude Code --> (stdio) --> sbox-mcp-server --> (file IPC) --> Bridge Addon --> s&box Editor
44
+ Check the bridge status.
46
45
  ```
47
46
 
48
- Communication uses **file-based IPC** through `%TEMP%/sbox-bridge-ipc/`. The MCP server writes request JSON files, the Bridge Addon (running inside s&box) polls for them, processes on the main editor thread, and writes response files back.
47
+ You should see `connected: true, handlerCount: 99`.
49
48
 
50
- WebSocket is not used — s&box's sandboxed C# environment does not allow `System.Net`.
49
+ ## How it works
51
50
 
52
- ## Tools (78 working, 89 defined)
51
+ ```
52
+ Claude Code → (stdio) → sbox-mcp-server → (file IPC) → bridge addon → s&box editor
53
+ ```
54
+
55
+ Communication uses file-based IPC through `%TEMP%/sbox-bridge-ipc/`. The MCP server writes request JSON files, the bridge addon (running inside s&box) polls and processes on the main editor thread, then writes response files back. WebSocket is not used — s&box's sandboxed C# environment blocks `System.Net`.
56
+
57
+ ## Tools (99 working)
53
58
 
54
59
  | Category | Tools |
55
60
  |----------|-------|
@@ -57,8 +62,8 @@ WebSocket is not used — s&box's sandboxed C# environment does not allow `Syste
57
62
  | **Scripts** | create_script, edit_script, delete_script, trigger_hotload |
58
63
  | **Scenes** | list_scenes, load_scene, save_scene, create_scene |
59
64
  | **GameObjects** | create/delete/duplicate/rename, set_parent/enabled/transform |
60
- | **Components** | get/set_property, get_all_properties, list_available, add_component |
61
- | **Hierarchy** | get_scene_hierarchy, get/select/focus_object |
65
+ | **Components** | get/set_property, get_all_properties, list_available, add_component, set_prefab_ref |
66
+ | **Hierarchy** | get_scene_hierarchy (with `maxDepth` + `rootId`), get/select/focus_object |
62
67
  | **Assets** | search_assets, list_asset_library, install_asset, get_asset_info |
63
68
  | **Materials** | assign_model, create/assign_material, set_material_property |
64
69
  | **Audio** | list_sounds, create_sound_event, assign_sound, play_sound_preview |
@@ -69,20 +74,38 @@ WebSocket is not used — s&box's sandboxed C# environment does not allow `Syste
69
74
  | **Physics** | add_physics, add_collider, add_joint, raycast |
70
75
  | **UI** | create_razor_ui, add_screen_panel, add_world_panel |
71
76
  | **Templates** | create_player/npc_controller, create_game_manager, create_trigger_zone |
72
- | **Networking** | network_helper, configure/status, spawn, ownership, sync, RPCs, templates |
73
- | **Publishing** | project_config, validate, thumbnail, package_details, install_asset |
77
+ | **Networking** | network_helper, configure/status, spawn, ownership, sync, RPCs, lobby/event templates |
78
+ | **Publishing** | project_config, validate, thumbnail, package_details |
79
+ | **World gen** | invoke_button, list_component_buttons, raycast_terrain, build_terrain_mesh |
80
+ | **Map edit** | add_terrain_hill/clearing/trail, clear_terrain_features, sculpt_terrain |
81
+ | **Caves / Forest** | add_cave_waypoint, clear_cave_path, add_forest_poi/trail, set_forest_seed, clear_forest_pois, paint_forest_density |
82
+ | **Placement** | place_along_path |
83
+ | **Discovery** | describe_type, search_types, get_method_signature, find_in_project |
74
84
  | **Status** | get_bridge_status |
75
85
 
76
- ### Not implementable (no s&box API)
86
+ ## Working with Claude effectively
77
87
 
78
- pause_play, resume_play, get_console_output, get_compile_errors, clear_console, build_project, get_build_status, clean_build, export_project, prepare_publish
88
+ Two disciplines prevent the iteration-loop trap:
89
+
90
+ 1. **After visual changes, call `take_screenshot` and read the PNG.** Claude is a multimodal model — it can see the result. Guessing about visual outcomes from code alone produces long iteration loops.
91
+ 2. **Before writing code that touches an unfamiliar s&box type, call `describe_type` or `search_types`.** Reflection is the source of truth; training data goes stale across SDK versions.
92
+
93
+ The companion plugin's `sbox-build-feature` skill encodes this workflow plus the common gotchas. If you're not using the plugin, the same rules apply manually.
79
94
 
80
95
  ## Requirements
81
96
 
82
97
  - **Node.js 18+**
83
- - **s&box** with the Bridge Addon installed
98
+ - **s&box** with the bridge addon installed in your project's `Libraries/` folder
84
99
  - **Claude Code**
85
100
 
101
+ ## Documentation
102
+
103
+ - [Main README](https://github.com/LouSputthole/Sbox-Claude/blob/main/README.md) — full project overview
104
+ - [INSTALL.md](https://github.com/LouSputthole/Sbox-Claude/blob/main/INSTALL.md) — install + manual fallback
105
+ - [TROUBLESHOOTING.md](https://github.com/LouSputthole/Sbox-Claude/blob/main/TROUBLESHOOTING.md) — 10 most common failures
106
+ - [CHANGELOG.md](https://github.com/LouSputthole/Sbox-Claude/blob/main/CHANGELOG.md) — release history
107
+ - [Plugin README](https://github.com/LouSputthole/Sbox-Claude/blob/main/plugins/sbox-claude/README.md) — Claude Code plugin docs
108
+
86
109
  ## License
87
110
 
88
111
  **GPL-3.0** — see [LICENSE](../LICENSE) for details.
package/dist/index.js CHANGED
@@ -17,7 +17,6 @@ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"
17
17
  import { BridgeClient } from "./transport/bridge-client.js";
18
18
  import { registerProjectTools } from "./tools/project.js";
19
19
  import { registerScriptTools } from "./tools/scripts.js";
20
- import { registerConsoleTools } from "./tools/console.js";
21
20
  import { registerSceneTools } from "./tools/scenes.js";
22
21
  import { registerGameObjectTools } from "./tools/gameobjects.js";
23
22
  import { registerComponentTools } from "./tools/components.js";
@@ -67,18 +66,17 @@ ENVIRONMENT VARIABLES
67
66
  CONNECT TO CLAUDE CODE
68
67
  claude mcp add sbox -- node /path/to/sbox-mcp-server/dist/index.js
69
68
 
70
- TOOLS (109 total)
69
+ TOOLS (99 working — was 109; 10 unimplementable tools removed in v1.3.0)
71
70
  Project: get_project_info, list_project_files, read_file, write_file
72
71
  Scripts: create_script, edit_script, delete_script, trigger_hotload
73
- Console: get_console_output, get_compile_errors, clear_console
74
72
  Scenes: list_scenes, load_scene, save_scene, create_scene
75
73
  GameObjects: create/delete/duplicate/rename_gameobject, set_parent/enabled/transform
76
74
  Components: get/set_property, get_all_properties, list_available_components, add_component_with_properties, set_prefab_ref
77
- Hierarchy: get_scene_hierarchy, get_selected_objects, select_object, focus_object
75
+ Hierarchy: get_scene_hierarchy (with maxDepth + rootId), get_selected_objects, select_object, focus_object
78
76
  Assets: search_assets, list_asset_library, install_asset, get_asset_info
79
77
  Materials: assign_model, create_material, assign_material, set_material_property
80
78
  Audio: list_sounds, create_sound_event, assign_sound, play_sound_preview
81
- Play Mode: start/stop/pause/resume_play, is_playing
79
+ Play Mode: start_play, stop_play, is_playing
82
80
  Runtime: get/set_runtime_property, take_screenshot
83
81
  Editor: undo, redo
84
82
  Prefabs: create_prefab, instantiate_prefab, list_prefabs, get_prefab_info
@@ -87,8 +85,7 @@ TOOLS (109 total)
87
85
  Templates: create_player_controller, create_npc_controller, create_game_manager, create_trigger_zone
88
86
  Networking: add_network_helper, configure_network, get_network_status, network_spawn, set_ownership
89
87
  Net Scripts: add_sync_property, add_rpc_method, create_networked_player, create_lobby_manager, create_network_events
90
- Publishing: get_project_config, set_project_config, validate_project, build_project, get_build_status, clean_build
91
- Export: export_project, set_project_thumbnail, get_package_details, prepare_publish
88
+ Publishing: get_project_config, set_project_config, validate_project, set_project_thumbnail, get_package_details
92
89
  World Gen: invoke_button, list_component_buttons, raycast_terrain, build_terrain_mesh
93
90
  Map Edit: add_terrain_hill/clearing/trail, clear_terrain_features, sculpt_terrain
94
91
  Caves: add_cave_waypoint, clear_cave_path
@@ -103,13 +100,36 @@ TOOLS (109 total)
103
100
  const server = new McpServer({
104
101
  name: "sbox-mcp",
105
102
  version: getVersion(),
103
+ }, {
104
+ // The `instructions` field surfaces every Claude Code session that uses this
105
+ // server (the way other MCP servers like Supabase / TurboTax do). Use it to
106
+ // tell Claude how to work effectively with the bridge — the disciplines that
107
+ // are easy to skip without a reminder.
108
+ instructions: `You are working with the s&box Claude Bridge — a file-based IPC bridge into the s&box game engine editor.
109
+
110
+ To get good results:
111
+
112
+ 1. Always call \`mcp__sbox__get_bridge_status\` first to confirm the bridge addon is connected and s&box is running. If ping responds but other tools time out, the editor side isn't processing requests.
113
+
114
+ 2. For visual changes (models, positions, animations, UI panels, lighting), call \`mcp__sbox__take_screenshot\` after the change and READ THE PNG yourself. You're a multimodal model — you can see the result. Guessing about visual outcomes from code alone produces long iteration loops. The screenshot tool saves to <sbox-install>/screenshots/sbox.<timestamp>.png — list the newest file and read it.
115
+
116
+ 3. Before writing code that touches an unfamiliar s&box type, call \`mcp__sbox__describe_type\` or \`mcp__sbox__search_types\`. s&box's API changes between SDK versions — reflection is the source of truth, not training data.
117
+
118
+ 4. \`get_scene_hierarchy\` honors \`maxDepth\` (default 10) and accepts optional \`rootId\` to traverse from a specific GameObject. Use these to avoid dumping the entire scene into a tool result.
119
+
120
+ 5. Scene-mutating tools (create_gameobject, set_property, etc.) refuse during play mode and return a clear error. Stop play before making scene edits.
121
+
122
+ If you're running inside Claude Code, install the companion plugin for the full workflow:
123
+ /plugin marketplace add LouSputthole/Sbox-Claude
124
+ /plugin install sbox-claude
125
+
126
+ The plugin ships an \`sbox-build-feature\` skill that codifies the workflow above plus a list of common s&box gotchas (MathF not available in sandbox, Cloud assets ephemeral, head bone case-sensitive, CitizenAnimationHelper.IkRightHand works at runtime, etc.). Read its SKILL.md before starting non-trivial features.`,
106
127
  });
107
128
  // Bridge client connects to s&box editor via WebSocket
108
129
  const bridge = new BridgeClient(process.env.SBOX_BRIDGE_HOST ?? "127.0.0.1", parseInt(process.env.SBOX_BRIDGE_PORT ?? "29015", 10));
109
130
  // Register all tools
110
131
  registerProjectTools(server, bridge);
111
132
  registerScriptTools(server, bridge);
112
- registerConsoleTools(server, bridge);
113
133
  registerSceneTools(server, bridge);
114
134
  registerGameObjectTools(server, bridge);
115
135
  registerComponentTools(server, bridge);
@@ -141,11 +141,17 @@ export function registerGameObjectTools(server, bridge) {
141
141
  };
142
142
  });
143
143
  // ── get_scene_hierarchy ──────────────────────────────────────────
144
- server.tool("get_scene_hierarchy", "Get the full scene tree — all GameObjects with their names, GUIDs, components, positions, and parent/child relationships. This is how you 'see' the scene", {
144
+ server.tool("get_scene_hierarchy", "Get the scene tree — GameObjects with their names, GUIDs, components, and parent/child relationships. Pair maxDepth with rootId to drill into a subtree without paying for the whole scene", {
145
145
  maxDepth: z
146
146
  .number()
147
+ .int()
148
+ .nonnegative()
147
149
  .optional()
148
- .describe("Maximum depth of the tree to return. Defaults to 10"),
150
+ .describe("Maximum recursion depth. Defaults to 10. Use 1 or 2 for cheap top-level overviews"),
151
+ rootId: z
152
+ .string()
153
+ .optional()
154
+ .describe("Optional GUID of a GameObject to start traversal from. Omit to walk from the scene roots"),
149
155
  }, async (params) => {
150
156
  const res = await bridge.send("get_scene_hierarchy", params);
151
157
  if (!res.success) {
@@ -27,26 +27,9 @@ export function registerPlayModeTools(server, bridge) {
27
27
  content: [{ type: "text", text: JSON.stringify(res.data, null, 2) }],
28
28
  };
29
29
  });
30
- // ── pause_play ───────────────────────────────────────────────────
31
- server.tool("pause_play", "Pause the running game freezes simulation but stays in play mode. Use resume_play to continue", {}, async () => {
32
- const res = await bridge.send("pause_play");
33
- if (!res.success) {
34
- return { content: [{ type: "text", text: `Error: ${res.error}` }] };
35
- }
36
- return {
37
- content: [{ type: "text", text: JSON.stringify(res.data, null, 2) }],
38
- };
39
- });
40
- // ── resume_play ──────────────────────────────────────────────────
41
- server.tool("resume_play", "Resume a paused game — unfreezes simulation", {}, async () => {
42
- const res = await bridge.send("resume_play");
43
- if (!res.success) {
44
- return { content: [{ type: "text", text: `Error: ${res.error}` }] };
45
- }
46
- return {
47
- content: [{ type: "text", text: JSON.stringify(res.data, null, 2) }],
48
- };
49
- });
30
+ // pause_play / resume_play removed in v1.3.0 — s&box does not expose a public
31
+ // API for pausing the editor's play mode, so the addon has no handler and the
32
+ // tool only ever returned "Unknown command". See GitHub issue #3.
50
33
  // ── is_playing ───────────────────────────────────────────────────
51
34
  server.tool("is_playing", "Check current play state — returns 'playing', 'paused', or 'stopped'", {}, async () => {
52
35
  const res = await bridge.send("is_playing");
@@ -2,10 +2,14 @@ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
2
  import { BridgeClient } from "../transport/bridge-client.js";
3
3
  /**
4
4
  * Publishing tools: get_project_config, set_project_config, validate_project,
5
- * build_project, get_build_status, clean_build, export_project,
6
- * set_project_thumbnail, get_package_details, prepare_publish.
5
+ * set_project_thumbnail, get_package_details.
7
6
  *
8
- * Manages project configuration, building, exporting, and publishing preparation.
7
+ * Manages project configuration and publishing metadata.
8
+ *
9
+ * build_project / get_build_status / clean_build / export_project / prepare_publish
10
+ * were removed in v1.3.0 — s&box does not expose a public API for these from
11
+ * inside an addon, so the bridge never had handlers for them and the tools only
12
+ * ever returned "Unknown command". See GitHub issue #3.
9
13
  */
10
14
  export declare function registerPublishingTools(server: McpServer, bridge: BridgeClient): void;
11
15
  //# sourceMappingURL=publishing.d.ts.map
@@ -1,10 +1,14 @@
1
1
  import { z } from "zod";
2
2
  /**
3
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.
4
+ * set_project_thumbnail, get_package_details.
6
5
  *
7
- * Manages project configuration, building, exporting, and publishing preparation.
6
+ * Manages project configuration and publishing metadata.
7
+ *
8
+ * build_project / get_build_status / clean_build / export_project / prepare_publish
9
+ * were removed in v1.3.0 — s&box does not expose a public API for these from
10
+ * inside an addon, so the bridge never had handlers for them and the tools only
11
+ * ever returned "Unknown command". See GitHub issue #3.
8
12
  */
9
13
  export function registerPublishingTools(server, bridge) {
10
14
  // ── get_project_config ───────────────────────────────────────────
@@ -63,60 +67,8 @@ export function registerPublishingTools(server, bridge) {
63
67
  content: [{ type: "text", text: JSON.stringify(res.data, null, 2) }],
64
68
  };
65
69
  });
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
- });
70
+ // build_project / get_build_status / clean_build / export_project removed
71
+ // in v1.3.0 no addon handler exists. See GitHub issue #3.
120
72
  // ── set_project_thumbnail ────────────────────────────────────────
121
73
  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
74
  sourcePath: z
@@ -154,15 +106,7 @@ export function registerPublishingTools(server, bridge) {
154
106
  content: [{ type: "text", text: JSON.stringify(res.data, null, 2) }],
155
107
  };
156
108
  });
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
- });
109
+ // prepare_publish removed in v1.3.0 — no addon handler. Equivalent intent is
110
+ // covered by validate_project (which IS implemented). GitHub issue #3.
167
111
  }
168
112
  //# sourceMappingURL=publishing.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sbox-mcp-server",
3
- "version": "1.2.0",
3
+ "version": "1.3.1",
4
4
  "description": "MCP Server for s&box game engine — enables Claude to build games through conversation",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",