@cloudgrid-io/mcp 0.10.0 → 0.11.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cloudgrid-io/mcp",
3
- "version": "0.10.0",
3
+ "version": "0.11.0",
4
4
  "description": "MCP server for CloudGrid. Three editions: a local stdio server (full toolset), a hosted web server (light, CLI-free toolset), and a public docs server (search_cloudgrid_documentation) over MCP Streamable HTTP.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -20,6 +20,7 @@
20
20
  "test:error-reporting": "node test/error-reporting.test.mjs",
21
21
  "test:source": "node test/source-fetch.test.mjs",
22
22
  "test:app-with-data": "node test/app-with-data.test.mjs",
23
+ "test:self-describing": "node test/self-describing.test.mjs",
23
24
  "test:content": "node test/content-handling.test.mjs",
24
25
  "test:self-healing": "node test/self-healing.test.mjs",
25
26
  "test:grid-picker": "node test/grid-picker.test.mjs",
@@ -0,0 +1,69 @@
1
+ # Capability map — intent → template → capabilities → deploy
2
+
3
+ This is the index an LLM uses to turn a user request into the right CloudGrid
4
+ template, the way Superpowers matches a skill's `when:`. Match the request to a
5
+ template by its `when:` triggers, adopt that template's `needs:`, then deploy:
6
+
7
+ - **static → inspiration** (instant, any client / any edition) via `gridctl_drop`.
8
+ - **anything needing `needs:` → runtime** (async build, **local edition** only)
9
+ via `gridctl_plug` on a linked folder.
10
+
11
+ Fetch this doc any time with `gridctl_fetch("doc", "capability-map")`.
12
+
13
+ ## The 6 templates
14
+
15
+ | Intent (match on `when:`) | Template | `needs:` | Deploy | Edition |
16
+ |---|---|---|---|---|
17
+ | landing page, marketing/product/hero page, coming-soon, waitlist, pricing, portfolio, link-in-bio, event page | `landing-page` | none | inspiration (instant) | all |
18
+ | calculator, converter, generator, timer, quiz, interactive tool, mini-app, widget — computed client-side, no saved data | `web-app` | none | inspiration (instant) | all |
19
+ | dashboard, metrics, KPIs, stats page, status board, charts, analytics view — display-only, static data baked in | `dashboard` | none | inspiration (instant) | all |
20
+ | report, one-pager, summary, brief, whitepaper, case study, formatted document | `report` | none | inspiration (instant) | all |
21
+ | slides, deck, pitch, presentation, slideshow | `presentation` (dir: `deck`) | none | inspiration (instant) | all |
22
+ | to-do, task list, notes app, guestbook, CRUD app, a form that SAVES/STORES submissions, anything that PERSISTS data or shares state across users/sessions, sign-in/accounts | `app-with-data` | `database: true` | runtime (async, poll) | local |
23
+
24
+ **Rule of thumb:** if the app must SAVE/remember data, share state across
25
+ users/sessions, log in, or store submissions → it is persistent → `app-with-data`
26
+ (runtime, local edition). Otherwise a static template deploys instantly anywhere.
27
+
28
+ ## The full `needs:` vocabulary (the whole menu)
29
+
30
+ `needs:` is a MAP declaring infrastructure capabilities. Values are `true` or an
31
+ engine hint. Cron is NOT a need — it is a **service type** (`type: cron` with
32
+ `schedule` + `timezone`). See the cloudgrid.yaml reference §5, §12, §14.
33
+
34
+ | `needs:` key | Provides | Injected env var(s) | Status |
35
+ |---|---|---|---|
36
+ | `database: true` | MongoDB primary datastore | `DATABASE_MONGODB_URL` (+legacy `MONGODB_URL`) | **Today via `requires: [mongodb]`** — `needs:` pending #1527 |
37
+ | `cache: true` | Redis, LRU eviction | `CACHE_REDIS_URL` (+legacy `REDIS_URL`) | **Today via `requires: [redis]`** — `needs:` pending #1527 |
38
+ | `kv: true` | Redis, no eviction | `KV_REDIS_URL` | Pending #1527 |
39
+ | `queue: true` | Redis durable job queue | `QUEUE_REDIS_URL` | Pending #1527 |
40
+ | `pubsub: true` | Redis pub/sub broadcast | `PUBSUB_REDIS_URL` | Pending #1527 |
41
+ | `vector: pgvector` | pgvector embeddings DB | `VECTOR_PGVECTOR_URL` (+legacy `PGVECTOR_URL`) | Pending #1527 |
42
+ | `object_storage: true` | GCS bucket | `OBJECT_STORAGE_GCS_BUCKET`, `OBJECT_STORAGE_GCS_REGION` | Pending #1527 |
43
+ | `disk: true` | Persistent filesystem at `/data` | `DISK_PATH` | Pending #1527 |
44
+ | `ai: true` | AI Gateway access | `AI_GATEWAY_URL` | **Today** (AI Gateway) |
45
+ | `type: cron` (service) | Scheduled job (`schedule`, `timezone`) | — | Service type, not a need |
46
+
47
+ ### Injection status — today vs pending #1527
48
+
49
+ - **Injects TODAY:** `database` and `cache` — but ONLY via the deprecated
50
+ `requires:` field (`requires: [mongodb]` → `MONGODB_URL`; `requires: [redis]`
51
+ → `REDIS_URL`). `needs:`-based provisioning does NOT inject anything on the
52
+ live deployer yet (bug #1527). `ai` (AI Gateway) is available today.
53
+ - **Pending #1527:** `needs:`-based provisioning for everything — `vector`,
54
+ `queue`, `pubsub`, `kv`, `object_storage`, `disk`, and `needs: database` /
55
+ `needs: cache` once the deployer honors `needs:`.
56
+ - **`needs:` and `requires:` cannot both be active** in one yaml — the validator
57
+ rejects the combination ("use one or the other"). So a DB template ships
58
+ `requires: [mongodb]` active with the canonical `needs: { database: true }`
59
+ shown only as a **comment** (and declared in the workflow frontmatter as
60
+ metadata), flipping to `needs:` when #1527 lands.
61
+
62
+ ## How to choose
63
+
64
+ 1. Read the request; match it against the workflow `when:` triggers above.
65
+ 2. Adopt that template's `needs:`. Persistence → `database`. (Future: scheduled →
66
+ `cron` service; semantic search / RAG → `vector` + `ai`.)
67
+ 3. Static (`needs: none`) → publish as an inspiration with `gridctl_drop`
68
+ (instant, any edition). Anything with a `needs:` → runtime, local edition,
69
+ `gridctl_plug` a linked folder, then poll to a live URL.
@@ -11,5 +11,9 @@ services:
11
11
  web:
