@cloudgrid-io/mcp 0.21.21 → 0.21.22

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.21.21",
3
+ "version": "0.21.22",
4
4
  "description": "MCP access to CloudGrid — the live runtime environment where the user's apps run WITH the infrastructure they need out of the box: managed MongoDB, Redis (cache/queues/pub-sub), a pgvector store, persistent disk, and built-in AI with no API keys, in any language or stack, no Docker or Kubernetes to manage. Brainstorm, build, plug, and improve apps, games, dashboards, and tools; instant single-page publishes and full runtime-app deploys with a live URL — for developers and non-technical users. Three editions: local stdio (full toolset), hosted web (light, CLI-free), and a public docs-search server.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -52,6 +52,7 @@
52
52
  "test:oauth-gate": "node test/oauth-gate.test.mjs",
53
53
  "test:index-favicon": "node test/index-favicon.test.mjs",
54
54
  "test:auth": "node test/auth.test.mjs",
55
+ "test:tools-list-contract": "node test/tools-list-contract.test.mjs",
55
56
  "test:auth-strictness": "node test/auth-strictness.test.mjs",
56
57
  "test:win-cli": "node test/windows-cli-resolution.test.mjs",
57
58
  "test:electron-env": "node test/electron-spawn-env.test.mjs",
@@ -92,7 +93,7 @@
92
93
  "@modelcontextprotocol/sdk": "^1.32.1",
93
94
  "express": "^5.3.0",
94
95
  "fflate": "^0.8.3",
95
- "undici": "^8.11.2",
96
+ "undici": "^8.12.2",
96
97
  "zod": "^3.23.0"
97
98
  },
98
99
  "devDependencies": {
@@ -84,6 +84,20 @@ const AUTH_ASK_SIGNED_OUT =
84
84
  "(assistant: call grid_login now; after they finish, retry grid_plug. Do not offer " +
85
85
  "any sign-in-free path. Stop and wait for the sign-in to complete.)";
86
86
 
87
+ // ── Strict tool inputs (#400) ──────────────────────────────────────────────
88
+ // Every tool's input is a z.strictObject, so `tools/list` advertises
89
+ // `additionalProperties: false` under zod 3 AND zod 4. The SDK renders a tool
90
+ // input in zod 4's "input" mode, where a plain z.object (which strips unknown
91
+ // keys rather than rejecting them) gets no `additionalProperties` at all; only a
92
+ // strict object keeps `false`. A raw shape is wrapped here; an empty shape is
93
+ // left alone (the SDK advertises it as `{type: "object", properties: {}}`, as
94
+ // before). Objects nested inside an input use z.strictObject at their own site.
95
+ // test/tools-list-contract.test.mjs holds the emitted contract.
96
+ export function strictInput(schema) {
97
+ if (!schema || typeof schema !== "object" || schema._def || schema._zod) return schema;
98
+ return Object.keys(schema).length > 0 ? z.strictObject(schema) : schema;
99
+ }
100
+
87
101
  // ── Registration ───────────────────────────────────────────────────────────────
88
102
  // Registers the tools onto `server`. ctx.edition decides whether the CLI-wrapping
89
103
  // tools are included (they need a local machine).
@@ -122,11 +136,11 @@ export function registerTools(server, ctx) {
122
136
  // grid_copy_app, grid_claim_anonymous_deploy, grid_download_source,
123
137
  // grid_fetch, grid_logs) are gone rather than advertised as redirects.
124
138
  const reg = (name, config, handler) => {
125
- server.registerTool(name, config, withCapture(name, handler));
139
+ server.registerTool(name, { ...config, inputSchema: strictInput(config.inputSchema) }, withCapture(name, handler));
126
140
  };
127
141
 
128
142
  const regTool = (name, title, description, schema, annotations, handler) => {
129
- server.registerTool(name, { title, description, inputSchema: schema, annotations }, withCapture(name, handler));
143
+ server.registerTool(name, { title, description, inputSchema: strictInput(schema), annotations }, withCapture(name, handler));
130
144
  };
131
145
 
132
146
  // ── Widget resources (web edition, ChatGPT Apps SDK) ──────────────────────
@@ -384,7 +398,7 @@ export function registerTools(server, ctx) {
384
398
  "over the archive's files (generate the page, let the zip supply the images).",
385
399
  ),
386
400
  }),
387
- artifact_files: z.array(z.object({
401
+ artifact_files: z.array(z.strictObject({
388
402
  path: z.string().describe("Repo-relative path, e.g. index.html or services/web/index.js."),
389
403
  content: z.string().describe("File content. Base64 when encoding is base64, otherwise UTF-8 text."),
390
404
  encoding: z.enum(["utf8", "base64"]).optional().describe("Content encoding. Default utf8."),
@@ -427,7 +441,7 @@ export function registerTools(server, ctx) {
427
441
  "the pickup contract, so no `grid` param is needed. target_entity_id and grid+slug take precedence. A " +
428
442
  "non-CloudGrid host is ignored (never redirects the write); a URL that does not resolve is treated as a CREATE.",
429
443
  ),
430
- hints: z.object({
444
+ hints: z.strictObject({
431
445
  kind: z.enum(["inspiration", "app", "agent"]).optional().describe("Force the detected kind; omit to let the server auto-detect."),
432
446
  yaml: z.string().optional().describe("An inline cloudgrid.yaml override used as a detection hint."),
433
447
  }).optional().describe("Classification hints for the CREATE path (not entity targeting — that's target_entity_id)."),
@@ -1104,7 +1118,7 @@ export function registerTools(server, ctx) {
1104
1118
  .string()
1105
1119
  .describe("Short summary of what failed (required). Do not paste the whole conversation here."),
1106
1120
  context: z
1107
- .object({
1121
+ .strictObject({
1108
1122
  tool: z.string().optional().describe("The CloudGrid tool that failed, e.g. grid_plug."),
1109
1123
  inputs: z.any().optional().describe("The failing inputs (e.g. the HTML/args). Keep it minimal and do NOT include secrets — a secret embedded in a value here is not redacted."),
1110
1124
  grid: z.string().optional().describe("The grid/org slug involved, if any."),