sbox-mcp-server 1.5.0 → 1.5.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/dist/index.js CHANGED
@@ -147,6 +147,8 @@ To get good results:
147
147
 
148
148
  5. Scene-mutating tools (create_gameobject, set_property, etc.) refuse during play mode and return a clear error. Stop play before making scene edits.
149
149
 
150
+ 6. First session with the bridge (or when the user asks "how do I start?" / "what can this do?")? Offer to run setup — invoke the \`sbox-setup\` skill: it verifies the connection, detects the user's installed libraries (\`list_libraries\`), recommends a first move, and points to help + feedback.
151
+
150
152
  If you're running inside Claude Code, install the companion plugin for the full workflow:
151
153
  /plugin marketplace add LouSputthole/Sbox-Claude
152
154
  /plugin install sbox-claude
@@ -18,6 +18,13 @@ export function registerDiscoveryTools(server, bridge) {
18
18
  return { content: [{ type: "text", text: `Error: ${res.error}` }] };
19
19
  return { content: [{ type: "text", text: JSON.stringify(res.data, null, 2) }] };
20
20
  });
21
+ // ── list_libraries ───────────────────────────────────────────────
22
+ server.tool("list_libraries", "List the s&box libraries/addons installed in this project (reads Libraries/ + each .sbproj). Discovers what's available to build ON — e.g. character controllers (fish.scc = Shrimple Character Controller, facepunch.playercontroller), world/spline/road tools — so you can leverage an installed library (add its components via add_component_with_properties, or generate code against its API) instead of writing from scratch. Returns ident/org/title/type/enabled per library. Read-only.", {}, async () => {
23
+ const res = await bridge.send("list_libraries", {});
24
+ if (!res.success)
25
+ return { content: [{ type: "text", text: `Error: ${res.error}` }] };
26
+ return { content: [{ type: "text", text: JSON.stringify(res.data, null, 2) }] };
27
+ });
21
28
  // ── search_types ─────────────────────────────────────────────────
22
29
  server.tool("search_types", "Find types matching a name pattern. Pass components_only=true to filter to Component subclasses only. Useful for discovering 'is there a built-in X for this?'", {
23
30
  pattern: z.string().describe("Substring to match against type name (case-insensitive)"),
@@ -1,3 +1,4 @@
1
+ import { z } from "zod";
1
2
  /**
2
3
  * Diagnostic and health-check tool (get_bridge_status).
3
4
  * Reports connection state, latency, host/port, and editor version.
@@ -60,5 +61,62 @@ export function registerStatusTools(server, bridge) {
60
61
  ],
61
62
  };
62
63
  });
64
+ // ── restart_editor ────────────────────────────────────────────────
65
+ server.tool("restart_editor", "Restart the s&box editor and wait for the bridge to reconnect — closes the C#-edit→recompile loop so addon/bridge changes apply without a manual restart. Relaunches straight back into the current project (EditorUtility.RestartEditor). Saves unsaved scenes by default (pass save:false to discard them). Blocks until the bridge is back (or waitMs elapses), then reports the handler count.", {
66
+ save: z
67
+ .boolean()
68
+ .optional()
69
+ .describe("Save unsaved scenes before restarting (default true; false discards them)"),
70
+ waitMs: z
71
+ .number()
72
+ .int()
73
+ .optional()
74
+ .describe("Max ms to wait for reconnect (default 150000)"),
75
+ }, async (params) => {
76
+ const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
77
+ // Fire the restart. The editor closes mid-request, so a timeout/no-response here is EXPECTED.
78
+ try {
79
+ await bridge.send("restart_editor", { save: params.save ?? true }, 5000);
80
+ }
81
+ catch {
82
+ /* editor going down — expected */
83
+ }
84
+ const waitMs = params.waitMs ?? 150000;
85
+ const deadline = Date.now() + waitMs;
86
+ // Let the old process actually exit (heartbeat goes stale) before checking, so we
87
+ // don't false-positive on the pre-restart connection.
88
+ await sleep(8000);
89
+ while (Date.now() < deadline) {
90
+ await sleep(2500);
91
+ if (bridge.isConnected()) {
92
+ // Heartbeat is fresh again — confirm the request loop drains + read the count.
93
+ try {
94
+ const st = await bridge.send("get_bridge_status", {}, 5000);
95
+ if (st.success && st.data) {
96
+ const hc = st.data.handlerCount;
97
+ return {
98
+ content: [
99
+ {
100
+ type: "text",
101
+ text: `Editor restarted — bridge reconnected${hc ? ` with ${hc} handlers` : ""}.`,
102
+ },
103
+ ],
104
+ };
105
+ }
106
+ }
107
+ catch {
108
+ /* still settling — keep polling */
109
+ }
110
+ }
111
+ }
112
+ return {
113
+ content: [
114
+ {
115
+ type: "text",
116
+ text: `Restart fired, but the bridge didn't reconnect within ${waitMs}ms — the editor may still be compiling. Try get_bridge_status in a moment.`,
117
+ },
118
+ ],
119
+ };
120
+ });
63
121
  }
64
122
  //# sourceMappingURL=status.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sbox-mcp-server",
3
- "version": "1.5.0",
3
+ "version": "1.5.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",