@probelabs/probe 0.6.0-rc208 → 0.6.0-rc210

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 (30) hide show
  1. package/bin/binaries/probe-v0.6.0-rc210-aarch64-apple-darwin.tar.gz +0 -0
  2. package/bin/binaries/probe-v0.6.0-rc210-aarch64-unknown-linux-musl.tar.gz +0 -0
  3. package/bin/binaries/probe-v0.6.0-rc210-x86_64-apple-darwin.tar.gz +0 -0
  4. package/bin/binaries/probe-v0.6.0-rc210-x86_64-pc-windows-msvc.zip +0 -0
  5. package/bin/binaries/probe-v0.6.0-rc210-x86_64-unknown-linux-musl.tar.gz +0 -0
  6. package/build/agent/ProbeAgent.d.ts +4 -2
  7. package/build/agent/ProbeAgent.js +87 -5
  8. package/build/agent/bashCommandUtils.js +98 -12
  9. package/build/agent/bashPermissions.js +207 -1
  10. package/build/agent/index.js +283 -23
  11. package/build/agent/mcp/client.js +2 -1
  12. package/build/delegate.js +11 -2
  13. package/build/tools/vercel.js +5 -2
  14. package/cjs/agent/ProbeAgent.cjs +277 -17
  15. package/cjs/index.cjs +277 -17
  16. package/index.d.ts +4 -2
  17. package/package.json +1 -1
  18. package/src/agent/ProbeAgent.d.ts +4 -2
  19. package/src/agent/ProbeAgent.js +87 -5
  20. package/src/agent/bashCommandUtils.js +98 -12
  21. package/src/agent/bashPermissions.js +207 -1
  22. package/src/agent/index.js +5 -5
  23. package/src/agent/mcp/client.js +2 -1
  24. package/src/delegate.js +11 -2
  25. package/src/tools/vercel.js +5 -2
  26. package/bin/binaries/probe-v0.6.0-rc208-aarch64-apple-darwin.tar.gz +0 -0
  27. package/bin/binaries/probe-v0.6.0-rc208-aarch64-unknown-linux-musl.tar.gz +0 -0
  28. package/bin/binaries/probe-v0.6.0-rc208-x86_64-apple-darwin.tar.gz +0 -0
  29. package/bin/binaries/probe-v0.6.0-rc208-x86_64-pc-windows-msvc.zip +0 -0
  30. package/bin/binaries/probe-v0.6.0-rc208-x86_64-unknown-linux-musl.tar.gz +0 -0
