@juspay/neurolink 9.27.0 → 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 +6 -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/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/generateTypes.d.ts +4 -0
- package/dist/lib/types/index.d.ts +1 -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/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/generateTypes.d.ts +4 -0
- package/dist/types/index.d.ts +1 -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 +1 -1
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tool Integration with Elicitation Context
|
|
3
|
+
*
|
|
4
|
+
* Provides integration between MCP tools and the elicitation protocol,
|
|
5
|
+
* enabling tools to request interactive user input during execution.
|
|
6
|
+
*
|
|
7
|
+
* @module mcp/toolIntegration
|
|
8
|
+
* @since 8.39.0
|
|
9
|
+
*/
|
|
10
|
+
import type { NeuroLinkExecutionContext, ToolResult } from "../types/mcpTypes.js";
|
|
11
|
+
import type { MCPServerTool, MCPToolAnnotations } from "./toolAnnotations.js";
|
|
12
|
+
import type { ElicitationContext, ElicitationHandler } from "./elicitation/types.js";
|
|
13
|
+
import { ElicitationManager } from "./elicitation/elicitationManager.js";
|
|
14
|
+
/**
|
|
15
|
+
* Tool execution context with elicitation support
|
|
16
|
+
*/
|
|
17
|
+
export type EnhancedExecutionContext = NeuroLinkExecutionContext & {
|
|
18
|
+
/**
|
|
19
|
+
* Elicitation context for interactive input
|
|
20
|
+
*/
|
|
21
|
+
elicitation: ElicitationContext;
|
|
22
|
+
/**
|
|
23
|
+
* Tool metadata
|
|
24
|
+
*/
|
|
25
|
+
toolMeta: {
|
|
26
|
+
name: string;
|
|
27
|
+
serverId?: string;
|
|
28
|
+
annotations?: MCPToolAnnotations;
|
|
29
|
+
};
|
|
30
|
+
};
|
|
31
|
+
/**
|
|
32
|
+
* Tool wrapper options
|
|
33
|
+
*/
|
|
34
|
+
export type ToolWrapperOptions = {
|
|
35
|
+
/**
|
|
36
|
+
* Elicitation manager to use
|
|
37
|
+
*/
|
|
38
|
+
elicitationManager?: ElicitationManager;
|
|
39
|
+
/**
|
|
40
|
+
* Auto-confirm destructive operations
|
|
41
|
+
*/
|
|
42
|
+
autoConfirmDestructive?: boolean;
|
|
43
|
+
/**
|
|
44
|
+
* Default timeout for elicitations
|
|
45
|
+
*/
|
|
46
|
+
elicitationTimeout?: number;
|
|
47
|
+
/**
|
|
48
|
+
* Enable logging
|
|
49
|
+
*/
|
|
50
|
+
enableLogging?: boolean;
|
|
51
|
+
};
|
|
52
|
+
/**
|
|
53
|
+
* Create elicitation context for a tool
|
|
54
|
+
*/
|
|
55
|
+
export declare function createElicitationContext(toolName: string, serverId: string | undefined, manager: ElicitationManager): ElicitationContext;
|
|
56
|
+
/**
|
|
57
|
+
* Wrap a tool with elicitation support
|
|
58
|
+
*/
|
|
59
|
+
export declare function wrapToolWithElicitation(tool: MCPServerTool, options?: ToolWrapperOptions): MCPServerTool;
|
|
60
|
+
/**
|
|
61
|
+
* Batch wrap tools with elicitation support
|
|
62
|
+
*/
|
|
63
|
+
export declare function wrapToolsWithElicitation(tools: MCPServerTool[], options?: ToolWrapperOptions): MCPServerTool[];
|
|
64
|
+
/**
|
|
65
|
+
* Tool execution middleware
|
|
66
|
+
*/
|
|
67
|
+
export type ToolMiddleware = (tool: MCPServerTool, params: unknown, context: EnhancedExecutionContext, next: () => Promise<ToolResult | unknown>) => Promise<ToolResult | unknown>;
|
|
68
|
+
/**
|
|
69
|
+
* Create a middleware chain for tool execution
|
|
70
|
+
*/
|
|
71
|
+
export declare function createToolMiddlewareChain(middlewares: ToolMiddleware[]): ToolMiddleware;
|
|
72
|
+
/**
|
|
73
|
+
* Built-in middleware: Logging
|
|
74
|
+
*/
|
|
75
|
+
export declare const loggingMiddleware: ToolMiddleware;
|
|
76
|
+
/**
|
|
77
|
+
* Built-in middleware: Confirmation for destructive operations
|
|
78
|
+
*/
|
|
79
|
+
export declare const confirmationMiddleware: ToolMiddleware;
|
|
80
|
+
/**
|
|
81
|
+
* Built-in middleware: Timeout
|
|
82
|
+
*/
|
|
83
|
+
export declare function createTimeoutMiddleware(timeoutMs: number): ToolMiddleware;
|
|
84
|
+
/**
|
|
85
|
+
* Built-in middleware: Retry
|
|
86
|
+
*/
|
|
87
|
+
export declare function createRetryMiddleware(maxRetries: number, delayMs?: number): ToolMiddleware;
|
|
88
|
+
/**
|
|
89
|
+
* Built-in middleware: Parameter validation
|
|
90
|
+
*/
|
|
91
|
+
export declare const validationMiddleware: ToolMiddleware;
|
|
92
|
+
/**
|
|
93
|
+
* Tool Integration Manager
|
|
94
|
+
*
|
|
95
|
+
* Manages tool execution with middleware and elicitation support.
|
|
96
|
+
*/
|
|
97
|
+
export declare class ToolIntegrationManager {
|
|
98
|
+
private elicitationManager;
|
|
99
|
+
private middlewares;
|
|
100
|
+
private wrappedTools;
|
|
101
|
+
constructor(elicitationManager?: ElicitationManager);
|
|
102
|
+
/**
|
|
103
|
+
* Set the elicitation handler
|
|
104
|
+
*/
|
|
105
|
+
setElicitationHandler(handler: ElicitationHandler): void;
|
|
106
|
+
/**
|
|
107
|
+
* Add middleware
|
|
108
|
+
*/
|
|
109
|
+
use(middleware: ToolMiddleware): this;
|
|
110
|
+
/**
|
|
111
|
+
* Register a tool with integration
|
|
112
|
+
*/
|
|
113
|
+
registerTool(tool: MCPServerTool): MCPServerTool;
|
|
114
|
+
/**
|
|
115
|
+
* Execute a tool with full middleware chain
|
|
116
|
+
*/
|
|
117
|
+
executeTool(toolName: string, params: unknown, context?: NeuroLinkExecutionContext): Promise<ToolResult | unknown>;
|
|
118
|
+
/**
|
|
119
|
+
* Get registered tool
|
|
120
|
+
*/
|
|
121
|
+
getTool(name: string): MCPServerTool | undefined;
|
|
122
|
+
/**
|
|
123
|
+
* Get all registered tools
|
|
124
|
+
*/
|
|
125
|
+
getAllTools(): MCPServerTool[];
|
|
126
|
+
/**
|
|
127
|
+
* Get the elicitation manager
|
|
128
|
+
*/
|
|
129
|
+
getElicitationManager(): ElicitationManager;
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* Module-level singleton ToolIntegrationManager.
|
|
133
|
+
* Note: The default ElicitationManager has no handler set. Consumers must call
|
|
134
|
+
* setElicitationHandler() before using elicitation methods.
|
|
135
|
+
*/
|
|
136
|
+
export declare const globalToolIntegrationManager: ToolIntegrationManager;
|
|
@@ -0,0 +1,334 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tool Integration with Elicitation Context
|
|
3
|
+
*
|
|
4
|
+
* Provides integration between MCP tools and the elicitation protocol,
|
|
5
|
+
* enabling tools to request interactive user input during execution.
|
|
6
|
+
*
|
|
7
|
+
* @module mcp/toolIntegration
|
|
8
|
+
* @since 8.39.0
|
|
9
|
+
*/
|
|
10
|
+
import { ElicitationManager } from "./elicitation/elicitationManager.js";
|
|
11
|
+
import { ErrorFactory, withTimeout } from "../utils/errorHandling.js";
|
|
12
|
+
import { logger } from "../utils/logger.js";
|
|
13
|
+
/**
|
|
14
|
+
* Create elicitation context for a tool
|
|
15
|
+
*/
|
|
16
|
+
export function createElicitationContext(toolName, serverId, manager) {
|
|
17
|
+
return {
|
|
18
|
+
confirm: async (message, options) => {
|
|
19
|
+
return manager.confirm(message, {
|
|
20
|
+
toolName,
|
|
21
|
+
serverId,
|
|
22
|
+
confirmLabel: options?.confirmLabel,
|
|
23
|
+
cancelLabel: options?.cancelLabel,
|
|
24
|
+
});
|
|
25
|
+
},
|
|
26
|
+
getText: async (message, options) => {
|
|
27
|
+
return manager.getText(message, {
|
|
28
|
+
toolName,
|
|
29
|
+
placeholder: options?.placeholder,
|
|
30
|
+
defaultValue: options?.defaultValue,
|
|
31
|
+
});
|
|
32
|
+
},
|
|
33
|
+
select: async (message, options) => {
|
|
34
|
+
return manager.select(message, options, { toolName });
|
|
35
|
+
},
|
|
36
|
+
multiSelect: async (message, options) => {
|
|
37
|
+
return manager.multiSelect(message, options, { toolName });
|
|
38
|
+
},
|
|
39
|
+
form: async (message, fields) => {
|
|
40
|
+
return manager.form(message, fields, { toolName, serverId });
|
|
41
|
+
},
|
|
42
|
+
request: async (elicitation) => {
|
|
43
|
+
return manager.request({
|
|
44
|
+
...elicitation,
|
|
45
|
+
toolName,
|
|
46
|
+
serverId,
|
|
47
|
+
});
|
|
48
|
+
},
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Wrap a tool with elicitation support
|
|
53
|
+
*/
|
|
54
|
+
export function wrapToolWithElicitation(tool, options = {}) {
|
|
55
|
+
const { elicitationManager, autoConfirmDestructive = false, elicitationTimeout = 60000, enableLogging = true, } = options;
|
|
56
|
+
const manager = elicitationManager ??
|
|
57
|
+
new ElicitationManager({ defaultTimeout: elicitationTimeout });
|
|
58
|
+
return {
|
|
59
|
+
...tool,
|
|
60
|
+
execute: async (params, context) => {
|
|
61
|
+
const config = context?.config;
|
|
62
|
+
const serverId = config?.serverId;
|
|
63
|
+
// Create elicitation context
|
|
64
|
+
const elicitationContext = createElicitationContext(tool.name, serverId, manager);
|
|
65
|
+
// Check if tool requires confirmation
|
|
66
|
+
const needsConfirmation = tool.annotations?.requiresConfirmation ||
|
|
67
|
+
tool.annotations?.destructiveHint;
|
|
68
|
+
if (needsConfirmation && !autoConfirmDestructive) {
|
|
69
|
+
if (enableLogging) {
|
|
70
|
+
logger.debug(`[ToolIntegration] Tool '${tool.name}' requires confirmation`);
|
|
71
|
+
}
|
|
72
|
+
const confirmed = await elicitationContext.confirm(`This operation (${tool.name}) ${tool.annotations?.destructiveHint ? "is destructive and " : ""}requires confirmation. Do you want to proceed?`, {
|
|
73
|
+
confirmLabel: "Yes, proceed",
|
|
74
|
+
cancelLabel: "Cancel",
|
|
75
|
+
});
|
|
76
|
+
if (!confirmed) {
|
|
77
|
+
return {
|
|
78
|
+
success: false,
|
|
79
|
+
error: "Operation cancelled by user",
|
|
80
|
+
metadata: {
|
|
81
|
+
toolName: tool.name,
|
|
82
|
+
cancelled: true,
|
|
83
|
+
},
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
// Create enhanced context
|
|
88
|
+
const enhancedContext = {
|
|
89
|
+
...context,
|
|
90
|
+
elicitation: elicitationContext,
|
|
91
|
+
toolMeta: {
|
|
92
|
+
name: tool.name,
|
|
93
|
+
serverId,
|
|
94
|
+
annotations: tool.annotations,
|
|
95
|
+
},
|
|
96
|
+
};
|
|
97
|
+
// Execute the tool
|
|
98
|
+
return tool.execute(params, enhancedContext);
|
|
99
|
+
},
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* Batch wrap tools with elicitation support
|
|
104
|
+
*/
|
|
105
|
+
export function wrapToolsWithElicitation(tools, options = {}) {
|
|
106
|
+
return tools.map((tool) => wrapToolWithElicitation(tool, options));
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* Create a middleware chain for tool execution
|
|
110
|
+
*/
|
|
111
|
+
export function createToolMiddlewareChain(middlewares) {
|
|
112
|
+
return async (tool, params, context, next) => {
|
|
113
|
+
const dispatch = async (index) => {
|
|
114
|
+
if (index >= middlewares.length) {
|
|
115
|
+
return next();
|
|
116
|
+
}
|
|
117
|
+
const middleware = middlewares[index];
|
|
118
|
+
return middleware(tool, params, context, () => dispatch(index + 1));
|
|
119
|
+
};
|
|
120
|
+
return dispatch(0);
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* Built-in middleware: Logging
|
|
125
|
+
*/
|
|
126
|
+
export const loggingMiddleware = async (tool, params, context, next) => {
|
|
127
|
+
const startTime = Date.now();
|
|
128
|
+
logger.debug(`[ToolMiddleware] Executing tool '${tool.name}'`);
|
|
129
|
+
try {
|
|
130
|
+
const result = await next();
|
|
131
|
+
const duration = Date.now() - startTime;
|
|
132
|
+
logger.debug(`[ToolMiddleware] Tool '${tool.name}' completed in ${duration}ms`);
|
|
133
|
+
return result;
|
|
134
|
+
}
|
|
135
|
+
catch (error) {
|
|
136
|
+
const duration = Date.now() - startTime;
|
|
137
|
+
logger.error(`[ToolMiddleware] Tool '${tool.name}' failed after ${duration}ms:`, error);
|
|
138
|
+
throw error;
|
|
139
|
+
}
|
|
140
|
+
};
|
|
141
|
+
/**
|
|
142
|
+
* Built-in middleware: Confirmation for destructive operations
|
|
143
|
+
*/
|
|
144
|
+
export const confirmationMiddleware = async (tool, params, context, next) => {
|
|
145
|
+
// Skip confirmation if elicitation context is not available
|
|
146
|
+
if (!context.elicitation?.confirm) {
|
|
147
|
+
return next();
|
|
148
|
+
}
|
|
149
|
+
if (tool.annotations?.destructiveHint ||
|
|
150
|
+
tool.annotations?.requiresConfirmation) {
|
|
151
|
+
const confirmed = await context.elicitation.confirm(`Confirm execution of ${tool.name}?`);
|
|
152
|
+
if (!confirmed) {
|
|
153
|
+
return {
|
|
154
|
+
success: false,
|
|
155
|
+
error: "Operation cancelled by user",
|
|
156
|
+
metadata: { cancelled: true },
|
|
157
|
+
};
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
return next();
|
|
161
|
+
};
|
|
162
|
+
/**
|
|
163
|
+
* Built-in middleware: Timeout
|
|
164
|
+
*/
|
|
165
|
+
export function createTimeoutMiddleware(timeoutMs) {
|
|
166
|
+
return async (tool, params, context, next) => {
|
|
167
|
+
return withTimeout(next(), timeoutMs, ErrorFactory.toolTimeout(tool.name, timeoutMs));
|
|
168
|
+
};
|
|
169
|
+
}
|
|
170
|
+
/**
|
|
171
|
+
* Built-in middleware: Retry
|
|
172
|
+
*/
|
|
173
|
+
export function createRetryMiddleware(maxRetries, delayMs = 1000) {
|
|
174
|
+
return async (tool, params, context, next) => {
|
|
175
|
+
// Only retry idempotent or read-only tools
|
|
176
|
+
const canRetry = tool.annotations?.idempotentHint || tool.annotations?.readOnlyHint;
|
|
177
|
+
if (!canRetry) {
|
|
178
|
+
return next();
|
|
179
|
+
}
|
|
180
|
+
const retries = Math.max(0, maxRetries);
|
|
181
|
+
let lastError;
|
|
182
|
+
for (let attempt = 0; attempt <= retries; attempt++) {
|
|
183
|
+
try {
|
|
184
|
+
return await next();
|
|
185
|
+
}
|
|
186
|
+
catch (error) {
|
|
187
|
+
lastError =
|
|
188
|
+
error instanceof Error
|
|
189
|
+
? error
|
|
190
|
+
: ErrorFactory.toolExecutionFailed(tool.name, new Error(String(error)));
|
|
191
|
+
if (attempt < retries) {
|
|
192
|
+
logger.warn(`[ToolMiddleware] Tool '${tool.name}' failed, retrying (${attempt + 1}/${retries})`);
|
|
193
|
+
await new Promise((resolve) => setTimeout(resolve, delayMs * (attempt + 1)));
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
throw (lastError ??
|
|
198
|
+
ErrorFactory.toolExecutionFailed(tool.name, new Error("Retry middleware exhausted without captured error")));
|
|
199
|
+
};
|
|
200
|
+
}
|
|
201
|
+
/**
|
|
202
|
+
* Built-in middleware: Parameter validation
|
|
203
|
+
*/
|
|
204
|
+
export const validationMiddleware = async (tool, params, context, next) => {
|
|
205
|
+
if (!tool.inputSchema) {
|
|
206
|
+
return next();
|
|
207
|
+
}
|
|
208
|
+
const schema = tool.inputSchema;
|
|
209
|
+
const required = schema.required ?? [];
|
|
210
|
+
const properties = schema.properties ?? {};
|
|
211
|
+
// Validate required parameters
|
|
212
|
+
const paramObj = (params ?? {});
|
|
213
|
+
const missing = [];
|
|
214
|
+
for (const req of required) {
|
|
215
|
+
if (paramObj[req] === undefined) {
|
|
216
|
+
missing.push(req);
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
if (missing.length > 0) {
|
|
220
|
+
// Try to elicit missing parameters
|
|
221
|
+
const formFields = missing.map((name) => {
|
|
222
|
+
const prop = properties[name];
|
|
223
|
+
return {
|
|
224
|
+
name,
|
|
225
|
+
label: name,
|
|
226
|
+
type: prop?.type ?? "text",
|
|
227
|
+
required: true,
|
|
228
|
+
description: prop?.description,
|
|
229
|
+
};
|
|
230
|
+
});
|
|
231
|
+
const formResult = await context.elicitation.form(`Missing required parameters for ${tool.name}`, formFields);
|
|
232
|
+
if (!formResult) {
|
|
233
|
+
return {
|
|
234
|
+
success: false,
|
|
235
|
+
error: `Missing required parameters: ${missing.join(", ")}`,
|
|
236
|
+
metadata: { missingParams: missing },
|
|
237
|
+
};
|
|
238
|
+
}
|
|
239
|
+
// Merge elicited values with params
|
|
240
|
+
Object.assign(paramObj, formResult);
|
|
241
|
+
}
|
|
242
|
+
return next();
|
|
243
|
+
};
|
|
244
|
+
/**
|
|
245
|
+
* Tool Integration Manager
|
|
246
|
+
*
|
|
247
|
+
* Manages tool execution with middleware and elicitation support.
|
|
248
|
+
*/
|
|
249
|
+
export class ToolIntegrationManager {
|
|
250
|
+
elicitationManager;
|
|
251
|
+
middlewares = [];
|
|
252
|
+
wrappedTools = new Map();
|
|
253
|
+
constructor(elicitationManager) {
|
|
254
|
+
this.elicitationManager = elicitationManager ?? new ElicitationManager();
|
|
255
|
+
}
|
|
256
|
+
/**
|
|
257
|
+
* Set the elicitation handler
|
|
258
|
+
*/
|
|
259
|
+
setElicitationHandler(handler) {
|
|
260
|
+
this.elicitationManager.setHandler(handler);
|
|
261
|
+
}
|
|
262
|
+
/**
|
|
263
|
+
* Add middleware
|
|
264
|
+
*/
|
|
265
|
+
use(middleware) {
|
|
266
|
+
this.middlewares.push(middleware);
|
|
267
|
+
return this;
|
|
268
|
+
}
|
|
269
|
+
/**
|
|
270
|
+
* Register a tool with integration
|
|
271
|
+
*/
|
|
272
|
+
registerTool(tool) {
|
|
273
|
+
const wrapped = wrapToolWithElicitation(tool, {
|
|
274
|
+
elicitationManager: this.elicitationManager,
|
|
275
|
+
});
|
|
276
|
+
this.wrappedTools.set(tool.name, wrapped);
|
|
277
|
+
return wrapped;
|
|
278
|
+
}
|
|
279
|
+
/**
|
|
280
|
+
* Execute a tool with full middleware chain
|
|
281
|
+
*/
|
|
282
|
+
async executeTool(toolName, params, context) {
|
|
283
|
+
const tool = this.wrappedTools.get(toolName);
|
|
284
|
+
if (!tool) {
|
|
285
|
+
throw ErrorFactory.toolNotFound(toolName, Array.from(this.wrappedTools.keys()));
|
|
286
|
+
}
|
|
287
|
+
// Normalize params to a mutable object so middleware (e.g. validationMiddleware)
|
|
288
|
+
// can merge elicited values and have them forwarded to tool.execute
|
|
289
|
+
const normalizedParams = params && typeof params === "object" ? params : {};
|
|
290
|
+
const config = context?.config;
|
|
291
|
+
const serverId = config?.serverId;
|
|
292
|
+
// Create enhanced context
|
|
293
|
+
const elicitationContext = createElicitationContext(toolName, serverId, this.elicitationManager);
|
|
294
|
+
const enhancedContext = {
|
|
295
|
+
...context,
|
|
296
|
+
elicitation: elicitationContext,
|
|
297
|
+
toolMeta: {
|
|
298
|
+
name: toolName,
|
|
299
|
+
serverId,
|
|
300
|
+
annotations: tool.annotations,
|
|
301
|
+
},
|
|
302
|
+
};
|
|
303
|
+
// Create middleware chain
|
|
304
|
+
if (this.middlewares.length === 0) {
|
|
305
|
+
return tool.execute(normalizedParams, enhancedContext);
|
|
306
|
+
}
|
|
307
|
+
const chain = createToolMiddlewareChain(this.middlewares);
|
|
308
|
+
return chain(tool, normalizedParams, enhancedContext, () => tool.execute(normalizedParams, enhancedContext));
|
|
309
|
+
}
|
|
310
|
+
/**
|
|
311
|
+
* Get registered tool
|
|
312
|
+
*/
|
|
313
|
+
getTool(name) {
|
|
314
|
+
return this.wrappedTools.get(name);
|
|
315
|
+
}
|
|
316
|
+
/**
|
|
317
|
+
* Get all registered tools
|
|
318
|
+
*/
|
|
319
|
+
getAllTools() {
|
|
320
|
+
return Array.from(this.wrappedTools.values());
|
|
321
|
+
}
|
|
322
|
+
/**
|
|
323
|
+
* Get the elicitation manager
|
|
324
|
+
*/
|
|
325
|
+
getElicitationManager() {
|
|
326
|
+
return this.elicitationManager;
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
/**
|
|
330
|
+
* Module-level singleton ToolIntegrationManager.
|
|
331
|
+
* Note: The default ElicitationManager has no handler set. Consumers must call
|
|
332
|
+
* setElicitationHandler() before using elicitation methods.
|
|
333
|
+
*/
|
|
334
|
+
export const globalToolIntegrationManager = new ToolIntegrationManager();
|