@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.
- package/CHANGELOG.md +12 -0
- package/README.md +59 -9
- package/dist/cli/commands/config.d.ts +4 -4
- package/dist/cli/commands/mcp.d.ts +87 -0
- package/dist/cli/commands/mcp.js +1524 -0
- package/dist/cli/loop/optionsSchema.js +4 -0
- package/dist/core/modules/ToolsManager.js +29 -2
- package/dist/index.d.ts +2 -1
- package/dist/index.js +27 -1
- package/dist/lib/core/modules/ToolsManager.js +29 -2
- package/dist/lib/index.d.ts +2 -1
- package/dist/lib/index.js +27 -1
- package/dist/lib/mcp/agentExposure.d.ts +228 -0
- package/dist/lib/mcp/agentExposure.js +357 -0
- package/dist/lib/mcp/batching/index.d.ts +11 -0
- package/dist/lib/mcp/batching/index.js +11 -0
- package/dist/lib/mcp/batching/requestBatcher.d.ts +202 -0
- package/dist/lib/mcp/batching/requestBatcher.js +442 -0
- package/dist/lib/mcp/caching/index.d.ts +11 -0
- package/dist/lib/mcp/caching/index.js +11 -0
- package/dist/lib/mcp/caching/toolCache.d.ts +221 -0
- package/dist/lib/mcp/caching/toolCache.js +434 -0
- package/dist/lib/mcp/elicitation/elicitationManager.d.ts +169 -0
- package/dist/lib/mcp/elicitation/elicitationManager.js +377 -0
- package/dist/lib/mcp/elicitation/index.d.ts +11 -0
- package/dist/lib/mcp/elicitation/index.js +12 -0
- package/dist/lib/mcp/elicitation/types.d.ts +278 -0
- package/dist/lib/mcp/elicitation/types.js +11 -0
- package/dist/lib/mcp/elicitationProtocol.d.ts +228 -0
- package/dist/lib/mcp/elicitationProtocol.js +376 -0
- package/dist/lib/mcp/enhancedToolDiscovery.d.ts +205 -0
- package/dist/lib/mcp/enhancedToolDiscovery.js +482 -0
- package/dist/lib/mcp/index.d.ts +38 -1
- package/dist/lib/mcp/index.js +36 -3
- package/dist/lib/mcp/mcpRegistryClient.d.ts +332 -0
- package/dist/lib/mcp/mcpRegistryClient.js +489 -0
- package/dist/lib/mcp/mcpServerBase.d.ts +227 -0
- package/dist/lib/mcp/mcpServerBase.js +374 -0
- package/dist/lib/mcp/multiServerManager.d.ts +310 -0
- package/dist/lib/mcp/multiServerManager.js +580 -0
- package/dist/lib/mcp/routing/index.d.ts +11 -0
- package/dist/lib/mcp/routing/index.js +11 -0
- package/dist/lib/mcp/routing/toolRouter.d.ts +219 -0
- package/dist/lib/mcp/routing/toolRouter.js +417 -0
- package/dist/lib/mcp/serverCapabilities.d.ts +341 -0
- package/dist/lib/mcp/serverCapabilities.js +503 -0
- package/dist/lib/mcp/toolAnnotations.d.ts +154 -0
- package/dist/lib/mcp/toolAnnotations.js +240 -0
- package/dist/lib/mcp/toolConverter.d.ts +178 -0
- package/dist/lib/mcp/toolConverter.js +259 -0
- package/dist/lib/mcp/toolIntegration.d.ts +136 -0
- package/dist/lib/mcp/toolIntegration.js +335 -0
- package/dist/lib/memory/hippocampusInitializer.d.ts +2 -2
- package/dist/lib/memory/hippocampusInitializer.js +1 -1
- package/dist/lib/neurolink.d.ts +275 -2
- package/dist/lib/neurolink.js +596 -56
- package/dist/lib/providers/litellm.d.ts +10 -0
- package/dist/lib/providers/litellm.js +104 -2
- package/dist/lib/types/configTypes.d.ts +56 -0
- package/dist/lib/types/conversation.d.ts +2 -2
- package/dist/lib/types/generateTypes.d.ts +4 -0
- package/dist/lib/types/index.d.ts +2 -1
- package/dist/lib/types/modelTypes.d.ts +6 -6
- package/dist/lib/types/streamTypes.d.ts +2 -0
- package/dist/lib/types/tools.d.ts +2 -0
- package/dist/lib/utils/pricing.js +177 -17
- package/dist/lib/utils/schemaConversion.d.ts +6 -1
- package/dist/lib/utils/schemaConversion.js +50 -28
- package/dist/lib/workflow/config.d.ts +16 -16
- package/dist/mcp/agentExposure.d.ts +228 -0
- package/dist/mcp/agentExposure.js +356 -0
- package/dist/mcp/batching/index.d.ts +11 -0
- package/dist/mcp/batching/index.js +10 -0
- package/dist/mcp/batching/requestBatcher.d.ts +202 -0
- package/dist/mcp/batching/requestBatcher.js +441 -0
- package/dist/mcp/caching/index.d.ts +11 -0
- package/dist/mcp/caching/index.js +10 -0
- package/dist/mcp/caching/toolCache.d.ts +221 -0
- package/dist/mcp/caching/toolCache.js +433 -0
- package/dist/mcp/elicitation/elicitationManager.d.ts +169 -0
- package/dist/mcp/elicitation/elicitationManager.js +376 -0
- package/dist/mcp/elicitation/index.d.ts +11 -0
- package/dist/mcp/elicitation/index.js +11 -0
- package/dist/mcp/elicitation/types.d.ts +278 -0
- package/dist/mcp/elicitation/types.js +10 -0
- package/dist/mcp/elicitationProtocol.d.ts +228 -0
- package/dist/mcp/elicitationProtocol.js +375 -0
- package/dist/mcp/enhancedToolDiscovery.d.ts +205 -0
- package/dist/mcp/enhancedToolDiscovery.js +481 -0
- package/dist/mcp/index.d.ts +38 -1
- package/dist/mcp/index.js +36 -3
- package/dist/mcp/mcpRegistryClient.d.ts +332 -0
- package/dist/mcp/mcpRegistryClient.js +488 -0
- package/dist/mcp/mcpServerBase.d.ts +227 -0
- package/dist/mcp/mcpServerBase.js +373 -0
- package/dist/mcp/multiServerManager.d.ts +310 -0
- package/dist/mcp/multiServerManager.js +579 -0
- package/dist/mcp/routing/index.d.ts +11 -0
- package/dist/mcp/routing/index.js +10 -0
- package/dist/mcp/routing/toolRouter.d.ts +219 -0
- package/dist/mcp/routing/toolRouter.js +416 -0
- package/dist/mcp/serverCapabilities.d.ts +341 -0
- package/dist/mcp/serverCapabilities.js +502 -0
- package/dist/mcp/toolAnnotations.d.ts +154 -0
- package/dist/mcp/toolAnnotations.js +239 -0
- package/dist/mcp/toolConverter.d.ts +178 -0
- package/dist/mcp/toolConverter.js +258 -0
- package/dist/mcp/toolIntegration.d.ts +136 -0
- package/dist/mcp/toolIntegration.js +334 -0
- package/dist/memory/hippocampusInitializer.d.ts +2 -2
- package/dist/memory/hippocampusInitializer.js +1 -1
- package/dist/neurolink.d.ts +275 -2
- package/dist/neurolink.js +596 -56
- package/dist/providers/litellm.d.ts +10 -0
- package/dist/providers/litellm.js +104 -2
- package/dist/types/configTypes.d.ts +56 -0
- package/dist/types/conversation.d.ts +2 -2
- package/dist/types/generateTypes.d.ts +4 -0
- package/dist/types/index.d.ts +2 -1
- package/dist/types/streamTypes.d.ts +2 -0
- package/dist/types/tools.d.ts +2 -0
- package/dist/utils/pricing.js +177 -17
- package/dist/utils/schemaConversion.d.ts +6 -1
- package/dist/utils/schemaConversion.js +50 -28
- 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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
-
//
|
|
5821
|
-
const
|
|
5822
|
-
const
|
|
5823
|
-
|
|
5824
|
-
|
|
5825
|
-
|
|
5826
|
-
|
|
5827
|
-
|
|
5828
|
-
|
|
5829
|
-
|
|
5830
|
-
|
|
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
|
-
|
|
5833
|
-
const
|
|
5834
|
-
|
|
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
|
-
|
|
5837
|
-
|
|
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
|
-
|
|
5843
|
-
|
|
5844
|
-
|
|
5845
|
-
|
|
5846
|
-
|
|
5847
|
-
|
|
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
|
|
5852
|
-
|
|
5853
|
-
|
|
5854
|
-
|
|
5855
|
-
|
|
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
|
-
|
|
5876
|
-
|
|
5877
|
-
|
|
5878
|
-
|
|
5879
|
-
|
|
5880
|
-
|
|
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
|
|
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) {
|