@cloudgrid-io/mcp 0.20.33 → 0.20.35
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/package.json +1 -1
- package/src/corpus/playbook.md +1 -1
- package/src/corpus/skill-claim.md +1 -1
- package/src/tools/deploy.js +35 -0
- package/src/tools/register.js +73 -62
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cloudgrid-io/mcp",
|
|
3
|
-
"version": "0.20.
|
|
3
|
+
"version": "0.20.35",
|
|
4
4
|
"description": "MCP access to CloudGrid — the live runtime environment where the user's apps run WITH the infrastructure they need out of the box: managed MongoDB, Redis (cache/queues/pub-sub), a pgvector store, persistent disk, and built-in AI with no API keys, in any language or stack, no Docker or Kubernetes to manage. Brainstorm, build, plug, and improve apps, games, dashboards, and tools; instant single-page publishes and full runtime-app deploys with a live URL — for developers and non-technical users. Three editions: local stdio (full toolset), hosted web (light, CLI-free), and a public docs-search server.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
package/src/corpus/playbook.md
CHANGED
|
@@ -18,7 +18,7 @@ Operating rules:
|
|
|
18
18
|
15. Editing an existing thing from just its URL (a fresh chat, no prior context — e.g. "change the background to green here <url>"): call grid_get_app_source(url) first. It resolves the entity_id and returns the current HTML plus its kind, single_html, capabilities, and replug_handle — read those to pick the branch:
|
|
19
19
|
- Single-HTML inspiration you can re-plug (single_html: true and capabilities.replug: true): edit the returned HTML and call grid_plug with target_entity_id (or grid+slug — the replug_handle) to update the SAME URL in place. This works on every edition, including hosted.
|
|
20
20
|
- Multi-file app or agent (kind is app or agent, or single_html: false): do NOT try to edit it as one inline HTML file. Tell the user it is a multi-file <kind>, give them the entity_id and the source (source_download_url), and explain that rebuilding it needs the local edition (Claude Desktop/Code) or the CLI — the hosted server cannot rebuild a multi-file app.
|
|
21
|
-
- Not yours (capabilities.replug: false, reason not_owner): do NOT attempt a re-plug. Offer to fork it into the user's own grid with
|
|
21
|
+
- Not yours (capabilities.replug: false, reason not_owner): do NOT attempt a re-plug. Offer to fork it into the user's own grid with grid_fork and edit the copy instead.
|
|
22
22
|
16. Help CloudGrid QA. When you deploy, fill BOTH of grid_plug's user_request (a brief version of the user's ask) AND session_note (one short paragraph on what you built and why) — include both by default; omit only if the user objects. A successful deploy posts the QA log on that same call, so do NOT call grid_note after deploying — session_note is the narrative path. Use grid_note only BEFORE a deploy, or in a session that ends without one. Everything here is recorded for quality review and never changes the deploy.
|
|
23
23
|
|
|
24
24
|
17. Auth check before an owned deploy, with an anonymous fallback. grid_start reports signed_in. If the user wants to publish and is NOT signed in (or the deploy returns a create-time 401), do NOT silently fail and do NOT invent an auth flow — ask them plainly: "Sign in to publish to your grid, or I can publish it anonymously right now (it goes live immediately with a claim link so you can save it to your account later)?" If they choose anonymous, re-call grid_plug with anon: true and surface the claim_url + owner_token. This is distinct from rule 6: rule 6 forbids the anon fallback on a SERVER error (5xx) for a signed-in user (it burns quota and downgrades ownership); THIS rule is about not being authenticated at all, where anonymous is a legitimate, offered choice.
|
|
@@ -69,5 +69,5 @@ new_expires_at, role_granted: "owner", ... }`.
|
|
|
69
69
|
## Notes
|
|
70
70
|
|
|
71
71
|
- One pickup claims one entity. To claim several, repeat with each entity id + token.
|
|
72
|
-
- The MCP `
|
|
72
|
+
- The MCP `grid_pickup` tool does this for you, and remembers the entity id +
|
|
73
73
|
token from the last anonymous drop so you can claim with no arguments.
|
package/src/tools/deploy.js
CHANGED
|
@@ -1635,6 +1635,41 @@ export async function runFork(ctx, { id, into_org_slug, name, source_version_id
|
|
|
1635
1635
|
};
|
|
1636
1636
|
}
|
|
1637
1637
|
|
|
1638
|
+
// Remix: cross-grid "make my own copy". Unlike fork (same-grid, byte-carrying),
|
|
1639
|
+
// remix mints a NEW entity in ANY grid the caller can build in, keeps lineage
|
|
1640
|
+
// back to the source, and strips the source's secrets/connection credentials —
|
|
1641
|
+
// the remixer supplies their own before plugging. Hits POST
|
|
1642
|
+
// /api/v2/runtimes/:id/remix.
|
|
1643
|
+
export async function runRemix(ctx, { id, into_org_slug, name, source_version_id }) {
|
|
1644
|
+
const data = await authedApiCall(ctx, {
|
|
1645
|
+
method: "POST",
|
|
1646
|
+
pathName: `/api/v2/runtimes/${encodeURIComponent(id)}/remix`,
|
|
1647
|
+
body: {
|
|
1648
|
+
...(into_org_slug ? { into_org_slug } : {}),
|
|
1649
|
+
...(name ? { name } : {}),
|
|
1650
|
+
...(source_version_id ? { source_version_id } : {}),
|
|
1651
|
+
},
|
|
1652
|
+
verb: "Remix",
|
|
1653
|
+
});
|
|
1654
|
+
const gridSlug = data?.grid_slug ?? data?.org?.slug ?? null;
|
|
1655
|
+
const lines = [
|
|
1656
|
+
`Remixed: ${data?.name ?? id} (entity_id=${data?.entity_id ?? "?"})${gridSlug ? ` in grid ${gridSlug}` : ""}`,
|
|
1657
|
+
`Lineage: forked_from=${data?.forked_from ?? "?"}. Secrets were not copied — set your own before you plug.`,
|
|
1658
|
+
];
|
|
1659
|
+
return {
|
|
1660
|
+
text: lines.join("\n"),
|
|
1661
|
+
structured: {
|
|
1662
|
+
entity_id: data?.entity_id ?? null,
|
|
1663
|
+
name: data?.name ?? null,
|
|
1664
|
+
kind: data?.kind ?? null,
|
|
1665
|
+
grid_slug: gridSlug,
|
|
1666
|
+
forked_from: data?.forked_from ?? null,
|
|
1667
|
+
forked_from_version_id: data?.forked_from_version_id ?? null,
|
|
1668
|
+
current_version_id: data?.current_version_id ?? null,
|
|
1669
|
+
},
|
|
1670
|
+
};
|
|
1671
|
+
}
|
|
1672
|
+
|
|
1638
1673
|
// Download: signed, time-limited (15-minute) source-bundle URLs. No entity is
|
|
1639
1674
|
// created and no registry state changes.
|
|
1640
1675
|
export async function runDownload(ctx, { id, version }) {
|
package/src/tools/register.js
CHANGED
|
@@ -23,6 +23,7 @@ import {
|
|
|
23
23
|
runClaim,
|
|
24
24
|
runPlug,
|
|
25
25
|
runFork,
|
|
26
|
+
runRemix,
|
|
26
27
|
runDownload,
|
|
27
28
|
runVisibility,
|
|
28
29
|
runSource,
|
|
@@ -76,35 +77,20 @@ export function registerTools(server, ctx) {
|
|
|
76
77
|
}
|
|
77
78
|
};
|
|
78
79
|
|
|
79
|
-
// Every
|
|
80
|
-
//
|
|
81
|
-
//
|
|
82
|
-
|
|
80
|
+
// Every tool registers under its canonical grid_* name ONLY. Deprecated
|
|
81
|
+
// aliases were removed entirely (founder directive, 2026-07-22): each alias
|
|
82
|
+
// doubled the ListTools surface for pure clutter, clients enumerate tools
|
|
83
|
+
// dynamically, and the renames' old names (grid_deploy, grid_set_sharing,
|
|
84
|
+
// grid_copy_app, grid_claim_anonymous_deploy, grid_download_source,
|
|
85
|
+
// grid_fetch, grid_logs) are gone rather than advertised as redirects.
|
|
83
86
|
const reg = (name, config, handler) => {
|
|
84
|
-
registered[name] = { kind: "reg", config, handler };
|
|
85
87
|
server.registerTool(name, config, withCapture(name, handler));
|
|
86
88
|
};
|
|
87
89
|
|
|
88
90
|
const regTool = (name, description, schema, annotations, handler) => {
|
|
89
|
-
registered[name] = { kind: "tool", description, schema, annotations, handler };
|
|
90
91
|
server.tool(name, description, schema, annotations, withCapture(name, handler));
|
|
91
92
|
};
|
|
92
93
|
|
|
93
|
-
// Register OLD tool names as deprecated aliases of their new (clearer) names.
|
|
94
|
-
// Same handler/schema; description is redirect-only so it never wins selection.
|
|
95
|
-
// Skips silently if the primary isn't registered in this edition (e.g. a
|
|
96
|
-
// CLI-only tool on the web edition).
|
|
97
|
-
const registerAlias = (oldName, newName) => {
|
|
98
|
-
const r = registered[newName];
|
|
99
|
-
if (!r) return;
|
|
100
|
-
const redirect = `Deprecated alias of ${newName}. Always call ${newName} instead; this name is kept for backward compatibility.`;
|
|
101
|
-
if (r.kind === "reg") {
|
|
102
|
-
server.registerTool(oldName, { ...r.config, description: redirect }, withCapture(oldName, r.handler));
|
|
103
|
-
} else {
|
|
104
|
-
server.tool(oldName, redirect, r.schema, r.annotations, withCapture(oldName, r.handler));
|
|
105
|
-
}
|
|
106
|
-
};
|
|
107
|
-
|
|
108
94
|
// ── Widget resources (web edition, ChatGPT Apps SDK) ──────────────────────
|
|
109
95
|
if (ctx.edition === "web") {
|
|
110
96
|
server.registerResource("cloudgrid-live-result", LIVE_RESULT_URI, {
|
|
@@ -134,19 +120,22 @@ export function registerTools(server, ctx) {
|
|
|
134
120
|
|
|
135
121
|
// ── Direct-API tools (both editions) ──────────────────────────────────────
|
|
136
122
|
|
|
137
|
-
//
|
|
123
|
+
// Pickup — both editions. Adopts an entity into the signed-in account's active
|
|
124
|
+
// grid (ownership transfer via POST /api/v2/entities/:id/pickup). Pass an
|
|
125
|
+
// anonymous drop's owner token as `claim_token` to take over something you
|
|
126
|
+
// dropped anonymously — that path replaces the old standalone "claim" verb.
|
|
138
127
|
reg(
|
|
139
|
-
"
|
|
128
|
+
"grid_pickup",
|
|
140
129
|
{
|
|
141
|
-
description: "
|
|
130
|
+
description: "Pick up (adopt) an entity into the signed-in account's active grid — an ownership transfer, keeping the same public URL. Use it to take over an entity you have access to, or to keep an anonymous drop you created: pass the drop's `claim_token` and it becomes owned and stops expiring on the anonymous schedule. Requires sign-in (grid_login). Calls the API directly, so it works on every edition. (This is the direct-API adopt; on the local edition grid_edit_existing_app additionally downloads the source and links the folder for editing.)",
|
|
142
131
|
inputSchema: {
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
132
|
+
entity_id: z.string().optional().describe("The entity id to pick up. Defaults to this session's last anonymous drop."),
|
|
133
|
+
claim_token: z.string().optional().describe("For an anonymous drop: its owner token (the owner_token in the drop result, also embedded in claim_url). Passing it takes over that drop."),
|
|
134
|
+
claim_url: z.string().optional().describe("Alternative to claim_token for an anonymous drop — the claim_url from the drop result; the token is read from it."),
|
|
146
135
|
},
|
|
147
136
|
outputSchema: {
|
|
148
|
-
claimed: z.number().describe("Number of
|
|
149
|
-
urls: z.array(z.string()).describe("URLs of the
|
|
137
|
+
claimed: z.number().describe("Number of entities picked up."),
|
|
138
|
+
urls: z.array(z.string()).describe("Public URLs of the picked-up entities."),
|
|
150
139
|
},
|
|
151
140
|
annotations: { readOnlyHint: false, destructiveHint: false, openWorldHint: true },
|
|
152
141
|
},
|
|
@@ -426,23 +415,24 @@ export function registerTools(server, ctx) {
|
|
|
426
415
|
}
|
|
427
416
|
};
|
|
428
417
|
reg("grid_plug", plugConfig, plugHandler);
|
|
429
|
-
// `grid_deploy`
|
|
430
|
-
//
|
|
431
|
-
//
|
|
432
|
-
// grid_plug's own description, so deploy-intent routing lands on grid_plug.
|
|
433
|
-
registerAlias("grid_deploy", "grid_plug");
|
|
418
|
+
// NOTE: no `grid_deploy` alias — the tool is grid_plug only. "deploy"/
|
|
419
|
+
// "publish"/"ship"/"make live" live in grid_plug's description, so
|
|
420
|
+
// deploy-intent routing lands there without a second listed name.
|
|
434
421
|
|
|
435
|
-
// ──
|
|
422
|
+
// ── grid_fork / grid_remix / grid_download — direct-API copy/source verbs ──────
|
|
423
|
+
// fork = same-grid byte-carrying copy; remix = cross-grid copy with secrets
|
|
424
|
+
// stripped; download = signed source-bundle URLs. All direct-API (both editions).
|
|
436
425
|
reg(
|
|
437
|
-
"
|
|
426
|
+
"grid_fork",
|
|
438
427
|
{
|
|
439
428
|
description:
|
|
440
|
-
"
|
|
441
|
-
"source's home grid by default; cross-grid only for system templates
|
|
442
|
-
"
|
|
443
|
-
"tries POST /api/v2/runtimes/:id/fork and
|
|
429
|
+
"Fork an entity: start a NEW entity from an existing one (copy-on-write, lineage recorded), carrying " +
|
|
430
|
+
"the source bytes. Lands in the source's home grid by default; cross-grid only for system templates " +
|
|
431
|
+
"or forkable:'public' sources — for a general cross-grid copy use grid_remix instead. Requires sign-in. " +
|
|
432
|
+
"Kind-aware: forks a runtime (app/agent) OR an inspiration — tries POST /api/v2/runtimes/:id/fork and " +
|
|
433
|
+
"falls back to /api/v2/inspirations/:id/fork.",
|
|
444
434
|
inputSchema: {
|
|
445
|
-
id: z.string().describe("The source
|
|
435
|
+
id: z.string().describe("The source entity: a canonical UUID or <grid-slug>/<entity-slug>."),
|
|
446
436
|
into_org_slug: z.string().optional().describe("Destination grid slug. Required only when you belong to more than one grid."),
|
|
447
437
|
name: z.string().optional().describe("Slug for the new entity. Omit to derive one from the source."),
|
|
448
438
|
source_version_id: z.string().optional().describe("Fork an older version instead of HEAD, e.g. v_a1b2c3d."),
|
|
@@ -469,12 +459,49 @@ export function registerTools(server, ctx) {
|
|
|
469
459
|
);
|
|
470
460
|
|
|
471
461
|
reg(
|
|
472
|
-
"
|
|
462
|
+
"grid_remix",
|
|
473
463
|
{
|
|
474
464
|
description:
|
|
475
|
-
"
|
|
476
|
-
"
|
|
477
|
-
"
|
|
465
|
+
"Remix an app: make your own copy of any app you can SEE (link/public/authenticated, or a grid you " +
|
|
466
|
+
"belong to) into ANY grid you can build in — cross-grid is allowed. Mints a NEW entity with lineage " +
|
|
467
|
+
"back to the source, WITHOUT the source's secrets or connection credentials (set your own before you " +
|
|
468
|
+
"plug). Distinct from grid_fork, which is same-grid and byte-carrying. Requires sign-in. Calls POST " +
|
|
469
|
+
"/api/v2/runtimes/:id/remix.",
|
|
470
|
+
inputSchema: {
|
|
471
|
+
id: z.string().describe("The source app: a canonical UUID or <grid-slug>/<entity-slug>."),
|
|
472
|
+
into_org_slug: z.string().optional().describe("Grid to create your copy in. Required only when you belong to more than one grid."),
|
|
473
|
+
name: z.string().optional().describe("Slug for your copy. Omit to derive one from the source."),
|
|
474
|
+
source_version_id: z.string().optional().describe("Remix an older version instead of HEAD, e.g. v_a1b2c3d."),
|
|
475
|
+
},
|
|
476
|
+
outputSchema: {
|
|
477
|
+
entity_id: z.string().nullable().describe("Your copy's entity id."),
|
|
478
|
+
name: z.string().nullable().describe("Your copy's slug."),
|
|
479
|
+
kind: z.string().nullable().describe("app | agent."),
|
|
480
|
+
grid_slug: z.string().nullable().describe("The grid your copy landed in."),
|
|
481
|
+
forked_from: z.string().nullable().describe("Source entity_id."),
|
|
482
|
+
forked_from_version_id: z.string().nullable().describe("Source version, when a specific one was remixed."),
|
|
483
|
+
current_version_id: z.string().nullable().describe("Your copy's current version id."),
|
|
484
|
+
},
|
|
485
|
+
annotations: { readOnlyHint: false, destructiveHint: false, openWorldHint: true },
|
|
486
|
+
},
|
|
487
|
+
async (input) => {
|
|
488
|
+
try {
|
|
489
|
+
if (!input?.id) return fail("`id` is required (a canonical UUID or <grid-slug>/<entity-slug>).");
|
|
490
|
+
return okResult(await runRemix(ctx, input));
|
|
491
|
+
} catch (err) {
|
|
492
|
+
return fail(err.message);
|
|
493
|
+
}
|
|
494
|
+
},
|
|
495
|
+
);
|
|
496
|
+
|
|
497
|
+
reg(
|
|
498
|
+
"grid_download",
|
|
499
|
+
{
|
|
500
|
+
description:
|
|
501
|
+
"Download an entity's source: the bundle last deployed for a runtime, as one signed, time-limited " +
|
|
502
|
+
"(15-minute) read URL per service tarball. No entity is created and no registry state changes (unlike " +
|
|
503
|
+
"grid_pickup/grid_fork/grid_remix, which adopt or copy). Requires sign-in. Calls GET " +
|
|
504
|
+
"/api/v2/runtimes/:id/source directly.",
|
|
478
505
|
inputSchema: {
|
|
479
506
|
id: z.string().describe("The runtime to download: a canonical UUID or <grid-slug>/<entity-slug>."),
|
|
480
507
|
version: z.string().optional().describe("Download an older version's bundle instead of HEAD, e.g. v_a1b2c3d."),
|
|
@@ -511,7 +538,7 @@ export function registerTools(server, ctx) {
|
|
|
511
538
|
"(replug/fork), and replug_handle — read those to decide whether to edit in place (single-HTML + " +
|
|
512
539
|
"capabilities.replug), fall back for a multi-file app/agent (use source_download_url + the local " +
|
|
513
540
|
"edition/CLI), or offer a fork when it isn't yours. For multi-file or runtime (app/agent) source " +
|
|
514
|
-
"bundles, use
|
|
541
|
+
"bundles, use grid_download (signed tarball URLs). Reads the HTML from the API server-side; " +
|
|
515
542
|
"read-only, creates nothing.",
|
|
516
543
|
inputSchema: {
|
|
517
544
|
entity_id: z.string().optional().describe("The drop's durable id. Defaults to this session's last drop."),
|
|
@@ -928,17 +955,6 @@ export function registerTools(server, ctx) {
|
|
|
928
955
|
},
|
|
929
956
|
);
|
|
930
957
|
|
|
931
|
-
// ── Kept alias (both editions): grid_fetch has real muscle memory in saved
|
|
932
|
-
// prompts and older docs. Every other legacy alias was dropped in 0.20.8 -
|
|
933
|
-
// 16 alias schemas were pure ListTools context weight on every session.
|
|
934
|
-
registerAlias("grid_fetch", "grid_get_template");
|
|
935
|
-
// grid_set_sharing → grid_visibility (2026-07-20, founder rename). Same handler
|
|
936
|
-
// and schema; old name kept as a redirect-only deprecated alias so any client
|
|
937
|
-
// still calling it works while the model prefers the new. MUST live here, above
|
|
938
|
-
// the local cutoff: grid_visibility is a both-editions tool, so the alias has
|
|
939
|
-
// to register on the web edition too (hosted callers keep back-compat).
|
|
940
|
-
registerAlias("grid_set_sharing", "grid_visibility");
|
|
941
|
-
|
|
942
958
|
if (ctx.edition !== "local") return; // web edition stops here — no CLI tools
|
|
943
959
|
|
|
944
960
|
// ── CLI-wrapping tools (local edition only) ───────────────────────────────
|
|
@@ -1257,9 +1273,4 @@ export function registerTools(server, ctx) {
|
|
|
1257
1273
|
}),
|
|
1258
1274
|
);
|
|
1259
1275
|
|
|
1260
|
-
// ── Deprecated aliases (tool-name cleanup): OLD CLI-tool names kept callable
|
|
1261
|
-
// (local edition) as redirect-only aliases of their new, clearer names.
|
|
1262
|
-
// Kept alias (local): grid_logs - muscle memory. The other legacy CLI-tool
|
|
1263
|
-
// aliases were dropped in 0.20.8 (see CHANGELOG).
|
|
1264
|
-
registerAlias("grid_logs", "grid_view_logs");
|
|
1265
1276
|
}
|