@juspay/neurolink 1.10.0 → 1.11.1

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 (144) hide show
  1. package/CHANGELOG.md +43 -33
  2. package/README.md +16 -0
  3. package/dist/agent/direct-tools.d.ts +9 -9
  4. package/dist/cli/commands/agent-generate.d.ts +1 -2
  5. package/dist/cli/commands/agent-generate.js +5 -8
  6. package/dist/cli/commands/config.d.ts +2 -2
  7. package/dist/cli/commands/config.js +1 -1
  8. package/dist/cli/commands/mcp.js +91 -100
  9. package/dist/cli/commands/ollama.d.ts +2 -7
  10. package/dist/cli/commands/ollama.js +5 -8
  11. package/dist/cli/index.js +185 -276
  12. package/dist/core/factory.js +9 -10
  13. package/dist/index.d.ts +23 -0
  14. package/dist/index.js +35 -0
  15. package/dist/lib/agent/direct-tools.d.ts +9 -9
  16. package/dist/lib/core/factory.js +9 -10
  17. package/dist/lib/index.d.ts +23 -0
  18. package/dist/lib/index.js +35 -0
  19. package/dist/lib/mcp/adapters/plugin-bridge.d.ts +39 -0
  20. package/dist/lib/mcp/adapters/plugin-bridge.js +82 -0
  21. package/dist/lib/mcp/auto-discovery.d.ts +38 -96
  22. package/dist/lib/mcp/auto-discovery.js +100 -744
  23. package/dist/lib/mcp/client.js +4 -4
  24. package/dist/lib/mcp/context-manager.js +72 -1
  25. package/dist/lib/mcp/contracts/mcp-contract.d.ts +162 -0
  26. package/dist/lib/mcp/contracts/mcp-contract.js +58 -0
  27. package/dist/lib/mcp/core/plugin-manager.d.ts +45 -0
  28. package/dist/lib/mcp/core/plugin-manager.js +110 -0
  29. package/dist/lib/mcp/demo/plugin-demo.d.ts +20 -0
  30. package/dist/lib/mcp/demo/plugin-demo.js +116 -0
  31. package/dist/lib/mcp/ecosystem.d.ts +75 -0
  32. package/dist/lib/mcp/ecosystem.js +161 -0
  33. package/dist/lib/mcp/external-client.d.ts +88 -0
  34. package/dist/lib/mcp/external-client.js +323 -0
  35. package/dist/lib/mcp/external-manager.d.ts +112 -0
  36. package/dist/lib/mcp/external-manager.js +302 -0
  37. package/dist/lib/mcp/factory.d.ts +4 -4
  38. package/dist/lib/mcp/function-calling.js +59 -34
  39. package/dist/lib/mcp/index.d.ts +39 -184
  40. package/dist/lib/mcp/index.js +72 -150
  41. package/dist/lib/mcp/initialize.js +5 -5
  42. package/dist/lib/mcp/logging.d.ts +27 -60
  43. package/dist/lib/mcp/logging.js +77 -165
  44. package/dist/lib/mcp/neurolink-mcp-client.js +31 -3
  45. package/dist/lib/mcp/orchestrator.d.ts +1 -1
  46. package/dist/lib/mcp/orchestrator.js +13 -12
  47. package/dist/lib/mcp/plugin-manager.d.ts +98 -0
  48. package/dist/lib/mcp/plugin-manager.js +294 -0
  49. package/dist/lib/mcp/plugins/core/filesystem-mcp.d.ts +35 -0
  50. package/dist/lib/mcp/plugins/core/filesystem-mcp.js +139 -0
  51. package/dist/lib/mcp/plugins/filesystem-mcp.d.ts +36 -0
  52. package/dist/lib/mcp/plugins/filesystem-mcp.js +54 -0
  53. package/dist/lib/mcp/registry.d.ts +27 -176
  54. package/dist/lib/mcp/registry.js +31 -372
  55. package/dist/lib/mcp/security-manager.d.ts +85 -0
  56. package/dist/lib/mcp/security-manager.js +344 -0
  57. package/dist/lib/mcp/servers/ai-providers/ai-workflow-tools.d.ts +2 -2
  58. package/dist/lib/mcp/tool-integration.d.ts +4 -14
  59. package/dist/lib/mcp/tool-integration.js +43 -21
  60. package/dist/lib/mcp/tool-registry.d.ts +66 -0
  61. package/dist/lib/mcp/tool-registry.js +160 -0
  62. package/dist/lib/mcp/unified-mcp.d.ts +123 -0
  63. package/dist/lib/mcp/unified-mcp.js +246 -0
  64. package/dist/lib/mcp/unified-registry.d.ts +42 -229
  65. package/dist/lib/mcp/unified-registry.js +96 -1346
  66. package/dist/lib/neurolink.d.ts +3 -4
  67. package/dist/lib/neurolink.js +17 -18
  68. package/dist/lib/providers/agent-enhanced-provider.js +2 -2
  69. package/dist/lib/providers/amazonBedrock.js +2 -2
  70. package/dist/lib/providers/anthropic.js +3 -3
  71. package/dist/lib/providers/azureOpenAI.js +3 -3
  72. package/dist/lib/providers/function-calling-provider.js +34 -25
  73. package/dist/lib/providers/googleAIStudio.js +9 -3
  74. package/dist/lib/providers/googleVertexAI.js +2 -2
  75. package/dist/lib/providers/huggingFace.js +2 -2
  76. package/dist/lib/providers/mcp-provider.js +33 -5
  77. package/dist/lib/providers/mistralAI.js +2 -2
  78. package/dist/lib/providers/ollama.js +2 -2
  79. package/dist/lib/providers/openAI.js +2 -2
  80. package/dist/lib/utils/providerUtils-fixed.js +9 -9
  81. package/dist/mcp/adapters/plugin-bridge.d.ts +39 -0
  82. package/dist/mcp/adapters/plugin-bridge.js +82 -0
  83. package/dist/mcp/auto-discovery.d.ts +38 -96
  84. package/dist/mcp/auto-discovery.js +100 -745
  85. package/dist/mcp/client.js +4 -4
  86. package/dist/mcp/context-manager.js +72 -1
  87. package/dist/mcp/contracts/mcp-contract.d.ts +162 -0
  88. package/dist/mcp/contracts/mcp-contract.js +58 -0
  89. package/dist/mcp/core/plugin-manager.d.ts +45 -0
  90. package/dist/mcp/core/plugin-manager.js +110 -0
  91. package/dist/mcp/demo/plugin-demo.d.ts +20 -0
  92. package/dist/mcp/demo/plugin-demo.js +116 -0
  93. package/dist/mcp/ecosystem.d.ts +75 -0
  94. package/dist/mcp/ecosystem.js +162 -0
  95. package/dist/mcp/external-client.d.ts +88 -0
  96. package/dist/mcp/external-client.js +323 -0
  97. package/dist/mcp/external-manager.d.ts +112 -0
  98. package/dist/mcp/external-manager.js +302 -0
  99. package/dist/mcp/factory.d.ts +4 -4
  100. package/dist/mcp/function-calling.js +59 -34
  101. package/dist/mcp/index.d.ts +39 -184
  102. package/dist/mcp/index.js +72 -150
  103. package/dist/mcp/initialize.js +5 -5
  104. package/dist/mcp/logging.d.ts +27 -60
  105. package/dist/mcp/logging.js +77 -165
  106. package/dist/mcp/neurolink-mcp-client.js +31 -3
  107. package/dist/mcp/orchestrator.d.ts +1 -1
  108. package/dist/mcp/orchestrator.js +13 -12
  109. package/dist/mcp/plugin-manager.d.ts +98 -0
  110. package/dist/mcp/plugin-manager.js +295 -0
  111. package/dist/mcp/plugins/core/filesystem-mcp.d.ts +35 -0
  112. package/dist/mcp/plugins/core/filesystem-mcp.js +139 -0
  113. package/dist/mcp/plugins/core/neurolink-mcp.json +17 -0
  114. package/dist/mcp/plugins/filesystem-mcp.d.ts +36 -0
  115. package/dist/mcp/plugins/filesystem-mcp.js +54 -0
  116. package/dist/mcp/registry.d.ts +27 -176
  117. package/dist/mcp/registry.js +31 -372
  118. package/dist/mcp/security-manager.d.ts +85 -0
  119. package/dist/mcp/security-manager.js +344 -0
  120. package/dist/mcp/servers/ai-providers/ai-workflow-tools.d.ts +2 -2
  121. package/dist/mcp/tool-integration.d.ts +4 -14
  122. package/dist/mcp/tool-integration.js +43 -21
  123. package/dist/mcp/tool-registry.d.ts +66 -0
  124. package/dist/mcp/tool-registry.js +160 -0
  125. package/dist/mcp/unified-mcp.d.ts +123 -0
  126. package/dist/mcp/unified-mcp.js +246 -0
  127. package/dist/mcp/unified-registry.d.ts +42 -229
  128. package/dist/mcp/unified-registry.js +96 -1345
  129. package/dist/neurolink.d.ts +3 -4
  130. package/dist/neurolink.js +17 -18
  131. package/dist/providers/agent-enhanced-provider.js +2 -2
  132. package/dist/providers/amazonBedrock.js +2 -2
  133. package/dist/providers/anthropic.js +3 -3
  134. package/dist/providers/azureOpenAI.js +3 -3
  135. package/dist/providers/function-calling-provider.js +34 -25
  136. package/dist/providers/googleAIStudio.js +9 -3
  137. package/dist/providers/googleVertexAI.js +2 -2
  138. package/dist/providers/huggingFace.js +2 -2
  139. package/dist/providers/mcp-provider.js +33 -5
  140. package/dist/providers/mistralAI.js +2 -2
  141. package/dist/providers/ollama.js +2 -2
  142. package/dist/providers/openAI.js +2 -2
  143. package/dist/utils/providerUtils-fixed.js +9 -9
  144. package/package.json +1 -1