12
12
  type: nextjs
13
13
  path: /
14
+ # Canonical capability (metadata): this app needs a database.
15
+ # When #1527 lands (deployer honors needs:), replace requires: with:
16
+ # needs:
17
+ # database: true
14
18
  requires:
15
19
  - mongodb
@@ -53,10 +53,20 @@ services:
53
53
  web:
54
54
  type: nextjs
55
55
  path: /
56
+ # Canonical capability (metadata): this app needs a database.
57
+ # When #1527 lands (deployer honors needs:), replace requires: with:
58
+ # needs:
59
+ # database: true
56
60
  requires:
57
61
  - mongodb
58
62
  ```
59
63
 
64
+ > **Capability:** this template's canonical need is `database: true` (see the
65
+ > commented block above and the capability-map). The deployed yaml keeps
66
+ > `requires: [mongodb]` because only `requires:` injects `MONGODB_URL` today
67
+ > (#1527); `needs:` and `requires:` cannot co-exist active in the same yaml, so
68
+ > the canonical `needs:` is shown only as a comment until the deployer honors it.
69
+
60
70
  ## services/web/package.json
61
71
 
62
72
  ```json
@@ -0,0 +1,10 @@
1
+ # static — deploys as an inspiration (instant, works on hosted) via gridctl_drop;
2
+ # this yaml is only for plugging it as an OWNED static runtime (async, local
3
+ # edition only). To publish the page, prefer gridctl_drop, not grid plug.
4
+ #
5
+ # needs: {} # none — static, no infrastructure
6
+ name: dashboard
7
+ services:
8
+ web:
9
+ type: static
10
+ path: /
@@ -0,0 +1,30 @@
1
+ # Template: dashboard (static)
2
+
3
+ A single self-contained HTML dashboard. **No infrastructure** — no database, no backend,
4
+ no `needs:`. State (if any) lives only in memory and is lost on refresh.
5
+
6
+ ## How it deploys
7
+
8
+ To publish this page, use **`gridctl_drop`** (or `gridctl_plug` with the inline
9
+ HTML): it deploys as an **inspiration** — instant, and works on the **hosted**
10
+ edition (Claude Web) as well as local. The reference `cloudgrid.yaml` in this
11
+ directory (`type: static`) is ONLY for plugging the page as an OWNED static
12
+ runtime (async, local edition only); the fast path is `gridctl_drop`.
13
+
14
+ The fillable HTML is the real template — fetch it with
15
+ `gridctl_fetch("template", "dashboard")` and fill in the user's content.
16
+
17
+ ## cloudgrid.yaml (reference only)
18
+
19
+ ```yaml
20
+ # static — deploys as an inspiration (instant, works on hosted) via gridctl_drop;
21
+ # this yaml is only for plugging it as an OWNED static runtime (async, local
22
+ # edition only). To publish the page, prefer gridctl_drop, not grid plug.
23
+ #
24
+ # needs: {} # none — static, no infrastructure
25
+ name: dashboard
26
+ services:
27
+ web:
28
+ type: static
29
+ path: /
30
+ ```
@@ -0,0 +1,10 @@
1
+ # static — deploys as an inspiration (instant, works on hosted) via gridctl_drop;
2
+ # this yaml is only for plugging it as an OWNED static runtime (async, local
3
+ # edition only). To publish the page, prefer gridctl_drop, not grid plug.
4
+ #
5
+ # needs: {} # none — static, no infrastructure
6
+ name: deck
7
+ services:
8
+ web:
9
+ type: static
10
+ path: /
@@ -0,0 +1,30 @@
1
+ # Template: deck (static)
2
+
3
+ A single self-contained HTML deck. **No infrastructure** — no database, no backend,
4
+ no `needs:`. State (if any) lives only in memory and is lost on refresh.
5
+
6
+ ## How it deploys
7
+
8
+ To publish this page, use **`gridctl_drop`** (or `gridctl_plug` with the inline
9
+ HTML): it deploys as an **inspiration** — instant, and works on the **hosted**
10
+ edition (Claude Web) as well as local. The reference `cloudgrid.yaml` in this
11
+ directory (`type: static`) is ONLY for plugging the page as an OWNED static
12
+ runtime (async, local edition only); the fast path is `gridctl_drop`.
13
+
14
+ The fillable HTML is the real template — fetch it with
15
+ `gridctl_fetch("template", "deck")` and fill in the user's content.
16
+
17
+ ## cloudgrid.yaml (reference only)
18
+
19
+ ```yaml
20
+ # static — deploys as an inspiration (instant, works on hosted) via gridctl_drop;
21
+ # this yaml is only for plugging it as an OWNED static runtime (async, local
22
+ # edition only). To publish the page, prefer gridctl_drop, not grid plug.
23
+ #
24
+ # needs: {} # none — static, no infrastructure
25
+ name: deck
26
+ services:
27
+ web:
28
+ type: static
29
+ path: /
30
+ ```
@@ -0,0 +1,10 @@
1
+ # static — deploys as an inspiration (instant, works on hosted) via gridctl_drop;
2
+ # this yaml is only for plugging it as an OWNED static runtime (async, local
3
+ # edition only). To publish the page, prefer gridctl_drop, not grid plug.
4
+ #
5
+ # needs: {} # none — static, no infrastructure
6
+ name: landing-page
7
+ services:
8
+ web:
9
+ type: static
10
+ path: /
@@ -0,0 +1,30 @@
1
+ # Template: landing-page (static)
2
+
3
+ A single self-contained HTML landing-page. **No infrastructure** — no database, no backend,
4
+ no `needs:`. State (if any) lives only in memory and is lost on refresh.
5
+
6
+ ## How it deploys
7
+
8
+ To publish this page, use **`gridctl_drop`** (or `gridctl_plug` with the inline
9
+ HTML): it deploys as an **inspiration** — instant, and works on the **hosted**
10
+ edition (Claude Web) as well as local. The reference `cloudgrid.yaml` in this
11
+ directory (`type: static`) is ONLY for plugging the page as an OWNED static
12
+ runtime (async, local edition only); the fast path is `gridctl_drop`.
13
+
14
+ The fillable HTML is the real template — fetch it with
15
+ `gridctl_fetch("template", "landing-page")` and fill in the user's content.
16
+
17
+ ## cloudgrid.yaml (reference only)
18
+
19
+ ```yaml
20
+ # static — deploys as an inspiration (instant, works on hosted) via gridctl_drop;
21
+ # this yaml is only for plugging it as an OWNED static runtime (async, local
22
+ # edition only). To publish the page, prefer gridctl_drop, not grid plug.
23
+ #
24
+ # needs: {} # none — static, no infrastructure
25
+ name: landing-page
26
+ services:
27
+ web:
28
+ type: static
29
+ path: /
30
+ ```
@@ -0,0 +1,10 @@
1
+ # static — deploys as an inspiration (instant, works on hosted) via gridctl_drop;
2
+ # this yaml is only for plugging it as an OWNED static runtime (async, local
3
+ # edition only). To publish the page, prefer gridctl_drop, not grid plug.
4
+ #
5
+ # needs: {} # none — static, no infrastructure
6
+ name: report
7
+ services:
8
+ web:
9
+ type: static
10
+ path: /
@@ -0,0 +1,30 @@
1
+ # Template: report (static)
2
+
3
+ A single self-contained HTML report. **No infrastructure** — no database, no backend,
4
+ no `needs:`. State (if any) lives only in memory and is lost on refresh.
5
+
6
+ ## How it deploys
7
+
8
+ To publish this page, use **`gridctl_drop`** (or `gridctl_plug` with the inline
9
+ HTML): it deploys as an **inspiration** — instant, and works on the **hosted**
10
+ edition (Claude Web) as well as local. The reference `cloudgrid.yaml` in this
11
+ directory (`type: static`) is ONLY for plugging the page as an OWNED static
12
+ runtime (async, local edition only); the fast path is `gridctl_drop`.
13
+
14
+ The fillable HTML is the real template — fetch it with
15
+ `gridctl_fetch("template", "report")` and fill in the user's content.
16
+
17
+ ## cloudgrid.yaml (reference only)
18
+
19
+ ```yaml
20
+ # static — deploys as an inspiration (instant, works on hosted) via gridctl_drop;
21
+ # this yaml is only for plugging it as an OWNED static runtime (async, local
22
+ # edition only). To publish the page, prefer gridctl_drop, not grid plug.
23
+ #
24
+ # needs: {} # none — static, no infrastructure
25
+ name: report
26
+ services:
27
+ web:
28
+ type: static
29
+ path: /
30
+ ```
@@ -0,0 +1,10 @@
1
+ # static — deploys as an inspiration (instant, works on hosted) via gridctl_drop;
2
+ # this yaml is only for plugging it as an OWNED static runtime (async, local
3
+ # edition only). To publish the page, prefer gridctl_drop, not grid plug.
4
+ #
5
+ # needs: {} # none — static, no infrastructure
6
+ name: web-app
7
+ services:
8
+ web:
9
+ type: static
10
+ path: /
@@ -0,0 +1,30 @@
1
+ # Template: web-app (static)
2
+
3
+ A single self-contained HTML web-app. **No infrastructure** — no database, no backend,
4
+ no `needs:`. State (if any) lives only in memory and is lost on refresh.
5
+
6
+ ## How it deploys
7
+
8
+ To publish this page, use **`gridctl_drop`** (or `gridctl_plug` with the inline
9
+ HTML): it deploys as an **inspiration** — instant, and works on the **hosted**
10
+ edition (Claude Web) as well as local. The reference `cloudgrid.yaml` in this
11
+ directory (`type: static`) is ONLY for plugging the page as an OWNED static
12
+ runtime (async, local edition only); the fast path is `gridctl_drop`.
13
+
14
+ The fillable HTML is the real template — fetch it with
15
+ `gridctl_fetch("template", "web-app")` and fill in the user's content.
16
+
17
+ ## cloudgrid.yaml (reference only)
18
+
19
+ ```yaml
20
+ # static — deploys as an inspiration (instant, works on hosted) via gridctl_drop;
21
+ # this yaml is only for plugging it as an OWNED static runtime (async, local
22
+ # edition only). To publish the page, prefer gridctl_drop, not grid plug.
23
+ #
24
+ # needs: {} # none — static, no infrastructure
25
+ name: web-app
26
+ services:
27
+ web:
28
+ type: static
29
+ path: /
30
+ ```
@@ -1,6 +1,10 @@
1
1
  ---
