@justanothermldude/mcp-exec 1.7.3 → 1.7.5

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.
@@ -177,8 +177,14 @@ function generateInterface(name, schema, definitions) {
177
177
  */
178
178
  function sanitizeJsDoc(text) {
179
179
  // Escape */ to prevent premature JSDoc comment closure
180
- // This handles glob patterns like "src/**/*.ts" in tool descriptions
181
- return text.replace(/\*\//g, '* /');
180
+ // (handles glob patterns like "src/**/*.ts" in tool descriptions)
181
+ let sanitized = text.replace(/\*\//g, '* /');
182
+ // Collapse newlines to prevent line-injection into JSDoc blocks
183
+ sanitized = sanitized.replace(/\r?\n/g, ' ');
184
+ // Escape @ at word boundaries to prevent JSDoc tag injection from a
185
+ // malicious tool description (e.g. "@param input.password string").
186
+ sanitized = sanitized.replace(/(?:^|\s)@([a-zA-Z_]\w*)/g, ' \\@$1');
187
+ return sanitized;
182
188
  }
183
189
  /**
184
190
  * Generate a recursive Proxy guard that warns on undefined field access on MCP responses.
@@ -203,14 +209,18 @@ function __guardFields(obj, label) {
203
209
  }
204
210
  });
205
211
  }
212
+ const __safeKeys = new Set(['then', 'toJSON', 'length', 'constructor', 'nodeType', 'valueOf', 'toString', 'inspect']);
213
+ const __dangerousKeys = new Set(['__proto__', '__defineGetter__', '__defineSetter__', '__lookupGetter__', '__lookupSetter__', 'hasOwnProperty', 'isPrototypeOf', 'propertyIsEnumerable', 'prototype']);
206
214
  return new Proxy(obj, {
207
215
  get(target, prop) {
208
- if (typeof prop === 'symbol' || prop === 'then' || prop === 'toJSON'
209
- || prop === 'length' || prop === 'constructor' || prop === 'nodeType'
210
- || prop === 'valueOf' || prop === 'toString' || prop === 'inspect') {
216
+ if (typeof prop === 'symbol') return target[prop];
217
+ const propStr = String(prop);
218
+ if (__dangerousKeys.has(propStr)) {
219
+ throw new TypeError('Access to "' + propStr + '" is not allowed on ' + label);
220
+ }
221
+ if (__safeKeys.has(propStr)) {
211
222
  return target[prop];
212
223
  }
213
- if (prop === '__proto__' || prop === 'prototype') return undefined;
214
224
  if (Object.prototype.hasOwnProperty.call(target, prop)) {
215
225
  const val = target[prop];
216
226
  if (val && typeof val === 'object') {
@@ -271,8 +281,11 @@ export function generateFuzzyProxy(targetVarName, contextName, helpString) {
271
281
  get(target, prop) {
272
282
  if (typeof prop !== 'string') return undefined;
273
283
 
274
- // Block prototype pollution vectors
275
- if (prop === '__proto__' || prop === 'constructor' || prop === 'prototype') return undefined;
284
+ // Block prototype pollution vectors with a loud error so callers cannot silently
285
+ // probe the proxy for __proto__ or prototype indirection.
286
+ if (prop === '__proto__' || prop === 'constructor' || prop === 'prototype') {
287
+ throw new TypeError('Access to "' + prop + '" is not allowed on ${safeContextName}');
288
+ }
276
289
 
277
290
  // Fast-path: exact match — use hasOwnProperty to avoid prototype chain leaks
278
291
  if (Object.prototype.hasOwnProperty.call(target, prop)) return target[prop];
package/dist/index.js CHANGED
@@ -230,7 +230,12 @@ function compactTypeHint(propSchema) {
230
230
  const keys = Object.keys(props);
231
231
  if (keys.length === 0)
232
232
  return "object";
233
- const parts = keys.map((k) => required.includes(k) ? k : k + "?");
233
+ const PRIM = /* @__PURE__ */ new Set(["string", "number", "integer", "boolean"]);
234
+ const parts = keys.map((k) => {
235
+ const sub = props[k]?.type;
236
+ const sfx = required.includes(k) ? "" : "?";
237
+ return PRIM.has(sub ?? "") ? `${k}${sfx}:${sub}` : `${k}${sfx}`;
238
+ });
234
239
  return `{${parts.join(", ")}}`;
235
240
  }
236
241
  if (type === "object") {
@@ -242,7 +247,12 @@ function compactTypeHint(propSchema) {
242
247
  const props = items.properties;
243
248
  const required = items.required || [];
244
249
  const keys = Object.keys(props);
245
- const parts = keys.map((k) => required.includes(k) ? k : k + "?");
250
+ const PRIM = /* @__PURE__ */ new Set(["string", "number", "integer", "boolean"]);
251
+ const parts = keys.map((k) => {
252
+ const sub = props[k]?.type;
253
+ const sfx = required.includes(k) ? "" : "?";
254
+ return PRIM.has(sub ?? "") ? `${k}${sfx}:${sub}` : `${k}${sfx}`;
255
+ });
246
256
  return `[{${parts.join(", ")}}]`;
247
257
  }
248
258
  return null;
@@ -488,7 +498,10 @@ function generateInterface(name, schema, definitions) {
488
498
  }
489
499
  __name(generateInterface, "generateInterface");
490
500
  function sanitizeJsDoc(text) {
491
- return text.replace(/\*\//g, "* /");
501
+ let sanitized = text.replace(/\*\//g, "* /");
502
+ sanitized = sanitized.replace(/\r?\n/g, " ");
503
+ sanitized = sanitized.replace(/(?:^|\s)@([a-zA-Z_]\w*)/g, " \\@$1");
504
+ return sanitized;
492
505
  }
493
506
  __name(sanitizeJsDoc, "sanitizeJsDoc");
494
507
  function generateFieldGuard() {
@@ -508,14 +521,18 @@ function __guardFields(obj, label) {
508
521
  }
509
522
  });
510
523
  }
524
+ const __safeKeys = new Set(['then', 'toJSON', 'length', 'constructor', 'nodeType', 'valueOf', 'toString', 'inspect']);
525
+ const __dangerousKeys = new Set(['__proto__', '__defineGetter__', '__defineSetter__', '__lookupGetter__', '__lookupSetter__', 'hasOwnProperty', 'isPrototypeOf', 'propertyIsEnumerable', 'prototype']);
511
526
  return new Proxy(obj, {
512
527
  get(target, prop) {
513
- if (typeof prop === 'symbol' || prop === 'then' || prop === 'toJSON'
514
- || prop === 'length' || prop === 'constructor' || prop === 'nodeType'
515
- || prop === 'valueOf' || prop === 'toString' || prop === 'inspect') {
528
+ if (typeof prop === 'symbol') return target[prop];
529
+ const propStr = String(prop);
530
+ if (__dangerousKeys.has(propStr)) {
531
+ throw new TypeError('Access to "' + propStr + '" is not allowed on ' + label);
532
+ }
533
+ if (__safeKeys.has(propStr)) {
516
534
  return target[prop];
517
535
  }
518
- if (prop === '__proto__' || prop === 'prototype') return undefined;
519
536
  if (Object.prototype.hasOwnProperty.call(target, prop)) {
520
537
  const val = target[prop];
521
538
  if (val && typeof val === 'object') {
@@ -555,8 +572,11 @@ function generateFuzzyProxy(targetVarName, contextName, helpString) {
555
572
  get(target, prop) {
556
573
  if (typeof prop !== 'string') return undefined;
557
574
 
558
- // Block prototype pollution vectors
559
- if (prop === '__proto__' || prop === 'constructor' || prop === 'prototype') return undefined;
575
+ // Block prototype pollution vectors with a loud error so callers cannot silently
576
+ // probe the proxy for __proto__ or prototype indirection.
577
+ if (prop === '__proto__' || prop === 'constructor' || prop === 'prototype') {
578
+ throw new TypeError('Access to "' + prop + '" is not allowed on ${safeContextName}');
579
+ }
560
580
 
561
581
  // Fast-path: exact match \u2014 use hasOwnProperty to avoid prototype chain leaks
562
582
  if (Object.prototype.hasOwnProperty.call(target, prop)) return target[prop];
@@ -1981,7 +2001,7 @@ __name(createMcpExecServer, "createMcpExecServer");
1981
2001
  // dist/index.js
1982
2002
  import { ServerPool, createConnection, getServerConfig as getServerConfig2, loadServerManifest as loadServerManifest2, cleanupOrphanedProcesses } from "@justanothermldude/meta-mcp-core";
1983
2003
  var APP_NAME = "mcp-exec";
1984
- var VERSION2 = "1.7.3";
2004
+ var VERSION2 = "1.7.4";
1985
2005
  var defaultExecutor = null;
1986
2006
  function getDefaultExecutor() {
1987
2007
  if (!defaultExecutor) {
@@ -44,7 +44,12 @@ function compactTypeHint(propSchema) {
44
44
  const keys = Object.keys(props);
45
45
  if (keys.length === 0)
46
46
  return 'object';
47
- const parts = keys.map(k => required.includes(k) ? k : k + '?');
47
+ const PRIM = new Set(['string', 'number', 'integer', 'boolean']);
48
+ const parts = keys.map(k => {
49
+ const sub = props[k]?.type;
50
+ const sfx = required.includes(k) ? '' : '?';
51
+ return PRIM.has(sub ?? '') ? `${k}${sfx}:${sub}` : `${k}${sfx}`;
52
+ });
48
53
  return `{${parts.join(', ')}}`;
49
54
  }
50
55
  // Freeform object — AI must call get_mcp_tool_schema before using
@@ -58,7 +63,12 @@ function compactTypeHint(propSchema) {
58
63
  const props = items.properties;
59
64
  const required = items.required || [];
60
65
  const keys = Object.keys(props);
61
- const parts = keys.map(k => required.includes(k) ? k : k + '?');
66
+ const PRIM = new Set(['string', 'number', 'integer', 'boolean']);
67
+ const parts = keys.map(k => {
68
+ const sub = props[k]?.type;
69
+ const sfx = required.includes(k) ? '' : '?';
70
+ return PRIM.has(sub ?? '') ? `${k}${sfx}:${sub}` : `${k}${sfx}`;
71
+ });
62
72
  return `[{${parts.join(', ')}}]`;
63
73
  }
64
74
  // Simple typed arrays (string[], number[]) — usually obvious
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@justanothermldude/mcp-exec",
3
- "version": "1.7.3",
3
+ "version": "1.7.5",
4
4
  "description": "MCP execution utilities for sandboxed code execution with OS-level isolation",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",