@@ -0,0 +1,302 @@
1
+ /**
2
+ * NeuroLink External MCP Manager
3
+ * Manages external MCP servers and bridges them into the NeuroLink factory ecosystem
4
+ * Reads .mcp-config.json and spawns external clients
5
+ */
6
+ import { readFile } from "fs/promises";
7
+ import { resolve } from "path";
8
+ import { createExternalMCPClient, } from "./external-client.js";
9
+ import { createMCPServer } from "./factory.js";
10
+ import { MCPToolRegistry } from "./tool-registry.js";
11
+ import { mcpLogger as logger } from "./logging.js";
12
+ /**
13
+ * External MCP Manager
14
+ * Bridges external MCP servers into NeuroLink's factory pattern ecosystem
15
+ */
16
+ export class ExternalMCPManager {
17
+ servers = new Map();
18
+ registry;
19
+ configPath;
20
+ config = null;
21
+ isInitialized = false;
22
+ constructor(configPath, registry) {
23
+ this.configPath = configPath || ".mcp-config.json";
24
+ this.registry = registry || new MCPToolRegistry();
25
+ }
26
+ /**
27
+ * Initialize the external MCP manager
28
+ * Reads config and connects to all external servers
29
+ */
30
+ async initialize() {
31
+ if (this.isInitialized) {
32
+ logger.debug("[External MCP Manager] Already initialized");
33
+ return;
34
+ }
35
+ try {
36
+ logger.info("[External MCP Manager] Initializing...");
37
+ // Load configuration
38
+ await this.loadConfig();
39
+ if (!this.config?.mcpServers) {
40
+ logger.warn("[External MCP Manager] No MCP servers configured");
41
+ this.isInitialized = true;
42
+ return;
43
+ }
44
+ // Connect to all configured servers
45
+ const serverNames = Object.keys(this.config.mcpServers);
46
+ logger.info(`[External MCP Manager] Connecting to ${serverNames.length} external servers: ${serverNames.join(", ")}`);
47
+ const connectionPromises = serverNames.map((serverName) => this.connectToServer(serverName).catch((error) => {
48
+ logger.error(`[External MCP Manager] Failed to connect to ${serverName}:`, error);
49
+ return null;
50
+ }));
51
+ const results = await Promise.allSettled(connectionPromises);
52
+ const connected = results.filter((r) => r.status === "fulfilled" && r.value !== null).length;
53
+ logger.info(`[External MCP Manager] Connected to ${connected}/${serverNames.length} external servers`);
54
+ this.isInitialized = true;
55
+ }
56
+ catch (error) {
57
+ logger.error("[External MCP Manager] Initialization failed:", error);
58
+ throw error;
59
+ }
60
+ }
61
+ /**
62
+ * Load MCP configuration from file
63
+ */
64
+ async loadConfig() {
65
+ try {
66
+ const configFile = resolve(this.configPath);
67
+ const configData = await readFile(configFile, "utf-8");
68
+ this.config = JSON.parse(configData);
69
+ logger.debug("[External MCP Manager] Config loaded:", {
70
+ serversCount: Object.keys(this.config?.mcpServers || {}).length,
71
+ autoDiscovery: this.config?.autoDiscovery?.enabled,
72
+ });
73
+ }
74
+ catch (error) {
75
+ if (error.code === "ENOENT") {
76
+ logger.warn(`[External MCP Manager] Config file not found: ${this.configPath}`);
77
+ this.config = { mcpServers: {} };
78
+ }
79
+ else {
80
+ logger.error("[External MCP Manager] Failed to load config:", error);
81
+ throw error;
82
+ }
83
+ }
84
+ }
85
+ /**
86
+ * Connect to a specific external server
87
+ */
88
+ async connectToServer(serverName) {
89
+ if (!this.config?.mcpServers[serverName]) {
90
+ throw new Error(`Server configuration not found: ${serverName}`);
91
+ }
92
+ const serverConfig = this.config.mcpServers[serverName];
93
+ try {
94
+ logger.info(`[External MCP Manager] Connecting to server: ${serverName}`);
95
+ // Create external client
96
+ const client = createExternalMCPClient({
97
+ name: serverName,
98
+ command: serverConfig.command,
99
+ args: serverConfig.args,
100
+ transport: serverConfig.transport,
101
+ env: serverConfig.env,
102
+ });
103
+ // Create server info
104
+ const serverInfo = {
105
+ name: serverName,
106
+ client,
107
+ server: createMCPServer({
108
+ id: `external-${serverName}`,
109
+ title: `External ${serverConfig.name || serverName}`,
110
+ description: `External MCP server: ${serverName}`,
111
+ category: "integrations",
112
+ visibility: "private",
113
+ metadata: {
114
+ external: true,
115
+ transport: "stdio",
116
+ command: serverConfig.command,
117
+ args: serverConfig.args,
118
+ },
119
+ }),
120
+ status: "connecting",
121
+ toolCount: 0,
122
+ retryCount: 0,
123
+ };
124
+ // Setup event handlers
125
+ client.on("connected", () => {
126
+ logger.info(`[External MCP Manager] Connected to ${serverName}`);
127
+ serverInfo.status = "connected";
128
+ this.registerServerTools(serverInfo);
129
+ });
130
+ client.on("disconnected", () => {
131
+ logger.warn(`[External MCP Manager] Disconnected from ${serverName}`);
132
+ serverInfo.status = "disconnected";
133
+ // TODO: Implement reconnection logic
134
+ });
135
+ client.on("error", (error) => {
136
+ logger.error(`[External MCP Manager] Error from ${serverName}:`, error);
137
+ serverInfo.status = "error";
138
+ serverInfo.lastError = error.message;
139
+ });
140
+ // Store server info
141
+ this.servers.set(serverName, serverInfo);
142
+ // Connect to the server
143
+ await client.connect();
144
+ return serverInfo;
145
+ }
146
+ catch (error) {
147
+ logger.error(`[External MCP Manager] Failed to connect to ${serverName}:`, error);
148
+ const serverInfo = {
149
+ name: serverName,
150
+ client: null,
151
+ server: null,
152
+ status: "error",
153
+ lastError: error instanceof Error ? error.message : String(error),
154
+ toolCount: 0,
155
+ retryCount: 0,
156
+ };
157
+ this.servers.set(serverName, serverInfo);
158
+ return null;
159
+ }
160
+ }
161
+ /**
162
+ * Register tools from an external server with the NeuroLink registry
163
+ */
164
+ async registerServerTools(serverInfo) {
165
+ try {
166
+ const tools = serverInfo.client.getNeuroLinkTools();
167
+ // Register each tool with the server
168
+ for (const [toolName, tool] of Object.entries(tools)) {
169
+ serverInfo.server.registerTool(tool);
170
+ }
171
+ serverInfo.toolCount = Object.keys(tools).length;
172
+ // Register the server with the registry
173
+ await this.registry.registerServer(serverInfo.name, serverInfo);
174
+ logger.info(`[External MCP Manager] Registered ${serverInfo.toolCount} tools from ${serverInfo.name}`);
175
+ }
176
+ catch (error) {
177
+ logger.error(`[External MCP Manager] Failed to register tools from ${serverInfo.name}:`, error);
178
+ }
179
+ }
180
+ /**
181
+ * Get all connected external servers
182
+ */
183
+ getConnectedServers() {
184
+ return Array.from(this.servers.values()).filter((s) => s.status === "connected");
185
+ }
186
+ /**
187
+ * Get server status
188
+ */
189
+ getServerStatus(serverName) {
190
+ return this.servers.get(serverName);
191
+ }
192
+ /**
193
+ * Get all server statuses
194
+ */
195
+ getAllServerStatuses() {
196
+ const statuses = {};
197
+ for (const [name, info] of this.servers) {
198
+ statuses[name] = {
199
+ ...info,
200
+ // Don't include the actual client/server objects in status
201
+ client: undefined,
202
+ server: undefined,
203
+ };
204
+ }
205
+ return statuses;
206
+ }
207
+ /**
208
+ * Execute a tool on any connected server
209
+ */
210
+ async executeTool(toolName, params, context) {
211
+ // Use the registry to execute the tool
212
+ return this.registry.executeTool(toolName, params, context);
213
+ }
214
+ /**
215
+ * List all available tools from external servers
216
+ */
217
+ listExternalTools() {
218
+ return this.registry.listTools();
219
+ }
220
+ /**
221
+ * Get registry instance
222
+ */
223
+ getRegistry() {
224
+ return this.registry;
225
+ }
226
+ /**
227
+ * Disconnect from a specific server
228
+ */
229
+ async disconnectServer(serverName) {
230
+ const serverInfo = this.servers.get(serverName);
231
+ if (!serverInfo || !serverInfo.client) {
232
+ return false;
233
+ }
234
+ try {
235
+ await serverInfo.client.disconnect();
236
+ this.registry.unregisterServer(`external-${serverName}`);
237
+ this.servers.delete(serverName);
238
+ logger.info(`[External MCP Manager] Disconnected from ${serverName}`);
239
+ return true;
240
+ }
241
+ catch (error) {
242
+ logger.error(`[External MCP Manager] Failed to disconnect from ${serverName}:`, error);
243
+ return false;
244
+ }
245
+ }
246
+ /**
247
+ * Disconnect from all servers
248
+ */
249
+ async disconnectAll() {
250
+ logger.info("[External MCP Manager] Disconnecting from all external servers");
251
+ const disconnectPromises = Array.from(this.servers.keys()).map((serverName) => this.disconnectServer(serverName));
252
+ await Promise.allSettled(disconnectPromises);
253
+ this.servers.clear();
254
+ this.isInitialized = false;
255
+ }
256
+ /**
257
+ * Refresh connections - reload config and reconnect
258
+ */
259
+ async refresh() {
260
+ logger.info("[External MCP Manager] Refreshing connections");
261
+ await this.disconnectAll();
262
+ await this.initialize();
263
+ }
264
+ /**
265
+ * Get comprehensive status
266
+ */
267
+ getStatus() {
268
+ const servers = Array.from(this.servers.values());
269
+ return {
270
+ isInitialized: this.isInitialized,
271
+ configPath: this.configPath,
272
+ totalServers: servers.length,
273
+ connected: servers.filter((s) => s.status === "connected").length,
274
+ connecting: servers.filter((s) => s.status === "connecting").length,
275
+ disconnected: servers.filter((s) => s.status === "disconnected").length,
276
+ errors: servers.filter((s) => s.status === "error").length,
277
+ totalTools: servers.reduce((sum, s) => sum + s.toolCount, 0),
278
+ servers: this.getAllServerStatuses(),
279
+ };
280
+ }
281
+ }
282
+ /**
283
+ * Default external MCP manager instance
284
+ */
285
+ export const defaultExternalMCPManager = new ExternalMCPManager();
286
+ /**
287
+ * Initialize external MCP servers with default manager
288
+ */
289
+ export async function initializeExternalMCP(configPath) {
290
+ if (configPath) {
291
+ const manager = new ExternalMCPManager(configPath);
292
+ await manager.initialize();
293
+ return;
294
+ }
295
+ await defaultExternalMCPManager.initialize();
296
+ }
297
+ /**
298
+ * Get the default external MCP manager
299
+ */
300
+ export function getExternalMCPManager() {
301
+ return defaultExternalMCPManager;
302
+ }
@@ -4,6 +4,7 @@
4
4
  * Compatible with Lighthouse MCP patterns for seamless migration