@@ -3764,7 +3764,10 @@ async function delegate({
3764
3764
  disableTools = false,
3765
3765
  searchDelegate = void 0,
3766
3766
  schema = null,
3767
- enableTasks = false
3767
+ enableTasks = false,
3768
+ enableMcp = false,
3769
+ mcpConfig = null,
3770
+ mcpConfigPath = null
3768
3771
  }) {
3769
3772
  if (!task || typeof task !== "string") {
3770
3773
  throw new Error("Task parameter is required and must be a string");
@@ -3820,8 +3823,14 @@ async function delegate({
3820
3823
  allowedTools,
3821
3824
  disableTools,
3822
3825
  searchDelegate,
3823
- enableTasks
3826
+ enableTasks,
3824
3827
  // Inherit from parent (subagent gets isolated TaskManager)
3828
+ enableMcp,
3829
+ // Inherit from parent (subagent creates own MCPXmlBridge)
3830
+ mcpConfig,
3831
+ // Inherit from parent
3832
+ mcpConfigPath
3833
+ // Inherit from parent
3825
3834
  });
3826
3835
  if (debug) {
3827
3836
  console.error(`[DELEGATE] Created subagent with session ${sessionId}`);
@@ -9791,7 +9800,7 @@ var init_vercel = __esm({
9791
9800
  });
9792
9801
  };
9793
9802
  delegateTool = (options = {}) => {
9794
- const { debug = false, timeout = 300, cwd, allowedFolders, enableBash = false, bashConfig, architectureFileName } = options;
9803
+ const { debug = false, timeout = 300, cwd, allowedFolders, enableBash = false, bashConfig, architectureFileName, enableMcp = false, mcpConfig = null, mcpConfigPath = null } = options;
9795
9804
  return tool2({
9796
9805
  name: "delegate",
9797
9806
  description: delegateDescription,
@@ -9850,7 +9859,10 @@ var init_vercel = __esm({
9850
9859
  enableBash,
9851
9860
  bashConfig,
9852
9861
  architectureFileName,
9853
- searchDelegate
9862
+ searchDelegate,
9863
+ enableMcp,
9864
+ mcpConfig,
9865
+ mcpConfigPath
9854
9866
  });
9855
9867
  return result;
9856
9868
  }
@@ -10377,6 +10389,38 @@ function parseSimpleCommand(command) {
10377
10389
  isComplex: false
10378
10390
  };
10379
10391
  }
10392
+ const stripQuotedContent = (str) => {
10393
+ let result = "";
10394
+ let inQuotes2 = false;
10395
+ let quoteChar2 = "";
10396
+ for (let i = 0; i < str.length; i++) {
10397
+ const char = str[i];
10398
+ const nextChar = str[i + 1];
10399
+ if (!inQuotes2 && char === "\\" && nextChar !== void 0) {
10400
+ i++;
10401
+ continue;
10402
+ }
10403
+ if (inQuotes2 && quoteChar2 === '"' && char === "\\" && nextChar !== void 0) {
10404
+ i++;
10405
+ continue;
10406
+ }
10407
+ if (!inQuotes2 && (char === '"' || char === "'")) {
10408
+ inQuotes2 = true;
10409
+ quoteChar2 = char;
10410
+ continue;
10411
+ }
10412
+ if (inQuotes2 && char === quoteChar2) {
10413
+ inQuotes2 = false;
10414
+ quoteChar2 = "";
10415
+ continue;
10416
+ }
10417
+ if (!inQuotes2) {
10418
+ result += char;
10419
+ }
10420
+ }
10421
+ return result;
10422
+ };
10423
+ const strippedForOperators = stripQuotedContent(trimmed);
10380
10424
  const complexPatterns = [
10381
10425
  /\|/,
10382
10426
  // Pipes
@@ -10402,7 +10446,7 @@ function parseSimpleCommand(command) {
10402
10446
  // Brace expansion like {a,b} or {1..10} (but not find {} placeholders)
10403
10447
  ];
10404
10448
  for (const pattern of complexPatterns) {
10405
- if (pattern.test(trimmed)) {
10449
+ if (pattern.test(strippedForOperators)) {
10406
10450
  return {
10407
10451
  success: false,
10408
10452
  error: "Complex shell commands with pipes, operators, or redirections are not supported for security reasons",
@@ -10417,17 +10461,17 @@ function parseSimpleCommand(command) {
10417
10461
  let current = "";
10418
10462
  let inQuotes = false;
10419
10463
  let quoteChar = "";
10420
- let escaped = false;
10421
10464
  for (let i = 0; i < trimmed.length; i++) {
10422
10465
  const char = trimmed[i];
10423
10466
  const nextChar = i + 1 < trimmed.length ? trimmed[i + 1] : "";
10424
- if (escaped) {
10425
- current += char;
10426
- escaped = false;
10467
+ if (!inQuotes && char === "\\" && nextChar) {
10468
+ current += nextChar;
10469
+ i++;
10427
10470
  continue;
10428
10471
  }
10429
- if (char === "\\" && !inQuotes) {
10430
- escaped = true;
10472
+ if (inQuotes && quoteChar === '"' && char === "\\" && nextChar) {
10473
+ current += nextChar;
10474
+ i++;
10431
10475
  continue;
10432
10476
  }
10433
10477
  if (!inQuotes && (char === '"' || char === "'")) {
@@ -10760,8 +10804,97 @@ var init_bashPermissions = __esm({
10760
10804
  });
10761
10805
  return result;
10762
10806
  }
10807
+ /**
10808
+ * Split a complex command into component commands by operators
10809
+ *
10810
+ * ## Escape Handling (Security-Critical)
10811
+ *
10812
+ * This function intentionally PRESERVES escape sequences (both backslash AND
10813
+ * escaped character) in the output. This is step 1 of a 2-step parsing process:
10814
+ *
10815
+ * 1. _splitComplexCommand: Splits by operators, PRESERVES escapes → `echo "test\" && b"`
10816
+ * 2. parseCommand: Interprets escapes in each component → args: ['test" && b']
10817
+ *
10818
+ * This differs from stripQuotedContent() in bashCommandUtils.js which REMOVES
10819
+ * escapes entirely (for operator detection only).
10820
+ *
10821
+ * The security rationale: if we stripped escapes here, `\"` would become `"`,
10822
+ * potentially causing incorrect quote boundary detection and allowing operator
10823
+ * injection. By preserving escapes, parseCommand() can correctly interpret them.
10824
+ *
10825
+ * See bashCommandUtils.js module header for the full escape handling architecture.
10826
+ *
10827
+ * @private
10828
+ * @param {string} command - Complex command to split
10829
+ * @returns {string[]} Array of component commands (with escapes preserved)
10830
+ */
10831
+ _splitComplexCommand(command) {
10832
+ const components = [];
10833
+ let current = "";
10834
+ let inQuotes = false;
10835
+ let quoteChar = "";
10836
+ let i = 0;
10837
+ while (i < command.length) {
10838
+ const char = command[i];
10839
+ const nextChar = command[i + 1] || "";
10840
+ if (!inQuotes && char === "\\") {
10841
+ current += char;
10842
+ if (nextChar) {
10843
+ current += nextChar;
10844
+ i += 2;
10845
+ } else {
10846
+ i++;
10847
+ }
10848
+ continue;
10849
+ }
10850
+ if (inQuotes && quoteChar === '"' && char === "\\" && nextChar) {
10851
+ current += char + nextChar;
10852
+ i += 2;
10853
+ continue;
10854
+ }
10855
+ if (!inQuotes && (char === '"' || char === "'")) {
10856
+ inQuotes = true;
10857
+ quoteChar = char;
10858
+ current += char;
10859
+ i++;
10860
+ continue;
10861
+ }
10862
+ if (inQuotes && char === quoteChar) {
10863
+ inQuotes = false;
10864
+ quoteChar = "";
10865
+ current += char;
10866
+ i++;
10867
+ continue;
10868
+ }
10869
+ if (!inQuotes) {
10870
+ if (char === "&" && nextChar === "&" || char === "|" && nextChar === "|") {
10871
+ if (current.trim()) {
10872
+ components.push(current.trim());
10873
+ }
10874
+ current = "";
10875
+ i += 2;
10876
+ continue;
10877
+ }
10878
+ if (char === "|") {
10879
+ if (current.trim()) {
10880
+ components.push(current.trim());
10881
+ }
10882
+ current = "";
10883
+ i++;
10884
+ continue;
10885
+ }
10886
+ }
10887
+ current += char;
10888
+ i++;
10889
+ }
10890
+ if (current.trim()) {
10891
+ components.push(current.trim());
10892
+ }
10893
+ return components;
10894
+ }
10763
10895
  /**
10764
10896
  * Check a complex command against complex patterns in allow/deny lists
10897
+ * Also supports auto-allowing commands where all components are individually allowed
10765
10898
  * @private
10766
10899
  * @param {string} command - Complex command to check
10767
10900
  * @returns {Object} Permission result
@@ -10816,6 +10949,85 @@ var init_bashPermissions = __esm({
10816
10949
  return result;
10817
10950
  }
10818
10951
  }
10952
+ const components = this._splitComplexCommand(command);
10953
+ if (this.debug) {
10954
+ console.log(`[BashPermissions] Checking ${components.length} command components: ${JSON.stringify(components)}`);
10955
+ }
10956
+ if (components.length > 1) {
10957
+ const componentResults = [];
10958
+ let allAllowed = true;
10959
+ let deniedComponent = null;
10960
+ let deniedReason = null;
10961
+ for (const component of components) {
10962
+ const parsed = parseCommand(component);
10963
+ if (parsed.error || parsed.isComplex) {
10964
+ if (this.debug) {
10965
+ console.log(`[BashPermissions] Component "${component}" is complex or has error: ${parsed.error}`);
10966
+ }
10967
+ allAllowed = false;
10968
+ deniedComponent = component;
10969
+ deniedReason = parsed.error || "Component contains nested complex constructs";
10970
+ break;
10971
+ }
10972
+ if (matchesAnyPattern(parsed, this.denyPatterns)) {
10973
+ if (this.debug) {
10974
+ console.log(`[BashPermissions] Component "${component}" matches deny pattern`);
10975
+ }
10976
+ allAllowed = false;
10977
+ deniedComponent = component;
10978
+ deniedReason = "Component matches deny pattern";
10979
+ break;
10980
+ }
10981
+ if (!matchesAnyPattern(parsed, this.allowPatterns)) {
10982
+ if (this.debug) {
10983
+ console.log(`[BashPermissions] Component "${component}" not in allow list`);
10984
+ }
10985
+ allAllowed = false;
10986
+ deniedComponent = component;
10987
+ deniedReason = "Component not in allow list";
10988
+ break;
10989
+ }
10990
+ componentResults.push({ component, parsed, allowed: true });
10991
+ }
10992
+ if (allAllowed) {
10993
+ if (this.debug) {
10994
+ console.log(`[BashPermissions] ALLOWED - all ${components.length} components passed individual checks`);
10995
+ }
10996
+ const result = {
10997
+ allowed: true,
10998
+ command,
10999
+ isComplex: true,
11000
+ allowedByComponents: true,
11001
+ components: componentResults
11002
+ };
11003
+ this.recordBashEvent("permission.allowed", {
11004
+ command,
11005
+ isComplex: true,
11006
+ allowedByComponents: true,
11007
+ componentCount: components.length
11008
+ });
11009
+ return result;
11010
+ } else {
11011
+ if (this.debug) {
11012
+ console.log(`[BashPermissions] DENIED - component "${deniedComponent}" failed: ${deniedReason}`);
11013
+ }
11014
+ const result = {
11015
+ allowed: false,
11016
+ reason: `Component "${deniedComponent}" not allowed: ${deniedReason}`,
11017
+ command,
11018
+ isComplex: true,
11019
+ failedComponent: deniedComponent
11020
+ };
11021
+ this.recordBashEvent("permission.denied", {
11022
+ command,
11023
+ reason: "component_not_allowed",
11024
+ failedComponent: deniedComponent,
11025
+ componentReason: deniedReason,
11026
+ isComplex: true
11027
+ });
11028
+ return result;
11029
+ }
11030
+ }
10819
11031
  if (this.debug) {
10820
11032
  console.log(`[BashPermissions] DENIED - no matching complex pattern found`);
10821
11033
  }
@@ -58583,7 +58795,7 @@ var init_client = __esm({
58583
58795
  clientInfo.client.callTool({
58584
58796
  name: tool4.originalName,
58585
58797
  arguments: args
58586
- }),
58798
+ }, void 0, { timeout }),
58587
58799
  timeoutPromise
58588
58800
  ]);
58589
58801
  const durationMs = Date.now() - startTime;
@@ -69138,7 +69350,7 @@ var init_ProbeAgent = __esm({
69138
69350
  this.maxIterations = options.maxIterations || null;
69139
69351
  this.disableMermaidValidation = !!options.disableMermaidValidation;
69140
69352
  this.disableJsonValidation = !!options.disableJsonValidation;
69141
- this.enableSkills = options.disableSkills ? false : options.enableSkills !== void 0 ? !!options.enableSkills : true;
69353
+ this.enableSkills = options.disableSkills ? false : !!(options.allowSkills || options.enableSkills);
69142
69354
  if (Array.isArray(options.skillDirs)) {
69143
69355
  this.skillDirs = options.skillDirs;
69144
69356
  } else if (typeof options.skillDirs === "string") {
@@ -71033,6 +71245,9 @@ You are working with a repository located at: ${searchDirectory}
71033
71245
  let lastFormatErrorType = null;
71034
71246
  let sameFormatErrorCount = 0;
71035
71247
  const MAX_REPEATED_FORMAT_ERRORS = 3;
71248
+ let lastNoToolResponse = null;
71249
+ let sameResponseCount = 0;
71250
+ const MAX_REPEATED_IDENTICAL_RESPONSES = 3;
71036
71251
  while (currentIteration < maxIterations && !completionAttempted) {
71037
71252
  currentIteration++;
71038
71253
  if (this.cancelled) throw new Error("Request was cancelled by the user");
@@ -71514,6 +71729,26 @@ ${errorXml}
71514
71729
  }
71515
71730
  break;
71516
71731
  }
71732
+ if (lastNoToolResponse !== null && assistantResponseContent === lastNoToolResponse) {
71733
+ sameResponseCount++;
71734
+ if (sameResponseCount >= MAX_REPEATED_IDENTICAL_RESPONSES) {
71735
+ let cleanedResponse = assistantResponseContent;
71736
+ cleanedResponse = cleanedResponse.replace(/<thinking>[\s\S]*?<\/thinking>/gi, "").trim();
71737
+ cleanedResponse = cleanedResponse.replace(/<thinking>[\s\S]*$/gi, "").trim();
71738
+ const hasSubstantialContent = cleanedResponse.length > 50 && !cleanedResponse.includes("<api_call>") && !cleanedResponse.includes("<tool_name>") && !cleanedResponse.includes("<function>");
71739
+ if (hasSubstantialContent) {
71740
+ if (this.debug) {
71741
+ console.log(`[DEBUG] Same response repeated ${sameResponseCount} times - accepting as final answer (${cleanedResponse.length} chars)`);
71742
+ }
71743
+ finalResult = cleanedResponse;
71744
+ completionAttempted = true;
71745
+ break;
71746
+ }
71747
+ }
71748
+ } else {
71749
+ lastNoToolResponse = assistantResponseContent;
71750
+ sameResponseCount = 1;
71751
+ }
71517
71752
  currentMessages.push({ role: "assistant", content: assistantResponseContent });
71518
71753
  const unrecognizedTool = detectUnrecognizedToolCall(assistantResponseContent, validTools);
71519
71754
  let reminderContent;
@@ -71586,10 +71821,35 @@ Or if your previous response already contains a complete, direct answer (not a t
71586
71821
 
71587
71822
  Note: <attempt_complete></attempt_complete> reuses your PREVIOUS assistant message as the final answer. Only use this if that message was already a valid, complete response to the user's question.`;
71588
71823
  }
71589
- currentMessages.push({
71590
- role: "user",
71591
- content: reminderContent
71592
- });
71824
+ const prevUserMsgIndex = currentMessages.length - 2;
71825
+ const prevUserMsg = currentMessages[prevUserMsgIndex];
71826
+ const isExistingReminder = prevUserMsg && prevUserMsg.role === "user" && (prevUserMsg.content.includes("Please use one of the available tools") || prevUserMsg.content.includes("<tool_result>"));
71827
+ if (isExistingReminder && sameResponseCount > 1) {
71828
+ const prevAssistantIndex = prevUserMsgIndex - 1;
71829
+ const hasSystemMessage2 = currentMessages.length > 0 && currentMessages[0].role === "system";
71830
+ const minValidIndex = hasSystemMessage2 ? 1 : 0;
71831
+ const canSafelyRemove = prevAssistantIndex >= minValidIndex && currentMessages[prevAssistantIndex] && currentMessages[prevAssistantIndex].role === "assistant" && currentMessages.length - 2 >= (hasSystemMessage2 ? 2 : 1);
71832
+ if (canSafelyRemove) {
71833
+ currentMessages.splice(prevAssistantIndex, 2);
71834
+ if (this.debug) {
71835
+ console.log(`[DEBUG] Removed duplicate assistant+reminder pair (iteration ${currentIteration}, same response #${sameResponseCount})`);
71836
+ }
71837
+ } else if (this.debug) {
71838
+ console.log(`[DEBUG] Skipped deduplication: pattern validation failed (prevAssistantIndex=${prevAssistantIndex}, arrayLength=${currentMessages.length})`);
71839
+ }
71840
+ const iterationHint = `
71841
+
71842
+ (Attempt #${sameResponseCount}: Your previous ${sameResponseCount} responses were identical. If you have a complete answer, use <attempt_complete></attempt_complete> to finalize it.)`;
71843
+ currentMessages.push({
71844
+ role: "user",
71845
+ content: reminderContent + iterationHint
71846
+ });
71847
+ } else {
71848
+ currentMessages.push({
71849
+ role: "user",
71850
+ content: reminderContent
71851
+ });
71852
+ }
71593
71853
  if (this.debug) {
71594
71854
  if (unrecognizedTool) {
71595
71855
  console.log(`[DEBUG] Unrecognized tool '${unrecognizedTool}' used. Providing error feedback.`);
@@ -73115,8 +73375,8 @@ function parseArgs() {
73115
73375
  // Tool filtering: ['*'] = all, [] = none, ['tool1', 'tool2'] = specific
73116
73376
  disableTools: false,
73117
73377
  // Convenience flag to disable all tools
73118
- disableSkills: false,
73119
- // Disable skill discovery and activation
73378
+ allowSkills: false,
73379
+ // Enable skill discovery and activation (disabled by default)
73120
73380
  skillDirs: null,
73121
73381
  // Comma-separated list of repo-relative skill directories
73122
73382
  // Task management
@@ -73188,8 +73448,8 @@ function parseArgs() {
73188
73448
  }
73189
73449
  } else if (arg === "--disable-tools") {
73190
73450
  config.disableTools = true;
73191
- } else if (arg === "--no-skills") {
73192
- config.disableSkills = true;
73451
+ } else if (arg === "--allow-skills") {
73452
+ config.allowSkills = true;
73193
73453
  } else if (arg === "--skills-dir" && i + 1 < args.length) {
73194
73454
  config.skillDirs = args[++i].split(",").map((dir) => dir.trim()).filter(Boolean);
73195
73455
  } else if (arg === "--allow-tasks") {
@@ -73246,8 +73506,8 @@ Options:
73246
73506
  Supports exclusion: '*,!bash' (all except bash)
73247
73507
  --disable-tools Disable all tools (raw AI mode, no code analysis)
73248
73508
  Convenience flag equivalent to --allowed-tools none
73509
+ --allow-skills Enable skill discovery and activation (disabled by default)
73249
73510
  --skills-dir <dirs> Comma-separated list of repo-relative skill directories to scan
73250
- --no-skills Disable skill discovery and activation
73251
73511
  --allow-tasks Enable task management for tracking multi-step progress
73252
73512
  --verbose Enable verbose output
73253
73513
  --outline Use outline-xml format for code search results
@@ -73719,7 +73979,7 @@ async function main() {
73719
73979
  disableMermaidValidation: config.noMermaidValidation,
73720
73980
  allowedTools: config.allowedTools,
73721
73981
  disableTools: config.disableTools,
73722
- enableSkills: !config.disableSkills,
73982
+ allowSkills: config.allowSkills,
73723
73983
  skillDirs: config.skillDirs,
73724
73984
  enableBash: config.enableBash,
73725
73985
  bashConfig,
@@ -474,11 +474,12 @@ export class MCPClientManager {
474
474
  });
475
475
 
476
476
  // Race between the actual call and timeout
477
+ // Pass timeout to SDK's callTool to override its default 60s timeout
477
478
  const result = await Promise.race([
478
479
  clientInfo.client.callTool({
479
480
  name: tool.originalName,
480
481
  arguments: args
481
- }),
482
+ }, undefined, { timeout }),
482
483
  timeoutPromise
483
484
  ]);
484
485
 
package/build/delegate.js CHANGED
@@ -186,6 +186,9 @@ const delegationManager = new DelegationManager();
186
186
  * @param {boolean} [options.searchDelegate] - Use delegated search in the subagent
187
187
  * @param {Object|string} [options.schema] - Optional JSON schema to enforce response format
188
188
  * @param {boolean} [options.enableTasks=false] - Enable task management for the subagent (isolated instance)
189
+ * @param {boolean} [options.enableMcp=false] - Enable MCP tool integration (inherited from parent)
190
+ * @param {Object} [options.mcpConfig] - MCP configuration object (inherited from parent)
191
+ * @param {string} [options.mcpConfigPath] - Path to MCP configuration file (inherited from parent)
189
192
  * @returns {Promise<string>} The response from the delegate agent
190
193
  */
191
194
  export async function delegate({
@@ -208,7 +211,10 @@ export async function delegate({
208
211
  disableTools = false,
209
212
  searchDelegate = undefined,
210
213
  schema = null,
211
- enableTasks = false
214
+ enableTasks = false,
215
+ enableMcp = false,
216
+ mcpConfig = null,
217
+ mcpConfigPath = null
212
218
  }) {
213
219
  if (!task || typeof task !== 'string') {
214
220
  throw new Error('Task parameter is required and must be a string');
@@ -270,7 +276,10 @@ export async function delegate({
270
276
  allowedTools,
271
277
  disableTools,
272
278
  searchDelegate,
273
- enableTasks // Inherit from parent (subagent gets isolated TaskManager)
279
+ enableTasks, // Inherit from parent (subagent gets isolated TaskManager)
280
+ enableMcp, // Inherit from parent (subagent creates own MCPXmlBridge)
281
+ mcpConfig, // Inherit from parent
282
+ mcpConfigPath // Inherit from parent
274
283
  });
275
284
 
276
285
  if (debug) {
@@ -469,7 +469,7 @@ export const extractTool = (options = {}) => {
469
469
  * @returns {Object} Configured delegate tool
470
470
  */
471
471
  export const delegateTool = (options = {}) => {
472
- const { debug = false, timeout = 300, cwd, allowedFolders, enableBash = false, bashConfig, architectureFileName } = options;
472
+ const { debug = false, timeout = 300, cwd, allowedFolders, enableBash = false, bashConfig, architectureFileName, enableMcp = false, mcpConfig = null, mcpConfigPath = null } = options;
473
473
 
474
474
  return tool({
475
475
  name: 'delegate',
@@ -558,7 +558,10 @@ export const delegateTool = (options = {}) => {
558
558
  enableBash,
559
559
  bashConfig,
560
560
  architectureFileName,
561
- searchDelegate
561
+ searchDelegate,
562
+ enableMcp,
563
+ mcpConfig,
564
+ mcpConfigPath
562
565
  });
563
566
 
564
567
  return result;