@wrongstack/mcp 0.318.0 → 0.319.1

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/dist/index.js +38 -5
  2. package/package.json +2 -2
package/dist/index.js CHANGED
@@ -817,10 +817,11 @@ function boundedServerName(value) {
817
817
 
818
818
  // src/client.ts
819
819
  import { spawn as spawn2 } from "node:child_process";
820
- import { buildChildEnv, buildWin32CmdShimInvocation, toErrorMessage } from "@wrongstack/core/utils";
820
+ import { buildChildEnv as buildChildEnv2, buildWin32CmdShimInvocation, toErrorMessage } from "@wrongstack/core/utils";
821
821
 
822
822
  // src/client-process.ts
823
823
  import { spawn } from "node:child_process";
824
+ import { buildChildEnv } from "@wrongstack/core/utils";
824
825
  function forceKillTree(child) {
825
826
  if (child.pid === void 0) {
826
827
  try {
@@ -832,6 +833,9 @@ function forceKillTree(child) {
832
833
  if (process.platform === "win32") {
833
834
  const killer = spawn("taskkill", ["/pid", String(child.pid), "/T", "/F"], {
834
835
  stdio: "ignore",
836
+ // H-8 convention (spawn-convention test): taskkill needs PATH only —
837
+ // do not hand it the credential-bearing parent environment.
838
+ env: buildChildEnv(),
835
839
  windowsHide: true
836
840
  });
837
841
  killer.once("error", () => {
@@ -2284,7 +2288,7 @@ var MCPClient = class _MCPClient {
2284
2288
  }
2285
2289
  const isWin = process.platform === "win32";
2286
2290
  const rawArgs = this.opts.args ?? [];
2287
- const spawnEnv = buildChildEnv({ extra: extraEnv });
2291
+ const spawnEnv = buildChildEnv2({ extra: extraEnv });
2288
2292
  const stdio = ["pipe", "pipe", "pipe"];
2289
2293
  const child = isWin ? (() => {
2290
2294
  const shim = buildWin32CmdShimInvocation(this.opts.command, rawArgs);
@@ -3036,6 +3040,11 @@ async function persist(configPath, full, servers) {
3036
3040
  full.mcpServers = servers;
3037
3041
  await writeConfig(configPath, full);
3038
3042
  }
3043
+ var UNSAFE_SERVER_NAMES = /* @__PURE__ */ new Set(["__proto__", "constructor", "prototype"]);
3044
+ function unsafeServerNameResult(name) {
3045
+ if (!UNSAFE_SERVER_NAMES.has(name)) return void 0;
3046
+ return { ok: false, message: `Invalid server name "${name}"` };
3047
+ }
3039
3048
  function normalizeTransport(t) {
3040
3049
  if (t === "sse") return "sse";
3041
3050
  if (t === "http" || t === "streamable-http") return "streamable-http";
@@ -3124,11 +3133,13 @@ async function listMcp(deps) {
3124
3133
  }
3125
3134
  async function addMcp(input, deps) {
3126
3135
  if (!input.name) return { ok: false, message: "Server name is required" };
3136
+ const unsafe = unsafeServerNameResult(input.name);
3137
+ if (unsafe) return unsafe;
3127
3138
  const { full, servers } = await readServers(deps.configPath);
3128
- if (servers[input.name]) {
3139
+ if (Object.hasOwn(servers, input.name)) {
3129
3140
  return { ok: false, message: `Server "${input.name}" already exists` };
3130
3141
  }
3131
- const preset = deps.presets?.[input.name];
3142
+ const preset = deps.presets && Object.hasOwn(deps.presets, input.name) ? deps.presets[input.name] : void 0;
3132
3143
  const hasExplicitConfig = !!(input.transport || input.command || input.url);
3133
3144
  const cfg = hasExplicitConfig ? buildConfig(input, preset) : preset ? buildConfig({ ...input, name: input.name }, preset) : buildConfig(input);
3134
3145
  if (!hasExplicitConfig && !preset) {
@@ -3153,7 +3164,12 @@ async function addMcp(input, deps) {
3153
3164
  }
3154
3165
  async function updateMcp(input, deps) {
3155
3166
  if (!input.name) return { ok: false, message: "Server name is required" };
3167
+ const unsafe = unsafeServerNameResult(input.name);
3168
+ if (unsafe) return unsafe;
3156
3169
  const { full, servers } = await readServers(deps.configPath);
3170
+ if (!Object.hasOwn(servers, input.name)) {
3171
+ return { ok: false, message: `Server "${input.name}" not found` };
3172
+ }
3157
3173
  const existing = servers[input.name];
3158
3174
  if (!existing) return { ok: false, message: `Server "${input.name}" not found` };
3159
3175
  const cfg = buildConfig(input, { ...existing, name: input.name });
@@ -3172,8 +3188,10 @@ async function updateMcp(input, deps) {
3172
3188
  }
3173
3189
  async function removeMcp(name, deps) {
3174
3190
  if (!name) return { ok: false, message: "Server name is required" };
3191
+ const unsafe = unsafeServerNameResult(name);
3192
+ if (unsafe) return unsafe;
3175
3193
  const { full, servers } = await readServers(deps.configPath);
3176
- if (!servers[name]) return { ok: false, message: `Server "${name}" not found` };
3194
+ if (!Object.hasOwn(servers, name)) return { ok: false, message: `Server "${name}" not found` };
3177
3195
  await safeStop(name, deps);
3178
3196
  forgetRegistryState(deps.registry, name);
3179
3197
  delete servers[name];
@@ -3182,7 +3200,12 @@ async function removeMcp(name, deps) {
3182
3200
  }
3183
3201
  async function enableMcp(name, deps) {
3184
3202
  if (!name) return { ok: false, message: "Server name is required" };
3203
+ const unsafe = unsafeServerNameResult(name);
3204
+ if (unsafe) return unsafe;
3185
3205
  const { full, servers } = await readServers(deps.configPath);
3206
+ if (!Object.hasOwn(servers, name)) {
3207
+ return { ok: false, message: `Server "${name}" is not in config. Add it first.` };
3208
+ }
3186
3209
  const cfg = servers[name];
3187
3210
  if (!cfg) {
3188
3211
  return { ok: false, message: `Server "${name}" is not in config. Add it first.` };
@@ -3194,7 +3217,12 @@ async function enableMcp(name, deps) {
3194
3217
  }
3195
3218
  async function disableMcp(name, deps) {
3196
3219
  if (!name) return { ok: false, message: "Server name is required" };
3220
+ const unsafe = unsafeServerNameResult(name);
3221
+ if (unsafe) return unsafe;
3197
3222
  const { full, servers } = await readServers(deps.configPath);
3223
+ if (!Object.hasOwn(servers, name)) {
3224
+ return { ok: false, message: `Server "${name}" is not in config.` };
3225
+ }
3198
3226
  const cfg = servers[name];
3199
3227
  if (!cfg) return { ok: false, message: `Server "${name}" is not in config.` };
3200
3228
  await safeStop(name, deps);
@@ -3210,6 +3238,8 @@ async function disableMcp(name, deps) {
3210
3238
  }
3211
3239
  async function restartMcp(name, deps) {
3212
3240
  if (!name) return { ok: false, message: "Server name is required" };
3241
+ const unsafe = unsafeServerNameResult(name);
3242
+ if (unsafe) return unsafe;
3213
3243
  const registered = deps.registry.list().some((s) => s.name === name);
3214
3244
  if (registered) {
3215
3245
  try {
@@ -3221,6 +3251,9 @@ async function restartMcp(name, deps) {
3221
3251
  }
3222
3252
  }
3223
3253
  const { servers } = await readServers(deps.configPath);
3254
+ if (!Object.hasOwn(servers, name)) {
3255
+ return { ok: false, message: `Server "${name}" is not in config.` };
3256
+ }
3224
3257
  const cfg = servers[name];
3225
3258
  if (!cfg) return { ok: false, message: `Server "${name}" is not in config.` };
3226
3259
  return startServer(name, { ...cfg, name }, deps, `Server "${name}" started`, { restart: true });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wrongstack/mcp",
3
- "version": "0.318.0",
3
+ "version": "0.319.1",
4
4
  "license": "MIT",
5
5
  "description": "WrongStack Model Context Protocol client and registry: stdio, SSE, and streamable HTTP transports.",
6
6
  "repository": {
@@ -26,7 +26,7 @@
26
26
  "!dist/**/*.map"
27
27
  ],
28
28
  "dependencies": {
29
- "@wrongstack/core": "0.318.0"
29
+ "@wrongstack/core": "0.319.1"
30
30
  },
31
31
  "devDependencies": {
32
32
  "@types/node": "^26.2.0",