@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.
Files changed (3) hide show
  1. package/README.md +13 -1
  2. package/dist/index.js +191 -10
  3. 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: "Functions, jobs, schedules, services \u2014 not Apps."
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 { url, title: entry.title, text: body, truncated };
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, and suggested gf commands. This is how the agent knows *what is here*; use docs_get for *how to do it*.",
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
- "Fetch a product doc page from docs.groundfloor.cloud (how/when to use CLI). Pass id from docs_list (agents, developers, coderunner, authentication, shell).",
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("Catalog id, e.g. agents | developers | coderunner")
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 {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@groundfloorcloud/mcp",
3
- "version": "0.1.1",
3
+ "version": "0.1.2",
4
4
  "description": "Groundfloor MCP — inspect workspace state and docs; take actions with the gf CLI.",
5
5
  "type": "module",
6
6
  "bin": {