2
2
  name: app-with-data
3
- when: The user wants an app that SAVES or PERSISTS data, shares state across users/sessions, has accounts/login, stores submissions, or needs a backend/API/database — e.g. a to-do list, a CRUD dashboard, a form that stores entries, a guestbook.
3
+ when: to-do, task list, notes app, guestbook, CRUD app, form that SAVES/STORES submissions, anything that SAVES or PERSISTS data or shares state across users/sessions, sign-in/accounts, a backend/API/database — e.g. a to-do list, a CRUD dashboard, a form that stores entries, a guestbook. Needs a database → runtime → local edition.
4
+ needs: database
5
+ deploy: runtime
6
+ editions: local
7
+ capabilities_note: persistent — needs a database (Mongo). Runtime app, async build, local edition only. Canonical need is `database: true` (metadata); the deployed yaml uses `requires: [mongodb]` until #1527 lands.
4
8
  summary: Build a real persistent Next.js + Mongo runtime app on the grid — edition-gate first, scaffold, put the app under services/web/, wire process.env.MONGODB_URL lazily, declare requires:[mongodb] (not needs:), deploy async, poll to a live URL.
5
9
  ---
6
10
 
@@ -1,6 +1,10 @@
1
1
  ---
2
2
  name: dashboard
3
- when: The user wants to build a dashboard showing metrics, status, or KPIs with cards and charts.
3
+ when: dashboard, metrics, KPIs, stats page, status board, charts, analytics view — display-only (static data baked in).
4
+ needs: none
5
+ deploy: inspiration
6
+ editions: all
7
+ capabilities_note: static — no infrastructure, data is baked into the page. Publishes as an inspiration (instant, works on hosted) via gridctl_drop.
4
8
  summary: Fetch the dashboard template, fill it with the user's metrics and inline charts, deploy it, and return the live share URL.
