@groundfloorcloud/mcp 0.1.1 → 0.1.2
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 +13 -1
- package/dist/index.js +191 -10
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -67,11 +67,23 @@ The `command` must be your Node (from `which node`), not `npx` and not Cursor’
|
|
|
67
67
|
| `coderunner_list` / `_get_status` / `_get_logs` | Inspect workloads |
|
|
68
68
|
| `apps_list` / `apps_get` | Inspect product Apps |
|
|
69
69
|
| `secrets_list` / `files_list` / `domains_list` / `dataplane_status` | Inspect (no secrets values) |
|
|
70
|
-
| `docs_list` / `docs_get` | Product docs |
|
|
70
|
+
| `docs_list` / `docs_get` | Product docs (`coderunner` returns the full type/auth/Dockerfile guide) |
|
|
71
71
|
| `suggest_cli` | Command to run: login, deploy, init_app, publish_app, … |
|
|
72
72
|
|
|
73
73
|
Never create `app_kind=coderunner`. Deploy with `gf deploy`.
|
|
74
74
|
|
|
75
|
+
**Coderunner how-to** is embedded: `docs_get` id `coderunner` (also
|
|
76
|
+
`coderunner-overview`). That page covers:
|
|
77
|
+
|
|
78
|
+
- Types: `function`, `job`, `schedule`, `service` (**also called Deployment**)
|
|
79
|
+
- **Authentication must be active** before creating a coderunner
|
|
80
|
+
- **Dockerfile is required** for `service` / Deployment
|
|
81
|
+
- Node `scripts.start` + listen on 8080
|
|
82
|
+
- Local development against live vault/files/secrets (`gf env` + `gf token`)
|
|
83
|
+
|
|
84
|
+
`workspace_context` includes a `coderunner_howto` summary so agents see this
|
|
85
|
+
without an extra fetch.
|
|
86
|
+
|
|
75
87
|
## Build (from this repo)
|
|
76
88
|
|
|
77
89
|
```bash
|
package/dist/index.js
CHANGED
|
@@ -380,6 +380,143 @@ async function resolveMcpConfig(overrides) {
|
|
|
380
380
|
return { apiUrl, workspaceId, token };
|
|
381
381
|
}
|
|
382
382
|
|
|
383
|
+
// src/coderunner-guide.ts
|
|
384
|
+
var CODERUNNER_GUIDE = `
|
|
385
|
+
# Coderunner workloads
|
|
386
|
+
|
|
387
|
+
Coderunner is Groundfloor's **apps runtime**. Deploy Node.js, Python, .NET, and
|
|
388
|
+
other workloads as **functions**, **jobs**, **schedules**, or **services**.
|
|
389
|
+
The Customer Portal, \`gf\` CLI, and this MCP all drive the same lifecycle.
|
|
390
|
+
|
|
391
|
+
Do **not** create an App to run code. \`POST \u2026/apps\` with \`app_kind=coderunner\`
|
|
392
|
+
is rejected. Optional Apps are Shell / product packaging only.
|
|
393
|
+
|
|
394
|
+
## Prerequisites (do these before create/deploy)
|
|
395
|
+
|
|
396
|
+
1. **Workspace Authentication is required** before creating a coderunner.
|
|
397
|
+
Portal \u2192 Administer \u2192 Authentication \u2192 set mode to \`groundfloor\` (or
|
|
398
|
+
\`external\` with an issuer) and wait until the realm is **active**.
|
|
399
|
+
Code Runner JWTs use the workspace site issuer. Mode \`none\` cannot mint
|
|
400
|
+
that token \u2014 create/deploy fails with "requires the workspace site issuer".
|
|
401
|
+
2. \`gf login\` (\`--stage\` / \`--dev\` as needed) and \`gf workspaces use <uuid>\`.
|
|
402
|
+
3. Dataplane for vault/files/secrets: \`gf dataplane provision\` if those APIs
|
|
403
|
+
are needed (local live data or the deployed workload).
|
|
404
|
+
|
|
405
|
+
## Workload types
|
|
406
|
+
|
|
407
|
+
Portal \`workload_type\` (CLI \`--workload-type\` / \`groundfloor.json\`
|
|
408
|
+
\`workloadType\`) maps to upstream \`deploymentType\`. **Service and Deployment
|
|
409
|
+
are the same type** \u2014 portal id \`service\`, UI often says Deployment,
|
|
410
|
+
upstream \`deploymentType=4\`.
|
|
411
|
+
|
|
412
|
+
| Portal id | Also called | Upstream | When to use | How it runs |
|
|
413
|
+
|-----------|-------------|----------|-------------|-------------|
|
|
414
|
+
| \`function\` | Function | 1 | Request/response HTTP handler (webhooks, APIs, agent invoke) | Scale-to-zero Knative. Invoke via Run or Deployment URL. |
|
|
415
|
+
| \`job\` | Background job | 2 | One-shot batch (import, report, backfill) | Run-to-completion. Deploy, then \`gf coderunner run\`. |
|
|
416
|
+
| \`schedule\` | Scheduled job | 3 | Cron (reminders, sync) | Same as job, plus cron. **No** public Deployment URL. |
|
|
417
|
+
| \`service\` | **Deployment** | 4 | Long-running HTTP process (web app, always-on API) | Stays up (replicas). Public Deployment URL. Custom domains when App-bound. |
|
|
418
|
+
|
|
419
|
+
Pick **one** type per coderunner. Changing type later means a new coderunner.
|
|
420
|
+
|
|
421
|
+
### Function
|
|
422
|
+
|
|
423
|
+
- ZIP at archive root (\`package.json\` / \`index.js\` or \`main.py\` not nested).
|
|
424
|
+
- Listen on \`process.env.PORT || 8080\` (health GET \`/\` or \`/health\`).
|
|
425
|
+
- **Node:** \`package.json\` **must** include \`"scripts": { "start": "node index.js" }\`.
|
|
426
|
+
The runtime image is \`CMD ["npm", "start"]\`. Missing \`start\` \u2192 crash loop,
|
|
427
|
+
probe \`127.0.0.1:8080\` connection refused, deployment **Failed (status 4)**.
|
|
428
|
+
- Python: process must bind 0.0.0.0:\${PORT:-8080}.
|
|
429
|
+
- After deploy: \`gf coderunner run -c <slug> --payload '{"hello":"world"}'\`.
|
|
430
|
+
|
|
431
|
+
### Job
|
|
432
|
+
|
|
433
|
+
- Same package rules as function. No need to serve forever; exit 0 on success.
|
|
434
|
+
- Deploy, then start a run (\`gf coderunner run\`). Check Process Log.
|
|
435
|
+
|
|
436
|
+
### Schedule
|
|
437
|
+
|
|
438
|
+
- Same as job, plus a cron expression at create/deploy (\`schedule\` /
|
|
439
|
+
\`CronExpression\`).
|
|
440
|
+
- No public invoke URL. Debug with Process Log, not curl.
|
|
441
|
+
|
|
442
|
+
### Service (Deployment)
|
|
443
|
+
|
|
444
|
+
- Long-running HTTP. **You must include a \`Dockerfile\` at the ZIP root.**
|
|
445
|
+
Kaniko builds with \`--dockerfile=Dockerfile\`. Language bootstrap does **not**
|
|
446
|
+
replace a missing Dockerfile for this type.
|
|
447
|
+
- Dockerfile must expose and listen on **8080** (or \`PORT\`).
|
|
448
|
+
- Node example:
|
|
449
|
+
|
|
450
|
+
\`\`\`dockerfile
|
|
451
|
+
FROM node:18-alpine
|
|
452
|
+
WORKDIR /app
|
|
453
|
+
COPY package*.json ./
|
|
454
|
+
RUN npm ci --omit=dev
|
|
455
|
+
COPY . .
|
|
456
|
+
EXPOSE 8080
|
|
457
|
+
ENV PORT=8080
|
|
458
|
+
CMD ["npm", "start"]
|
|
459
|
+
\`\`\`
|
|
460
|
+
|
|
461
|
+
- Still require Node \`"start"\` if CMD is \`npm start\`.
|
|
462
|
+
- Prefer curling the Deployment URL (\`/health\`) over \`\u2026/run\`.
|
|
463
|
+
|
|
464
|
+
## Latest deploy rules (all types)
|
|
465
|
+
|
|
466
|
+
- \`gf deploy\` from the project dir (or \`--path\` / \`--git\`). Creates the
|
|
467
|
+
coderunner if the slug is new; otherwise uploads a new version and deploys it.
|
|
468
|
+
- Status: upload/build \`1\u20134\` (3=Completed, 4=Failed). Deployment \`1\u20137\`
|
|
469
|
+
(3=Deployed, 4=Failed). A templated \`deployment_url\` with empty
|
|
470
|
+
\`externalEndpoint\` and status 4 means the container never became ready \u2014
|
|
471
|
+
read Process Log (\`runner_id\` = deployment id).
|
|
472
|
+
- Strip \`.env*\`, \`.git\`, \`node_modules\` from ZIPs. Put secrets in
|
|
473
|
+
\`gf secrets\` / deploy \`-e\`, never in the archive.
|
|
474
|
+
- Zip **contents** at root, not a wrapping folder.
|
|
475
|
+
- Optional \`groundfloor.json\`: \`name\`, \`runtime\`, \`workloadType\`,
|
|
476
|
+
\`cpu\`, \`memory\`, \`env\`.
|
|
477
|
+
|
|
478
|
+
## Local development with live workspace data
|
|
479
|
+
|
|
480
|
+
Run the process on your laptop; call the **same** Control Plane + Dataplane
|
|
481
|
+
the deployed coderunner uses. Do not copy production data into fixtures.
|
|
482
|
+
|
|
483
|
+
\`\`\`bash
|
|
484
|
+
gf login --stage # or --dev / production
|
|
485
|
+
gf workspaces use <uuid>
|
|
486
|
+
eval "$(gf env)" # GROUNDFLOOR_TOKEN, CONTROLPLANE_URL, GROUNDFLOOR_WORKSPACE_ID
|
|
487
|
+
gf dataplane status # provision if needed: gf dataplane provision
|
|
488
|
+
gf secrets ls
|
|
489
|
+
\`\`\`
|
|
490
|
+
|
|
491
|
+
Local HTTP (Node function/service):
|
|
492
|
+
|
|
493
|
+
\`\`\`bash
|
|
494
|
+
export PORT=8080
|
|
495
|
+
npm start # same entrypoint as production
|
|
496
|
+
# other terminal:
|
|
497
|
+
curl -sS -X POST http://127.0.0.1:8080/ -H 'Content-Type: application/json' \\
|
|
498
|
+
-d '{"hello":"local"}'
|
|
499
|
+
\`\`\`
|
|
500
|
+
|
|
501
|
+
Live vault / files / secrets from the laptop:
|
|
502
|
+
|
|
503
|
+
\`\`\`bash
|
|
504
|
+
curl -sS -H "Authorization: Bearer $(gf token)" \\
|
|
505
|
+
"$CONTROLPLANE_URL/v1/workspaces/$GROUNDFLOOR_WORKSPACE_ID/vault/collections"
|
|
506
|
+
\`\`\`
|
|
507
|
+
|
|
508
|
+
In app code, use \`CONTROLPLANE_URL\` + Bearer (\`gf token\` locally;
|
|
509
|
+
injected env / workspace secrets after \`gf deploy\`). Never put
|
|
510
|
+
\`DATAPLANE_SERVICE_API_KEY\` in a browser bundle.
|
|
511
|
+
|
|
512
|
+
When the handler looks right locally, \`gf deploy\` the same tree.
|
|
513
|
+
|
|
514
|
+
## Agent actions
|
|
515
|
+
|
|
516
|
+
Inspect: \`workspace_context\`, \`docs_get\` id \`coderunner\`, \`suggest_cli\`.
|
|
517
|
+
Act: \`gf deploy\`, \`gf coderunner run|status\`. MCP does not deploy.
|
|
518
|
+
`.trim();
|
|
519
|
+
|
|
383
520
|
// src/docs.ts
|
|
384
521
|
var DOCS_ORIGIN = "https://docs.groundfloor.cloud";
|
|
385
522
|
var DOC_CATALOG = [
|
|
@@ -387,22 +524,36 @@ var DOC_CATALOG = [
|
|
|
387
524
|
id: "agents",
|
|
388
525
|
title: "Deploy with agents",
|
|
389
526
|
path: "/docs/customer-portal/agents",
|
|
390
|
-
summary: "How agents should deploy Coderunner workloads and init/publish Shell apps with gf / MCP."
|
|
527
|
+
summary: "How agents should deploy Coderunner workloads and init/publish Shell apps with gf / MCP. Enable workspace Authentication before create. Service (Deployment) requires a Dockerfile."
|
|
391
528
|
},
|
|
392
529
|
{
|
|
393
530
|
id: "developers",
|
|
394
531
|
title: "Developers (gf CLI)",
|
|
395
532
|
path: "/docs/customer-portal/developers",
|
|
396
|
-
summary: "gf login, workspaces, deploy, secrets, files, apps."
|
|
533
|
+
summary: "gf login, workspaces, deploy, secrets, files, apps. Coderunner types: function, job, schedule, service (also called Deployment)."
|
|
397
534
|
},
|
|
398
535
|
{
|
|
399
536
|
id: "coderunner",
|
|
400
537
|
title: "Coderunner",
|
|
401
538
|
path: "/docs/customer-portal/coderunner",
|
|
402
|
-
summary: "
|
|
539
|
+
summary: "Workload types (function, job, schedule, service/Deployment), Dockerfile for services, Authentication before create, local live data, gf deploy.",
|
|
540
|
+
embedded: CODERUNNER_GUIDE
|
|
541
|
+
},
|
|
542
|
+
{
|
|
543
|
+
id: "coderunner-overview",
|
|
544
|
+
title: "Coderunner overview",
|
|
545
|
+
path: "/docs/integrations/coderunner/overview",
|
|
546
|
+
summary: "Architecture and lifecycle. Prefer docs_get id coderunner for type usage, Dockerfile, and auth prerequisites.",
|
|
547
|
+
embedded: CODERUNNER_GUIDE
|
|
403
548
|
},
|
|
404
549
|
{
|
|
405
550
|
id: "authentication",
|
|
551
|
+
title: "Workspace Authentication",
|
|
552
|
+
path: "/docs/customer-portal/authentication",
|
|
553
|
+
summary: "Workspace site auth (Groundfloor or external) must be active before creating a Coderunner. Separate from portal Members & Roles."
|
|
554
|
+
},
|
|
555
|
+
{
|
|
556
|
+
id: "api-authentication",
|
|
406
557
|
title: "API authentication",
|
|
407
558
|
path: "/docs/api/authentication",
|
|
408
559
|
summary: "Control Plane Bearer tokens and workspace identity."
|
|
@@ -421,7 +572,7 @@ function findDoc(query) {
|
|
|
421
572
|
const q = query.trim().toLowerCase();
|
|
422
573
|
if (!q) return DOC_CATALOG;
|
|
423
574
|
return DOC_CATALOG.filter((d) => {
|
|
424
|
-
const hay = `${d.id} ${d.title} ${d.summary} ${d.path}`.toLowerCase();
|
|
575
|
+
const hay = `${d.id} ${d.title} ${d.summary} ${d.path} ${d.embedded ?? ""}`.toLowerCase();
|
|
425
576
|
return q.split(/\s+/).every((part) => hay.includes(part));
|
|
426
577
|
});
|
|
427
578
|
}
|
|
@@ -432,6 +583,15 @@ function htmlToText(html) {
|
|
|
432
583
|
var MAX_CHARS = 12e3;
|
|
433
584
|
async function fetchDocPage(entry) {
|
|
434
585
|
const url = docUrl(entry);
|
|
586
|
+
if (entry.embedded?.trim()) {
|
|
587
|
+
return {
|
|
588
|
+
url,
|
|
589
|
+
title: entry.title,
|
|
590
|
+
text: entry.embedded.trim(),
|
|
591
|
+
truncated: false,
|
|
592
|
+
source: "embedded"
|
|
593
|
+
};
|
|
594
|
+
}
|
|
435
595
|
const res = await fetch(url, {
|
|
436
596
|
headers: { Accept: "text/html", "User-Agent": "groundfloor-mcp/0.1" },
|
|
437
597
|
redirect: "follow"
|
|
@@ -444,7 +604,13 @@ async function fetchDocPage(entry) {
|
|
|
444
604
|
const truncated = body.length > MAX_CHARS;
|
|
445
605
|
if (truncated) body = `${body.slice(0, MAX_CHARS)}
|
|
446
606
|
\u2026`;
|
|
447
|
-
return {
|
|
607
|
+
return {
|
|
608
|
+
url,
|
|
609
|
+
title: entry.title,
|
|
610
|
+
text: body,
|
|
611
|
+
truncated,
|
|
612
|
+
source: "docs.groundfloor.cloud"
|
|
613
|
+
};
|
|
448
614
|
}
|
|
449
615
|
|
|
450
616
|
// src/playbook.ts
|
|
@@ -467,7 +633,7 @@ function suggestCli(intent, args) {
|
|
|
467
633
|
case "deploy":
|
|
468
634
|
return {
|
|
469
635
|
command: name ? `gf deploy -n ${name}${ws}` : `gf deploy${ws}`,
|
|
470
|
-
why: "Package the current (or --path) folder and deploy as a Coderunner. Do not create an App for this.",
|
|
636
|
+
why: "Package the current (or --path) folder and deploy as a Coderunner. Workspace Authentication (groundfloor/external) must already be active. workloadType function|job|schedule|service (service = Deployment; requires a Dockerfile). Node needs package.json scripts.start. Do not create an App for this.",
|
|
471
637
|
docs: "https://docs.groundfloor.cloud/docs/customer-portal/coderunner"
|
|
472
638
|
};
|
|
473
639
|
case "run":
|
|
@@ -582,7 +748,7 @@ server.tool(
|
|
|
582
748
|
);
|
|
583
749
|
server.tool(
|
|
584
750
|
"workspace_context",
|
|
585
|
-
"Live context for the selected workspace: session, coderunners, apps, dataplane,
|
|
751
|
+
"Live context for the selected workspace: session, coderunners, apps, dataplane, suggested gf commands, and Coderunner type/auth/Dockerfile rules. Use docs_get id coderunner for the full how-to.",
|
|
586
752
|
{ workspace_id: wsId },
|
|
587
753
|
async ({ workspace_id }) => {
|
|
588
754
|
try {
|
|
@@ -613,6 +779,18 @@ server.tool(
|
|
|
613
779
|
status: app.status
|
|
614
780
|
})),
|
|
615
781
|
dataplane,
|
|
782
|
+
coderunner_howto: {
|
|
783
|
+
docs_get: "coderunner",
|
|
784
|
+
before_create: "Enable Administer \u2192 Authentication (mode groundfloor or external, realm active). Mode none cannot mint a Code Runner JWT.",
|
|
785
|
+
types: {
|
|
786
|
+
function: "HTTP handler on PORT/8080. Invoke with gf coderunner run or the Deployment URL. Node requires package.json scripts.start.",
|
|
787
|
+
job: "Run-to-completion worker. Deploy, then gf coderunner run.",
|
|
788
|
+
schedule: "Cron job. No public Deployment URL. Set schedule/cron at create or deploy.",
|
|
789
|
+
service: "Long-running Deployment (same type as service). Dockerfile at ZIP root is required. Listen on 8080."
|
|
790
|
+
},
|
|
791
|
+
node: 'Bootstrap image uses CMD ["npm","start"]. Missing scripts.start \u2192 deploy Failed (status 4), 8080 connection refused.',
|
|
792
|
+
local_live_data: 'eval "$(gf env)" then call Control Plane vault/files/secrets with Bearer $(gf token). Do not zip .env files.'
|
|
793
|
+
},
|
|
616
794
|
actions: {
|
|
617
795
|
deploy: suggestCli("deploy"),
|
|
618
796
|
switch_workspace: suggestCli("switch_workspace"),
|
|
@@ -621,7 +799,8 @@ server.tool(
|
|
|
621
799
|
docs: DOC_CATALOG.map((d) => ({
|
|
622
800
|
id: d.id,
|
|
623
801
|
title: d.title,
|
|
624
|
-
url: `https://docs.groundfloor.cloud${d.path}
|
|
802
|
+
url: `https://docs.groundfloor.cloud${d.path}`,
|
|
803
|
+
summary: d.summary
|
|
625
804
|
}))
|
|
626
805
|
});
|
|
627
806
|
} catch (e) {
|
|
@@ -819,9 +998,11 @@ server.tool(
|
|
|
819
998
|
);
|
|
820
999
|
server.tool(
|
|
821
1000
|
"docs_get",
|
|
822
|
-
"
|
|
1001
|
+
"How-to for Coderunner types, Dockerfile, Authentication, local live data, gf CLI, Shell. Pass id from docs_list (coderunner, coderunner-overview, agents, developers, authentication, api-authentication, shell). Prefer id coderunner before deploying.",
|
|
823
1002
|
{
|
|
824
|
-
id: z.string().min(1).describe(
|
|
1003
|
+
id: z.string().min(1).describe(
|
|
1004
|
+
"Catalog id, e.g. coderunner | coderunner-overview | agents | developers | authentication | api-authentication | shell"
|
|
1005
|
+
)
|
|
825
1006
|
},
|
|
826
1007
|
async ({ id }) => {
|
|
827
1008
|
try {
|