5
5
  */
6
6
  import { z } from "zod";
7
+ import type { ExecutionContext } from "./contracts/mcp-contract.js";
7
8
  /**
8
9
  * MCP Server Categories for organization and discovery
9
10
  */
@@ -11,10 +12,9 @@ export type MCPServerCategory = "ai-providers" | "frameworks" | "development" |
11
12
  /**
12
13
  * Tool execution context - Rich context passed to every tool execution
13
14
  * Following Lighthouse's pattern for rich tool context
15
+ * Extends ExecutionContext for compatibility
14
16
  */
15
- export interface NeuroLinkExecutionContext {
16
- sessionId: string;
17
- userId?: string;
17
+ export interface NeuroLinkExecutionContext extends ExecutionContext {
18
18
  aiProvider?: string;
19
19
  modelId?: string;
20
20
  temperature?: number;
@@ -51,7 +51,7 @@ export interface NeuroLinkExecutionContext {
51
51
  export interface ToolResult {
52
52
  success: boolean;
53
53
  data?: any;
54
- error?: string;
54
+ error?: string | Error;
55
55
  usage?: {
56
56
  tokens?: number;
57
57
  cost?: number;
@@ -5,7 +5,7 @@
5
5
  */
6
6
  import { tool } from "ai";
7
7
  import { z } from "zod";
8
- import { defaultUnifiedRegistry } from "./unified-registry.js";
8
+ import { unifiedRegistry } from "./unified-registry.js";
9
9
  import { createExecutionContext } from "./context-manager.js";
10
10
  import { mcpLogger } from "./logging.js";
11
11
  /**
@@ -74,18 +74,21 @@ export async function getAvailableFunctionTools() {
74
74
  const { initializeNeuroLinkMCP } = await import("./initialize.js");
75
75
  await initializeNeuroLinkMCP();
76
76
  // Ensure unified registry is initialized
77
- await defaultUnifiedRegistry.initialize();
77
+ await unifiedRegistry.initialize();
78
78
  // Try to activate important servers like filesystem
79
79
  mcpLogger.debug(`[${functionTag}] Attempting to activate important servers...`);
80
80
  try {
81
81
  // Get auto-discovered servers
82
- const autoServers = defaultUnifiedRegistry.getAutoDiscoveredServers();
82
+ const autoServers = unifiedRegistry.getAutoDiscoveredServers();
83
83
  // Try to activate filesystem server specifically
84
- for (const [serverId, entry] of autoServers) {
85
- if (serverId.includes("filesystem") &&
86
- entry.status !== "activated") {
87
- mcpLogger.debug(`[${functionTag}] Activating filesystem server: ${serverId}`);
88
- await defaultUnifiedRegistry.lazyActivateServer(serverId, entry);
84
+ for (const server of autoServers) {
85
+ if (server.metadata.name.includes("filesystem")) {
86
+ mcpLogger.debug(`[${functionTag}] Activating filesystem server: ${server.metadata.name}`);
87
+ const serverName = server.metadata.name;
88
+ if (typeof serverName === "string" && serverName.length > 0) {
89
+ // @ts-ignore - serverName is verified as string with length > 0 above
90
+ await unifiedRegistry.lazyActivateServer(serverName);
91
+ }
89
92
  }
90
93
  }
91
94
  }
@@ -93,7 +96,7 @@ export async function getAvailableFunctionTools() {
93
96
  mcpLogger.debug(`[${functionTag}] Error activating servers: ${error}`);
94
97
  }
95
98
  // Get all tools from unified registry directly
96
- const allTools = await defaultUnifiedRegistry.listAllTools();
99
+ const allTools = await unifiedRegistry.listAllTools();
97
100
  mcpLogger.debug(`[${functionTag}] Found ${allTools.length} total tools`);
98
101
  // Try to activate servers that have "-tools" entries to get real tools
99
102
  const serversToActivate = allTools
@@ -101,18 +104,19 @@ export async function getAvailableFunctionTools() {
101
104
  .map((tool) => tool.server);
102
105
  mcpLogger.debug(`[${functionTag}] Attempting to activate ${serversToActivate.length} servers for real tool discovery`);
103
106
  // Activate servers to convert placeholders to real tools
104
- for (const serverId of [...new Set(serversToActivate)]) {
107
+ for (const serverId of [...new Set(serversToActivate)].filter((id) => typeof id === "string" && id !== "unknown")) {
105
108
  try {
106
109
  mcpLogger.debug(`[${functionTag}] Activating server: ${serverId}`);
107
110
  // Get the server entry from auto-discovered or manual servers
108
- const autoServers = defaultUnifiedRegistry.getAutoDiscoveredServers();
109
- const manualServers = defaultUnifiedRegistry.getManualServers();
110
- const serverEntry = autoServers.get(serverId) || manualServers.get(serverId);
111
- if (serverEntry) {
112
- await defaultUnifiedRegistry.lazyActivateServer(serverId, serverEntry);
111
+ const autoServers = unifiedRegistry.getAutoDiscoveredServers();
112
+ const manualServers = unifiedRegistry.getManualServers();
113
+ const serverEntry = autoServers.find((s) => s.metadata.name === serverId) ||
114
+ manualServers.get(serverId);
115
+ if (serverEntry && serverId.length > 0) {
116
+ await unifiedRegistry.lazyActivateServer(serverId);
113
117
  }
114
118
  else {
115
- mcpLogger.debug(`[${functionTag}] Server entry not found for: ${serverId}`);
119
+ mcpLogger.debug(`[${functionTag}] Server entry not found for: ${serverId || "undefined"}`);
116
120
  }
117
121
  }
118
122
  catch (error) {
@@ -120,7 +124,7 @@ export async function getAvailableFunctionTools() {
120
124
  }
121
125
  }
122
126
  // Get tools again after activation
123
- const activatedTools = await defaultUnifiedRegistry.listAllTools();
127
+ const activatedTools = await unifiedRegistry.listAllTools();
124
128
  mcpLogger.debug(`[${functionTag}] Found ${activatedTools.length} total tools after activation`);
125
129
  // Filter to get real, individual tools (not placeholder or grouped tools)
126
130
  const realTools = activatedTools.filter((toolInfo) => {
@@ -152,7 +156,7 @@ export async function getAvailableFunctionTools() {
152
156
  let functionName;
153
157
  let originalFunctionName;
154
158
  // Convert server name to underscore format to check if it's embedded in tool name
155
- const sanitizedServerCheck = toolInfo.server.replace(/[^a-zA-Z0-9_]/g, "_");
159
+ const sanitizedServerCheck = (toolInfo.server || "unknown").replace(/[^a-zA-Z0-9_]/g, "_");
156
160
  if (toolInfo.name.includes(sanitizedServerCheck) ||
157
161
  toolInfo.name.endsWith("-tools") ||
158
162
  toolInfo.name.startsWith("github_com_") ||
@@ -202,7 +206,7 @@ export async function getAvailableFunctionTools() {
202
206
  }
203
207
  else {
204
208
  // Tool name doesn't include server info, create compound name
205
- const sanitizedServerName = toolInfo.server.replace(/[^a-zA-Z0-9_]/g, "_");
209
+ const sanitizedServerName = (toolInfo.server || "unknown").replace(/[^a-zA-Z0-9_]/g, "_");
206
210
  const sanitizedToolName = toolInfo.name.replace(/[^a-zA-Z0-9_]/g, "_");
207
211
  // Check if it's a filesystem tool from MCP
208
212
  if (sanitizedServerName.includes("modelcontextprotocol") &&
@@ -235,7 +239,7 @@ export async function getAvailableFunctionTools() {
235
239
  }
236
240
  }
237
241
  }
238
- originalFunctionName = `${toolInfo.server}.${toolInfo.name}`;
242
+ originalFunctionName = `${toolInfo.server || "unknown"}.${toolInfo.name}`;
239
243
  }
240
244
  // Create AI SDK tool using the proper tool() helper
241
245
  const aiTool = tool({
@@ -273,7 +277,7 @@ export async function getAvailableFunctionTools() {
273
277
  tools.push(aiTool);
274
278
  // Store mapping for execution - CRITICAL: Use sanitized functionName as key
275
279
  toolMap.set(functionName, {
276
- serverId: toolInfo.server,
280
+ serverId: toolInfo.server || "unknown",
277
281
  toolName: toolInfo.name,
278
282
  });
279
283
  mcpLogger.debug(`[${functionTag}] Converted tool: ${functionName} (original: ${originalFunctionName})`);
@@ -312,7 +316,17 @@ export async function getAvailableFunctionTools() {
312
316
  export async function executeFunctionCall(functionName, parameters, context) {
313
317
  const functionTag = "executeFunctionCall";
314
318
  try {
315
- mcpLogger.debug(`[${functionTag}] Executing function call: ${functionName}`, { parameters });
319
+ // CRITICAL FIX: Unwrap 'input' parameter if it exists
320
+ // AI function calling wraps parameters in { input: { actualParams } }
321
+ // but MCP tools expect direct parameters
322
+ let actualParameters = parameters;
323
+ if (parameters.input &&
324
+ typeof parameters.input === "object" &&
325
+ parameters.input !== null) {
326
+ actualParameters = parameters.input;
327
+ mcpLogger.debug(`[${functionTag}] Unwrapped input parameter for ${functionName}`, { original: parameters, unwrapped: actualParameters });
328
+ }
329
+ mcpLogger.debug(`[${functionTag}] Executing function call: ${functionName}`, { parameters: actualParameters });
316
330
  // Create context if not provided
317
331
  let finalContext = context;
318
332
  if (!finalContext) {
@@ -325,23 +339,34 @@ export async function executeFunctionCall(functionName, parameters, context) {
325
339
  // Parse server and tool name from function name
326
340
  // First try underscore format (sanitized), then fallback to dot format
327
341
  let parts = functionName.split("_");
328
- let serverId;
329
- let toolName;
342
+ let serverId = "unknown";
343
+ let toolName = functionName;
330
344
  if (parts.length >= 2) {
331
345
  // Handle underscore format (sanitized names)
332
- serverId = parts[0];
346
+ const firstPart = parts[0];
347
+ if (firstPart && typeof firstPart === "string" && firstPart.length > 0) {
348
+ serverId = firstPart;
349
+ }
350
+ else {
351
+ serverId = "unknown";
352
+ }
333
353
  toolName = parts.slice(1).join("_"); // Rejoin in case tool name had underscores
334
354
  }
335
355
  else {
336
356
  // Fallback to dot format for backward compatibility
337
357
  parts = functionName.split(".");
338
358
  if (parts.length === 2) {
339
- [serverId, toolName] = parts;
359
+ const parsedServerId = parts[0];
360
+ const parsedToolName = parts[1];
361
+ if (parsedServerId && parsedToolName) {
362
+ serverId = parsedServerId;
363
+ toolName = parsedToolName;
364
+ }
340
365
  }
341
366
  else {
342
367
  // Can't parse - try executing as-is through unified registry
343
368
  mcpLogger.debug(`[${functionTag}] Cannot parse function name format: ${functionName}, trying unified registry`);
344
- const result = await defaultUnifiedRegistry.executeTool(functionName, parameters, finalContext);
369
+ const result = await unifiedRegistry.executeTool(functionName, actualParameters, finalContext);
345
370
  return result;
346
371
  }
347
372
  }
@@ -352,15 +377,15 @@ export async function executeFunctionCall(functionName, parameters, context) {
352
377
  serverId === "neurolink_ai_core") {
353
378
  mcpLogger.debug(`[${functionTag}] Executing built-in tool: ${toolName} from ${serverId}`);
354
379
  // Import and execute from default registry
355
- const { defaultToolRegistry } = await import("./registry.js");
356
- return await defaultToolRegistry.executeTool(toolName, parameters, finalContext);
380
+ const { defaultToolRegistry } = await import("./tool-registry.js");
381
+ return await defaultToolRegistry.executeTool(toolName, actualParameters, finalContext);
357
382
  }
358
383
  // Handle filesystem server with special activation logic
359
384
  if (serverId === "filesystem") {
360
385
  mcpLogger.debug(`[${functionTag}] Executing filesystem tool: ${toolName}`);
361
386
  try {
362
387
  // First, try to execute through unified registry
363
- const result = await defaultUnifiedRegistry.executeTool(functionName, parameters, finalContext);
388
+ const result = await unifiedRegistry.executeTool(functionName, actualParameters, finalContext);
364
389
  if (result.success) {
365
390
  return result;
366
391
  }
@@ -372,7 +397,7 @@ export async function executeFunctionCall(functionName, parameters, context) {
372
397
  try {
373
398
  // Force activation by attempting to activate the filesystem server directly
374
399
  // This should convert placeholders to real tools
375
- await defaultUnifiedRegistry.initialize();
400
+ await unifiedRegistry.initialize();
376
401
  // Try a few common activation patterns
377
402
  const activationAttempts = [
378
403
  `${serverId}.list_directory`,
@@ -381,7 +406,7 @@ export async function executeFunctionCall(functionName, parameters, context) {
381
406
  ];
382
407
  for (const attempt of activationAttempts) {
383
408
  try {
384
- const result = await defaultUnifiedRegistry.executeTool(attempt, parameters, finalContext);
409
+ const result = await unifiedRegistry.executeTool(attempt, actualParameters, finalContext);
385
410
  if (result.success) {
386
411
  mcpLogger.debug(`[${functionTag}] Filesystem tool executed successfully with: ${attempt}`);
387
412
  return result;
@@ -394,7 +419,7 @@ export async function executeFunctionCall(functionName, parameters, context) {
394
419
  // If all attempts fail, return a helpful error
395
420
  return {
396
421
  success: false,
397
- error: `Filesystem tool '${toolName}' could not be activated. Available parameters: ${JSON.stringify(parameters)}`,
422
+ error: `Filesystem tool '${toolName}' could not be activated. Available parameters: ${JSON.stringify(actualParameters)}`,
398
423
  metadata: {
399
424
  functionName,
400
425
  timestamp: Date.now(),
@@ -417,7 +442,7 @@ export async function executeFunctionCall(functionName, parameters, context) {
417
442
  }
418
443
  // For other tools, use unified registry
419
444
  mcpLogger.debug(`[${functionTag}] Executing through unified registry: ${functionName}`);
420
- const result = await defaultUnifiedRegistry.executeTool(functionName, parameters, finalContext);
445
+ const result = await unifiedRegistry.executeTool(functionName, actualParameters, finalContext);
421
446
  mcpLogger.debug(`[${functionTag}] Function call completed: ${functionName}`, {
422
447
  success: result.success,
423
448
  hasData: !!result.data,