@groundfloorcloud/mcp 0.1.13 → 0.1.14

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 +3 -2
  2. package/dist/index.js +207 -41
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -84,8 +84,9 @@ then `npm run release` and `gf apps publish --path release.zip`. Do not invent
84
84
  `App.tsx` / `vite.config`, zip `dist/`, or upload only `remoteEntry.js`.
85
85
  Own CSS framework: `docs_get` id `css-and-styling` (`FederatedStyleRoot`).
86
86
 
87
- **Databases:** `docs_get` id `databases`. Dataplane is not a database. ArangoDB
88
- is ready through Dataplane; Postgres is what you can deploy today.
87
+ **Databases:** `docs_get` id `databases`. Dataplane is not a database. Shared
88
+ PostgreSQL is ready through Dataplane; a dedicated PostgreSQL is what you can
89
+ deploy today. No other engines are offered.
89
90
 
90
91
  **Coderunner how-to** is embedded: `docs_get` id `coderunner` (also
91
92
  `coderunner-overview`). That page covers:
package/dist/index.js CHANGED
@@ -327,6 +327,12 @@ function listSecrets(apiUrl, workspaceId, environmentId) {
327
327
  })}`
328
328
  );
329
329
  }
330
+ function listFlags(apiUrl, workspaceId, environmentId) {
331
+ return cpGet(
332
+ apiUrl,
333
+ `${wsPath(workspaceId, "/flags")}${queryString({ environment_id: environmentId })}`
334
+ );
335
+ }
330
336
  function listFiles(apiUrl, workspaceId) {
331
337
  return cpGet(apiUrl, wsPath(workspaceId, "/files"));
332
338
  }
@@ -776,43 +782,40 @@ Dataplane is not a database. It is how Groundfloor talks to databases.
776
782
  When the user starts any data or database work, say this first. Do not mention
777
783
  infrastructure internals (cluster operators, installers, and the like):
778
784
 
779
- You have Postgres ready to use through Dataplane \u2014 a shared, platform-managed
780
- cluster, already there, no deploy step. If you want a different engine, or a
781
- database that is entirely your own (own scaling, own backups schedule), you
782
- can deploy one first.
785
+ You have PostgreSQL ready to use through Dataplane \u2014 a shared,
786
+ platform-managed cluster, already there, no deploy step. If you want a
787
+ database that is entirely your own (own scaling, own backup schedule), you can
788
+ deploy a dedicated PostgreSQL first.
783
789
 
784
790
  ## Options
785
791
 
786
- - Postgres (shared) \u2014 platform-managed, already there. Default for app data
792
+ - PostgreSQL (shared) \u2014 platform-managed, already there. Default for app data
787
793
  and Vault. No deploy step. This is NOT a workspace-owned resource: it does
788
794
  not appear on the customer Databases page, and there is nothing to scale,
789
795
  back up, or delete yourself \u2014 it's offered, not provisioned. Query via
790
796
  Control Plane vault: POST /v1/workspaces/{id}/vault/collections/{name}/query
791
- - ArangoDB \u2014 also shared, managed, already there, no deploy step. Still fully
792
- supported; just no longer the pre-selected engine for new collections.
793
- - A dedicated database you deploy and own (Postgres, Redis, ClickHouse,
794
- Qdrant) \u2014 portal Data \u2192 Databases, or
795
- POST /v1/workspaces/{id}/managed-databases. Heavier than the shared
796
- default: you own its scaling, backups, and lifecycle. Use this when you
797
- need a tier/engine the shared default doesn't offer (Redis, ClickHouse,
798
- Qdrant) or want a database isolated to this workspace.
797
+ - Dedicated PostgreSQL you deploy and own \u2014 portal Data \u2192 Databases, or
798
+ POST /v1/workspaces/{id}/managed-databases with engine postgres. Heavier
799
+ than the shared default: you own its scaling, backups, and lifecycle. Use it
800
+ when you want a database isolated to this workspace.
799
801
  - A database they already run \u2014 through Dataplane if they wire it, or direct.
800
802
 
801
- Do not list other engines as available to deploy. Do not call Dataplane hosts
802
- from apps or embed service keys.
803
+ PostgreSQL is the only engine offered today, shared or dedicated. Do not offer
804
+ other engines (ArangoDB, MongoDB, Redis, ClickHouse, Qdrant, \u2026) as available,
805
+ even if you see them mentioned elsewhere. Do not call Dataplane hosts from apps
806
+ or embed service keys.
803
807
 
804
808
  ## Creating a collection / table
805
809
 
806
810
  Pass the engine explicitly \u2014 do not rely on Dataplane's default connector
807
811
  resolution. POST /v1/workspaces/{id}/vault/collections with
808
- \`"schema": {"engine": "postgresql", ...}\` for the shared default, or
809
- \`"engine": "arangodb"\` to use ArangoDB instead.
812
+ \`"schema": {"engine": "postgresql", ...}\`.
810
813
 
811
814
  ## Paths
812
815
 
813
816
  - Browse / edit rows \u2192 Data Vault (portal or vault APIs)
814
- - Deploy your own database \u2192 Customer Portal Databases page, or
815
- POST /v1/workspaces/{id}/managed-databases with engine postgres|redis|clickhouse|qdrant
817
+ - Deploy your own PostgreSQL \u2192 Customer Portal Databases page, or
818
+ POST /v1/workspaces/{id}/managed-databases with engine postgres
816
819
  - Shell 403 / empty vault \u2192 collection Access for the site role
817
820
 
818
821
  docs_get id databases. Human docs: /docs/customer-portal/databases and /docs/customer-portal/data-vault
@@ -865,6 +868,112 @@ stay in Shadow DOM. Render modals inside that root, not document.body.
865
868
  Full steps: docs_get id css-and-styling.
866
869
  `;
