@juspay/neurolink 9.26.2 → 9.28.0

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 (125) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/README.md +59 -9
  3. package/dist/cli/commands/config.d.ts +4 -4
  4. package/dist/cli/commands/mcp.d.ts +87 -0
  5. package/dist/cli/commands/mcp.js +1524 -0
  6. package/dist/cli/loop/optionsSchema.js +4 -0
  7. package/dist/core/modules/ToolsManager.js +29 -2
  8. package/dist/index.d.ts +2 -1
  9. package/dist/index.js +27 -1
  10. package/dist/lib/core/modules/ToolsManager.js +29 -2
  11. package/dist/lib/index.d.ts +2 -1
  12. package/dist/lib/index.js +27 -1
  13. package/dist/lib/mcp/agentExposure.d.ts +228 -0
  14. package/dist/lib/mcp/agentExposure.js +357 -0
  15. package/dist/lib/mcp/batching/index.d.ts +11 -0
  16. package/dist/lib/mcp/batching/index.js +11 -0
  17. package/dist/lib/mcp/batching/requestBatcher.d.ts +202 -0
  18. package/dist/lib/mcp/batching/requestBatcher.js +442 -0
  19. package/dist/lib/mcp/caching/index.d.ts +11 -0
  20. package/dist/lib/mcp/caching/index.js +11 -0
  21. package/dist/lib/mcp/caching/toolCache.d.ts +221 -0
  22. package/dist/lib/mcp/caching/toolCache.js +434 -0
  23. package/dist/lib/mcp/elicitation/elicitationManager.d.ts +169 -0
  24. package/dist/lib/mcp/elicitation/elicitationManager.js +377 -0
  25. package/dist/lib/mcp/elicitation/index.d.ts +11 -0
  26. package/dist/lib/mcp/elicitation/index.js +12 -0
  27. package/dist/lib/mcp/elicitation/types.d.ts +278 -0
  28. package/dist/lib/mcp/elicitation/types.js +11 -0
  29. package/dist/lib/mcp/elicitationProtocol.d.ts +228 -0
  30. package/dist/lib/mcp/elicitationProtocol.js +376 -0
  31. package/dist/lib/mcp/enhancedToolDiscovery.d.ts +205 -0
  32. package/dist/lib/mcp/enhancedToolDiscovery.js +482 -0
  33. package/dist/lib/mcp/index.d.ts +38 -1
  34. package/dist/lib/mcp/index.js +36 -3
  35. package/dist/lib/mcp/mcpRegistryClient.d.ts +332 -0
  36. package/dist/lib/mcp/mcpRegistryClient.js +489 -0
  37. package/dist/lib/mcp/mcpServerBase.d.ts +227 -0
  38. package/dist/lib/mcp/mcpServerBase.js +374 -0
  39. package/dist/lib/mcp/multiServerManager.d.ts +310 -0
  40. package/dist/lib/mcp/multiServerManager.js +580 -0
  41. package/dist/lib/mcp/routing/index.d.ts +11 -0
  42. package/dist/lib/mcp/routing/index.js +11 -0
  43. package/dist/lib/mcp/routing/toolRouter.d.ts +219 -0
  44. package/dist/lib/mcp/routing/toolRouter.js +417 -0
  45. package/dist/lib/mcp/serverCapabilities.d.ts +341 -0
  46. package/dist/lib/mcp/serverCapabilities.js +503 -0
  47. package/dist/lib/mcp/toolAnnotations.d.ts +154 -0
  48. package/dist/lib/mcp/toolAnnotations.js +240 -0
  49. package/dist/lib/mcp/toolConverter.d.ts +178 -0
  50. package/dist/lib/mcp/toolConverter.js +259 -0
  51. package/dist/lib/mcp/toolIntegration.d.ts +136 -0
  52. package/dist/lib/mcp/toolIntegration.js +335 -0
  53. package/dist/lib/memory/hippocampusInitializer.d.ts +2 -2
  54. package/dist/lib/memory/hippocampusInitializer.js +1 -1
  55. package/dist/lib/neurolink.d.ts +275 -2
  56. package/dist/lib/neurolink.js +596 -56
  57. package/dist/lib/providers/litellm.d.ts +10 -0
  58. package/dist/lib/providers/litellm.js +104 -2
  59. package/dist/lib/types/configTypes.d.ts +56 -0
  60. package/dist/lib/types/conversation.d.ts +2 -2
  61. package/dist/lib/types/generateTypes.d.ts +4 -0
  62. package/dist/lib/types/index.d.ts +2 -1
  63. package/dist/lib/types/modelTypes.d.ts +6 -6
  64. package/dist/lib/types/streamTypes.d.ts +2 -0
  65. package/dist/lib/types/tools.d.ts +2 -0
  66. package/dist/lib/utils/pricing.js +177 -17
  67. package/dist/lib/utils/schemaConversion.d.ts +6 -1
  68. package/dist/lib/utils/schemaConversion.js +50 -28
  69. package/dist/lib/workflow/config.d.ts +16 -16
  70. package/dist/mcp/agentExposure.d.ts +228 -0
  71. package/dist/mcp/agentExposure.js +356 -0
  72. package/dist/mcp/batching/index.d.ts +11 -0
  73. package/dist/mcp/batching/index.js +10 -0
  74. package/dist/mcp/batching/requestBatcher.d.ts +202 -0
  75. package/dist/mcp/batching/requestBatcher.js +441 -0
  76. package/dist/mcp/caching/index.d.ts +11 -0
  77. package/dist/mcp/caching/index.js +10 -0
  78. package/dist/mcp/caching/toolCache.d.ts +221 -0
  79. package/dist/mcp/caching/toolCache.js +433 -0
  80. package/dist/mcp/elicitation/elicitationManager.d.ts +169 -0
  81. package/dist/mcp/elicitation/elicitationManager.js +376 -0
  82. package/dist/mcp/elicitation/index.d.ts +11 -0
  83. package/dist/mcp/elicitation/index.js +11 -0
  84. package/dist/mcp/elicitation/types.d.ts +278 -0
  85. package/dist/mcp/elicitation/types.js +10 -0
  86. package/dist/mcp/elicitationProtocol.d.ts +228 -0
  87. package/dist/mcp/elicitationProtocol.js +375 -0
  88. package/dist/mcp/enhancedToolDiscovery.d.ts +205 -0
  89. package/dist/mcp/enhancedToolDiscovery.js +481 -0
  90. package/dist/mcp/index.d.ts +38 -1
  91. package/dist/mcp/index.js +36 -3
  92. package/dist/mcp/mcpRegistryClient.d.ts +332 -0
  93. package/dist/mcp/mcpRegistryClient.js +488 -0
  94. package/dist/mcp/mcpServerBase.d.ts +227 -0
  95. package/dist/mcp/mcpServerBase.js +373 -0
  96. package/dist/mcp/multiServerManager.d.ts +310 -0
  97. package/dist/mcp/multiServerManager.js +579 -0
  98. package/dist/mcp/routing/index.d.ts +11 -0
  99. package/dist/mcp/routing/index.js +10 -0
  100. package/dist/mcp/routing/toolRouter.d.ts +219 -0
  101. package/dist/mcp/routing/toolRouter.js +416 -0
  102. package/dist/mcp/serverCapabilities.d.ts +341 -0
  103. package/dist/mcp/serverCapabilities.js +502 -0
  104. package/dist/mcp/toolAnnotations.d.ts +154 -0
  105. package/dist/mcp/toolAnnotations.js +239 -0
  106. package/dist/mcp/toolConverter.d.ts +178 -0
  107. package/dist/mcp/toolConverter.js +258 -0
  108. package/dist/mcp/toolIntegration.d.ts +136 -0
  109. package/dist/mcp/toolIntegration.js +334 -0
  110. package/dist/memory/hippocampusInitializer.d.ts +2 -2
  111. package/dist/memory/hippocampusInitializer.js +1 -1
  112. package/dist/neurolink.d.ts +275 -2
  113. package/dist/neurolink.js +596 -56
  114. package/dist/providers/litellm.d.ts +10 -0
  115. package/dist/providers/litellm.js +104 -2
  116. package/dist/types/configTypes.d.ts +56 -0
  117. package/dist/types/conversation.d.ts +2 -2
  118. package/dist/types/generateTypes.d.ts +4 -0
  119. package/dist/types/index.d.ts +2 -1
  120. package/dist/types/streamTypes.d.ts +2 -0
  121. package/dist/types/tools.d.ts +2 -0
  122. package/dist/utils/pricing.js +177 -17
  123. package/dist/utils/schemaConversion.d.ts +6 -1
  124. package/dist/utils/schemaConversion.js +50 -28
  125. package/package.json +2 -2
