@juspay/neurolink 7.29.1 → 7.29.2

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 (59) hide show
  1. package/CHANGELOG.md +6 -0
  2. package/dist/cli/commands/config.d.ts +3 -3
  3. package/dist/cli/commands/mcp.js +25 -0
  4. package/dist/cli/factories/commandFactory.d.ts +1 -0
  5. package/dist/cli/factories/commandFactory.js +115 -21
  6. package/dist/cli/index.js +8 -0
  7. package/dist/core/factory.js +77 -4
  8. package/dist/factories/providerFactory.js +3 -0
  9. package/dist/factories/providerRegistry.js +2 -2
  10. package/dist/lib/core/factory.js +77 -4
  11. package/dist/lib/factories/providerFactory.js +3 -0
  12. package/dist/lib/factories/providerRegistry.js +2 -2
  13. package/dist/lib/mcp/externalServerManager.js +13 -14
  14. package/dist/lib/mcp/flexibleToolValidator.d.ts +50 -0
  15. package/dist/lib/mcp/flexibleToolValidator.js +161 -0
  16. package/dist/lib/mcp/toolRegistry.d.ts +2 -2
  17. package/dist/lib/mcp/toolRegistry.js +25 -50
  18. package/dist/lib/neurolink.d.ts +2 -0
  19. package/dist/lib/neurolink.js +137 -69
  20. package/dist/lib/providers/amazonBedrock.d.ts +47 -6
  21. package/dist/lib/providers/amazonBedrock.js +282 -23
  22. package/dist/lib/providers/aws/credentialProvider.d.ts +58 -0
  23. package/dist/lib/providers/aws/credentialProvider.js +267 -0
  24. package/dist/lib/providers/aws/credentialTester.d.ts +49 -0
  25. package/dist/lib/providers/aws/credentialTester.js +394 -0
  26. package/dist/lib/proxy/awsProxyIntegration.d.ts +23 -0
  27. package/dist/lib/proxy/awsProxyIntegration.js +285 -0
  28. package/dist/lib/proxy/proxyFetch.d.ts +9 -5
  29. package/dist/lib/proxy/proxyFetch.js +232 -98
  30. package/dist/lib/proxy/utils/noProxyUtils.d.ts +39 -0
  31. package/dist/lib/proxy/utils/noProxyUtils.js +149 -0
  32. package/dist/lib/types/providers.d.ts +43 -0
  33. package/dist/lib/utils/providerConfig.d.ts +1 -0
  34. package/dist/lib/utils/providerConfig.js +2 -1
  35. package/dist/lib/utils/providerHealth.js +123 -5
  36. package/dist/mcp/externalServerManager.js +13 -14
  37. package/dist/mcp/flexibleToolValidator.d.ts +50 -0
  38. package/dist/mcp/flexibleToolValidator.js +161 -0
  39. package/dist/mcp/toolRegistry.d.ts +2 -2
  40. package/dist/mcp/toolRegistry.js +25 -50
  41. package/dist/neurolink.d.ts +2 -0
  42. package/dist/neurolink.js +137 -69
  43. package/dist/providers/amazonBedrock.d.ts +47 -6
  44. package/dist/providers/amazonBedrock.js +282 -23
  45. package/dist/providers/aws/credentialProvider.d.ts +58 -0
  46. package/dist/providers/aws/credentialProvider.js +267 -0
  47. package/dist/providers/aws/credentialTester.d.ts +49 -0
  48. package/dist/providers/aws/credentialTester.js +394 -0
  49. package/dist/proxy/awsProxyIntegration.d.ts +23 -0
  50. package/dist/proxy/awsProxyIntegration.js +285 -0
  51. package/dist/proxy/proxyFetch.d.ts +9 -5
  52. package/dist/proxy/proxyFetch.js +232 -98
  53. package/dist/proxy/utils/noProxyUtils.d.ts +39 -0
  54. package/dist/proxy/utils/noProxyUtils.js +149 -0
  55. package/dist/types/providers.d.ts +43 -0
  56. package/dist/utils/providerConfig.d.ts +1 -0
  57. package/dist/utils/providerConfig.js +2 -1
  58. package/dist/utils/providerHealth.js +123 -5
  59. package/package.json +5 -1