867
870
 
871
+ // src/flags-guide.ts
872
+ var FLAGS_GUIDE = `
873
+ # Feature Flags
874
+
875
+ Groundfloor has built-in feature flags: per-environment key \u2192 value toggles
876
+ (boolean, string, number or JSON) stored in Control Plane. **Use them instead
877
+ of building a flags table in a Vault collection or reading \`.env\`.** Each
878
+ environment (dev / staging / prod) has its own values; \`promote\` copies
879
+ between them.
880
+
881
+ ## Manage (builder)
882
+
883
+ \`\`\`bash
884
+ gf flags ls -e dev # -e takes an environment id or name
885
+ gf flags set new-checkout true -e dev # type inferred; --type json for objects
886
+ gf flags compare dev prod
887
+ gf flags promote dev prod --dry-run
888
+ gf flags rm new-checkout -e dev
889
+ \`\`\`
890
+
891
+ Or the Portal: Workspace \u2192 Feature Flags. API (builder \`gf token\`):
892
+ \`GET|PUT|DELETE /v1/workspaces/{id}/flags[/{key}]?environment_id=\`,
893
+ \`GET \u2026/flags/compare\`, \`POST \u2026/flags/promote\` \u2014 docs_get id \`flags-api\`.
894
+
895
+ - **Keys**: trimmed + lowercased, then \`^[a-z][a-z0-9_.-]{0,62}$\` (\`new-checkout\`,
896
+ \`ui.dark_mode\`). \`compare\`, \`promote\`, \`runtime\` are reserved.
897
+ - **Values**: \`value_type\` defaults to \`boolean\`; a mismatched value is 422.
898
+ - **Default environment**: omit \`environment_id\` \u2192 the active env named
899
+ \`dev\` (or the only active env). The response echoes the resolved
900
+ \`environment_id\`. Pass it explicitly for anything prod-facing.
901
+
902
+ ## Read at runtime (apps)
903
+
904
+ One endpoint for every runtime:
905
+
906
+ \`GET /v1/workspaces/{workspace_id}/flags/runtime?environment_id=<env>\`
907
+ \u2192 \`{ "workspace_id", "environment_id", "flags": { "new-checkout": true, \u2026 } }\`
908
+
909
+ Weak \`ETag\` + \`Cache-Control: private, no-cache\`. Send \`If-None-Match\` \u2192 304.
910
+ Poll no faster than every 30s (the kit uses 60s). No push channel yet.
911
+ Flag values are not secrets \u2014 every signed-in end user can read them.
912
+
913
+ ### Shell federated app (browser)
914
+
915
+ - **Token**: the Shell end-user JWT, \`await window.__GF_GET_ACCESS_TOKEN__()\`.
916
+ - **Permission**: workspace \`read\`. Site users get it from a recognised site
917
+ role (member/admin); self-registered users with no role get 403 (same rule
918
+ as Vault). No per-flag Access grant exists or is needed.
919
+ - **Environment**: \`window.__GF_ENVIRONMENT_ID__\` \u2014 the environment the app is
920
+ bound to, published by the Shell before your remote mounts. Unset in local
921
+ Dev Shell \u2192 server default (dev); \`VITE_GF_ENVIRONMENT_ID\` pins one.
922
+ - **Code**: the starter kit ships \`src/lib/flags.ts\`. Do not hand-roll it.
923
+
924
+ \`\`\`tsx
925
+ import { useFlag, useFlags } from './lib/flags';
926
+
927
+ export function Checkout() {
928
+ const newCheckout = useFlag('new-checkout', false);
929
+ const maxItems = useFlag('max-items', 10);
930
+ return newCheckout ? <NewCheckout max={maxItems} /> : <LegacyCheckout />;
931
+ }
932
+ // Many flags: const { flags, loading, error } = useFlags();
933
+ \`\`\`
934
+
935
+ ### Coderunner (server)
936
+
937
+ - **Token**: M2M \u2014 \`gf m2m token\` locally, or exchange
938
+ \`GROUNDFLOOR_M2M_CLIENT_ID\`/\`_SECRET\` at \`POST \u2026/m2m/token\` in code. M2M is
939
+ **read-only** on flags (PUT/DELETE/promote \u2192 403). Workload-identity Vault
940
+ JWTs cannot read flags (403).
941
+ - **Environment**: \`GROUNDFLOOR_ENVIRONMENT_ID\` is injected on deploy (the
942
+ Coderunner's bound environment). \`GROUNDFLOOR_WORKSPACE_ID\`,
943
+ \`CONTROLPLANE_URL\` and the M2M client id/secret are injected when an M2M
944
+ client is attached. Redeploy once to pick up the variable on older deploys.
945
+
946
+ \`\`\`js
947
+ const CP = process.env.CONTROLPLANE_URL;
948
+ const WS = process.env.GROUNDFLOOR_WORKSPACE_ID;
949
+ const ENV = process.env.GROUNDFLOOR_ENVIRONMENT_ID;
950
+ let cache = { etag: null, flags: {} };
951
+
952
+ export async function getFlags(token) {
953
+ const qs = ENV ? \`?environment_id=\${encodeURIComponent(ENV)}\` : '';
954
+ const res = await fetch(\`\${CP}/v1/workspaces/\${WS}/flags/runtime\${qs}\`, {
955
+ headers: {
956
+ Authorization: \`Bearer \${token}\`,
957
+ ...(cache.etag ? { 'If-None-Match': cache.etag } : {}),
958
+ },
959
+ });
960
+ if (res.status === 304) return cache.flags;
961
+ if (!res.ok) throw new Error(\`flags \${res.status}: \${await res.text()}\`);
962
+ const body = await res.json();
963
+ cache = { etag: res.headers.get('etag'), flags: body.flags };
964
+ return cache.flags;
965
+ }
966
+ // Call per request with a cached M2M token; refresh at most every 30\u201360s.
967
+ \`\`\`
968
+
969
+ ## Errors
970
+
971
+ 401 bad/missing token \xB7 403 no workspace read, M2M write, or workload identity \xB7
972
+ 404 unknown workspace/environment/flag \xB7 409 environment not active, or no
973
+ active environments \xB7 400 bad or reserved key \xB7 422 value/value_type mismatch \xB7
974
+ 423 workspace frozen (writes).
975
+ `.trim();
976
+
868
977
  // src/shell-guide.ts
