@juspay/neurolink 7.33.1 → 7.33.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.
package/CHANGELOG.md CHANGED
@@ -1,3 +1,9 @@
1
+ ## [7.33.2](https://github.com/juspay/neurolink/compare/v7.33.1...v7.33.2) (2025-09-04)
2
+
3
+ ### Bug Fixes
4
+
5
+ - **(latency):** Reduced Tool Latency via Concurrent Server Init ([eb36fc9](https://github.com/juspay/neurolink/commit/eb36fc9a0ba32bb9b23c0ea163aadf2aa918d323))
6
+
1
7
  ## [7.33.1](https://github.com/juspay/neurolink/compare/v7.33.0...v7.33.1) (2025-09-03)
2
8
 
3
9
  ## [7.33.0](https://github.com/juspay/neurolink/compare/v7.32.0...v7.33.0) (2025-09-03)
@@ -22,12 +22,27 @@ export declare class ExternalServerManager extends EventEmitter {
22
22
  enableMainRegistryIntegration?: boolean;
23
23
  });
24
24
  /**
25
- * Load MCP server configurations from .mcp-config.json file
25
+ * Load MCP server configurations from .mcp-config.json file with parallel loading support
26
26
  * Automatically registers servers found in the configuration
27
27
  * @param configPath Optional path to config file (defaults to .mcp-config.json in cwd)
28
- * @returns Promise resolving to number of servers loaded
28
+ * @param options Loading options including parallel support
29
+ * @returns Promise resolving to { serversLoaded, errors }
29
30
  */
30
- loadMCPConfiguration(configPath?: string): Promise<ServerLoadResult>;
31
+ loadMCPConfiguration(configPath?: string, options?: {
32
+ parallel?: boolean;
33
+ }): Promise<ServerLoadResult>;
34
+ /**
35
+ * Load MCP servers in parallel for improved performance
36
+ * @param configPath Optional path to config file (defaults to .mcp-config.json in cwd)
37
+ * @returns Promise resolving to batch operation result
38
+ */
39
+ loadMCPConfigurationParallel(configPath?: string | null): Promise<ServerLoadResult>;
40
+ /**
41
+ * Load MCP servers sequentially (original implementation for backward compatibility)
42
+ * @param configPath Optional path to config file (defaults to .mcp-config.json in cwd)
43
+ * @returns Promise resolving to batch operation result
44
+ */
45
+ loadMCPConfigurationSequential(configPath?: string): Promise<ServerLoadResult>;
31
46
  /**
32
47
  * Validate external MCP server configuration
33
48
  */
@@ -107,12 +107,134 @@ export class ExternalServerManager extends EventEmitter {
107
107
  process.on("beforeExit", () => this.shutdown());
108
108
  }
109
109
  /**
110
- * Load MCP server configurations from .mcp-config.json file
110
+ * Load MCP server configurations from .mcp-config.json file with parallel loading support
111
111
  * Automatically registers servers found in the configuration
112
112
  * @param configPath Optional path to config file (defaults to .mcp-config.json in cwd)
113
- * @returns Promise resolving to number of servers loaded
113
+ * @param options Loading options including parallel support
114
+ * @returns Promise resolving to { serversLoaded, errors }
114
115
  */
115
- async loadMCPConfiguration(configPath) {
116
+ async loadMCPConfiguration(configPath, options = {}) {
117
+ if (options.parallel) {
118
+ return this.loadMCPConfigurationParallel(configPath);
119
+ }
120
+ return this.loadMCPConfigurationSequential(configPath);
121
+ }
122
+ /**
123
+ * Load MCP servers in parallel for improved performance
124
+ * @param configPath Optional path to config file (defaults to .mcp-config.json in cwd)
125
+ * @returns Promise resolving to batch operation result
126
+ */
127
+ async loadMCPConfigurationParallel(configPath) {
128
+ const fs = await import("fs");
129
+ const path = await import("path");
130
+ const finalConfigPath = configPath || path.join(process.cwd(), ".mcp-config.json");
131
+ if (!fs.existsSync(finalConfigPath)) {
132
+ mcpLogger.debug(`[ExternalServerManager] No MCP config found at ${finalConfigPath}`);
133
+ return { serversLoaded: 0, errors: [] };
134
+ }
135
+ mcpLogger.debug(`[ExternalServerManager] Loading MCP configuration in PARALLEL mode from ${finalConfigPath}`);
136
+ try {
137
+ const configContent = fs.readFileSync(finalConfigPath, "utf8");
138
+ const config = JSON.parse(configContent);
139
+ if (!config.mcpServers || typeof config.mcpServers !== "object") {
140
+ mcpLogger.debug("[ExternalServerManager] No mcpServers found in configuration");
141
+ return { serversLoaded: 0, errors: [] };
142
+ }
143
+ // Create promises for all servers to start them concurrently
144
+ const serverPromises = Object.entries(config.mcpServers).map(async ([serverId, serverConfig]) => {
145
+ try {
146
+ // Validate and convert config format to MCPServerInfo
147
+ if (!isValidExternalMCPServerConfig(serverConfig)) {
148
+ throw new Error(`Invalid server config for ${serverId}: missing required properties or wrong types`);
149
+ }
150
+ const externalConfig = {
151
+ id: serverId,
152
+ name: serverId,
153
+ description: `External MCP server: ${serverId}`,
154
+ transport: typeof serverConfig.transport === "string"
155
+ ? serverConfig.transport
156
+ : "stdio",
157
+ status: "initializing",
158
+ tools: [],
159
+ command: serverConfig.command,
160
+ args: Array.isArray(serverConfig.args)
161
+ ? serverConfig.args
162
+ : [],
163
+ env: isNonNullObject(serverConfig.env)
164
+ ? serverConfig.env
165
+ : {},
166
+ timeout: typeof serverConfig.timeout === "number"
167
+ ? serverConfig.timeout
168
+ : undefined,
169
+ retries: typeof serverConfig.retries === "number"
170
+ ? serverConfig.retries
171
+ : undefined,
172
+ healthCheckInterval: typeof serverConfig.healthCheckInterval === "number"
173
+ ? serverConfig.healthCheckInterval
174
+ : undefined,
175
+ autoRestart: typeof serverConfig.autoRestart === "boolean"
176
+ ? serverConfig.autoRestart
177
+ : undefined,
178
+ cwd: typeof serverConfig.cwd === "string"
179
+ ? serverConfig.cwd
180
+ : undefined,
181
+ url: typeof serverConfig.url === "string"
182
+ ? serverConfig.url
183
+ : undefined,
184
+ metadata: safeMetadataConversion(serverConfig.metadata),
185
+ };
186
+ const result = await this.addServer(serverId, externalConfig);
187
+ return { serverId, result };
188
+ }
189
+ catch (error) {
190
+ const errorMsg = `Failed to load MCP server ${serverId}: ${error instanceof Error ? error.message : String(error)}`;
191
+ mcpLogger.warn(`[ExternalServerManager] ${errorMsg}`);
192
+ return { serverId, error: errorMsg };
193
+ }
194
+ });
195
+ // Start all servers concurrently and wait for completion
196
+ const results = await Promise.allSettled(serverPromises);
197
+ // Process results to count successes and collect errors
198
+ let serversLoaded = 0;
199
+ const errors = [];
200
+ for (const result of results) {
201
+ if (result.status === "fulfilled") {
202
+ const { serverId, result: serverResult, error } = result.value;
203
+ if (serverResult && serverResult.success) {
204
+ serversLoaded++;
205
+ mcpLogger.debug(`[ExternalServerManager] Successfully loaded MCP server in parallel: ${serverId}`);
206
+ }
207
+ else if (error) {
208
+ errors.push(error);
209
+ }
210
+ else if (serverResult && !serverResult.success) {
211
+ const errorMsg = `Failed to load server ${serverId}: ${serverResult.error}`;
212
+ errors.push(errorMsg);
213
+ mcpLogger.warn(`[ExternalServerManager] ${errorMsg}`);
214
+ }
215
+ }
216
+ else {
217
+ // Promise.allSettled rejected - this shouldn't happen with our error handling
218
+ const errorMsg = `Unexpected error during parallel loading: ${result.reason}`;
219
+ errors.push(errorMsg);
220
+ mcpLogger.error(`[ExternalServerManager] ${errorMsg}`);
221
+ }
222
+ }
223
+ mcpLogger.info(`[ExternalServerManager] PARALLEL MCP configuration loading complete: ${serversLoaded} servers loaded, ${errors.length} errors`);
224
+ return { serversLoaded, errors };
225
+ }
226
+ catch (error) {
227
+ const errorMsg = `Failed to load MCP configuration in parallel mode: ${error instanceof Error ? error.message : String(error)}`;
228
+ mcpLogger.error(`[ExternalServerManager] ${errorMsg}`);
229
+ return { serversLoaded: 0, errors: [errorMsg] };
230
+ }
231
+ }
232
+ /**
233
+ * Load MCP servers sequentially (original implementation for backward compatibility)
234
+ * @param configPath Optional path to config file (defaults to .mcp-config.json in cwd)
235
+ * @returns Promise resolving to batch operation result
236
+ */
237
+ async loadMCPConfigurationSequential(configPath) {
116
238
  const fs = await import("fs");
117
239
  const path = await import("path");
118
240
  const finalConfigPath = configPath || path.join(process.cwd(), ".mcp-config.json");
@@ -146,7 +146,7 @@ export declare class NeuroLink {
146
146
  */
147
147
  private registerDirectToolsServerInternal;
148
148
  /**
149
- * Load MCP configuration from .mcp-config.json
149
+ * Load MCP configuration from .mcp-config.json with parallel loading for improved performance
150
150
  */
151
151
  private loadMCPConfigurationInternal;
152
152
  /**
@@ -705,7 +705,7 @@ export class NeuroLink {
705
705
  }
706
706
  }
707
707
  /**
708
- * Load MCP configuration from .mcp-config.json
708
+ * Load MCP configuration from .mcp-config.json with parallel loading for improved performance
709
709
  */
710
710
  async loadMCPConfigurationInternal(mcpInitId, mcpInitStartTime, mcpInitHrTimeStart) {
711
711
  const mcpConfigStartTime = process.hrtime.bigint();
@@ -720,7 +720,8 @@ export class NeuroLink {
720
720
  message: "Starting MCP configuration loading from .mcp-config.json",
721
721
  });
722
722
  try {
723
- const configResult = await this.externalServerManager.loadMCPConfiguration();
723
+ const configResult = await this.externalServerManager.loadMCPConfiguration(undefined, // Use default config path
724
+ { parallel: true });
724
725
  const mcpConfigSuccessTime = process.hrtime.bigint();
725
726
  const mcpConfigDurationNs = mcpConfigSuccessTime - mcpConfigStartTime;
726
727
  logger.debug(`[NeuroLink] ✅ LOG_POINT_M015_MCP_CONFIG_SUCCESS`, {
@@ -22,12 +22,27 @@ export declare class ExternalServerManager extends EventEmitter {
22
22
  enableMainRegistryIntegration?: boolean;
23
23
  });
24
24
  /**
25
- * Load MCP server configurations from .mcp-config.json file
25
+ * Load MCP server configurations from .mcp-config.json file with parallel loading support
26
26
  * Automatically registers servers found in the configuration
27
27
  * @param configPath Optional path to config file (defaults to .mcp-config.json in cwd)
28
- * @returns Promise resolving to number of servers loaded
28
+ * @param options Loading options including parallel support
29
+ * @returns Promise resolving to { serversLoaded, errors }
29
30
  */
30
- loadMCPConfiguration(configPath?: string): Promise<ServerLoadResult>;
31
+ loadMCPConfiguration(configPath?: string, options?: {
32
+ parallel?: boolean;
33
+ }): Promise<ServerLoadResult>;
34
+ /**
35
+ * Load MCP servers in parallel for improved performance
36
+ * @param configPath Optional path to config file (defaults to .mcp-config.json in cwd)
37
+ * @returns Promise resolving to batch operation result
38
+ */
39
+ loadMCPConfigurationParallel(configPath?: string | null): Promise<ServerLoadResult>;
40
+ /**
41
+ * Load MCP servers sequentially (original implementation for backward compatibility)
42
+ * @param configPath Optional path to config file (defaults to .mcp-config.json in cwd)
43
+ * @returns Promise resolving to batch operation result
44
+ */
45
+ loadMCPConfigurationSequential(configPath?: string): Promise<ServerLoadResult>;
31
46
  /**
32
47
  * Validate external MCP server configuration
33
48
  */
@@ -107,12 +107,134 @@ export class ExternalServerManager extends EventEmitter {
107
107
  process.on("beforeExit", () => this.shutdown());
108
108
  }
109
109
  /**
110
- * Load MCP server configurations from .mcp-config.json file
110
+ * Load MCP server configurations from .mcp-config.json file with parallel loading support
111
111
  * Automatically registers servers found in the configuration
112
112
  * @param configPath Optional path to config file (defaults to .mcp-config.json in cwd)
113
- * @returns Promise resolving to number of servers loaded
113
+ * @param options Loading options including parallel support
114
+ * @returns Promise resolving to { serversLoaded, errors }
114
115
  */
115
- async loadMCPConfiguration(configPath) {
116
+ async loadMCPConfiguration(configPath, options = {}) {
117
+ if (options.parallel) {
118
+ return this.loadMCPConfigurationParallel(configPath);
119
+ }
120
+ return this.loadMCPConfigurationSequential(configPath);
121
+ }
122
+ /**
123
+ * Load MCP servers in parallel for improved performance
124
+ * @param configPath Optional path to config file (defaults to .mcp-config.json in cwd)
125
+ * @returns Promise resolving to batch operation result
126
+ */
127
+ async loadMCPConfigurationParallel(configPath) {
128
+ const fs = await import("fs");
129
+ const path = await import("path");
130
+ const finalConfigPath = configPath || path.join(process.cwd(), ".mcp-config.json");
131
+ if (!fs.existsSync(finalConfigPath)) {
132
+ mcpLogger.debug(`[ExternalServerManager] No MCP config found at ${finalConfigPath}`);
133
+ return { serversLoaded: 0, errors: [] };
134
+ }
135
+ mcpLogger.debug(`[ExternalServerManager] Loading MCP configuration in PARALLEL mode from ${finalConfigPath}`);
136
+ try {
137
+ const configContent = fs.readFileSync(finalConfigPath, "utf8");
138
+ const config = JSON.parse(configContent);
139
+ if (!config.mcpServers || typeof config.mcpServers !== "object") {
140
+ mcpLogger.debug("[ExternalServerManager] No mcpServers found in configuration");
141
+ return { serversLoaded: 0, errors: [] };
142
+ }
143
+ // Create promises for all servers to start them concurrently
144
+ const serverPromises = Object.entries(config.mcpServers).map(async ([serverId, serverConfig]) => {
145
+ try {
146
+ // Validate and convert config format to MCPServerInfo
147
+ if (!isValidExternalMCPServerConfig(serverConfig)) {
148
+ throw new Error(`Invalid server config for ${serverId}: missing required properties or wrong types`);
149
+ }
150
+ const externalConfig = {
151
+ id: serverId,
152
+ name: serverId,
153
+ description: `External MCP server: ${serverId}`,
154
+ transport: typeof serverConfig.transport === "string"
155
+ ? serverConfig.transport
156
+ : "stdio",
157
+ status: "initializing",
158
+ tools: [],
159
+ command: serverConfig.command,
160
+ args: Array.isArray(serverConfig.args)
161
+ ? serverConfig.args
162
+ : [],
163
+ env: isNonNullObject(serverConfig.env)
164
+ ? serverConfig.env
165
+ : {},
166
+ timeout: typeof serverConfig.timeout === "number"
167
+ ? serverConfig.timeout
168
+ : undefined,
169
+ retries: typeof serverConfig.retries === "number"
170
+ ? serverConfig.retries
171
+ : undefined,
172
+ healthCheckInterval: typeof serverConfig.healthCheckInterval === "number"
173
+ ? serverConfig.healthCheckInterval
174
+ : undefined,
175
+ autoRestart: typeof serverConfig.autoRestart === "boolean"
176
+ ? serverConfig.autoRestart
177
+ : undefined,
178
+ cwd: typeof serverConfig.cwd === "string"
179
+ ? serverConfig.cwd
180
+ : undefined,
181
+ url: typeof serverConfig.url === "string"
182
+ ? serverConfig.url
183
+ : undefined,
184
+ metadata: safeMetadataConversion(serverConfig.metadata),
185
+ };
186
+ const result = await this.addServer(serverId, externalConfig);
187
+ return { serverId, result };
188
+ }
189
+ catch (error) {
190
+ const errorMsg = `Failed to load MCP server ${serverId}: ${error instanceof Error ? error.message : String(error)}`;
191
+ mcpLogger.warn(`[ExternalServerManager] ${errorMsg}`);
192
+ return { serverId, error: errorMsg };
193
+ }
194
+ });
195
+ // Start all servers concurrently and wait for completion
196
+ const results = await Promise.allSettled(serverPromises);
197
+ // Process results to count successes and collect errors
198
+ let serversLoaded = 0;
199
+ const errors = [];
200
+ for (const result of results) {
201
+ if (result.status === "fulfilled") {
202
+ const { serverId, result: serverResult, error } = result.value;
203
+ if (serverResult && serverResult.success) {
204
+ serversLoaded++;
205
+ mcpLogger.debug(`[ExternalServerManager] Successfully loaded MCP server in parallel: ${serverId}`);
206
+ }
207
+ else if (error) {
208
+ errors.push(error);
209
+ }
210
+ else if (serverResult && !serverResult.success) {
211
+ const errorMsg = `Failed to load server ${serverId}: ${serverResult.error}`;
212
+ errors.push(errorMsg);
213
+ mcpLogger.warn(`[ExternalServerManager] ${errorMsg}`);
214
+ }
215
+ }
216
+ else {
217
+ // Promise.allSettled rejected - this shouldn't happen with our error handling
218
+ const errorMsg = `Unexpected error during parallel loading: ${result.reason}`;
219
+ errors.push(errorMsg);
220
+ mcpLogger.error(`[ExternalServerManager] ${errorMsg}`);
221
+ }
222
+ }
223
+ mcpLogger.info(`[ExternalServerManager] PARALLEL MCP configuration loading complete: ${serversLoaded} servers loaded, ${errors.length} errors`);
224
+ return { serversLoaded, errors };
225
+ }
226
+ catch (error) {
227
+ const errorMsg = `Failed to load MCP configuration in parallel mode: ${error instanceof Error ? error.message : String(error)}`;
228
+ mcpLogger.error(`[ExternalServerManager] ${errorMsg}`);
229
+ return { serversLoaded: 0, errors: [errorMsg] };
230
+ }
231
+ }
232
+ /**
233
+ * Load MCP servers sequentially (original implementation for backward compatibility)
234
+ * @param configPath Optional path to config file (defaults to .mcp-config.json in cwd)
235
+ * @returns Promise resolving to batch operation result
236
+ */
237
+ async loadMCPConfigurationSequential(configPath) {
116
238
  const fs = await import("fs");
117
239
  const path = await import("path");
118
240
  const finalConfigPath = configPath || path.join(process.cwd(), ".mcp-config.json");
@@ -146,7 +146,7 @@ export declare class NeuroLink {
146
146
  */
147
147
  private registerDirectToolsServerInternal;
148
148
  /**
149
- * Load MCP configuration from .mcp-config.json
149
+ * Load MCP configuration from .mcp-config.json with parallel loading for improved performance
150
150
  */
151
151
  private loadMCPConfigurationInternal;
152
152
  /**
package/dist/neurolink.js CHANGED
@@ -705,7 +705,7 @@ export class NeuroLink {
705
705
  }
706
706
  }
707
707
  /**
708
- * Load MCP configuration from .mcp-config.json
708
+ * Load MCP configuration from .mcp-config.json with parallel loading for improved performance
709
709
  */
710
710
  async loadMCPConfigurationInternal(mcpInitId, mcpInitStartTime, mcpInitHrTimeStart) {
711
711
  const mcpConfigStartTime = process.hrtime.bigint();
@@ -720,7 +720,8 @@ export class NeuroLink {
720
720
  message: "Starting MCP configuration loading from .mcp-config.json",
721
721
  });
722
722
  try {
723
- const configResult = await this.externalServerManager.loadMCPConfiguration();
723
+ const configResult = await this.externalServerManager.loadMCPConfiguration(undefined, // Use default config path
724
+ { parallel: true });
724
725
  const mcpConfigSuccessTime = process.hrtime.bigint();
725
726
  const mcpConfigDurationNs = mcpConfigSuccessTime - mcpConfigStartTime;
726
727
  logger.debug(`[NeuroLink] ✅ LOG_POINT_M015_MCP_CONFIG_SUCCESS`, {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@juspay/neurolink",
3
- "version": "7.33.1",
3
+ "version": "7.33.2",
4
4
  "description": "Universal AI Development Platform with working MCP integration, multi-provider support, and professional CLI. Built-in tools operational, 58+ external MCP servers discoverable. Connect to filesystem, GitHub, database operations, and more. Build, test, and deploy AI applications with 9 major providers: OpenAI, Anthropic, Google AI, AWS Bedrock, Azure, Hugging Face, Ollama, and Mistral AI.",
5
5
  "author": {
6
6
  "name": "Juspay Technologies",