@@ -0,0 +1,50 @@
1
+ /**
2
+ * FlexibleToolValidator - Universal Safety Checks Only
3
+ *
4
+ * Following Anthropic's MCP specification which intentionally leaves tool naming flexible,
5
+ * this validator only blocks truly dangerous cases to support maximum MCP tool compatibility.
6
+ *
7
+ * Phase 1 Implementation:
8
+ * - Universal safety checks only (empty names, control characters, excessive length)
9
+ * - No context-specific validation or arbitrary pattern restrictions
10
+ * - Designed to support ALL legitimate MCP tools (github.create_repo, filesystem.read_file, etc.)
11
+ */
12
+ export interface FlexibleValidationResult {
13
+ isValid: boolean;
14
+ error?: string;
15
+ warnings?: string[];
16
+ }
17
+ export declare class FlexibleToolValidator {
18
+ private static readonly MAX_TOOL_NAME_LENGTH;
19
+ private static readonly MIN_TOOL_NAME_LENGTH;
20
+ /**
21
+ * Validate tool name with universal safety checks only
22
+ *
23
+ * This method only blocks truly dangerous cases:
24
+ * 1. Empty or whitespace-only names
25
+ * 2. Control characters that could break systems
26
+ * 3. Excessively long names that could cause memory issues
27
+ *
28
+ * Everything else is allowed to support maximum MCP tool compatibility.
29
+ */
30
+ static validateToolName(toolId: string): FlexibleValidationResult;
31
+ /**
32
+ * Validate tool information with minimal safety checks
33
+ */
34
+ static validateToolInfo(toolId: string, toolInfo: {
35
+ description?: string;
36
+ serverId?: string;
37
+ }): FlexibleValidationResult;
38
+ /**
39
+ * Get information about what this validator checks
40
+ */
41
+ static getValidationInfo(): {
42
+ philosophy: string;
43
+ checks: string[];
44
+ whatIsAllowed: string[];
45
+ examples: {
46
+ valid: string[];
47
+ invalid: string[];
48
+ };
49
+ };
50
+ }
@@ -0,0 +1,161 @@
1
+ /**
2
+ * FlexibleToolValidator - Universal Safety Checks Only
3
+ *
4
+ * Following Anthropic's MCP specification which intentionally leaves tool naming flexible,
5
+ * this validator only blocks truly dangerous cases to support maximum MCP tool compatibility.
6
+ *
7
+ * Phase 1 Implementation:
8
+ * - Universal safety checks only (empty names, control characters, excessive length)
9
+ * - No context-specific validation or arbitrary pattern restrictions
10
+ * - Designed to support ALL legitimate MCP tools (github.create_repo, filesystem.read_file, etc.)
11
+ */
12
+ import { registryLogger } from "../utils/logger.js";
13
+ export class FlexibleToolValidator {
14
+ // Universal safety limits (generous to support all legitimate tools)
15
+ static MAX_TOOL_NAME_LENGTH = 1000; // Much more generous than npm's 214
16
+ static MIN_TOOL_NAME_LENGTH = 1;
17
+ /**
18
+ * Validate tool name with universal safety checks only
19
+ *
20
+ * This method only blocks truly dangerous cases:
21
+ * 1. Empty or whitespace-only names
22
+ * 2. Control characters that could break systems
23
+ * 3. Excessively long names that could cause memory issues
24
+ *
25
+ * Everything else is allowed to support maximum MCP tool compatibility.
26
+ */
27
+ static validateToolName(toolId) {
28
+ const warnings = [];
29
+ // Safety Check 1: Empty or whitespace-only names
30
+ if (!toolId || typeof toolId !== "string") {
31
+ return {
32
+ isValid: false,
33
+ error: "Tool name is required and must be a string",
34
+ };
35
+ }
36
+ // Safety Check 2: Control characters that could break systems (check BEFORE trimming!)
37
+ // Only block truly dangerous control characters, not printable characters
38
+ //
39
+ // This regex blocks dangerous C0 control characters and DEL:
40
+ // - \x00-\x08: NULL, SOH, STX, ETX, EOT, ENQ, ACK, BEL, BS
41
+ // - \x0B: Vertical Tab (VT)
42
+ // - \x0C: Form Feed (FF)
43
+ // - \x0E-\x1F: SO, SI, DLE, DC1-4, NAK, SYN, ETB, CAN, EM, SUB, ESC, FS-US
44
+ // - \x7F: DEL
45
+ //
46
+ // Explicitly ALLOWS these printable control characters:
47
+ // - \x09: TAB (horizontal tab) - commonly used in text
48
+ // - \x0A: LF (line feed) - commonly used in text
49
+ // - \x0D: CR (carriage return) - commonly used in text
50
+ // eslint-disable-next-line no-control-regex
51
+ const hasControlCharacters = /[\x00-\x08\x0B\x0C\x0E-\x1F\x7F]/.test(toolId);
52
+ if (hasControlCharacters) {
53
+ return {
54
+ isValid: false,
55
+ error: "Tool name contains control characters that could break systems",
56
+ };
57
+ }
58
+ const trimmedName = toolId.trim();
59
+ if (trimmedName.length === 0) {
60
+ return {
61
+ isValid: false,
62
+ error: "Tool name cannot be empty or whitespace-only",
63
+ };
64
+ }
65
+ // Safety Check 3: Length limits (very generous)
66
+ if (trimmedName.length < this.MIN_TOOL_NAME_LENGTH) {
67
+ return {
68
+ isValid: false,
69
+ error: `Tool name must be at least ${this.MIN_TOOL_NAME_LENGTH} character long`,
70
+ };
71
+ }
72
+ if (trimmedName.length > this.MAX_TOOL_NAME_LENGTH) {
73
+ return {
74
+ isValid: false,
75
+ error: `Tool name exceeds maximum length of ${this.MAX_TOOL_NAME_LENGTH} characters`,
76
+ };
77
+ }
78
+ // Optional warnings for unusual but not dangerous patterns
79
+ if (trimmedName !== toolId) {
80
+ warnings.push("Tool name has leading/trailing whitespace (will be trimmed)");
81
+ }
82
+ if (trimmedName.length > 200) {
83
+ warnings.push("Tool name is unusually long but allowed");
84
+ }
85
+ registryLogger.debug(`✅ FlexibleToolValidator: Tool '${toolId}' passed universal safety checks`);
86
+ return {
87
+ isValid: true,
88
+ warnings: warnings.length > 0 ? warnings : undefined,
89
+ };
90
+ }
91
+ /**
92
+ * Validate tool information with minimal safety checks
93
+ */
94
+ static validateToolInfo(toolId, toolInfo) {
95
+ // First validate the tool name
96
+ const nameValidation = this.validateToolName(toolId);
97
+ if (!nameValidation.isValid) {
98
+ return nameValidation;
99
+ }
100
+ const warnings = [...(nameValidation.warnings || [])];
101
+ // Minimal safety checks for tool info
102
+ if (toolInfo.description && typeof toolInfo.description !== "string") {
103
+ return {
104
+ isValid: false,
105
+ error: "Tool description must be a string if provided",
106
+ };
107
+ }
108
+ if (toolInfo.serverId && typeof toolInfo.serverId !== "string") {
109
+ return {
110
+ isValid: false,
111
+ error: "Tool serverId must be a string if provided",
112
+ };
113
+ }
114
+ registryLogger.debug(`✅ FlexibleToolValidator: Tool info for '${toolId}' passed validation`);
115
+ return {
116
+ isValid: true,
117
+ warnings: warnings.length > 0 ? warnings : undefined,
118
+ };
119
+ }
120
+ /**
121
+ * Get information about what this validator checks
122
+ */
123
+ static getValidationInfo() {
124
+ return {
125
+ philosophy: "Maximum flexibility with universal safety only - following Anthropic's MCP specification",
126
+ checks: [
127
+ "Empty or whitespace-only names",
128
+ "Excessive length (over 1000 characters)",
129
+ "Control characters that could break systems",
130
+ ],
131
+ whatIsAllowed: [
132
+ "Dots (github.create_repo, filesystem.read_file)",
133
+ "Hyphens and underscores (my-tool, user_helper)",
134
+ "Numbers (tool1, my_tool_v2)",
135
+ "Unicode characters (🚀_tool, café_manager)",
136
+ "Mixed case (createRepo, ReadFile)",
137
+ "Long descriptive names (enterprise_database_connection_manager)",
138
+ "Any legitimate MCP tool naming pattern",
139
+ ],
140
+ examples: {
141
+ valid: [
142
+ "github.create_repo",
143
+ "filesystem.read_file",
144
+ "my-custom-tool",
145
+ "user_helper",
146
+ "tool1",
147
+ "🚀_rocket_tool",
148
+ "enterprise.database.connection.manager",
149
+ "UPPERCASE_TOOL",
150
+ "mixed_Case.Tool-Name_123",
151
+ ],
152
+ invalid: [
153
+ "", // Empty
154
+ " ", // Whitespace only
155
+ "tool\x00", // Control character
156
+ "a".repeat(1001), // Too long
157
+ ],
158
+ },
159
+ };
160
+ }
161
+ }
@@ -29,7 +29,7 @@ export interface ToolExecutionOptions {
29
29
  }