package/dist/neurolink.js CHANGED
@@ -32,9 +32,15 @@ import { ProviderRegistry } from "./factories/providerRegistry.js";
32
32
  import { FileReferenceRegistry } from "./files/fileReferenceRegistry.js";
33
33
  import { createFileTools } from "./files/fileTools.js";
34
34
  import { HITLManager } from "./hitl/hitlManager.js";
35
+ import { ToolCallBatcher } from "./mcp/batching/index.js";
36
+ // MCP Enhancement modules - wired into core execution path
37
+ import { ToolResultCache } from "./mcp/caching/index.js";
38
+ import { EnhancedToolDiscovery } from "./mcp/enhancedToolDiscovery.js";
35
39
  import { ExternalServerManager } from "./mcp/externalServerManager.js";
40
+ import { ToolRouter } from "./mcp/routing/index.js";
36
41
  // Import direct tools server for automatic registration
37
42
  import { directToolsServer } from "./mcp/servers/agent/directToolsServer.js";
43
+ import { inferAnnotations, isSafeToRetry } from "./mcp/toolAnnotations.js";
38
44
  import { MCPToolRegistry } from "./mcp/toolRegistry.js";
39
45
  import { initializeHippocampus, } from "./memory/hippocampusInitializer.js";
40
46
  import { initializeMem0 } from "./memory/mem0Initializer.js";
@@ -179,6 +185,14 @@ export class NeuroLink {
179
185
  return (options.context
180
186
  ?.sessionId || "__default__");
181
187
  }
188
+ // MCP Enhancement modules - wired into core execution path
189
+ mcpToolResultCache;
190
+ mcpToolRouter;
191
+ mcpToolBatcher;
192
+ mcpEnhancedDiscovery;
193
+ mcpToolMiddlewares = [];
194
+ _disableToolCacheForCurrentRequest = false;
195
+ mcpEnhancementsConfig;
182
196
  // Enhanced error handling support
183
197
  toolCircuitBreakers = new Map();
184
198
  toolExecutionMetrics = new Map();
@@ -442,6 +456,7 @@ export class NeuroLink {
442
456
  this.initializeConversationMemory(config, constructorId, constructorStartTime, constructorHrTimeStart);
443
457
  this.initializeExternalServerManager(constructorId, constructorStartTime, constructorHrTimeStart);
444
458
  this.initializeHITL(config, constructorId, constructorStartTime, constructorHrTimeStart);
459
+ this.initializeMCPEnhancements(config);
445
460
  this.registerFileTools();
446
461
  this.registerMemoryRetrievalTools();
447
462
  this.initializeLangfuse(constructorId, constructorStartTime, constructorHrTimeStart);
@@ -598,6 +613,56 @@ export class NeuroLink {
598
613
  });
599
614
  }
600
615
  }
