@solarisdk/mcp 0.3.2 → 0.3.3
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 +1 -1
- package/dist/server.js +57 -4
- package/dist/solari-mcp-http.bundle.cjs +44 -4
- package/dist/solari-mcp.bundle.cjs +44 -4
- package/dist/version.d.ts +1 -0
- package/dist/version.js +11 -0
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -178,7 +178,7 @@ cookie count and origins it stored, so they can see what was persisted.
|
|
|
178
178
|
|---|---|
|
|
179
179
|
| `solari_sandbox_create` | Create a headless sandbox → `sessionId` |
|
|
180
180
|
| `solari_desktop_create` | Create a GUI desktop → `sessionId` + `streamUrl` |
|
|
181
|
-
| `solari_list` | List the org's sandboxes |
|
|
181
|
+
| `solari_list` | List the org's VMs — **both** sandboxes and desktops, each labelled with its `kind` (optional `kind`/`state` filters) |
|
|
182
182
|
| `solari_kill` | Destroy a session |
|
|
183
183
|
| `solari_connect` | Re-attach to a session by id across restarts (auto-resumes if paused) |
|
|
184
184
|
| `solari_exec` | Run a shell command (via `sh -c`) → `{stdout,stderr,exitCode}` |
|
package/dist/server.js
CHANGED
|
@@ -12,11 +12,14 @@ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
|
12
12
|
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
13
13
|
import { z } from "zod";
|
|
14
14
|
import { SolariClient } from "@solarisdk/sdk";
|
|
15
|
+
import { VERSION } from "./version.js";
|
|
15
16
|
import { makeBrowserToolset, releaseAllBrowserSessions, } from "./browser.js";
|
|
16
17
|
// Guest output (file reads, command stdout, code results) is unbounded on the
|
|
17
18
|
// wire; cap it so one `cat` of a big file can't blow the MCP payload budget or
|
|
18
19
|
// OOM the shared hosted task.
|
|
19
20
|
const MAX_TOOL_TEXT = 30_000;
|
|
21
|
+
// Pages of `GET /sandboxes` solari_list will follow per kind (100 rows each).
|
|
22
|
+
const MAX_LIST_PAGES = 5;
|
|
20
23
|
const text = (o) => {
|
|
21
24
|
const s = typeof o === "string" ? o : JSON.stringify(o, null, 2);
|
|
22
25
|
const capped = s.length > MAX_TOOL_TEXT
|
|
@@ -81,9 +84,59 @@ export function makeToolset(client, reg) {
|
|
|
81
84
|
},
|
|
82
85
|
},
|
|
83
86
|
solari_list: {
|
|
84
|
-
description: "List the org's sandboxes."
|
|
85
|
-
|
|
86
|
-
|
|
87
|
+
description: "List the org's live VMs — BOTH sandboxes and desktops. Each entry is labelled " +
|
|
88
|
+
"with its `kind`; `registered:true` means this MCP session already holds a handle " +
|
|
89
|
+
"so the other tools accept its sessionId directly (otherwise call solari_connect " +
|
|
90
|
+
"first). Optional kind/state filters.",
|
|
91
|
+
inputSchema: {
|
|
92
|
+
kind: z.enum(["sandbox", "desktop"]).optional(),
|
|
93
|
+
state: z.string().optional(),
|
|
94
|
+
},
|
|
95
|
+
handler: async (a) => {
|
|
96
|
+
// GET /sandboxes is the unified VM index (desktops write the same
|
|
97
|
+
// SandboxRecord), but it is queried per-kind here so the two flavours
|
|
98
|
+
// are merged EXPLICITLY: an agent asking "what do I have running"
|
|
99
|
+
// must never silently lose desktops to a default filter, and the
|
|
100
|
+
// per-kind counts are what make the answer legible.
|
|
101
|
+
const kinds = a.kind ? [a.kind] : ["sandbox", "desktop"];
|
|
102
|
+
const vms = [];
|
|
103
|
+
const counts = { sandbox: 0, desktop: 0 };
|
|
104
|
+
let truncated = false;
|
|
105
|
+
for (const kind of kinds) {
|
|
106
|
+
// Follow nextCursor so a big org's desktops aren't cut off by the
|
|
107
|
+
// gateway's 100-row default page — bounded so one call can't spin.
|
|
108
|
+
let cursor;
|
|
109
|
+
for (let page = 0; page < MAX_LIST_PAGES; page++) {
|
|
110
|
+
const res = await client.sandboxes.list({
|
|
111
|
+
kind,
|
|
112
|
+
// `state` is a closed union on the SDK; an unknown value is
|
|
113
|
+
// simply ignored by the gateway, so pass it through.
|
|
114
|
+
...(a.state ? { state: a.state } : {}),
|
|
115
|
+
...(cursor ? { cursor } : {}),
|
|
116
|
+
});
|
|
117
|
+
for (const v of res.sandboxes ?? []) {
|
|
118
|
+
const rec = v;
|
|
119
|
+
// The wire calls the id `sandboxId` for both kinds; re-label it
|
|
120
|
+
// `sessionId` because that is what every other tool here takes.
|
|
121
|
+
const id = (rec.sandboxId ?? rec.sessionId);
|
|
122
|
+
const k = rec.kind ?? kind;
|
|
123
|
+
vms.push({
|
|
124
|
+
...rec,
|
|
125
|
+
...(id ? { sessionId: id } : {}),
|
|
126
|
+
kind: k,
|
|
127
|
+
registered: id ? reg.sessions.has(id) : false,
|
|
128
|
+
});
|
|
129
|
+
counts[k] = (counts[k] ?? 0) + 1;
|
|
130
|
+
}
|
|
131
|
+
cursor = res.nextCursor;
|
|
132
|
+
if (!cursor)
|
|
133
|
+
break;
|
|
134
|
+
if (page === MAX_LIST_PAGES - 1)
|
|
135
|
+
truncated = true;
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
return text({ counts, total: vms.length, ...(truncated ? { truncated } : {}), vms });
|
|
139
|
+
},
|
|
87
140
|
},
|
|
88
141
|
solari_kill: {
|
|
89
142
|
description: "Destroy a session by id.",
|
|
@@ -284,7 +337,7 @@ export function buildServerParts(client, browserCfg) {
|
|
|
284
337
|
process.env.SOLARI_BASE_URL ??
|
|
285
338
|
"https://api.getsolari.com",
|
|
286
339
|
};
|
|
287
|
-
const server = new McpServer({ name: "solari-mcp", version:
|
|
340
|
+
const server = new McpServer({ name: "solari-mcp", version: VERSION });
|
|
288
341
|
const browserReg = { sessions: new Map() };
|
|
289
342
|
const vmReg = { sessions: new Map() };
|
|
290
343
|
registerToolset(server, {
|
|
@@ -112357,6 +112357,9 @@ var SolariClient = class {
|
|
|
112357
112357
|
}
|
|
112358
112358
|
};
|
|
112359
112359
|
|
|
112360
|
+
// src/version.ts
|
|
112361
|
+
var VERSION = "0.3.3";
|
|
112362
|
+
|
|
112360
112363
|
// node_modules/puppeteer-core/lib/esm/puppeteer/index.js
|
|
112361
112364
|
init_index_browser();
|
|
112362
112365
|
|
|
@@ -114238,6 +114241,7 @@ async function releaseAllBrowserSessions(cfg, reg, fetchApi = api) {
|
|
|
114238
114241
|
// src/server.ts
|
|
114239
114242
|
var import_meta2 = {};
|
|
114240
114243
|
var MAX_TOOL_TEXT = 3e4;
|
|
114244
|
+
var MAX_LIST_PAGES = 5;
|
|
114241
114245
|
var text2 = (o) => {
|
|
114242
114246
|
const s = typeof o === "string" ? o : JSON.stringify(o, null, 2);
|
|
114243
114247
|
const capped = s.length > MAX_TOOL_TEXT ? `${s.slice(0, MAX_TOOL_TEXT)}
|
|
@@ -114294,9 +114298,45 @@ function makeToolset(client, reg) {
|
|
|
114294
114298
|
}
|
|
114295
114299
|
},
|
|
114296
114300
|
solari_list: {
|
|
114297
|
-
description: "List the org's sandboxes.",
|
|
114298
|
-
inputSchema: {
|
|
114299
|
-
|
|
114301
|
+
description: "List the org's live VMs \u2014 BOTH sandboxes and desktops. Each entry is labelled with its `kind`; `registered:true` means this MCP session already holds a handle so the other tools accept its sessionId directly (otherwise call solari_connect first). Optional kind/state filters.",
|
|
114302
|
+
inputSchema: {
|
|
114303
|
+
kind: external_exports.enum(["sandbox", "desktop"]).optional(),
|
|
114304
|
+
state: external_exports.string().optional()
|
|
114305
|
+
},
|
|
114306
|
+
handler: async (a2) => {
|
|
114307
|
+
const kinds = a2.kind ? [a2.kind] : ["sandbox", "desktop"];
|
|
114308
|
+
const vms = [];
|
|
114309
|
+
const counts = { sandbox: 0, desktop: 0 };
|
|
114310
|
+
let truncated = false;
|
|
114311
|
+
for (const kind of kinds) {
|
|
114312
|
+
let cursor;
|
|
114313
|
+
for (let page = 0; page < MAX_LIST_PAGES; page++) {
|
|
114314
|
+
const res = await client.sandboxes.list({
|
|
114315
|
+
kind,
|
|
114316
|
+
// `state` is a closed union on the SDK; an unknown value is
|
|
114317
|
+
// simply ignored by the gateway, so pass it through.
|
|
114318
|
+
...a2.state ? { state: a2.state } : {},
|
|
114319
|
+
...cursor ? { cursor } : {}
|
|
114320
|
+
});
|
|
114321
|
+
for (const v2 of res.sandboxes ?? []) {
|
|
114322
|
+
const rec = v2;
|
|
114323
|
+
const id = rec.sandboxId ?? rec.sessionId;
|
|
114324
|
+
const k = rec.kind ?? kind;
|
|
114325
|
+
vms.push({
|
|
114326
|
+
...rec,
|
|
114327
|
+
...id ? { sessionId: id } : {},
|
|
114328
|
+
kind: k,
|
|
114329
|
+
registered: id ? reg.sessions.has(id) : false
|
|
114330
|
+
});
|
|
114331
|
+
counts[k] = (counts[k] ?? 0) + 1;
|
|
114332
|
+
}
|
|
114333
|
+
cursor = res.nextCursor;
|
|
114334
|
+
if (!cursor) break;
|
|
114335
|
+
if (page === MAX_LIST_PAGES - 1) truncated = true;
|
|
114336
|
+
}
|
|
114337
|
+
}
|
|
114338
|
+
return text2({ counts, total: vms.length, ...truncated ? { truncated } : {}, vms });
|
|
114339
|
+
}
|
|
114300
114340
|
},
|
|
114301
114341
|
solari_kill: {
|
|
114302
114342
|
description: "Destroy a session by id.",
|
|
@@ -114470,7 +114510,7 @@ function buildServerParts(client, browserCfg) {
|
|
|
114470
114510
|
apiKey: process.env.SOLARI_BROWSER_API_KEY ?? apiKey,
|
|
114471
114511
|
baseUrl: process.env.SOLARI_BROWSER_URL ?? process.env.SOLARI_BASE_URL ?? "https://api.getsolari.com"
|
|
114472
114512
|
};
|
|
114473
|
-
const server = new McpServer({ name: "solari-mcp", version:
|
|
114513
|
+
const server = new McpServer({ name: "solari-mcp", version: VERSION });
|
|
114474
114514
|
const browserReg = { sessions: /* @__PURE__ */ new Map() };
|
|
114475
114515
|
const vmReg = { sessions: /* @__PURE__ */ new Map() };
|
|
114476
114516
|
registerToolset(server, {
|
|
@@ -111026,6 +111026,9 @@ var SolariClient = class {
|
|
|
111026
111026
|
}
|
|
111027
111027
|
};
|
|
111028
111028
|
|
|
111029
|
+
// src/version.ts
|
|
111030
|
+
var VERSION = "0.3.3";
|
|
111031
|
+
|
|
111029
111032
|
// node_modules/puppeteer-core/lib/esm/puppeteer/index.js
|
|
111030
111033
|
init_index_browser();
|
|
111031
111034
|
|
|
@@ -112907,6 +112910,7 @@ async function releaseAllBrowserSessions(cfg, reg, fetchApi = api) {
|
|
|
112907
112910
|
// src/server.ts
|
|
112908
112911
|
var import_meta2 = {};
|
|
112909
112912
|
var MAX_TOOL_TEXT = 3e4;
|
|
112913
|
+
var MAX_LIST_PAGES = 5;
|
|
112910
112914
|
var text2 = (o) => {
|
|
112911
112915
|
const s = typeof o === "string" ? o : JSON.stringify(o, null, 2);
|
|
112912
112916
|
const capped = s.length > MAX_TOOL_TEXT ? `${s.slice(0, MAX_TOOL_TEXT)}
|
|
@@ -112963,9 +112967,45 @@ function makeToolset(client, reg) {
|
|
|
112963
112967
|
}
|
|
112964
112968
|
},
|
|
112965
112969
|
solari_list: {
|
|
112966
|
-
description: "List the org's sandboxes.",
|
|
112967
|
-
inputSchema: {
|
|
112968
|
-
|
|
112970
|
+
description: "List the org's live VMs \u2014 BOTH sandboxes and desktops. Each entry is labelled with its `kind`; `registered:true` means this MCP session already holds a handle so the other tools accept its sessionId directly (otherwise call solari_connect first). Optional kind/state filters.",
|
|
112971
|
+
inputSchema: {
|
|
112972
|
+
kind: external_exports.enum(["sandbox", "desktop"]).optional(),
|
|
112973
|
+
state: external_exports.string().optional()
|
|
112974
|
+
},
|
|
112975
|
+
handler: async (a2) => {
|
|
112976
|
+
const kinds = a2.kind ? [a2.kind] : ["sandbox", "desktop"];
|
|
112977
|
+
const vms = [];
|
|
112978
|
+
const counts = { sandbox: 0, desktop: 0 };
|
|
112979
|
+
let truncated = false;
|
|
112980
|
+
for (const kind of kinds) {
|
|
112981
|
+
let cursor;
|
|
112982
|
+
for (let page = 0; page < MAX_LIST_PAGES; page++) {
|
|
112983
|
+
const res = await client.sandboxes.list({
|
|
112984
|
+
kind,
|
|
112985
|
+
// `state` is a closed union on the SDK; an unknown value is
|
|
112986
|
+
// simply ignored by the gateway, so pass it through.
|
|
112987
|
+
...a2.state ? { state: a2.state } : {},
|
|
112988
|
+
...cursor ? { cursor } : {}
|
|
112989
|
+
});
|
|
112990
|
+
for (const v2 of res.sandboxes ?? []) {
|
|
112991
|
+
const rec = v2;
|
|
112992
|
+
const id = rec.sandboxId ?? rec.sessionId;
|
|
112993
|
+
const k = rec.kind ?? kind;
|
|
112994
|
+
vms.push({
|
|
112995
|
+
...rec,
|
|
112996
|
+
...id ? { sessionId: id } : {},
|
|
112997
|
+
kind: k,
|
|
112998
|
+
registered: id ? reg.sessions.has(id) : false
|
|
112999
|
+
});
|
|
113000
|
+
counts[k] = (counts[k] ?? 0) + 1;
|
|
113001
|
+
}
|
|
113002
|
+
cursor = res.nextCursor;
|
|
113003
|
+
if (!cursor) break;
|
|
113004
|
+
if (page === MAX_LIST_PAGES - 1) truncated = true;
|
|
113005
|
+
}
|
|
113006
|
+
}
|
|
113007
|
+
return text2({ counts, total: vms.length, ...truncated ? { truncated } : {}, vms });
|
|
113008
|
+
}
|
|
112969
113009
|
},
|
|
112970
113010
|
solari_kill: {
|
|
112971
113011
|
description: "Destroy a session by id.",
|
|
@@ -113139,7 +113179,7 @@ function buildServerParts(client, browserCfg) {
|
|
|
113139
113179
|
apiKey: process.env.SOLARI_BROWSER_API_KEY ?? apiKey,
|
|
113140
113180
|
baseUrl: process.env.SOLARI_BROWSER_URL ?? process.env.SOLARI_BASE_URL ?? "https://api.getsolari.com"
|
|
113141
113181
|
};
|
|
113142
|
-
const server = new McpServer({ name: "solari-mcp", version:
|
|
113182
|
+
const server = new McpServer({ name: "solari-mcp", version: VERSION });
|
|
113143
113183
|
const browserReg = { sessions: /* @__PURE__ */ new Map() };
|
|
113144
113184
|
const vmReg = { sessions: /* @__PURE__ */ new Map() };
|
|
113145
113185
|
registerToolset(server, {
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const VERSION = "0.3.3";
|
package/dist/version.js
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
// The single source of truth for the version this server reports to MCP
|
|
2
|
+
// clients (`initialize` → serverInfo.version).
|
|
3
|
+
//
|
|
4
|
+
// It CANNOT be imported straight from package.json: tsconfig pins
|
|
5
|
+
// `rootDir: "src"`, so `import "../package.json"` is outside the root and tsc
|
|
6
|
+
// refuses it; widening rootDir would emit `dist/src/*.js` and break the `bin`
|
|
7
|
+
// path + the esbuild bundles. So it is a literal here — and
|
|
8
|
+
// `test/version.test.mjs` FAILS the build if it ever drifts from package.json.
|
|
9
|
+
//
|
|
10
|
+
// KEEP IN SYNC WITH sdk/mcp/package.json "version".
|
|
11
|
+
export const VERSION = "0.3.3";
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@solarisdk/mcp",
|
|
3
|
-
"version": "0.3.
|
|
4
|
-
"description": "Model Context Protocol server for the Solari cloud browser, sandboxes + desktops
|
|
3
|
+
"version": "0.3.3",
|
|
4
|
+
"description": "Model Context Protocol server for the Solari cloud browser, sandboxes + desktops — drive them from Claude Desktop/Cowork, Claude Code, Cursor, etc.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
7
7
|
"solari-mcp": "./dist/cli.js"
|