@cloudgrid-io/mcp 0.5.1 → 0.5.3
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 -6
- package/package.json +2 -1
- package/src/tools.js +98 -52
package/README.md
CHANGED
|
@@ -13,6 +13,13 @@ The local edition wraps the `cloudgrid` CLI for authenticated operations (the CL
|
|
|
13
13
|
handles auth, org context, and error formatting) and calls the API directly for the
|
|
14
14
|
drop, claim, and login tools.
|
|
15
15
|
|
|
16
|
+
## CLI compatibility
|
|
17
|
+
|
|
18
|
+
MCP 0.5.2 is tested against CLI 0.10.1. The lazy-npx fallback pins
|
|
19
|
+
`@cloudgrid-io/cli@~0.10.1` so a future CLI major with renamed verbs cannot
|
|
20
|
+
silently break a released MCP. A CI drift guard (`npm run test:drift-guard`)
|
|
21
|
+
asserts every wrapped verb exists in the CLI help.
|
|
22
|
+
|
|
16
23
|
## Prerequisite
|
|
17
24
|
|
|
18
25
|
Install and log in to the CLI:
|
|
@@ -67,24 +74,24 @@ also work in the web edition where no CLI exists. `cloudgrid_login` writes the s
|
|
|
67
74
|
| `cloudgrid_logs` | `cloudgrid logs` | Snapshot of recent logs. Does not stream. Read-only. |
|
|
68
75
|
| `cloudgrid_share` | `cloudgrid visibility set` | Set visibility, default link. |
|
|
69
76
|
| `cloudgrid_feedback` | `cloudgrid feedback list` | Read the org feedback feed. Read-only. |
|
|
70
|
-
| `cloudgrid_brain` | `cloudgrid brain refresh` | Re-run the Grid Brain hooks. |
|
|
71
77
|
| `cloudgrid_whoami` | `cloudgrid whoami` | Show the signed-in user and active org. Read-only. |
|
|
72
78
|
| `cloudgrid_use` | `cloudgrid use` | Switch the active org. |
|
|
73
79
|
| `cloudgrid_logout` | `cloudgrid logout` | Sign out and clear local credentials. Destructive. |
|
|
74
80
|
| `cloudgrid_status` | `cloudgrid status` | Org dashboard or entity detail. Read-only. |
|
|
75
81
|
| `cloudgrid_info` | `cloudgrid info` | Entity metadata. Read-only. |
|
|
76
|
-
| `
|
|
77
|
-
| `
|
|
78
|
-
| `
|
|
82
|
+
| `cloudgrid_get` | `cloudgrid get grids\|entities\|spaces` | List grids, entities, or spaces. Read-only. |
|
|
83
|
+
| `cloudgrid_describe_grid` | `cloudgrid describe grid <slug>` | Grid detail. Read-only. |
|
|
84
|
+
| `cloudgrid_pickup` | `cloudgrid pickup <name>` | Download an entity's source and bind the folder. |
|
|
85
|
+
| `cloudgrid_rename` | `cloudgrid rename` | Rename an entity's display name. |
|
|
79
86
|
| `cloudgrid_unplug` | `cloudgrid unplug` | Take an entity off the grid. Destructive; requires confirm. |
|
|
80
|
-
| `cloudgrid_delete` | `cloudgrid delete` | Archive
|
|
87
|
+
| `cloudgrid_delete` | `cloudgrid delete entity` | Archive an inspiration. Destructive; requires confirm. |
|
|
81
88
|
| `cloudgrid_rollback` | `cloudgrid rollback` | Rollback to a previous version. |
|
|
82
89
|
| `cloudgrid_versions` | `cloudgrid versions` | List published versions. Read-only. |
|
|
83
90
|
| `cloudgrid_env` | `cloudgrid env` | Get, set, or list environment variables. |
|
|
84
91
|
| `cloudgrid_secrets` | `cloudgrid secrets` | Set or list secret names. Never returns secret values. |
|
|
85
92
|
| `cloudgrid_scaffold` | `cloudgrid scaffold` | Generate starter files. |
|
|
86
93
|
| `cloudgrid_doctor` | `cloudgrid doctor` | Run local diagnostics. Read-only. |
|
|
87
|
-
| `cloudgrid_open` | `cloudgrid open` | Return the public URL. Does not open a browser. Read-only. |
|
|
94
|
+
| `cloudgrid_open` | `cloudgrid open --print` | Return the public URL. Does not open a browser. Read-only. |
|
|
88
95
|
|
|
89
96
|
`cloudgrid_share` and `cloudgrid_visibility` overlap on purpose: `cloudgrid_share`
|
|
90
97
|
wraps the CLI and defaults to `link`; `cloudgrid_visibility` is direct API, takes an
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cloudgrid-io/mcp",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.3",
|
|
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": {
|
|
@@ -16,6 +16,7 @@
|
|
|
16
16
|
"start": "node src/index.js",
|
|
17
17
|
"start:web": "node src/web.js",
|
|
18
18
|
"smoke": "node test/smoke.mjs",
|
|
19
|
+
"test:drift-guard": "node test/drift-guard.mjs",
|
|
19
20
|
"smoke:drop": "node test/smoke-drop.mjs",
|
|
20
21
|
"smoke:login": "node test/smoke-login.mjs",
|
|
21
22
|
"smoke:claim": "node test/smoke-claim.mjs",
|
package/src/tools.js
CHANGED
|
@@ -75,10 +75,39 @@ function resolveCwd(cwd) {
|
|
|
75
75
|
}
|
|
76
76
|
|
|
77
77
|
// Pin the CLI version for the lazy npx fallback so behaviour is reproducible.
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
78
|
+
// MCP 0.5.2 is tested against CLI 0.10.1.
|
|
79
|
+
const CLI_NPX_PKG = "@cloudgrid-io/cli@~0.10.1";
|
|
80
|
+
|
|
81
|
+
// Minimum CLI version that supports the verbs and flags the MCP passes.
|
|
82
|
+
const MIN_CLI_VERSION = "0.10.1";
|
|
83
|
+
|
|
84
|
+
// Verb map for the drift guard: each CLI-wrapping tool's top-level verb(s).
|
|
85
|
+
// The drift-guard test imports this and asserts every verb exists in `cloudgrid --help`.
|
|
86
|
+
export const CLI_TOOL_VERBS = {
|
|
87
|
+
cloudgrid_init: ["init"],
|
|
88
|
+
cloudgrid_plug: ["plug"],
|
|
89
|
+
cloudgrid_logs: ["logs"],
|
|
90
|
+
cloudgrid_share: ["visibility"],
|
|
91
|
+
cloudgrid_feedback: ["feedback"],
|
|
92
|
+
cloudgrid_whoami: ["whoami"],
|
|
93
|
+
cloudgrid_use: ["use"],
|
|
94
|
+
cloudgrid_logout: ["logout"],
|
|
95
|
+
cloudgrid_status: ["status"],
|
|
96
|
+
cloudgrid_info: ["info"],
|
|
97
|
+
cloudgrid_get: ["get"],
|
|
98
|
+
cloudgrid_describe_grid: ["describe"],
|
|
99
|
+
cloudgrid_pickup: ["pickup"],
|
|
100
|
+
cloudgrid_rename: ["rename"],
|
|
101
|
+
cloudgrid_unplug: ["unplug"],
|
|
102
|
+
cloudgrid_delete: ["delete"],
|
|
103
|
+
cloudgrid_rollback: ["rollback"],
|
|
104
|
+
cloudgrid_versions: ["versions"],
|
|
105
|
+
cloudgrid_env: ["env"],
|
|
106
|
+
cloudgrid_secrets: ["secrets"],
|
|
107
|
+
cloudgrid_scaffold: ["scaffold"],
|
|
108
|
+
cloudgrid_doctor: ["doctor"],
|
|
109
|
+
cloudgrid_open: ["open"],
|
|
110
|
+
};
|
|
82
111
|
|
|
83
112
|
// Simple semver comparison: true when `version` >= MIN_CLI_VERSION.
|
|
84
113
|
function meetsMinVersion(version) {
|
|
@@ -1006,7 +1035,7 @@ export function registerTools(server, ctx) {
|
|
|
1006
1035
|
"Set an entity's visibility and print its URL. Defaults to link (anyone with the URL). Wraps `cloudgrid visibility set`.",
|
|
1007
1036
|
{
|
|
1008
1037
|
name: z.string().describe("Entity slug."),
|
|
1009
|
-
mode: z.enum(["link", "private", "authenticated", "
|
|
1038
|
+
mode: z.enum(["link", "private", "authenticated", "grid"]).optional().describe("Visibility mode. Default link."),
|
|
1010
1039
|
},
|
|
1011
1040
|
{ readOnlyHint: false, destructiveHint: false, openWorldHint: true },
|
|
1012
1041
|
cliTool(({ name, mode }) => ["visibility", "set", name, mode ?? "link"]),
|
|
@@ -1030,23 +1059,6 @@ export function registerTools(server, ctx) {
|
|
|
1030
1059
|
}),
|
|
1031
1060
|
);
|
|
1032
1061
|
|
|
1033
|
-
server.tool(
|
|
1034
|
-
"cloudgrid_brain",
|
|
1035
|
-
"Re-run an entity's Grid Brain hooks to re-classify its description, tags, and diagram. Wraps `cloudgrid brain refresh`.",
|
|
1036
|
-
{
|
|
1037
|
-
name: z.string().describe("Entity slug."),
|
|
1038
|
-
wait: z.boolean().optional().describe("Wait for the refresh to finish. Default true."),
|
|
1039
|
-
org: z.string().optional().describe("Target an entity in another org."),
|
|
1040
|
-
},
|
|
1041
|
-
{ readOnlyHint: false, destructiveHint: false, openWorldHint: true },
|
|
1042
|
-
cliTool(({ name, wait, org }) => {
|
|
1043
|
-
const args = ["brain", "refresh", name];
|
|
1044
|
-
if (wait !== false) args.push("--wait");
|
|
1045
|
-
if (org) args.push("--org", org);
|
|
1046
|
-
return args;
|
|
1047
|
-
}),
|
|
1048
|
-
);
|
|
1049
|
-
|
|
1050
1062
|
// ── New CLI-wrapping tools (local edition only) ───────────────────────────
|
|
1051
1063
|
|
|
1052
1064
|
server.tool(
|
|
@@ -1093,36 +1105,77 @@ export function registerTools(server, ctx) {
|
|
|
1093
1105
|
}),
|
|
1094
1106
|
);
|
|
1095
1107
|
|
|
1108
|
+
// cloudgrid_get is the single canonical lister for grids, entities, and spaces
|
|
1109
|
+
// (wraps `cloudgrid get <resource> --json`). It replaces the former
|
|
1110
|
+
// cloudgrid_grid (which wrapped only `get entities`) — retired here so there is
|
|
1111
|
+
// exactly one way to list entities. resource="entities" reproduces the old
|
|
1112
|
+
// cloudgrid_grid behaviour with `grid` mapping to the CLI's `--grid` flag.
|
|
1096
1113
|
server.tool(
|
|
1097
|
-
"
|
|
1098
|
-
"List
|
|
1114
|
+
"cloudgrid_get",
|
|
1115
|
+
"List CloudGrid grids, entities, or spaces. Wraps `cloudgrid get <grids|entities|spaces> --json`.",
|
|
1099
1116
|
{
|
|
1100
|
-
|
|
1101
|
-
|
|
1117
|
+
resource: z.enum(["grids", "entities", "spaces"]).describe("What to list: grids, entities, or spaces."),
|
|
1118
|
+
grid: z.string().optional().describe("Grid slug (entities/spaces only). Omit for the active grid."),
|
|
1119
|
+
kind: z.enum(["app", "agent", "inspiration"]).optional().describe("Filter by kind (entities only)."),
|
|
1120
|
+
status: z.enum(["charged", "live", "dark", "archived"]).optional().describe("Filter by status (entities only)."),
|
|
1121
|
+
space: z.string().optional().describe("Only entities scoped to this space slug (entities only)."),
|
|
1122
|
+
archived: z.boolean().optional().describe("Include archived entities (entities only)."),
|
|
1102
1123
|
},
|
|
1103
1124
|
{ readOnlyHint: true, destructiveHint: false, openWorldHint: true },
|
|
1104
|
-
cliTool(({
|
|
1105
|
-
const args = ["
|
|
1106
|
-
|
|
1107
|
-
if (
|
|
1125
|
+
cliTool(({ resource, grid, kind, status, space, archived }) => {
|
|
1126
|
+
const args = ["get", resource];
|
|
1127
|
+
// --grid applies to entities and spaces; grids has no such flag.
|
|
1128
|
+
if (grid && resource !== "grids") args.push("--grid", grid);
|
|
1129
|
+
if (resource === "entities") {
|
|
1130
|
+
if (kind) args.push("--kind", kind);
|
|
1131
|
+
if (status) args.push("--status", status);
|
|
1132
|
+
if (space) args.push("--space", space);
|
|
1133
|
+
if (archived) args.push("--archived");
|
|
1134
|
+
}
|
|
1135
|
+
args.push("--json");
|
|
1108
1136
|
return args;
|
|
1109
1137
|
}),
|
|
1110
1138
|
);
|
|
1111
1139
|
|
|
1112
1140
|
server.tool(
|
|
1113
|
-
"
|
|
1114
|
-
"
|
|
1115
|
-
{
|
|
1141
|
+
"cloudgrid_describe_grid",
|
|
1142
|
+
"Show a grid's detail: role, members, spaces, tier, wildcard-TLS state. Wraps `cloudgrid describe grid <slug> --json`.",
|
|
1143
|
+
{ grid: z.string().describe("Grid slug to describe.") },
|
|
1116
1144
|
{ readOnlyHint: true, destructiveHint: false, openWorldHint: true },
|
|
1117
|
-
cliTool(({
|
|
1145
|
+
cliTool(({ grid }) => ["describe", "grid", grid, "--json"]),
|
|
1146
|
+
);
|
|
1147
|
+
|
|
1148
|
+
server.tool(
|
|
1149
|
+
"cloudgrid_pickup",
|
|
1150
|
+
"Download an entity's source + cloudgrid.yaml and link the folder to it. Overwrites with --force. Wraps `cloudgrid pickup`.",
|
|
1151
|
+
{
|
|
1152
|
+
name: z.string().describe("Entity slug or id to pick up."),
|
|
1153
|
+
target_dir: z.string().optional().describe("Directory to pick up into (relative to cwd). Defaults to the entity name."),
|
|
1154
|
+
grid: z.string().optional().describe("Grid to resolve the entity in. Defaults to the active grid."),
|
|
1155
|
+
version: z.string().optional().describe("Pick up an older version's source instead of HEAD."),
|
|
1156
|
+
force: z.boolean().optional().describe("Pick up into a non-empty directory."),
|
|
1157
|
+
no_bind: z.boolean().optional().describe("Download source only — skip cloudgrid.yaml and the link."),
|
|
1158
|
+
cwd: z.string().optional().describe("Working directory the CLI runs in. The download lands here; pass an explicit, writable directory."),
|
|
1159
|
+
},
|
|
1160
|
+
{ readOnlyHint: false, destructiveHint: true, openWorldHint: true },
|
|
1161
|
+
cliTool(({ name, target_dir, grid, version, force, no_bind }) => {
|
|
1162
|
+
const args = ["pickup", name];
|
|
1163
|
+
if (target_dir) args.push(target_dir);
|
|
1164
|
+
// The CLI's pickup --help exposes `--org <slug>` (legacy naming) for the grid.
|
|
1165
|
+
if (grid) args.push("--org", grid);
|
|
1166
|
+
if (version) args.push("--version", version);
|
|
1167
|
+
if (force) args.push("--force");
|
|
1168
|
+
if (no_bind) args.push("--no-bind");
|
|
1169
|
+
return args;
|
|
1170
|
+
}, { cwdParam: true }),
|
|
1118
1171
|
);
|
|
1119
1172
|
|
|
1120
1173
|
server.tool(
|
|
1121
1174
|
"cloudgrid_rename",
|
|
1122
|
-
"Rename a CloudGrid entity. Wraps `cloudgrid rename`.",
|
|
1175
|
+
"Rename a CloudGrid entity's display name (slug stays the same). Wraps `cloudgrid rename`.",
|
|
1123
1176
|
{
|
|
1124
|
-
name: z.string().describe("
|
|
1125
|
-
new_name: z.string().describe("New
|
|
1177
|
+
name: z.string().describe("Entity slug."),
|
|
1178
|
+
new_name: z.string().describe("New display name."),
|
|
1126
1179
|
},
|
|
1127
1180
|
{ readOnlyHint: false, destructiveHint: false, openWorldHint: true },
|
|
1128
1181
|
cliTool(({ name, new_name }) => ["rename", name, new_name]),
|
|
@@ -1141,13 +1194,13 @@ export function registerTools(server, ctx) {
|
|
|
1141
1194
|
|
|
1142
1195
|
server.tool(
|
|
1143
1196
|
"cloudgrid_delete",
|
|
1144
|
-
"Archive
|
|
1197
|
+
"Archive a CloudGrid inspiration. Destructive. Wraps `cloudgrid delete entity`.",
|
|
1145
1198
|
{
|
|
1146
1199
|
name: z.string().describe("Entity slug to delete (required)."),
|
|
1147
1200
|
confirm: z.literal(true).describe("Must be true to proceed."),
|
|
1148
1201
|
},
|
|
1149
1202
|
{ readOnlyHint: false, destructiveHint: true, openWorldHint: true },
|
|
1150
|
-
cliTool(({ name }) => ["delete", name, "--yes"]),
|
|
1203
|
+
cliTool(({ name }) => ["delete", "entity", name, "--yes"]),
|
|
1151
1204
|
);
|
|
1152
1205
|
|
|
1153
1206
|
server.tool(
|
|
@@ -1159,7 +1212,7 @@ export function registerTools(server, ctx) {
|
|
|
1159
1212
|
},
|
|
1160
1213
|
{ readOnlyHint: false, destructiveHint: false, openWorldHint: true },
|
|
1161
1214
|
cliTool(({ name, to }) => {
|
|
1162
|
-
const args = ["rollback", name];
|
|
1215
|
+
const args = ["rollback", name, "--yes"];
|
|
1163
1216
|
if (to) args.push("--to", to);
|
|
1164
1217
|
return args;
|
|
1165
1218
|
}),
|
|
@@ -1215,7 +1268,7 @@ export function registerTools(server, ctx) {
|
|
|
1215
1268
|
cliTool(({ action, name, key, value }) => {
|
|
1216
1269
|
if (action === "set") {
|
|
1217
1270
|
if (!key || value === undefined) throw new Error("key and value are required for set");
|
|
1218
|
-
return ["secrets", "set", name, key
|
|
1271
|
+
return ["secrets", "set", name, `${key}=${value}`];
|
|
1219
1272
|
}
|
|
1220
1273
|
return ["secrets", "list", name];
|
|
1221
1274
|
}, { cwdParam: true }),
|
|
@@ -1223,19 +1276,12 @@ export function registerTools(server, ctx) {
|
|
|
1223
1276
|
|
|
1224
1277
|
server.tool(
|
|
1225
1278
|
"cloudgrid_scaffold",
|
|
1226
|
-
"
|
|
1279
|
+
"Scaffold service folders declared in cloudgrid.yaml (idempotent). Wraps `cloudgrid scaffold`.",
|
|
1227
1280
|
{
|
|
1228
|
-
template: z.string().optional().describe("Template name."),
|
|
1229
|
-
dir: z.string().optional().describe("Target directory."),
|
|
1230
1281
|
cwd: z.string().optional().describe("Working directory. The CLI runs in this directory. Defaults to the MCP server's working directory."),
|
|
1231
1282
|
},
|
|
1232
1283
|
{ readOnlyHint: false, destructiveHint: false, openWorldHint: true },
|
|
1233
|
-
cliTool((
|
|
1234
|
-
const args = ["scaffold"];
|
|
1235
|
-
if (template) args.push(template);
|
|
1236
|
-
if (dir) args.push("--dir", dir);
|
|
1237
|
-
return args;
|
|
1238
|
-
}, { cwdParam: true }),
|
|
1284
|
+
cliTool(() => ["scaffold"], { cwdParam: true }),
|
|
1239
1285
|
);
|
|
1240
1286
|
|
|
1241
1287
|
server.tool(
|
|
@@ -1248,11 +1294,11 @@ export function registerTools(server, ctx) {
|
|
|
1248
1294
|
|
|
1249
1295
|
server.tool(
|
|
1250
1296
|
"cloudgrid_open",
|
|
1251
|
-
"Return the public URL for an entity. Does not open a browser. Wraps `cloudgrid open --
|
|
1297
|
+
"Return the public URL for an entity. Does not open a browser. Wraps `cloudgrid open --print`.",
|
|
1252
1298
|
{ name: z.string().optional().describe("Entity name. Omit for the entity linked to the current directory.") },
|
|
1253
1299
|
{ readOnlyHint: true, destructiveHint: false, openWorldHint: true },
|
|
1254
1300
|
cliTool(({ name }) => {
|
|
1255
|
-
const args = ["open", "--
|
|
1301
|
+
const args = ["open", "--print"];
|
|
1256
1302
|
if (name) args.push(name);
|
|
1257
1303
|
return args;
|
|
1258
1304
|
}),
|