869
978
  var SHELL_APP_GUIDE = `
870
979
  # Shell federated apps
@@ -899,10 +1008,9 @@ remoteEntry.js. Header logos: manifest \`theme.logoUrl\` (absolute https).
899
1008
  UI look: \`docs_get\` id \`design-standard\`. CSS: Tailwind by default;
900
1009
  own framework uses FederatedStyleRoot (Shadow DOM) \u2014 \`docs_get\` id
901
1010
  \`css-and-styling\`. Data: Dataplane is not a database. Say first: you have
902
- Postgres (shared, platform-managed, no deploy step) ready through Dataplane
903
- by default; ArangoDB is also ready the same way. Deploy your own dedicated
904
- database only if you need a different engine or workspace-owned isolation
905
- (\`docs_get\` id \`databases\`). Local UI without live vault:
1011
+ PostgreSQL (shared, platform-managed, no deploy step) ready through Dataplane.
1012
+ Deploy a dedicated PostgreSQL only if you want workspace-owned isolation.
1013
+ No other engines are offered (\`docs_get\` id \`databases\`). Local UI without live vault:
906
1014
  \`npm run dev:fixtures\`.
907
1015
 
908
1016
  Detail routes (e.g. \`records/:id\`): once the record loads, call
@@ -934,12 +1042,14 @@ POST \`/v1/workspaces/{id}/vault/collections\` with a **JSON Schema** object
934
1042
  **400** with a field error \u2014 not a 500.
935
1043
 
936
1044
  Pass \`engine\` explicitly \u2014 don't rely on Dataplane's default connector.
937
- \`"postgresql"\` is the platform default (shared, no deploy step);
938
- \`"arangodb"\` is also available the same way.
1045
+ \`"postgresql"\` is the platform default (shared, no deploy step) and the only
1046
+ engine offered today. \`?connection=\` must be \`postgresql\` or the name of a dedicated
1047
+ PostgreSQL in this workspace \u2014 another engine or an unknown name is **400**.
939
1048
 
940
- \`id\` and \`tenant_id\` are reserved field names on Postgres (and any SQL-shaped
941
- engine) \u2014 Dataplane adds them automatically as system columns on every table.
942
- Declaring either as a property is a **400**, not a 500. Not reserved on ArangoDB.
1049
+ \`id\`, \`tenant_id\`, and \`gf_extra\` are reserved field names \u2014 Dataplane adds
1050
+ them automatically as system columns on every Postgres table. Declaring any of
1051
+ them as a property is a **400**, not a 500. Undeclared record fields are kept in \`gf_extra\` and
1052
+ merged back on read, so extra keys are not lost.
943
1053
 
944
1054
  Example:
945
1055
 
@@ -1028,7 +1138,7 @@ var DOC_CATALOG = [
1028
1138
  id: "developers",
1029
1139
  title: "Developers (gf CLI)",
1030
1140
  path: "/docs/customer-portal/developers",
1031
- summary: "gf login, workspaces, deploy, secrets, files, apps, gf m2m token. Coderunner types: function, job, schedule, service (also called Deployment). App authentication optional."
1141
+ summary: "gf login, workspaces, deploy, secrets, feature flags (gf flags), files, apps, gf m2m token. Coderunner types: function, job, schedule, service (also called Deployment). App authentication optional."
1032
1142
  },
1033
1143
  {
1034
1144
  id: "coderunner",
@@ -1084,7 +1194,7 @@ var DOC_CATALOG = [
1084
1194
  path: "/docs/integrations/shell",
1085
1195
  summary: "Product Apps vs Coderunner. Always gf apps init --slug <portal-slug>, then npm run release and gf apps publish --path release.zip. Never zip dist/ or upload only remoteEntry.js.",
1086
1196
  embedded: SHELL_APP_GUIDE,
1087
- lastUpdated: "2026-09-24"
1197
+ lastUpdated: "2026-09-26"
1088
1198
  },
1089
1199
  {
1090
1200
  id: "design-standard",
@@ -1106,9 +1216,9 @@ var DOC_CATALOG = [
1106
1216
  id: "databases",
1107
1217
  title: "Databases",
1108
1218
  path: "/docs/customer-portal/databases",
1109
- summary: "Dataplane is not a database. Postgres (shared, platform-managed) is the default, ready through Dataplane with no deploy step. ArangoDB is also ready the same way. A dedicated database you deploy and own is a separate, heavier path.",
1219
+ summary: "Dataplane is not a database. PostgreSQL (shared, platform-managed) is ready through Dataplane with no deploy step. A dedicated PostgreSQL you deploy and own is a separate, heavier path. PostgreSQL is the only engine offered.",
1110
1220
  embedded: DATABASES_GUIDE,
1111
- lastUpdated: "2026-09-22"
1221
+ lastUpdated: "2026-09-26"
1112
1222
  },
1113
1223
  {
1114
1224
  id: "vault",
@@ -1116,7 +1226,23 @@ var DOC_CATALOG = [
1116
1226
  path: "/docs/api/vault",
1117
1227
  summary: "Create collections with JSON Schema, query totals vs limit, ACLs, implicit tables, nested filters, identities vs M2M.",
1118
1228
  embedded: VAULT_GUIDE,
1119
- lastUpdated: "2026-09-22"
1229
+ lastUpdated: "2026-09-26"
1230
+ },
1231
+ {
1232
+ id: "feature-flags",
1233
+ title: "Feature Flags",
1234
+ path: "/docs/customer-portal/feature-flags",
1235
+ summary: "Built-in per-environment feature flags (toggles / config values) \u2014 use these, not a Vault collection. gf flags ls|set|compare|promote. Apps read GET \u2026/flags/runtime: Shell apps with the end-user JWT + window.__GF_ENVIRONMENT_ID__ (starter-kit useFlag), Coderunners with gf m2m token + GROUNDFLOOR_ENVIRONMENT_ID. Default environment is dev.",
1236
+ embedded: FLAGS_GUIDE,
1237
+ lastUpdated: "2026-09-26"
1238
+ },
1239
+ {
1240
+ id: "flags-api",
1241
+ title: "Feature flags API",
1242
+ path: "/docs/api/flags",
1243
+ summary: "REST reference for flags: list/get/put/delete per environment_id (omitted \u2192 workspace default, dev), compare, promote, runtime read. Key format, value_type validation, auth per method (M2M read-only), error codes.",
1244
+ embedded: FLAGS_GUIDE,
1245
+ lastUpdated: "2026-09-26"
1120
1246
  },
1121
1247
  {
1122
1248
  id: "scheduled-jobs",
@@ -1252,6 +1378,12 @@ function suggestCli(intent, args) {
1252
1378
  why: "Mutations: gf secrets set|get|rm. MCP only lists keys.",
1253
1379
  docs: "https://docs.groundfloor.cloud/docs/customer-portal/developers"
1254
1380
  };
1381
+ case "flags":
1382
+ return {
1383
+ command: `gf flags ls${ws}`,
1384
+ why: "Feature flags per environment. Mutations: gf flags set|rm|compare|promote (-e <id|name>). Apps read GET \u2026/flags/runtime (docs_get id feature-flags). Do not build flags in a Vault collection.",
1385
+ docs: "https://docs.groundfloor.cloud/docs/customer-portal/feature-flags"
1386
+ };
1255
1387
  case "dataplane":
1256
1388
  return {
1257
1389
  command: `gf dataplane status${ws} # provision: gf dataplane provision`,