616
+ /**
617
+ * Initialize MCP enhancement modules (cache, router, batcher, discovery).
618
+ * Wires standalone MCP modules into the core SDK execution path.
619
+ */
620
+ initializeMCPEnhancements(config) {
621
+ const mcpConfig = config?.mcp;
622
+ this.mcpEnhancementsConfig = mcpConfig;
623
+ // ToolCache — disabled by default, opt-in
624
+ if (mcpConfig?.cache?.enabled) {
625
+ this.mcpToolResultCache = new ToolResultCache({
626
+ ttl: mcpConfig.cache.ttl ?? 300_000,
627
+ maxSize: mcpConfig.cache.maxSize ?? 500,
628
+ strategy: mcpConfig.cache.strategy ?? "lru",
629
+ });
630
+ logger.debug("[NeuroLink] MCP tool result cache initialized", {
631
+ ttl: mcpConfig.cache.ttl ?? 300_000,
632
+ maxSize: mcpConfig.cache.maxSize ?? 500,
633
+ strategy: mcpConfig.cache.strategy ?? "lru",
634
+ });
635
+ }
636
+ // ToolCallBatcher — disabled by default, opt-in
637
+ if (mcpConfig?.batcher?.enabled) {
638
+ this.mcpToolBatcher = new ToolCallBatcher({
639
+ maxBatchSize: mcpConfig.batcher.maxBatchSize ?? 10,
640
+ maxWaitMs: mcpConfig.batcher.maxWaitMs ?? 100,
641
+ });
642
+ // Wire batcher to execute tools via the internal execution path (bypass batcher itself)
643
+ this.mcpToolBatcher.setToolExecutor(async (tool, args) => {
644
+ return this.executeToolInternal(tool, args, {
645
+ timeout: TOOL_TIMEOUTS.EXECUTION_DEFAULT_MS,
646
+ maxRetries: RETRY_ATTEMPTS.DEFAULT,
647
+ retryDelayMs: RETRY_DELAYS.BASE_MS,
648
+ });
649
+ });
650
+ logger.debug("[NeuroLink] MCP tool call batcher initialized");
651
+ }
652
+ // EnhancedToolDiscovery — enabled by default
653
+ if (mcpConfig?.discovery?.enabled !== false) {
654
+ this.mcpEnhancedDiscovery = new EnhancedToolDiscovery();
655
+ logger.debug("[NeuroLink] Enhanced tool discovery initialized");
656
+ }
657
+ // Middleware — store from config (empty by default)
658
+ if (mcpConfig?.middleware?.length) {
659
+ this.mcpToolMiddlewares = [...mcpConfig.middleware];
660
+ logger.debug("[NeuroLink] MCP tool middlewares registered", {
661
+ count: this.mcpToolMiddlewares.length,
662
+ });
663
+ }
664
+ // ToolRouter — lazy-initialized when 2+ external servers exist (see addExternalMCPServer)
665
+ }
601
666
  /**
602
667
  * Register file reference tools with the MCP tool registry.
603
668
  *
@@ -2113,6 +2178,9 @@ Current user's request: ${currentInput}`;
2113
2178
  : { ...optionsOrPrompt };
2114
2179
  // NL-004: Resolve model aliases/deprecations before processing
2115
2180
  options.model = resolveModel(options.model, this.modelAliasConfig);
2181
+ // MCP Enhancement: propagate disableToolCache to tool execution
2182
+ this._disableToolCacheForCurrentRequest =
2183
+ !!options.disableToolCache;
2116
2184
  // Set span attributes for observability
2117
2185
  generateSpan.setAttribute("neurolink.provider", options.provider || "default");
2118
2186
  generateSpan.setAttribute("neurolink.model", options.model || "default");
@@ -2440,6 +2508,7 @@ Current user's request: ${currentInput}`;
2440
2508
  throw error;
2441
2509
  }
2442
2510
  finally {
2511
+ this._disableToolCacheForCurrentRequest = false;
2443
2512
  generateSpan.end();
2444
2513
  }
2445
2514
  }); // end metricsTraceContextStorage.run
@@ -3441,7 +3510,9 @@ Current user's request: ${currentInput}`;
3441
3510
  // Enable tool execution for the provider using BaseProvider method
3442
3511
  provider.setupToolExecutor({
3443
3512
  customTools: this.getCustomTools(),
3444
- executeTool: this.executeTool.bind(this),
3513
+ executeTool: (toolName, params) => this.executeTool(toolName, params, {
3514
+ disableToolCache: options.disableToolCache,
3515
+ }),
3445
3516
  }, functionTag);
3446
3517
  logger.debug("[Observability] User input to LLM", {
3447
3518
  requestId,
@@ -3670,7 +3741,9 @@ Current user's request: ${currentInput}`;
3670
3741
  // Enable tool execution for direct provider generation using BaseProvider method
3671
3742
  provider.setupToolExecutor({
3672
3743
  customTools: this.getCustomTools(),
3673
- executeTool: this.executeTool.bind(this),
3744
+ executeTool: (toolName, params) => this.executeTool(toolName, params, {
3745
+ disableToolCache: options.disableToolCache,
3746
+ }),
3674
3747
  }, functionTag);
3675
3748
  const result = await provider.generate({
3676
3749
  ...options,
@@ -3922,6 +3995,8 @@ Current user's request: ${currentInput}`;
3922
3995
  },
3923
3996
  });
3924
3997
  const spanStartTime = Date.now();
3998
+ // MCP Enhancement: propagate disableToolCache to tool execution
3999
+ this._disableToolCacheForCurrentRequest = !!options.disableToolCache;
3925
4000
  try {
3926
4001
  // NL-004: Resolve model aliases/deprecations before processing
3927
4002
  options.model = resolveModel(options.model, this.modelAliasConfig);
@@ -3954,6 +4029,7 @@ Current user's request: ${currentInput}`;
3954
4029
  const result = await this.streamWithWorkflow(options, startTime);
3955
4030
  // Wrap the workflow stream so the span stays open until fully consumed
3956
4031
  const originalWorkflowStream = result.stream;
4032
+ const selfWorkflow = this;
3957
4033
  result.stream = (async function* () {
3958
4034
  try {
3959
4035
  for await (const chunk of originalWorkflowStream) {
@@ -3969,6 +4045,7 @@ Current user's request: ${currentInput}`;
3969
4045
  throw error;
3970
4046
  }
3971
4047
  finally {
4048
+ selfWorkflow._disableToolCacheForCurrentRequest = false;
3972
4049
  streamSpan.setAttribute("neurolink.response_time_ms", Date.now() - spanStartTime);
3973
4050
  streamSpan.end();
3974
4051
  }
@@ -4087,6 +4164,7 @@ Current user's request: ${currentInput}`;
4087
4164
  throw error;
4088
4165
  }
4089
4166
  finally {
4167
+ self._disableToolCacheForCurrentRequest = false;
4090
4168
  cleanupListeners();
4091
4169
  // Finalize span now that the stream is fully consumed
4092
4170
  streamSpan.setAttribute("neurolink.response_time_ms", Date.now() - spanStartTime);
@@ -4416,7 +4494,9 @@ Current user's request: ${currentInput}`;
4416
4494
  // Ensure fallback provider can execute tools
4417
4495
  fallbackProvider.setupToolExecutor({
4418
4496
  customTools: this.getCustomTools(),
4419
- executeTool: this.executeTool.bind(this),
4497
+ executeTool: (toolName, params) => this.executeTool(toolName, params, {
4498
+ disableToolCache: enhancedOptions.disableToolCache,
4499
+ }),
4420
4500
  }, "NeuroLink.fallbackStream");
4421
4501
  // Get conversation messages for context (same as primary stream)
4422
4502
  const conversationMessages = await getConversationMessages(this.conversationMemory, {
@@ -4584,7 +4664,9 @@ Current user's request: ${currentInput}`;
4584
4664
  // Enable tool execution for the provider using BaseProvider method
4585
4665
  provider.setupToolExecutor({
4586
4666
  customTools: this.getCustomTools(),
4587
- executeTool: this.executeTool.bind(this),
4667
+ executeTool: (toolName, params) => this.executeTool(toolName, params, {
4668
+ disableToolCache: options.disableToolCache,
4669
+ }),
4588
4670
  }, "NeuroLink.createMCPStream");
4589
4671
  // 🔧 FIX: Get available tools and create tool-aware system prompt
4590
4672
  // Use SAME pattern as tryMCPGeneration (generate mode)
@@ -5299,6 +5381,38 @@ Current user's request: ${currentInput}`;
5299
5381
  }
5300
5382
  return removed;
5301
5383
  }
5384
+ // ==================== MCP Enhancement Public APIs ====================
5385
+ /**
5386
+ * Register a global tool middleware that runs on every tool execution.
5387
+ * Middleware receives the tool, params, context, and a next() function.
5388
+ * @param middleware - The middleware function to register
5389
+ * @returns this (for chaining)
5390
+ */
5391
+ useToolMiddleware(middleware) {
5392
+ this.mcpToolMiddlewares.push(middleware);
5393
+ logger.debug(`[NeuroLink] Registered tool middleware (total: ${this.mcpToolMiddlewares.length})`);
5394
+ return this;
5395
+ }
5396
+ /**
5397
+ * Get all registered tool middlewares
5398
+ */
5399
+ getToolMiddlewares() {
5400
+ return [...this.mcpToolMiddlewares];
5401
+ }
5402
+ /**
5403
+ * Flush any pending batched tool calls immediately
5404
+ */
5405
+ async flushToolBatch() {
5406
+ if (this.mcpToolBatcher) {
5407
+ await this.mcpToolBatcher.flush();
5408
+ }
5409
+ }
5410
+ /**
5411
+ * Get the current MCP enhancements configuration
5412
+ */
5413
+ getMCPEnhancementsConfig() {
5414
+ return this.mcpEnhancementsConfig;
5415
+ }
5302
5416
  /**
5303
5417
  * Update agentic loop report metadata for a conversation session.
5304
5418
  * Upserts a report entry by reportId — updates existing or adds new.
@@ -5516,6 +5630,10 @@ Current user's request: ${currentInput}`;
5516
5630
  async executeTool(toolName, params = {}, options) {
5517
5631
  const functionTag = "NeuroLink.executeTool";
5518
5632
  const executionStartTime = Date.now();
5633
+ // === MCP ENHANCEMENT: RequestBatcher — batch programmatic tool calls ===
5634
+ if (this.mcpToolBatcher && !options?.bypassBatcher) {
5635
+ return this.mcpToolBatcher.execute(toolName, params);
5636
+ }
5519
5637
  // Determine tool type for span attributes
5520
5638
  const externalTools = this.externalServerManager.getAllTools();
5521
5639
  const externalTool = externalTools.find((tool) => tool.name === toolName);
@@ -5583,6 +5701,7 @@ Current user's request: ${currentInput}`;
5583
5701
  maxRetries: options?.maxRetries || RETRY_ATTEMPTS.DEFAULT, // Default 2 retries for retriable errors
5584
5702
  retryDelayMs: options?.retryDelayMs || RETRY_DELAYS.BASE_MS, // 1 second delay between retries
5585
5703
  authContext: options?.authContext, // Pass through authentication context
5704
+ disableToolCache: options?.disableToolCache, // Pass through cache bypass flag
5586
5705
  };
5587
5706
  // Track memory usage for tool execution
5588
5707
  const { MemoryManager } = await import("./utils/performance.js");
@@ -5813,75 +5932,210 @@ Current user's request: ${currentInput}`;
5813
5932
  });
5814
5933
  }
5815
5934
  /**
5816
- * Internal tool execution method (extracted for better error handling)
5935
+ * Internal tool execution method with MCP enhancements wired in:
5936
+ * - ToolCache: check/store cached results for non-destructive tools
5937
+ * - ToolRouter: route to best server when same tool exists on multiple servers
5938
+ * - Annotations: skip cache for destructive tools, retry safe tools on failure
5939
+ * - Middleware: apply global middleware chain before execution
5817
5940
  */
