@luxorai/mcp 0.3.1 → 0.4.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/CHANGELOG.md +37 -0
- package/README.md +13 -8
- package/SECURITY.md +2 -2
- package/dist/client.d.ts +16 -1
- package/dist/client.js +62 -16
- package/dist/env.d.ts +6 -0
- package/dist/env.js +25 -0
- package/dist/http.js +13 -10
- package/dist/index.js +9 -8
- package/dist/oauth.d.ts +7 -1
- package/dist/oauth.js +29 -9
- package/dist/server.d.ts +25 -5
- package/dist/server.js +88 -53
- package/dist/tools/artifacts.d.ts +3 -3
- package/dist/tools/artifacts.js +6 -6
- package/dist/tools/auth_status.d.ts +3 -3
- package/dist/tools/auth_status.js +8 -9
- package/dist/tools/common.d.ts +35 -0
- package/dist/tools/common.js +78 -0
- package/dist/tools/egress.d.ts +38 -0
- package/dist/tools/egress.js +153 -0
- package/dist/tools/exec.js +1 -1
- package/dist/tools/files.js +36 -3
- package/dist/tools/files_ops.js +9 -1
- package/dist/tools/git.d.ts +0 -1
- package/dist/tools/git.js +85 -23
- package/dist/tools/ports.d.ts +8 -1
- package/dist/tools/ports.js +24 -3
- package/dist/tools/previews.js +59 -22
- package/dist/tools/sandboxes.d.ts +1 -1
- package/dist/tools/sandboxes.js +342 -26
- package/dist/tools/sessions_admin.js +63 -23
- package/dist/tools/snapshots.js +41 -22
- package/dist/tools/ssh.d.ts +3 -3
- package/dist/tools/ssh.js +35 -9
- package/dist/tools/templates.d.ts +2 -1
- package/dist/tools/templates.js +36 -16
- package/dist/tools/titles.d.ts +8 -0
- package/dist/tools/titles.js +102 -0
- package/dist/tools/volumes.js +36 -11
- package/dist/tools/workspace.d.ts +9 -1
- package/dist/tools/workspace.js +29 -90
- package/package.json +5 -4
package/dist/tools/workspace.js
CHANGED
|
@@ -11,9 +11,17 @@ async function resolveWorkspaceId(client, provided) {
|
|
|
11
11
|
const owner = await client.resolveOwner();
|
|
12
12
|
return owner.workspaceId;
|
|
13
13
|
}
|
|
14
|
-
/**
|
|
14
|
+
/**
|
|
15
|
+
* Workspace-level sandbox usage, CI runner sizes and wildcard preview domains.
|
|
16
|
+
*
|
|
17
|
+
* The workspace quota/retention settings RPCs (Get/UpdateWorkspaceSandboxSettings,
|
|
18
|
+
* Get/UpdateWorkspaceSnapshotRetentionSettings) were REMOVED from the API
|
|
19
|
+
* (tenki-app #5007, 2026-08-07; they 404 on staging and production), so their
|
|
20
|
+
* tools are gone. Quotas now come from the workspace plan and are read-only
|
|
21
|
+
* through tenki_get_workspace_usage.
|
|
22
|
+
*/
|
|
15
23
|
export function registerWorkspace(server, client) {
|
|
16
|
-
server.tool("tenki_get_workspace_usage", "Get
|
|
24
|
+
server.tool("tenki_get_workspace_usage", "Get a workspace's sandbox usage against its plan limits (concurrent sandboxes, snapshots, templates, volumes, storage bytes, preview URLs) — each row has current + max. Use this for quota and cost visibility; the limits themselves come from the plan and are not editable through the API.", {
|
|
17
25
|
workspace_id: z
|
|
18
26
|
.string()
|
|
19
27
|
.optional()
|
|
@@ -24,106 +32,37 @@ export function registerWorkspace(server, client) {
|
|
|
24
32
|
...(workspaceId ? { workspaceId } : {}),
|
|
25
33
|
}));
|
|
26
34
|
});
|
|
27
|
-
server.tool("
|
|
35
|
+
server.tool("tenki_list_ci_runner_sizes", "List the Linux x64 runner sizes Tenki CI can run for a workspace — each runs-on label with its vCPUs and memory in GiB, smallest first, limited to the workspace's job-size limits — and defaultRunsOnLabel, the size a job gets when its runs-on names none. Use it to pick a runs-on label for a GitHub Actions workflow.", {
|
|
28
36
|
workspace_id: z
|
|
29
37
|
.string()
|
|
30
38
|
.optional()
|
|
31
|
-
.describe("Workspace to
|
|
39
|
+
.describe("Workspace to list sizes for. Omit to use the API key's first workspace."),
|
|
32
40
|
}, async ({ workspace_id }) => {
|
|
33
41
|
const workspaceId = await resolveWorkspaceId(client, workspace_id);
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
})
|
|
42
|
+
const resp = await client.control("ListCIRunnerSizes", { ...(workspaceId ? { workspaceId } : {}) });
|
|
43
|
+
// protojson omits empty fields; an empty workspace would otherwise come back as {}.
|
|
44
|
+
return ok({ ...resp, sizes: resp.sizes ?? [], defaultRunsOnLabel: resp.defaultRunsOnLabel ?? "" });
|
|
37
45
|
});
|
|
38
|
-
server.tool("
|
|
46
|
+
server.tool("tenki_get_workspace_preview_domains", "Read whether wildcard preview domains are enabled for a workspace, the per-region wildcard hostnames and their certificate readiness, and how many existing preview URLs use the wildcard scheme. Explains the `wildcard`/`wildcardStatus` fields on expose/preview responses.", {
|
|
39
47
|
workspace_id: z
|
|
40
48
|
.string()
|
|
41
49
|
.optional()
|
|
42
|
-
.describe("Workspace to
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
.positive()
|
|
47
|
-
.optional()
|
|
48
|
-
.describe("How long a paused sandbox's snapshot is kept before it becomes unresumable."),
|
|
49
|
-
clear_pause_retention: z.boolean().optional().describe("Remove the pause-retention override (use the platform default)."),
|
|
50
|
-
snapshot_retention_days: z
|
|
51
|
-
.number()
|
|
52
|
-
.int()
|
|
53
|
-
.positive()
|
|
54
|
-
.optional()
|
|
55
|
-
.describe("How long snapshots are kept before automatic cleanup."),
|
|
56
|
-
clear_snapshot_retention: z
|
|
57
|
-
.boolean()
|
|
58
|
-
.optional()
|
|
59
|
-
.describe("Remove the snapshot-retention override, i.e. keep snapshots indefinitely."),
|
|
60
|
-
max_snapshots: z.number().int().positive().optional().describe("Maximum snapshots in the workspace."),
|
|
61
|
-
max_templates: z.number().int().positive().optional().describe("Maximum templates in the workspace."),
|
|
62
|
-
max_volumes: z.number().int().positive().optional().describe("Maximum volumes in the workspace."),
|
|
63
|
-
max_total_bytes: z.number().int().positive().optional().describe("Maximum combined snapshot + volume storage in bytes."),
|
|
64
|
-
max_concurrent_sessions: z.number().int().positive().optional().describe("Maximum simultaneously active sandboxes."),
|
|
65
|
-
max_sticky_sessions: z.number().int().positive().optional().describe("Maximum sticky sandboxes."),
|
|
66
|
-
max_preview_urls: z.number().int().positive().optional().describe("Maximum preview URLs in the workspace."),
|
|
67
|
-
}, async (a) => {
|
|
68
|
-
const workspaceId = await resolveWorkspaceId(client, a.workspace_id);
|
|
69
|
-
const body = { ...(workspaceId ? { workspaceId } : {}) };
|
|
70
|
-
// Durations are protobuf Duration — JSON wants a seconds string ("2592000s").
|
|
71
|
-
if (a.pause_retention_days !== undefined)
|
|
72
|
-
body.pauseRetention = `${a.pause_retention_days * 86400}s`;
|
|
73
|
-
if (a.clear_pause_retention)
|
|
74
|
-
body.clearPauseRetention = true;
|
|
75
|
-
if (a.snapshot_retention_days !== undefined)
|
|
76
|
-
body.snapshotRetention = `${a.snapshot_retention_days * 86400}s`;
|
|
77
|
-
if (a.clear_snapshot_retention)
|
|
78
|
-
body.clearSnapshotRetention = true;
|
|
79
|
-
if (a.max_snapshots !== undefined)
|
|
80
|
-
body.maxSnapshots = a.max_snapshots;
|
|
81
|
-
if (a.max_templates !== undefined)
|
|
82
|
-
body.maxTemplates = a.max_templates;
|
|
83
|
-
if (a.max_volumes !== undefined)
|
|
84
|
-
body.maxVolumes = a.max_volumes;
|
|
85
|
-
// int64 on the wire — send as a string so large values survive JSON.
|
|
86
|
-
if (a.max_total_bytes !== undefined)
|
|
87
|
-
body.maxTotalBytes = String(a.max_total_bytes);
|
|
88
|
-
if (a.max_concurrent_sessions !== undefined)
|
|
89
|
-
body.maxConcurrentSessions = a.max_concurrent_sessions;
|
|
90
|
-
if (a.max_sticky_sessions !== undefined)
|
|
91
|
-
body.maxStickySessions = a.max_sticky_sessions;
|
|
92
|
-
// The per-project field is deprecated; the workspace alias is backed by the same quota.
|
|
93
|
-
if (a.max_preview_urls !== undefined)
|
|
94
|
-
body.maxPreviewUrlsPerWorkspace = a.max_preview_urls;
|
|
95
|
-
if (Object.keys(body).length <= 1) {
|
|
96
|
-
throw new Error("tenki_update_workspace_settings: pass at least one setting to change. Nothing was sent — the API would have returned the unchanged settings, which reads like a successful update.");
|
|
97
|
-
}
|
|
98
|
-
return ok(await client.control("UpdateWorkspaceSandboxSettings", body));
|
|
99
|
-
});
|
|
100
|
-
server.tool("tenki_get_snapshot_retention_settings", "Get the workspace's pause- and snapshot-retention periods. DEPRECATED upstream: this RPC is marked deprecated in the API — tenki_get_workspace_settings returns the same retention fields alongside the quotas. An empty response means no retention override, i.e. kept indefinitely.", { workspace_id: z.string().optional().describe("Workspace (defaults to the key's first workspace).") }, async ({ workspace_id }) => {
|
|
101
|
-
const workspaceId = workspace_id ?? (await client.resolveOwner()).workspaceId;
|
|
102
|
-
return ok(await client.control("GetWorkspaceSnapshotRetentionSettings", { ...(workspaceId ? { workspaceId } : {}) }));
|
|
50
|
+
.describe("Workspace to read. Omit to use the API key's first workspace."),
|
|
51
|
+
}, async ({ workspace_id }) => {
|
|
52
|
+
const workspaceId = await resolveWorkspaceId(client, workspace_id);
|
|
53
|
+
return ok(await client.control("GetWorkspacePreviewDomains", { ...(workspaceId ? { workspaceId } : {}) }));
|
|
103
54
|
});
|
|
104
|
-
server.tool("
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
.
|
|
108
|
-
.positive()
|
|
109
|
-
.optional()
|
|
110
|
-
.describe("Days to retain snapshots before automatic cleanup. Omit and pass clear_retention to keep them indefinitely."),
|
|
111
|
-
clear_retention: z
|
|
112
|
-
.boolean()
|
|
55
|
+
server.tool("tenki_update_workspace_preview_domains", "Enable or disable wildcard preview domains for a workspace. Enabling provisions one wildcard certificate per region and is limited to Pro-tier workspaces. DISABLING releases the certificates and existing wildcard-scheme preview URLs stop serving with a valid certificate — check wildcardPreviewUrlCount via tenki_get_workspace_preview_domains first.", {
|
|
56
|
+
enabled: z.boolean().describe("true to enable wildcard preview domains, false to disable them."),
|
|
57
|
+
workspace_id: z
|
|
58
|
+
.string()
|
|
113
59
|
.optional()
|
|
114
|
-
.describe("
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
throw new Error("tenki_update_snapshot_retention_settings: pass exactly one of retention_days (to set a period) or clear_retention: true (to keep snapshots indefinitely).");
|
|
119
|
-
}
|
|
120
|
-
const workspaceId = workspace_id ?? (await client.resolveOwner()).workspaceId;
|
|
121
|
-
return ok(await client.control("UpdateWorkspaceSnapshotRetentionSettings", {
|
|
60
|
+
.describe("Workspace to update. Omit to use the API key's first workspace."),
|
|
61
|
+
}, async ({ enabled, workspace_id }) => {
|
|
62
|
+
const workspaceId = await resolveWorkspaceId(client, workspace_id);
|
|
63
|
+
return ok(await client.control("UpdateWorkspacePreviewDomains", {
|
|
122
64
|
...(workspaceId ? { workspaceId } : {}),
|
|
123
|
-
|
|
124
|
-
// there is no `retentionDays` field (sending one is silently dropped).
|
|
125
|
-
...(retention_days !== undefined ? { snapshotRetention: `${retention_days * 86400}s` } : {}),
|
|
126
|
-
...(clear_retention ? { clearSnapshotRetention: true } : {}),
|
|
65
|
+
enabled,
|
|
127
66
|
}));
|
|
128
67
|
});
|
|
129
68
|
}
|
package/package.json
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@luxorai/mcp",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"mcpName": "io.github.LuxorLabs/
|
|
3
|
+
"version": "0.4.0",
|
|
4
|
+
"mcpName": "io.github.LuxorLabs/luxor-mcp",
|
|
5
5
|
"description": "Model Context Protocol server for Tenki Cloud — disposable microVM sandboxes for AI agents. Create sandboxes, run code, read/write files, run git, expose preview URLs — from any MCP client.",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"bin": {
|
|
8
|
-
"tenki-mcp": "dist/index.js"
|
|
8
|
+
"tenki-mcp": "dist/index.js",
|
|
9
|
+
"luxor-mcp": "dist/index.js"
|
|
9
10
|
},
|
|
10
11
|
"files": [
|
|
11
12
|
"dist",
|
|
@@ -21,7 +22,7 @@
|
|
|
21
22
|
"prepack": "npm run build",
|
|
22
23
|
"prepublishOnly": "npm run build",
|
|
23
24
|
"pretest": "npm run build",
|
|
24
|
-
"test": "node test/offline.test.mjs && node test/public-shapes.test.mjs && node test/exec-output.test.mjs && node test/http-input.test.mjs && node test/oauth-http.test.mjs && node test/security.test.mjs && node test/client-net.test.mjs",
|
|
25
|
+
"test": "node test/offline.test.mjs && node test/presubmission.test.mjs && node test/public-shapes.test.mjs && node test/exec-output.test.mjs && node test/http-input.test.mjs && node test/oauth-http.test.mjs && node test/security.test.mjs && node test/client-net.test.mjs && node test/wire-shapes.test.mjs",
|
|
25
26
|
"test:all": "npm run build && node test/run.mjs",
|
|
26
27
|
"test:offline": "npm run build && node test/offline.test.mjs"
|
|
27
28
|
},
|