@@ -1268,7 +1400,7 @@ function suggestCli(intent, args) {
1268
1400
  default:
1269
1401
  return {
1270
1402
  command: "gf --help",
1271
- why: `Unknown intent "${intent}". Use login | switch_workspace | deploy | run | status | logs | environments | cancel_deployment | init_app | publish_app | secrets | dataplane | vault_token.`,
1403
+ why: `Unknown intent "${intent}". Use login | switch_workspace | deploy | run | status | logs | environments | cancel_deployment | init_app | publish_app | secrets | flags | dataplane | vault_token.`,
1272
1404
  docs: "https://docs.groundfloor.cloud/docs/customer-portal/developers"
1273
1405
  };
1274
1406
  }
@@ -1339,16 +1471,18 @@ server.tool(
1339
1471
  );
1340
1472
  server.tool(
1341
1473
  "workspace_context",
1342
- "Live context for the selected workspace: session, coderunners, apps, dataplane (access layer, not a database), databases_howto, suggested gf commands. Use docs_get id coderunner before deploying; id databases for data work; id css-and-styling for own CSS framework.",
1474
+ "Live context for the selected workspace: session, coderunners, apps, environments (with the default one), feature flags, dataplane (access layer, not a database), databases_howto, suggested gf commands. Use docs_get id coderunner before deploying; id databases for data work; id feature-flags for toggles/config; id css-and-styling for own CSS framework.",
1343
1475
  { workspace_id: wsId },
1344
1476
  async ({ workspace_id }) => {
1345
1477
  try {
1346
1478
  const c = await cfg(workspace_id);
1347
1479
  const claims = decodeJwt(c.token) ?? {};
1348
- const [coderunners, apps, dataplane] = await Promise.all([
1480
+ const [coderunners, apps, dataplane, environments, flags] = await Promise.all([
1349
1481
  listCoderunners(c.apiUrl, c.workspaceId),
1350
1482
  listApps(c.apiUrl, c.workspaceId).catch(() => ({ apps: [] })),
1351
- getDataplaneStatus(c.apiUrl, c.workspaceId).catch(() => null)
1483
+ getDataplaneStatus(c.apiUrl, c.workspaceId).catch(() => null),
1484
+ listWorkspaceEnvironments(c.apiUrl, c.workspaceId).catch(() => []),
1485
+ listFlags(c.apiUrl, c.workspaceId).catch(() => null)
1352
1486
  ]);
1353
1487
  return text({
1354
1488
  session: {
@@ -1370,6 +1504,21 @@ server.tool(
1370
1504
  status: app.status
1371
1505
  })),
1372
1506
  dataplane,
1507
+ environments: environments.map((env) => ({
1508
+ id: env.id,
1509
+ name: env.name,
1510
+ status: env.status,
1511
+ default: flags ? env.id === flags.environment_id : void 0
1512
+ })),
1513
+ feature_flags_howto: {
1514
+ docs_get: "feature-flags",
1515
+ rule: "Groundfloor has built-in per-environment feature flags. Use them; never build a flags collection in Vault or read toggles from .env.",
1516
+ default_environment_id: flags?.environment_id ?? null,
1517
+ default_environment_flags: flags ? flags.flags.map((f) => ({ key: f.key, value_type: f.value_type, value: f.value })) : null,
1518
+ manage: "gf flags ls|get|set|rm|compare|promote -e <env id or name>. Omitting -e uses the default environment (dev).",
1519
+ shell_app: "Starter-kit src/lib/flags.ts: useFlag('key', fallback). Calls GET /v1/workspaces/{id}/flags/runtime?environment_id=window.__GF_ENVIRONMENT_ID__ with the Shell end-user JWT (needs a site role \u2192 workspace read).",
1520
+ coderunner: "GET \u2026/flags/runtime?environment_id=$GROUNDFLOOR_ENVIRONMENT_ID with an M2M token (gf m2m token). M2M is read-only on flags; workload-identity tokens are rejected."
1521
+ },
1373
1522
  coderunner_howto: {
1374
1523
  docs_get: "coderunner",
1375
1524
  runtime_contract: "coderunner-runtime",
@@ -1393,10 +1542,10 @@ server.tool(
1393
1542
  databases_howto: {
1394
1543
  docs_get: "databases",
1395
1544
  dataplane: "Dataplane is not a database. It is how Groundfloor talks to databases.",
1396
- say_first: "You have Postgres ready to use through Dataplane \u2014 shared, platform-managed, already there, no deploy step. ArangoDB is also available the same way. If you want your own dedicated database instead, deploy it first.",
1545
+ say_first: "You have PostgreSQL ready to use through Dataplane \u2014 shared, platform-managed, already there, no deploy step. If you want your own dedicated database instead, deploy a dedicated PostgreSQL first.",
1397
1546
  shared_postgres: 'Default for app data and Vault. Platform-managed, not workspace-owned \u2014 nothing to scale/backup/delete yourself. Pass engine "postgresql" explicitly when creating a collection.',
1398
- arango: "Also shared, managed, already there, no deploy step. Still fully supported; just no longer pre-selected.",
1399
- deploy: "A dedicated Postgres/Redis/ClickHouse/Qdrant you own is what you can deploy today (portal Data \u2192 Databases)."
1547
+ deploy: "A dedicated PostgreSQL you own is what you can deploy today (portal Data \u2192 Databases).",
1548
+ engines: "PostgreSQL only, shared or dedicated. Do not offer ArangoDB, MongoDB, Redis, ClickHouse, Qdrant or other engines."
1400
1549
  },
1401
1550
  actions: {
1402
1551
  deploy: suggestCli("deploy"),
@@ -1404,6 +1553,7 @@ server.tool(
1404
1553
  run: suggestCli("run"),
1405
1554
  logs: suggestCli("logs"),
1406
1555
  environments: suggestCli("environments"),
1556
+ flags: suggestCli("flags"),
1407
1557
  cancel_deployment: suggestCli("cancel_deployment"),
1408
1558
  vault_token: suggestCli("m2m_token"),
1409
1559
  init_app: suggestCli("init_app"),
@@ -1641,6 +1791,21 @@ server.tool(
1641
1791
  }
1642
1792
  }
1643
1793
  );
1794
+ server.tool(
1795
+ "flags_list",
1796
+ "List feature flags and values in one environment (omit environment_id \u2192 workspace default, dev; response echoes the resolved id). To set/delete/promote, use `gf flags`. docs_get id feature-flags for runtime use.",
1797
+ { workspace_id: wsId, environment_id: z.string().optional() },
1798
+ async (args) => {
1799
+ try {
1800
+ const c = await cfg(args.workspace_id);
1801
+ return text(
1802
+ await listFlags(c.apiUrl, c.workspaceId, args.environment_id)
1803
+ );
1804
+ } catch (e) {
1805
+ return errText(e);
1806
+ }
1807
+ }
1808
+ );
1644
1809
  server.tool(
1645
1810
  "files_list",
1646
1811
  "List workspace files (read-only). Upload/download with `gf files`.",
@@ -1674,7 +1839,7 @@ server.tool(
1674
1839
  );
1675
1840
  server.tool(
1676
1841
  "dataplane_status",
1677
- "Dataplane setup status (Dataplane is how Groundfloor talks to databases, not a database itself). Postgres (shared, platform-managed) is ready through it by default; ArangoDB is also ready. Provision with `gf dataplane provision`.",
1842
+ "Dataplane setup status (Dataplane is how Groundfloor talks to databases, not a database itself). PostgreSQL (shared, platform-managed) is ready through it by default. Provision with `gf dataplane provision`.",
1678
1843
  { workspace_id: wsId },
1679
1844
  async ({ workspace_id }) => {
1680
1845
  try {
@@ -1744,6 +1909,7 @@ server.tool(
1744
1909
  "init_app",
1745
1910
  "publish_app",
1746
1911
  "secrets",
1912
+ "flags",
1747
1913
  "dataplane",
1748
1914
  "vault_token",
1749
1915
  "m2m_token"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@groundfloorcloud/mcp",
3
- "version": "0.1.13",
3
+ "version": "0.1.14",
4
4
  "description": "Groundfloor MCP — inspect workspace state and docs; take actions with the gf CLI.",
5
5
  "type": "module",
6
6
  "bin": {