5818
5941
  async executeToolInternal(toolName, params, options) {
5819
5942
  const functionTag = "NeuroLink.executeToolInternal";
5820
- // Check external MCP servers
5821
- const externalTools = this.externalServerManager.getAllTools();
5822
- const externalTool = externalTools.find((tool) => tool.name === toolName);
5823
- logger.debug(`[${functionTag}] External MCP tool search:`, {
5824
- toolName,
5825
- externalToolsCount: externalTools.length,
5826
- foundTool: !!externalTool,
5827
- isAvailable: externalTool?.isAvailable,
5828
- serverId: externalTool?.serverId,
5829
- });
5830
- if (externalTool && externalTool.isAvailable) {
5943
+ // === MCP ENHANCEMENT: Infer annotations for cache/retry decisions ===
5944
+ const toolAnnotations = this.getToolAnnotationsForExecution(toolName);
5945
+ const isCacheEnabled = this.mcpToolResultCache &&
5946
+ !options.disableToolCache &&
5947
+ !this._disableToolCacheForCurrentRequest &&
5948
+ !toolAnnotations?.destructiveHint;
5949
+ // === MCP ENHANCEMENT: Cache check (before execution) ===
5950
+ if (isCacheEnabled) {
5951
+ const cached = this.mcpToolResultCache.getCachedResult(toolName, params);
5952
+ if (cached !== undefined) {
5953
+ logger.debug(`[${functionTag}] Cache HIT for tool: ${toolName}`);
5954
+ return cached;
5955
+ }
5956
+ }
5957
+ // === MCP ENHANCEMENT: Middleware chain wrapper ===
5958
+ const executeWithMiddleware = async (executeFn) => {
5959
+ if (this.mcpToolMiddlewares.length === 0) {
5960
+ return executeFn();
5961
+ }
5962
+ // Build middleware chain: each middleware calls next() to proceed
5963
+ let index = 0;
5964
+ const next = async () => {
5965
+ if (index < this.mcpToolMiddlewares.length) {
5966
+ const middleware = this.mcpToolMiddlewares[index++];
5967
+ // Cast to MCPServerTool — middleware only inspects name/description/annotations
5968
+ const toolStub = {
5969
+ name: toolName,
5970
+ description: "",
5971
+ inputSchema: {},
5972
+ annotations: toolAnnotations,
5973
+ execute: async () => ({}),
5974
+ };
5975
+ // Provide minimal context — elicitation is optional for most middleware
5976
+ const middlewareContext = {
5977
+ toolMeta: { name: toolName, annotations: toolAnnotations },
5978
+ };
5979
+ return middleware(toolStub, params, middlewareContext, next);
5980
+ }
5981
+ return executeFn();
5982
+ };
5983
+ return (await next());
5984
+ };
5985
+ // === Execute the tool (with middleware wrapper) ===
5986
+ const executeCore = async () => {
5987
+ // Check external MCP servers
5988
+ const externalTools = this.externalServerManager.getAllTools();
5989
+ // === MCP ENHANCEMENT: ToolRouter for multi-server routing ===
5990
+ const matchingTools = externalTools.filter((tool) => tool.name === toolName && tool.isAvailable);
5991
+ let externalTool;
5992
+ if (matchingTools.length > 1 && this.mcpToolRouter) {
5993
+ // Multiple servers have this tool — use router to pick the best one
5994
+ try {
5995
+ const mcpTool = {
5996
+ name: toolName,
5997
+ description: matchingTools[0].description ?? "",
5998
+ serverId: matchingTools[0].serverId,
5999
+ inputSchema: {},
6000
+ };
6001
+ const decision = this.mcpToolRouter.route(mcpTool);
6002
+ externalTool =
6003
+ matchingTools.find((t) => t.serverId === decision.serverId) ||
6004
+ matchingTools[0];
6005
+ logger.debug(`[${functionTag}] Router selected server: ${decision.serverId}`, {
6006
+ strategy: decision.strategy,
6007
+ confidence: decision.confidence,
6008
+ });
6009
+ }
6010
+ catch (routerError) {
6011
+ logger.warn(`[${functionTag}] Router failed, falling back to first match`, { error: routerError });
6012
+ externalTool = matchingTools[0];
6013
+ }
6014
+ }
6015
+ else {
6016
+ externalTool = matchingTools[0];
6017
+ }
6018
+ logger.debug(`[${functionTag}] External MCP tool search:`, {
6019
+ toolName,
6020
+ externalToolsCount: externalTools.length,
6021
+ foundTool: !!externalTool,
6022
+ isAvailable: externalTool?.isAvailable,
6023
+ serverId: externalTool?.serverId,
6024
+ });
6025
+ if (externalTool && externalTool.isAvailable) {
6026
+ try {
6027
+ mcpLogger.debug(`[${functionTag}] Executing external MCP tool: ${toolName} from ${externalTool.serverId}`);
6028
+ const result = await this.externalServerManager.executeTool(externalTool.serverId, toolName, params, { timeout: options.timeout });
6029
+ logger.debug(`[${functionTag}] External MCP tool execution successful:`, {
6030
+ toolName,
6031
+ serverId: externalTool.serverId,
6032
+ resultType: typeof result,
6033
+ });
6034
+ return result;
6035
+ }
6036
+ catch (error) {
6037
+ logger.error(`[${functionTag}] External MCP tool execution failed:`, {
6038
+ toolName,
6039
+ serverId: externalTool.serverId,
6040
+ error: error instanceof Error ? error.message : String(error),
6041
+ });
6042
+ throw ErrorFactory.toolExecutionFailed(toolName, error instanceof Error ? error : new Error(String(error)), externalTool.serverId);
6043
+ }
6044
+ }
6045
+ // Execute via tool registry (custom/built-in tools)
5831
6046
  try {
5832
- mcpLogger.debug(`[${functionTag}] Executing external MCP tool: ${toolName} from ${externalTool.serverId}`);
5833
- const result = await this.externalServerManager.executeTool(externalTool.serverId, toolName, params, { timeout: options.timeout });
5834
- logger.debug(`[${functionTag}] External MCP tool execution successful:`, {
6047
+ const storedContext = this.toolExecutionContext || {};
6048
+ const passedAuthContext = options.authContext || {};
6049
+ const context = {
6050
+ ...storedContext,
6051
+ ...passedAuthContext,
6052
+ };
6053
+ logger.debug(`[Using merged context for unified registry tool:`, {
5835
6054
  toolName,
5836
- serverId: externalTool.serverId,
5837
- resultType: typeof result,
6055
+ storedContextKeys: Object.keys(storedContext),
6056
+ finalContextKeys: Object.keys(context),
5838
6057
  });
6058
+ const result = (await this.toolRegistry.executeTool(toolName, params, context));
6059
+ // Check if result indicates a failure and emit error event
6060
+ if (result &&
6061
+ typeof result === "object" &&
6062
+ "success" in result &&
6063
+ result.success === false) {
6064
+ const errorMessage = result.error || "Tool execution failed";
6065
+ const errorToEmit = new Error(errorMessage);
6066
+ this.emitter.emit("error", errorToEmit);
6067
+ }
5839
6068
  return result;
5840
6069
  }
5841
6070
  catch (error) {
5842
- logger.error(`[${functionTag}] External MCP tool execution failed:`, {
5843
- toolName,
5844
- serverId: externalTool.serverId,
5845
- error: error instanceof Error ? error.message : String(error),
5846
- });
5847
- throw ErrorFactory.toolExecutionFailed(toolName, error instanceof Error ? error : new Error(String(error)), externalTool.serverId);
6071
+ const errorToEmit = error instanceof Error ? error : new Error(String(error));
6072
+ this.emitter.emit("error", errorToEmit);
6073
+ // Check if tool was not found
6074
+ if (error instanceof Error && error.message.includes("not found")) {
6075
+ const availableTools = await this.getAllAvailableTools();
6076
+ throw ErrorFactory.toolNotFound(toolName, availableTools.map((t) => t.name));
6077
+ }
6078
+ throw ErrorFactory.toolExecutionFailed(toolName, error instanceof Error ? error : new Error(String(error)));
5848
6079
  }
5849
- }
6080
+ };
6081
+ // Execute with middleware chain
5850
6082
  try {
5851
- const storedContext = this.toolExecutionContext || {};
5852
- const passedAuthContext = options.authContext || {};
5853
- const context = {
5854
- ...storedContext,
5855
- ...passedAuthContext,
5856
- };
5857
- logger.debug(`[Using merged context for unified registry tool:`, {
5858
- toolName,
5859
- storedContextKeys: Object.keys(storedContext),
5860
- finalContextKeys: Object.keys(context),
5861
- });
5862
- const result = (await this.toolRegistry.executeTool(toolName, params, context));
5863
- // ADD: Check if result indicates a failure and emit error event
5864
- if (result &&
5865
- typeof result === "object" &&
5866
- "success" in result &&
5867
- result.success === false) {
5868
- const errorMessage = result.error || "Tool execution failed";
5869
- const errorToEmit = new Error(errorMessage);
5870
- this.emitter.emit("error", errorToEmit);
6083
+ const result = await executeWithMiddleware(executeCore);
6084
+ // === MCP ENHANCEMENT: Cache store (after successful execution) ===
6085
+ if (isCacheEnabled && result !== undefined) {
6086
+ this.mcpToolResultCache.cacheResult(toolName, params, result);
6087
+ logger.debug(`[${functionTag}] Cached result for tool: ${toolName}`);
5871
6088
  }
5872
6089
  return result;
5873
6090
  }
5874
6091
  catch (error) {
5875
- const errorToEmit = error instanceof Error ? error : new Error(String(error));
5876
- this.emitter.emit("error", errorToEmit);
5877
- // Check if tool was not found
5878
- if (error instanceof Error && error.message.includes("not found")) {
5879
- const availableTools = await this.getAllAvailableTools();
5880
- throw ErrorFactory.toolNotFound(toolName, availableTools.map((t) => t.name));
6092
+ // === MCP ENHANCEMENT: Retry safe tools on failure ===
6093
+ const toolStubForRetry = toolAnnotations
6094
+ ? {
6095
+ name: toolName,
6096
+ description: "",
6097
+ annotations: toolAnnotations,
6098
+ execute: async () => ({}),
6099
+ }
6100
+ : undefined;
6101
+ if (toolStubForRetry &&
6102
+ isSafeToRetry(toolStubForRetry) &&
6103
+ error instanceof Error &&
6104
+ isRetriableError(error)) {
6105
+ logger.debug(`[${functionTag}] Tool ${toolName} is safe to retry, attempting once more`);
6106
+ try {
6107
+ const retryResult = await executeWithMiddleware(executeCore);
6108
+ // Cache the retry result
6109
+ if (isCacheEnabled && retryResult !== undefined) {
6110
+ this.mcpToolResultCache.cacheResult(toolName, params, retryResult);
6111
+ }
6112
+ return retryResult;
6113
+ }
6114
+ catch {
6115
+ // Retry failed, throw original error
6116
+ }
5881
6117
  }
5882
- throw ErrorFactory.toolExecutionFailed(toolName, error instanceof Error ? error : new Error(String(error)));
6118
+ throw error;
5883
6119
  }
5884
6120
  }
6121
+ /**
6122
+ * Get tool annotations for execution decisions (cache, retry).
6123
+ * Checks cached tool list first, falls back to inference from tool name.
6124
+ */
6125
+ getToolAnnotationsForExecution(toolName) {
6126
+ // Check tool cache for stored annotations
6127
+ if (this.toolCache?.tools) {
6128
+ const tool = this.toolCache.tools.find((t) => t.name === toolName);
6129
+ if (tool?.annotations) {
6130
+ return tool.annotations;
6131
+ }
6132
+ }
6133
+ // Fallback: infer from tool name if annotations are enabled
6134
+ if (this.mcpEnhancementsConfig?.annotations?.autoInfer !== false) {
6135
+ return inferAnnotations({ name: toolName, description: "" });
6136
+ }
6137
+ return undefined;
6138
+ }
5885
6139
  /**
5886
6140
  * Get all available tools including custom and in-memory ones
5887
6141
  * @returns Array of available tools with metadata
@@ -6003,6 +6257,17 @@ Current user's request: ${currentInput}`;
6003
6257
  mcpLogger.debug("💡 Tool collection optimized for large sets. Memory usage reduced through efficient object reuse.");
6004
6258
  }
6005
6259
  }
6260
+ // === MCP ENHANCEMENT: Auto-infer annotations for all tools ===
6261
+ if (this.mcpEnhancementsConfig?.annotations?.autoInfer !== false) {
6262
+ for (const tool of uniqueTools) {
6263
+ if (!tool.annotations) {
6264
+ tool.annotations = inferAnnotations({
6265
+ name: tool.name,
6266
+ description: tool.description || "",
6267
+ });
6268
+ }
6269
+ }
6270
+ }
6006
6271
  // Return canonical ToolInfo[]; defer presentation transforms to call sites
6007
6272
  const tools = uniqueTools;
6008
6273
  // Update the cache
@@ -6830,6 +7095,24 @@ Current user's request: ${currentInput}`;
6830
7095
  toolsDiscovered: result.metadata?.toolsDiscovered || 0,
6831
7096
  duration: result.duration,
6832
7097
  });
7098
+ // === MCP ENHANCEMENT: Lazy-init ToolRouter when 2+ servers exist ===
7099
+ if (this.mcpEnhancementsConfig?.router?.enabled !== false) {
7100
+ const servers = this.externalServerManager.listServers();
7101
+ if (servers.length >= 2 && !this.mcpToolRouter) {
7102
+ this.mcpToolRouter = new ToolRouter({
7103
+ strategy: this.mcpEnhancementsConfig?.router?.strategy ?? "least-loaded",
7104
+ enableAffinity: this.mcpEnhancementsConfig?.router?.enableAffinity ?? false,
7105
+ });
7106
+ // Register all existing servers
7107
+ for (const server of servers) {
7108
+ this.mcpToolRouter.registerServer(server.id || serverId);
7109
+ }
7110
+ logger.debug("[NeuroLink] ToolRouter auto-initialized (2+ external servers)");
7111
+ }
7112
+ else if (this.mcpToolRouter) {
7113
+ this.mcpToolRouter.registerServer(serverId);
7114
+ }
7115
+ }
6833
7116
  // Emit server added event
6834
7117
  this.emitter.emit("externalMCP:serverAdded", {
6835
7118
  serverId,
@@ -6950,7 +7233,7 @@ Current user's request: ${currentInput}`;
6950
7233
  */
6951
7234
  async testExternalMCPConnection(config) {
6952
7235
  try {
6953
- const { MCPClientFactory } = await import("./mcp/mcpClientFactory.js");
7236
+ const { MCPClientFactory } = await withTimeout(import("./mcp/mcpClientFactory.js"), 10000);
6954
7237
  const testResult = await MCPClientFactory.testConnection(config, 10000);
6955
7238
  return {
6956
7239
  success: testResult.success,
@@ -6990,6 +7273,254 @@ Current user's request: ${currentInput}`;
6990
7273
  throw error;
6991
7274
  }
6992
7275
  }
7276
+ // ===== MCP ENHANCEMENTS SDK METHODS =====
7277
+ /**
7278
+ * Get the global elicitation manager for interactive tool input
7279
+ * Elicitation allows tools to request additional information from users during execution
7280
+ * @returns The global ElicitationManager instance
7281
+ * @example
7282
+ * ```typescript
7283
+ * const elicitationManager = neurolink.getElicitationManager();
7284
+ *
7285
+ * // Register a handler for confirmations
7286
+ * elicitationManager.registerHandler(async (request) => {
7287
+ * if (request.type === 'confirmation') {
7288
+ * const answer = await askUser(request.message);
7289
+ * return { confirmed: answer === 'yes' };
7290
+ * }
7291
+ * });
7292
+ * ```
7293
+ */
7294
+ async getElicitationManager() {
7295
+ // Dynamically import to avoid circular dependencies
7296
+ const mod = (await withTimeout(import("./mcp/elicitation/index.js"), 10000));
7297
+ return mod.globalElicitationManager;
7298
+ }
7299
+ /**
7300
+ * Register an elicitation handler for interactive tool input
7301
+ * Handlers are called when tools need user input during execution
7302
+ * @param handler - Function to handle elicitation requests
7303
+ * @example
7304
+ * ```typescript
7305
+ * neurolink.registerElicitationHandler(async (request) => {
7306
+ * switch (request.type) {
7307
+ * case 'confirmation':
7308
+ * return { confirmed: await confirmWithUser(request.message) };
7309
+ * case 'text':
7310
+ * return { value: await promptUser(request.message) };
7311
+ * case 'select':
7312
+ * return { value: await selectFromOptions(request.options) };
7313
+ * }
7314
+ * });
7315
+ * ```
7316
+ */
7317
+ async registerElicitationHandler(handler) {
7318
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
7319
+ const elicitationManager = (await this.getElicitationManager());
7320
+ elicitationManager.registerHandler(handler);
7321
+ }
7322
+ /**
7323
+ * Get the multi-server manager for load balancing and coordination
7324
+ * Allows managing multiple MCP servers with failover and load balancing
7325
+ * @returns The global MultiServerManager instance
7326
+ * @example
7327
+ * ```typescript
7328
+ * const multiServer = neurolink.getMultiServerManager();
7329
+ *
7330
+ * // Create a server group with load balancing
7331
+ * await multiServer.createServerGroup('ai-tools', {
7332
+ * servers: ['openai-server', 'anthropic-server'],
7333
+ * strategy: 'round-robin'
7334
+ * });
7335
+ * ```
7336
+ */
7337
+ async getMultiServerManager() {
7338
+ const mod = (await withTimeout(import("./mcp/multiServerManager.js"), 10000));
7339
+ return mod.globalMultiServerManager;
7340
+ }
7341
+ /**
7342
+ * Get the enhanced tool discovery service
7343
+ * Provides advanced search, filtering, and compatibility checking for tools
7344
+ * @returns EnhancedToolDiscovery instance
7345
+ * @example
7346
+ * ```typescript
7347
+ * const discovery = neurolink.getEnhancedToolDiscovery();
7348
+ *
7349
+ * // Search for tools by criteria
7350
+ * const results = await discovery.searchTools({
7351
+ * category: 'data-processing',
7352
+ * capabilities: ['streaming', 'batch'],
7353
+ * minReliability: 0.9
7354
+ * });
7355
+ * ```
7356
+ */
7357
+ async getEnhancedToolDiscovery() {
7358
+ const mod = (await withTimeout(import("./mcp/enhancedToolDiscovery.js"), 10000));
7359
+ return new mod.EnhancedToolDiscovery(this.toolRegistry);
7360
+ }
7361
+ /**
7362
+ * Get the MCP registry client for discovering servers from registries
7363
+ * Supports multiple registry sources (official, community, custom)
7364
+ * @returns The global MCPRegistryClient instance
7365
+ * @example
7366
+ * ```typescript
7367
+ * const registryClient = neurolink.getMCPRegistryClient();
7368
+ *
7369
+ * // Search for servers
7370
+ * const servers = await registryClient.searchServers({
7371
+ * query: 'database',
7372
+ * categories: ['data', 'storage']
7373
+ * });
7374
+ *
7375
+ * // Get a well-known server config
7376
+ * const githubServer = registryClient.getWellKnownServer('github');
7377
+ * ```
7378
+ */
7379
+ async getMCPRegistryClient() {
7380
+ const mod = (await withTimeout(import("./mcp/mcpRegistryClient.js"), 10000));
7381
+ return mod.globalMCPRegistryClient;
7382
+ }
7383
+ /**
7384
+ * Expose a NeuroLink agent as an MCP tool
7385
+ * This allows agents to be called by other systems via MCP
7386
+ * @param agent - The agent to expose (must include id, name, description, and execute)
7387
+ * @param options - Exposure configuration options (prefix, defaultAnnotations, etc.)
7388
+ * @returns The exposed tool definition
7389
+ * @example
7390
+ * ```typescript
7391
+ * const agent = {
7392
+ * id: 'my-agent',
7393
+ * name: 'My Agent',
7394
+ * description: 'An agent that processes data',
7395
+ * execute: async (params) => { ... }
7396
+ * };
7397
+ * const tool = await neurolink.exposeAgentAsTool(agent, {
7398
+ * prefix: 'agent_'
7399
+ * });
7400
+ * ```
7401
+ */
7402
+ async exposeAgentAsTool(agent, options) {
7403
+ const agentExposure = await withTimeout(import("./mcp/agentExposure.js"), 10000);
7404
+ return agentExposure.exposeAgentAsTool(agent, options);
7405
+ }
7406
+ /**
7407
+ * Expose a workflow as an MCP tool
7408
+ * This allows workflows to be called by other systems via MCP
7409
+ * @param workflow - The workflow to expose (must include id, name, description, and execute)
7410
+ * @param options - Exposure configuration options (prefix, defaultAnnotations, etc.)
7411
+ * @returns The exposed tool definition
7412
+ * @example
7413
+ * ```typescript
7414
+ * const workflow = {
7415
+ * id: 'data-pipeline',
7416
+ * name: 'Data Pipeline',
7417
+ * description: 'Runs the data processing pipeline',
7418
+ * execute: async (params) => { ... }
7419
+ * };
7420
+ * const tool = await neurolink.exposeWorkflowAsTool(workflow, {
7421
+ * prefix: 'workflow_'
7422
+ * });
7423
+ * ```
7424
+ */
7425
+ async exposeWorkflowAsTool(workflow, options) {
7426
+ const agentExposure = await withTimeout(import("./mcp/agentExposure.js"), 10000);
7427
+ return agentExposure.exposeWorkflowAsTool(workflow, options);
7428
+ }
7429
+ /**
7430
+ * Get the tool integration manager for middleware and elicitation
7431
+ * Provides advanced tool wrapping with confirmation, timeout, retry, etc.
7432
+ * @returns The global ToolIntegrationManager instance
7433
+ * @example
7434
+ * ```typescript
7435
+ * const integration = neurolink.getToolIntegrationManager();
7436
+ *
7437
+ * // Register a tool with middleware
7438
+ * integration.registerTool(myTool, {
7439
+ * timeout: 30000,
7440
+ * retries: 3,
7441
+ * requireConfirmation: true
7442
+ * });
7443
+ * ```
7444
+ */
7445
+ async getToolIntegrationManager() {
7446
+ const mod = (await withTimeout(import("./mcp/toolIntegration.js"), 10000));
7447
+ return mod.globalToolIntegrationManager;
7448
+ }
7449
+ /**
7450
+ * Convert NeuroLink tools to MCP format
7451
+ * Useful for exposing local tools to external MCP clients
7452
+ * @param tools - Array of NeuroLink tool definitions
7453
+ * @param options - Conversion options
7454
+ * @returns Array of MCP-formatted tools
7455
+ * @example
7456
+ * ```typescript
7457
+ * const mcpTools = neurolink.convertToolsToMCPFormat([
7458
+ * { name: 'myTool', description: 'Does something', execute: async () => {} }
7459
+ * ]);
7460
+ * ```
7461
+ */
7462
+ async convertToolsToMCPFormat(tools, options = {}) {
7463
+ const mod = (await withTimeout(import("./mcp/toolConverter.js"), 10000));
7464
+ // Ensure all tools have an execute function (required by NeuroLinkTool)
7465
+ const normalizedTools = tools.map((tool) => ({
7466
+ ...tool,
7467
+ execute: tool.execute ??
7468
+ (async () => ({
7469
+ success: false,
7470
+ error: "No execute function provided",
7471
+ })),
7472
+ }));
7473
+ return mod.batchConvertToMCP(normalizedTools, options);
7474
+ }
7475
+ /**
7476
+ * Convert MCP tools to NeuroLink format
7477
+ * Useful for importing tools from external MCP servers
7478
+ * @param tools - Array of MCP tool definitions
7479
+ * @param options - Conversion options
7480
+ * @returns Array of NeuroLink-formatted tools
7481
+ * @example
7482
+ * ```typescript
7483
+ * const neurolinkTools = neurolink.convertToolsFromMCPFormat(externalTools, {
7484
+ * removeNamespacePrefix: 'external_'
7485
+ * });
7486
+ * ```
7487
+ */
7488
+ async convertToolsFromMCPFormat(tools, options = {}) {
7489
+ const mod = (await withTimeout(import("./mcp/toolConverter.js"), 10000));
7490
+ return mod.batchConvertToNeuroLink(tools, options);
7491
+ }
7492
+ /**
7493
+ * Get tool annotations and safety information
7494
+ * Provides insights about tool behavior, safety levels, and retry-ability
7495
+ * @param toolName - Name of the tool to analyze
7496
+ * @returns Tool annotation summary
7497
+ * @example
7498
+ * ```typescript
7499
+ * const annotations = await neurolink.getToolAnnotations('deleteFile');
7500
+ * // Returns: { destructive: true, requiresConfirmation: true, safeToRetry: false }
7501
+ * ```
7502
+ */
7503
+ async getToolAnnotations(toolName) {
7504
+ const { inferAnnotations, mergeAnnotations, getAnnotationSummary } = await withTimeout(import("./mcp/toolAnnotations.js"), 10000);
7505
+ const toolInfo = this.toolRegistry.getToolInfo(toolName);
7506
+ if (!toolInfo) {
7507
+ return null;
7508
+ }
7509
+ // Check for explicit annotations set on the tool first
7510
+ const explicitAnnotations = toolInfo.tool
7511
+ .annotations;
7512
+ // Infer annotations from the tool name/description as fallback
7513
+ const inferredAnnotations = inferAnnotations({
7514
+ name: toolInfo.tool.name,
7515
+ description: toolInfo.tool.description ?? "",
7516
+ });
7517
+ // Merge: inferred first, then explicit overrides (explicit takes precedence)
7518
+ const annotations = mergeAnnotations(inferredAnnotations, explicitAnnotations);
7519
+ return {
7520
+ annotations,
7521
+ summary: getAnnotationSummary(annotations),
7522
+ };
7523
+ }
6993
7524
  /**
6994
7525
  * Convert external MCP tools to Vercel AI SDK tool format
6995
7526
  * This allows AI providers to use external tools directly
@@ -7203,6 +7734,15 @@ Current user's request: ${currentInput}`;
7203
7734
  this.toolCache.tools = [];
7204
7735
  this.toolCache.timestamp = 0;
7205
7736
  }
7737
+ // Cleanup MCP enhancement modules
7738
+ this.mcpToolResultCache?.destroy();
7739
+ this.mcpToolRouter?.destroy();
7740
+ this.mcpToolBatcher?.destroy();
7741
+ this.mcpToolResultCache = undefined;
7742
+ this.mcpToolRouter = undefined;
7743
+ this.mcpToolBatcher = undefined;
7744
+ this.mcpEnhancedDiscovery = undefined;
7745
+ this.mcpToolMiddlewares = [];
7206
7746
  logger.debug("[NeuroLink] Maps and caches cleared successfully");
7207
7747
  }
7208
7748
  catch (error) {