@cloudgrid-io/mcp 0.4.2 → 0.4.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.
Files changed (2) hide show
  1. package/package.json +1 -1
  2. package/src/tools.js +44 -15
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cloudgrid-io/mcp",
3
- "version": "0.4.2",
3
+ "version": "0.4.3",
4
4
  "description": "MCP server for CloudGrid. Two editions: a local stdio server (full toolset) and a hosted web server (light, CLI-free toolset) over MCP Streamable HTTP.",
5
5
  "type": "module",
6
6
  "bin": {
package/src/tools.js CHANGED
@@ -11,8 +11,8 @@
11
11
  import { execFile } from "node:child_process";
12
12
  import { promisify } from "node:util";
13
13
  import { readFile } from "node:fs/promises";
14
- import { readFileSync } from "node:fs";
15
- import { basename } from "node:path";
14
+ import { readFileSync, existsSync, statSync } from "node:fs";
15
+ import { basename, resolve } from "node:path";
16
16
  import { z } from "zod";
17
17
  import { newLoginCode, buildLoginUrl, pollStatusOnce, decodeJwt } from "./auth.js";
18
18
 
@@ -59,11 +59,29 @@ function okResult({ text, structured, meta }) {
59
59
  }
60
60
 
61
61
  // ── CLI wrapping (local edition only) ──────────────────────────────────────────
62
- async function runCloudgrid(args) {
62
+
63
+ // Resolve and validate a caller-supplied working directory. Returns the resolved
64
+ // absolute path, or process.cwd() when omitted.
65
+ function resolveCwd(cwd) {
66
+ if (cwd === undefined || cwd === null || cwd === "") return undefined; // let execFile default
67
+ const abs = resolve(cwd);
68
+ if (!existsSync(abs)) {
69
+ throw new Error(`Directory does not exist: ${abs}`);
70
+ }
71
+ if (!statSync(abs).isDirectory()) {
72
+ throw new Error(`Not a directory: ${abs}`);
73
+ }
74
+ return abs;
75
+ }
76
+
77
+ async function runCloudgrid(args, opts = {}) {
78
+ const cwd = resolveCwd(opts.cwd);
63
79
  try {
64
80
  const { stdout, stderr } = await execFileAsync("cloudgrid", args, {
65
81
  maxBuffer: 16 * 1024 * 1024,
66
82
  timeout: 10 * 60 * 1000,
83
+ stdio: ["ignore", "pipe", "pipe"],
84
+ ...(cwd ? { cwd } : {}),
67
85
  });
68
86
  return (stdout || stderr || "").trim() || "Done.";
69
87
  } catch (err) {
@@ -80,10 +98,16 @@ async function runCloudgrid(args) {
80
98
  }
81
99
  }
82
100
 
83
- function cliTool(buildArgs) {
101
+ function cliTool(buildArgs, { cwdParam = false } = {}) {
84
102
  return async (input) => {
85
103
  try {
86
- return ok(await runCloudgrid(buildArgs(input || {})));
104
+ const params = input || {};
105
+ const opts = {};
106
+ if (cwdParam) {
107
+ // Accept cwd, directory, or dir as the working-directory override.
108
+ opts.cwd = params.cwd ?? params.directory ?? params.dir;
109
+ }
110
+ return ok(await runCloudgrid(buildArgs(params), opts));
87
111
  } catch (err) {
88
112
  return fail(err.message);
89
113
  }
@@ -774,6 +798,7 @@ export function registerTools(server, ctx) {
774
798
  description: z.string().optional().describe("Initial one-line description."),
775
799
  dir: z.string().optional().describe("Target directory. Defaults to ./<name>."),
776
800
  org: z.string().optional().describe("Override the active org for this init."),
801
+ cwd: z.string().optional().describe("Working directory. The CLI runs in this directory. Defaults to the MCP server's working directory."),
777
802
  },
778
803
  { readOnlyHint: false, destructiveHint: false, openWorldHint: true },
779
804
  cliTool(({ kind, name, type, description, dir, org }) => {
@@ -783,7 +808,7 @@ export function registerTools(server, ctx) {
783
808
  if (dir) args.push("--dir", dir);
784
809
  if (org) args.push("--org", org);
785
810
  return args;
786
- }),
811
+ }, { cwdParam: true }),
787
812
  );
788
813
 
789
814
  server.tool(
@@ -793,6 +818,7 @@ export function registerTools(server, ctx) {
793
818
  target: z.string().optional().describe("Path or URL. Omit to deploy the entity linked to the current directory."),
794
819
  org: z.string().optional().describe("Pick or override the org."),
795
820
  no_deploy: z.boolean().optional().describe("Register the entity but do not build or deploy."),
821
+ cwd: z.string().optional().describe("Working directory. The CLI runs in this directory. Defaults to the MCP server's working directory."),
796
822
  },
797
823
  { readOnlyHint: false, destructiveHint: false, openWorldHint: true },
798
824
  cliTool(({ target, org, no_deploy }) => {
@@ -800,9 +826,9 @@ export function registerTools(server, ctx) {
800
826
  if (target) args.push(target);
801
827
  if (org) args.push("--org", org);
802
828
  if (no_deploy) args.push("--no-deploy");
803
- args.push("--no-clipboard", "--no-notify");
829
+ args.push("--auto", "--no-clipboard", "--no-notify");
804
830
  return args;
805
- }),
831
+ }, { cwdParam: true }),
806
832
  );
807
833
 
808
834
  server.tool(
@@ -958,7 +984,7 @@ export function registerTools(server, ctx) {
958
984
  confirm: z.literal(true).describe("Must be true to proceed."),
959
985
  },
960
986
  { readOnlyHint: false, destructiveHint: true, openWorldHint: true },
961
- cliTool(({ name }) => ["unplug", name]),
987
+ cliTool(({ name }) => ["unplug", name, "--skip-confirm"]),
962
988
  );
963
989
 
964
990
  server.tool(
@@ -969,7 +995,7 @@ export function registerTools(server, ctx) {
969
995
  confirm: z.literal(true).describe("Must be true to proceed."),
970
996
  },
971
997
  { readOnlyHint: false, destructiveHint: true, openWorldHint: true },
972
- cliTool(({ name }) => ["delete", name]),
998
+ cliTool(({ name }) => ["delete", name, "--yes"]),
973
999
  );
974
1000
 
975
1001
  server.tool(
@@ -1007,19 +1033,20 @@ export function registerTools(server, ctx) {
1007
1033
  name: z.string().describe("Entity slug."),
1008
1034
  key: z.string().optional().describe("Variable name. Required for get and set."),
1009
1035
  value: z.string().optional().describe("Variable value. Required for set."),
1036
+ cwd: z.string().optional().describe("Working directory. The CLI runs in this directory. Defaults to the MCP server's working directory."),
1010
1037
  },
1011
1038
  { readOnlyHint: false, destructiveHint: false, openWorldHint: true },
1012
1039
  cliTool(({ action, name, key, value }) => {
1013
1040
  if (action === "set") {
1014
1041
  if (!key || value === undefined) throw new Error("key and value are required for set");
1015
- return ["env", "set", name, key, value];
1042
+ return ["env", "set", name, `${key}=${value}`];
1016
1043
  }
1017
1044
  if (action === "get") {
1018
1045
  if (!key) throw new Error("key is required for get");
1019
- return ["env", "get", name, key];
1046
+ return ["env", "get", key, name];
1020
1047
  }
1021
1048
  return ["env", "list", name];
1022
- }),
1049
+ }, { cwdParam: true }),
1023
1050
  );
1024
1051
 
1025
1052
  server.tool(
@@ -1030,6 +1057,7 @@ export function registerTools(server, ctx) {
1030
1057
  name: z.string().describe("Entity slug."),
1031
1058
  key: z.string().optional().describe("Secret name. Required for set."),
1032
1059
  value: z.string().optional().describe("Secret value. Required for set."),
1060
+ cwd: z.string().optional().describe("Working directory. The CLI runs in this directory. Defaults to the MCP server's working directory."),
1033
1061
  },
1034
1062
  { readOnlyHint: false, destructiveHint: false, openWorldHint: true },
1035
1063
  cliTool(({ action, name, key, value }) => {
@@ -1038,7 +1066,7 @@ export function registerTools(server, ctx) {
1038
1066
  return ["secrets", "set", name, key, value];
1039
1067
  }
1040
1068
  return ["secrets", "list", name];
1041
- }),
1069
+ }, { cwdParam: true }),
1042
1070
  );
1043
1071
 
1044
1072
  server.tool(
@@ -1047,6 +1075,7 @@ export function registerTools(server, ctx) {
1047
1075
  {
1048
1076
  template: z.string().optional().describe("Template name."),
1049
1077
  dir: z.string().optional().describe("Target directory."),
1078
+ cwd: z.string().optional().describe("Working directory. The CLI runs in this directory. Defaults to the MCP server's working directory."),
1050
1079
  },
1051
1080
  { readOnlyHint: false, destructiveHint: false, openWorldHint: true },
1052
1081
  cliTool(({ template, dir }) => {
@@ -1054,7 +1083,7 @@ export function registerTools(server, ctx) {
1054
1083
  if (template) args.push(template);
1055
1084
  if (dir) args.push("--dir", dir);
1056
1085
  return args;
1057
- }),
1086
+ }, { cwdParam: true }),
1058
1087
  );
1059
1088
 
1060
1089
  server.tool(