30
30
  export declare class MCPToolRegistry extends MCPRegistry {
31
31
  private tools;
32
- private toolImpls;
32
+ private toolImplementations;
33
33
  private toolExecutionStats;
34
34
  private builtInServerInfos;
35
35
  constructor();
@@ -122,7 +122,7 @@ export declare class MCPToolRegistry extends MCPRegistry {
122
122
  * Register a tool with implementation directly
123
123
  * This is used for external MCP server tools
124
124
  */
125
- registerTool(toolId: string, toolInfo: ToolInfo, toolImpl: ToolImplementation): void;
125
+ registerTool(toolId: string, toolInfo: ToolInfo, toolImpl: ToolImplementation): Promise<void>;
126
126
  /**
127
127
  * Remove a tool
128
128
  */
@@ -8,9 +8,10 @@ import { randomUUID } from "crypto";
8
8
  import { shouldDisableBuiltinTools } from "../utils/toolUtils.js";
9
9
  import { directAgentTools } from "../agent/directTools.js";
10
10
  import { detectCategory, createMCPServerInfo } from "../utils/mcpDefaults.js";
11
+ import { FlexibleToolValidator } from "./flexibleToolValidator.js";
11
12
  export class MCPToolRegistry extends MCPRegistry {
12
13
  tools = new Map();
13
- toolImpls = new Map(); // Store actual tool implementations
14
+ toolImplementations = new Map(); // Store actual tool implementations
14
15
  toolExecutionStats = new Map();
15
16
  builtInServerInfos = []; // DIRECT storage for MCPServerInfo
16
17
  constructor() {
@@ -38,7 +39,7 @@ export class MCPToolRegistry extends MCPRegistry {
38
39
  category: detectCategory({ isBuiltIn: true, serverId: "direct" }),
39
40
  };
40
41
  this.tools.set(toolId, toolInfo);
41
- this.toolImpls.set(toolId, {
42
+ this.toolImplementations.set(toolId, {
42
43
  execute: async (params, context) => {
43
44
  try {
44
45
  // Direct tools from AI SDK expect their specific parameter structure
@@ -153,7 +154,7 @@ export class MCPToolRegistry extends MCPRegistry {
153
154
  // Register only with fully-qualified toolId to avoid collisions
154
155
  this.tools.set(toolId, toolInfo);
155
156
  // Store the actual tool implementation for execution using toolId as key
156
- this.toolImpls.set(toolId, {
157
+ this.toolImplementations.set(toolId, {
157
158
  execute: tool.execute ||
158
159
  (async () => {
159
160
  throw new Error(`Tool ${tool.name} has no execute function`);
@@ -234,9 +235,9 @@ export class MCPToolRegistry extends MCPRegistry {
234
235
  ...context,
235
236
  };
236
237
  // Get the tool implementation using the resolved toolId
237
- const toolImpl = this.toolImpls.get(toolId);
238
+ const toolImpl = this.toolImplementations.get(toolId);
238
239
  registryLogger.debug(`Looking for tool '${toolName}' (toolId: '${toolId}'), found: ${!!toolImpl}, type: ${typeof toolImpl?.execute}`);
239
- registryLogger.debug(`Available tools:`, Array.from(this.toolImpls.keys()));
240
+ registryLogger.debug(`Available tools:`, Array.from(this.toolImplementations.keys()));
240
241
  if (!toolImpl || typeof toolImpl?.execute !== "function") {
241
242
  throw new Error(`Tool '${toolName}' implementation not found or not executable`);
242
243
  }
@@ -450,55 +451,25 @@ export class MCPToolRegistry extends MCPRegistry {
450
451
  * Register a tool with implementation directly
451
452
  * This is used for external MCP server tools
452
453
  */
453
- registerTool(toolId, toolInfo, toolImpl) {
454
+ async registerTool(toolId, toolInfo, toolImpl) {
454
455
  registryLogger.debug(`Registering tool: ${toolId}`);
455
- // Import validation functions synchronously - they are pure functions
456
- let validateTool;
457
- let isToolNameAvailable;
458
- let suggestToolNames;
459
- try {
460
- // Try ES module import first
461
- const toolRegistrationModule = require("../sdk/toolRegistration.js");
462
- ({ validateTool, isToolNameAvailable, suggestToolNames } =
463
- toolRegistrationModule);
464
- }
465
- catch (error) {
466
- // Fallback: skip validation if import fails (graceful degradation)
467
- registryLogger.warn("Tool validation module not available, skipping advanced validation", {
468
- error: error instanceof Error ? error.message : String(error),
469
- });
470
- // Create minimal validation functions
471
- validateTool = () => { }; // No-op
472
- isToolNameAvailable = () => true; // Allow all names
473
- suggestToolNames = () => ["alternative_tool"];
474
- }
475
- // Check if tool name is available (not reserved)
476
- if (!isToolNameAvailable(toolId)) {
477
- const suggestions = suggestToolNames(toolId);
478
- registryLogger.error(`Tool registration failed for ${toolId}: Name not available`);
479
- throw new Error(`Tool name '${toolId}' is not available (reserved or invalid format). ` +
480
- `Suggested alternatives: ${suggestions.slice(0, 3).join(", ")}`);
456
+ // Universal safety validation using FlexibleToolValidator
457
+ // Only blocks truly dangerous cases to support maximum MCP tool compatibility
458
+ const validation = FlexibleToolValidator.validateToolInfo(toolId, {
459
+ description: toolInfo.description,
460
+ serverId: toolInfo.serverId,
461
+ });
462
+ if (!validation.isValid) {
463
+ registryLogger.error(`Tool registration failed for ${toolId}: ${validation.error}`);
464
+ throw new Error(`Tool validation failed: ${validation.error}`);
481
465
  }
482
- // Create a simplified tool object for validation
483
- const toolForValidation = {
484
- description: toolInfo.description || "",
485
- execute: async () => "",
486
- parameters: undefined,
487
- metadata: {
488
- category: toolInfo.category,
489
- serverId: toolInfo.serverId,
490
- },
491
- };
492
- // Use comprehensive validation logic
493
- try {
494
- validateTool(toolId, toolForValidation);
495
- }
496
- catch (error) {
497
- registryLogger.error(`Tool registration failed for ${toolId}:`, error instanceof Error ? error.message : String(error));
498
- throw error;
466
+ // Log any warnings but allow registration to proceed
467
+ if (validation.warnings && validation.warnings.length > 0) {
468
+ registryLogger.warn(`Tool registration warnings for ${toolId}:`, validation.warnings);
499
469
  }
470
+ registryLogger.debug(`✅ Tool '${toolId}' passed flexible validation - registration proceeding`);
500
471
  this.tools.set(toolId, toolInfo);
501
- this.toolImpls.set(toolId, toolImpl);
472
+ this.toolImplementations.set(toolId, toolImpl);
502
473
  registryLogger.debug(`Successfully registered tool: ${toolId}`);
503
474
  }
504
475
  /**
@@ -509,6 +480,7 @@ export class MCPToolRegistry extends MCPRegistry {
509
480
  let removed = false;
510
481
  if (this.tools.has(toolName)) {
511
482
  this.tools.delete(toolName);
483
+ this.toolImplementations.delete(toolName); // Fix memory leak
512
484
  this.toolExecutionStats.delete(toolName);
513
485
  registryLogger.info(`Removed tool: ${toolName}`);
514
486
  removed = true;
@@ -518,6 +490,7 @@ export class MCPToolRegistry extends MCPRegistry {
518
490
  for (const [toolId, tool] of Array.from(this.tools.entries())) {
519
491
  if (tool.name === toolName) {
520
492
  this.tools.delete(toolId);
493
+ this.toolImplementations.delete(toolId); // Fix memory leak
521
494
  this.toolExecutionStats.delete(toolId);
522
495
  registryLogger.info(`Removed tool: ${toolId}`);
523
496
  removed = true;
@@ -567,6 +540,8 @@ export class MCPToolRegistry extends MCPRegistry {
567
540
  for (const [toolId, tool] of this.tools.entries()) {
568
541
  if (tool.serverId === serverId) {
569
542
  this.tools.delete(toolId);
543
+ this.toolImplementations.delete(toolId); // Fix memory leak
544
+ this.toolExecutionStats.delete(toolId); // Fix memory leak
570
545
  removedTools.push(toolId);
571
546
  }
572
547
  }
@@ -54,6 +54,8 @@ export declare class NeuroLink {
54
54
  * @param toolName - Name of the tool
55
55
  * @param startTime - Timestamp when tool execution started
56
56
  * @param success - Whether the tool execution was successful
57
+ * @param result - The result of the tool execution (optional)
58
+ * @param error - The error if execution failed (optional)
57
59
  */
58
60
  private emitToolEndEvent;
59
61
  private conversationMemory?;