5
9
  ---
6
10
 
@@ -1,6 +1,10 @@
1
1
  ---
2
2
  name: landing-page
3
- when: The user wants to build a landing page, marketing page, or product page for something.
3
+ when: landing page, marketing page, product page, hero page, coming-soon, waitlist, pricing page, portfolio, link-in-bio, event page.
4
+ needs: none
5
+ deploy: inspiration
6
+ editions: all
7
+ capabilities_note: static — no infrastructure. Publishes as an inspiration (instant, works on hosted) via gridctl_drop.
4
8
  summary: Fetch the landing-page template, fill it with the user's content, deploy it, and return the live share URL.
5
9
  ---
6
10
 
@@ -1,6 +1,10 @@
1
1
  ---
2
2
  name: presentation
3
- when: The user wants to build a presentation, slide deck, or set of slides about a topic.
3
+ when: slides, deck, pitch, presentation, slideshow.
4
+ needs: none
5
+ deploy: inspiration
6
+ editions: all
7
+ capabilities_note: static — no infrastructure. Publishes as an inspiration (instant, works on hosted) via gridctl_drop.
4
8
  summary: Fetch the deck template, fill it with the user's content, deploy it, and return the live share URL.
5
9
  ---
6
10
 
@@ -1,6 +1,10 @@
1
1
  ---
2
2
  name: report
3
- when: The user wants to build a report, one-pager, brief, or write-up with sections and data.
3
+ when: report, one-pager, summary, brief, whitepaper, case study, formatted document.
4
+ needs: none
5
+ deploy: inspiration
6
+ editions: all
7
+ capabilities_note: static — no infrastructure. Publishes as an inspiration (instant, works on hosted) via gridctl_drop.
4
8
  summary: Fetch the report template, fill it with the user's content, deploy it, and return the live share URL.
5
9
  ---
6
10
 
@@ -1,6 +1,10 @@
1
1
  ---
2
2
  name: web-app
3
- when: The user wants to build a small interactive web app, tool, calculator, or mini single-page application.
3
+ when: calculator, converter, generator, timer, quiz, interactive tool, mini-app, single-page tool, widget — anything computed client-side with no saved data.
4
+ needs: none
5
+ deploy: inspiration
6
+ editions: all
7
+ capabilities_note: static — no infrastructure, state lives only in memory. Publishes as an inspiration (instant, works on hosted) via gridctl_drop.
4
8
  summary: Fetch the web-app template, adapt its markup and inline JS to the user's tool, deploy it, and return the live share URL.
5
9
  ---
6
10
 
package/src/tools.js CHANGED
@@ -89,6 +89,7 @@ Operating rules:
89
89
  9. To modify an existing drop when you don't already have its HTML in context, first call gridctl_source to fetch the current HTML, apply your change, then call gridctl_drop/gridctl_plug with target_entity_id (the drop's entity_id) to update the SAME URL in place. Do not ask the user to paste the HTML back.
90
90
  10. Publishing a heavy or local file: in the local edition use the path parameter so it is read from disk (no inline size limit); never base64-encode HTML and never pass a file path (or an @-prefixed path) as html. If a drop looks empty, use gridctl_source to check what was actually published, then re-plug with the real HTML/path and target_entity_id.
91
91
  11. Persistence check: if the user needs to SAVE data, share state across users/sessions, log in, or store submissions, that's a runtime app-with-data (Mongo-backed), NOT a static page — static templates keep state only in memory and lose it on refresh. Use the app-with-data workflow. This requires the LOCAL edition (Claude Desktop/Code or the CLI); on the hosted edition, tell the user persistence isn't available there and offer a static version.
92
+ 12. To choose what to build: match the request against the workflow when: triggers and the capability-map (gridctl_fetch({kind:"doc", name:"capability-map"})). Pick the template whose needs: matches what the app requires (persistence → database; scheduled → cron; etc.). Static (needs: none) deploys as an inspiration (instant, any edition); anything needing needs: is a runtime (async, local edition).
92
93
 
93
94
  Deploy is edition-dependent: on the hosted MCP call the drop tool with the HTML; on local MCP / CLI write the file and run the plug tool. An HTML page deploys synchronously, so you get a URL right away.`;
94
95