@juspay/neurolink 1.5.3 → 1.9.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 +241 -1
- package/README.md +113 -20
- package/dist/agent/direct-tools.d.ts +1203 -0
- package/dist/agent/direct-tools.js +387 -0
- package/dist/cli/commands/agent-generate.d.ts +2 -0
- package/dist/cli/commands/agent-generate.js +70 -0
- package/dist/cli/commands/config.d.ts +76 -9
- package/dist/cli/commands/config.js +358 -233
- package/dist/cli/commands/mcp.d.ts +2 -1
- package/dist/cli/commands/mcp.js +874 -146
- package/dist/cli/commands/ollama.d.ts +8 -0
- package/dist/cli/commands/ollama.js +333 -0
- package/dist/cli/index.js +591 -327
- package/dist/cli/utils/complete-setup.d.ts +19 -0
- package/dist/cli/utils/complete-setup.js +81 -0
- package/dist/cli/utils/env-manager.d.ts +44 -0
- package/dist/cli/utils/env-manager.js +226 -0
- package/dist/cli/utils/interactive-setup.d.ts +48 -0
- package/dist/cli/utils/interactive-setup.js +302 -0
- package/dist/core/dynamic-models.d.ts +208 -0
- package/dist/core/dynamic-models.js +250 -0
- package/dist/core/factory.d.ts +13 -6
- package/dist/core/factory.js +180 -50
- package/dist/core/types.d.ts +8 -3
- package/dist/core/types.js +7 -4
- package/dist/index.d.ts +16 -16
- package/dist/index.js +16 -16
- package/dist/lib/agent/direct-tools.d.ts +1203 -0
- package/dist/lib/agent/direct-tools.js +387 -0
- package/dist/lib/core/dynamic-models.d.ts +208 -0
- package/dist/lib/core/dynamic-models.js +250 -0
- package/dist/lib/core/factory.d.ts +13 -6
- package/dist/lib/core/factory.js +180 -50
- package/dist/lib/core/types.d.ts +8 -3
- package/dist/lib/core/types.js +7 -4
- package/dist/lib/index.d.ts +16 -16
- package/dist/lib/index.js +16 -16
- package/dist/lib/mcp/auto-discovery.d.ts +120 -0
- package/dist/lib/mcp/auto-discovery.js +793 -0
- package/dist/lib/mcp/client.d.ts +66 -0
- package/dist/lib/mcp/client.js +245 -0
- package/dist/lib/mcp/config.d.ts +31 -0
- package/dist/lib/mcp/config.js +74 -0
- package/dist/lib/mcp/context-manager.d.ts +4 -4
- package/dist/lib/mcp/context-manager.js +24 -18
- package/dist/lib/mcp/factory.d.ts +28 -11
- package/dist/lib/mcp/factory.js +36 -29
- package/dist/lib/mcp/function-calling.d.ts +51 -0
- package/dist/lib/mcp/function-calling.js +510 -0
- package/dist/lib/mcp/index.d.ts +190 -0
- package/dist/lib/mcp/index.js +156 -0
- package/dist/lib/mcp/initialize-tools.d.ts +28 -0
- package/dist/lib/mcp/initialize-tools.js +209 -0
- package/dist/lib/mcp/initialize.d.ts +17 -0
- package/dist/lib/mcp/initialize.js +51 -0
- package/dist/lib/mcp/logging.d.ts +71 -0
- package/dist/lib/mcp/logging.js +183 -0
- package/dist/lib/mcp/manager.d.ts +67 -0
- package/dist/lib/mcp/manager.js +176 -0
- package/dist/lib/mcp/neurolink-mcp-client.d.ts +96 -0
- package/dist/lib/mcp/neurolink-mcp-client.js +417 -0
- package/dist/lib/mcp/orchestrator.d.ts +3 -3
- package/dist/lib/mcp/orchestrator.js +46 -43
- package/dist/lib/mcp/registry.d.ts +2 -2
- package/dist/lib/mcp/registry.js +42 -33
- package/dist/lib/mcp/servers/ai-providers/ai-analysis-tools.d.ts +1 -1
- package/dist/lib/mcp/servers/ai-providers/ai-analysis-tools.js +205 -66
- package/dist/lib/mcp/servers/ai-providers/ai-core-server.js +143 -99
- package/dist/lib/mcp/servers/ai-providers/ai-workflow-tools.d.ts +6 -6
- package/dist/lib/mcp/servers/ai-providers/ai-workflow-tools.js +404 -251
- package/dist/lib/mcp/servers/utilities/utility-server.d.ts +8 -0
- package/dist/lib/mcp/servers/utilities/utility-server.js +326 -0
- package/dist/lib/mcp/tool-integration.d.ts +67 -0
- package/dist/lib/mcp/tool-integration.js +179 -0
- package/dist/lib/mcp/unified-registry.d.ts +269 -0
- package/dist/lib/mcp/unified-registry.js +1411 -0
- package/dist/lib/neurolink.d.ts +68 -6
- package/dist/lib/neurolink.js +314 -42
- package/dist/lib/providers/agent-enhanced-provider.d.ts +59 -0
- package/dist/lib/providers/agent-enhanced-provider.js +242 -0
- package/dist/lib/providers/amazonBedrock.d.ts +3 -3
- package/dist/lib/providers/amazonBedrock.js +54 -50
- package/dist/lib/providers/anthropic.d.ts +2 -2
- package/dist/lib/providers/anthropic.js +92 -84
- package/dist/lib/providers/azureOpenAI.d.ts +2 -2
- package/dist/lib/providers/azureOpenAI.js +97 -86
- package/dist/lib/providers/function-calling-provider.d.ts +70 -0
- package/dist/lib/providers/function-calling-provider.js +359 -0
- package/dist/lib/providers/googleAIStudio.d.ts +10 -5
- package/dist/lib/providers/googleAIStudio.js +60 -38
- package/dist/lib/providers/googleVertexAI.d.ts +3 -3
- package/dist/lib/providers/googleVertexAI.js +96 -86
- package/dist/lib/providers/huggingFace.d.ts +31 -0
- package/dist/lib/providers/huggingFace.js +362 -0
- package/dist/lib/providers/index.d.ts +14 -8
- package/dist/lib/providers/index.js +18 -12
- package/dist/lib/providers/mcp-provider.d.ts +62 -0
- package/dist/lib/providers/mcp-provider.js +183 -0
- package/dist/lib/providers/mistralAI.d.ts +32 -0
- package/dist/lib/providers/mistralAI.js +223 -0
- package/dist/lib/providers/ollama.d.ts +51 -0
- package/dist/lib/providers/ollama.js +508 -0
- package/dist/lib/providers/openAI.d.ts +7 -3
- package/dist/lib/providers/openAI.js +45 -33
- package/dist/lib/utils/logger.js +2 -2
- package/dist/lib/utils/providerUtils.js +59 -22
- package/dist/mcp/auto-discovery.d.ts +120 -0
- package/dist/mcp/auto-discovery.js +794 -0
- package/dist/mcp/client.d.ts +66 -0
- package/dist/mcp/client.js +245 -0
- package/dist/mcp/config.d.ts +31 -0
- package/dist/mcp/config.js +74 -0
- package/dist/mcp/context-manager.d.ts +4 -4
- package/dist/mcp/context-manager.js +24 -18
- package/dist/mcp/factory.d.ts +28 -11
- package/dist/mcp/factory.js +36 -29
- package/dist/mcp/function-calling.d.ts +51 -0
- package/dist/mcp/function-calling.js +510 -0
- package/dist/mcp/index.d.ts +190 -0
- package/dist/mcp/index.js +156 -0
- package/dist/mcp/initialize-tools.d.ts +28 -0
- package/dist/mcp/initialize-tools.js +210 -0
- package/dist/mcp/initialize.d.ts +17 -0
- package/dist/mcp/initialize.js +51 -0
- package/dist/mcp/logging.d.ts +71 -0
- package/dist/mcp/logging.js +183 -0
- package/dist/mcp/manager.d.ts +67 -0
- package/dist/mcp/manager.js +176 -0
- package/dist/mcp/neurolink-mcp-client.d.ts +96 -0
- package/dist/mcp/neurolink-mcp-client.js +417 -0
- package/dist/mcp/orchestrator.d.ts +3 -3
- package/dist/mcp/orchestrator.js +46 -43
- package/dist/mcp/registry.d.ts +2 -2
- package/dist/mcp/registry.js +42 -33
- package/dist/mcp/servers/ai-providers/ai-analysis-tools.d.ts +1 -1
- package/dist/mcp/servers/ai-providers/ai-analysis-tools.js +205 -66
- package/dist/mcp/servers/ai-providers/ai-core-server.js +143 -99
- package/dist/mcp/servers/ai-providers/ai-workflow-tools.d.ts +6 -6
- package/dist/mcp/servers/ai-providers/ai-workflow-tools.js +404 -253
- package/dist/mcp/servers/utilities/utility-server.d.ts +8 -0
- package/dist/mcp/servers/utilities/utility-server.js +326 -0
- package/dist/mcp/tool-integration.d.ts +67 -0
- package/dist/mcp/tool-integration.js +179 -0
- package/dist/mcp/unified-registry.d.ts +269 -0
- package/dist/mcp/unified-registry.js +1411 -0
- package/dist/neurolink.d.ts +68 -6
- package/dist/neurolink.js +314 -42
- package/dist/providers/agent-enhanced-provider.d.ts +59 -0
- package/dist/providers/agent-enhanced-provider.js +242 -0
- package/dist/providers/amazonBedrock.d.ts +3 -3
- package/dist/providers/amazonBedrock.js +54 -50
- package/dist/providers/anthropic.d.ts +2 -2
- package/dist/providers/anthropic.js +92 -84
- package/dist/providers/azureOpenAI.d.ts +2 -2
- package/dist/providers/azureOpenAI.js +97 -86
- package/dist/providers/function-calling-provider.d.ts +70 -0
- package/dist/providers/function-calling-provider.js +359 -0
- package/dist/providers/googleAIStudio.d.ts +10 -5
- package/dist/providers/googleAIStudio.js +60 -38
- package/dist/providers/googleVertexAI.d.ts +3 -3
- package/dist/providers/googleVertexAI.js +96 -86
- package/dist/providers/huggingFace.d.ts +31 -0
- package/dist/providers/huggingFace.js +362 -0
- package/dist/providers/index.d.ts +14 -8
- package/dist/providers/index.js +18 -12
- package/dist/providers/mcp-provider.d.ts +62 -0
- package/dist/providers/mcp-provider.js +183 -0
- package/dist/providers/mistralAI.d.ts +32 -0
- package/dist/providers/mistralAI.js +223 -0
- package/dist/providers/ollama.d.ts +51 -0
- package/dist/providers/ollama.js +508 -0
- package/dist/providers/openAI.d.ts +7 -3
- package/dist/providers/openAI.js +45 -33
- package/dist/utils/logger.js +2 -2
- package/dist/utils/providerUtils.js +59 -22
- package/package.json +28 -4
package/dist/mcp/factory.js
CHANGED
|
@@ -3,31 +3,33 @@
|
|
|
3
3
|
* Factory-First Architecture: MCP servers create tools for internal orchestration
|
|
4
4
|
* Compatible with Lighthouse MCP patterns for seamless migration
|
|
5
5
|
*/
|
|
6
|
-
import { z } from
|
|
6
|
+
import { z } from "zod";
|
|
7
7
|
/**
|
|
8
8
|
* Input validation schemas
|
|
9
9
|
*/
|
|
10
10
|
const ServerConfigSchema = z.object({
|
|
11
|
-
id: z.string().min(1,
|
|
12
|
-
title: z.string().min(1,
|
|
11
|
+
id: z.string().min(1, "Server ID is required"),
|
|
12
|
+
title: z.string().min(1, "Server title is required"),
|
|
13
13
|
description: z.string().optional(),
|
|
14
14
|
version: z.string().optional(),
|
|
15
|
-
category: z
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
15
|
+
category: z
|
|
16
|
+
.enum([
|
|
17
|
+
"ai-providers",
|
|
18
|
+
"frameworks",
|
|
19
|
+
"development",
|
|
20
|
+
"business",
|
|
21
|
+
"content",
|
|
22
|
+
"data",
|
|
23
|
+
"integrations",
|
|
24
|
+
"automation",
|
|
25
|
+
"analysis",
|
|
26
|
+
"custom",
|
|
27
|
+
])
|
|
28
|
+
.optional(),
|
|
29
|
+
visibility: z.enum(["public", "private", "organization"]).optional(),
|
|
28
30
|
metadata: z.record(z.any()).optional(),
|
|
29
31
|
dependencies: z.array(z.string()).optional(),
|
|
30
|
-
capabilities: z.array(z.string()).optional()
|
|
32
|
+
capabilities: z.array(z.string()).optional(),
|
|
31
33
|
});
|
|
32
34
|
/**
|
|
33
35
|
* Create MCP Server Factory Function
|
|
@@ -67,9 +69,9 @@ export function createMCPServer(config) {
|
|
|
67
69
|
title: validatedConfig.title,
|
|
68
70
|
// Optional fields with defaults
|
|
69
71
|
description: validatedConfig.description,
|
|
70
|
-
version: validatedConfig.version ||
|
|
71
|
-
category: validatedConfig.category ||
|
|
72
|
-
visibility: validatedConfig.visibility ||
|
|
72
|
+
version: validatedConfig.version || "1.0.0",
|
|
73
|
+
category: validatedConfig.category || "custom",
|
|
74
|
+
visibility: validatedConfig.visibility || "private",
|
|
73
75
|
// Tool management
|
|
74
76
|
tools: {},
|
|
75
77
|
// Tool registration method
|
|
@@ -90,15 +92,15 @@ export function createMCPServer(config) {
|
|
|
90
92
|
...tool.metadata,
|
|
91
93
|
serverId: this.id,
|
|
92
94
|
serverCategory: this.category,
|
|
93
|
-
registeredAt: Date.now()
|
|
94
|
-
}
|
|
95
|
+
registeredAt: Date.now(),
|
|
96
|
+
},
|
|
95
97
|
};
|
|
96
98
|
return this;
|
|
97
99
|
},
|
|
98
100
|
// Extension points
|
|
99
101
|
metadata: validatedConfig.metadata || {},
|
|
100
102
|
dependencies: validatedConfig.dependencies || [],
|
|
101
|
-
capabilities: validatedConfig.capabilities || []
|
|
103
|
+
capabilities: validatedConfig.capabilities || [],
|
|
102
104
|
};
|
|
103
105
|
return server;
|
|
104
106
|
}
|
|
@@ -108,17 +110,22 @@ export function createMCPServer(config) {
|
|
|
108
110
|
export function validateTool(tool) {
|
|
109
111
|
try {
|
|
110
112
|
// Check required fields
|
|
111
|
-
if (!tool.name || typeof tool.name !==
|
|
113
|
+
if (!tool.name || typeof tool.name !== "string") {
|
|
112
114
|
return false;
|
|
113
|
-
|
|
115
|
+
}
|
|
116
|
+
if (!tool.description || typeof tool.description !== "string") {
|
|
114
117
|
return false;
|
|
115
|
-
|
|
118
|
+
}
|
|
119
|
+
if (!tool.execute || typeof tool.execute !== "function") {
|
|
116
120
|
return false;
|
|
121
|
+
}
|
|
117
122
|
// Validate optional schemas if present
|
|
118
|
-
if (tool.inputSchema && !(tool.inputSchema instanceof z.ZodSchema))
|
|
123
|
+
if (tool.inputSchema && !(tool.inputSchema instanceof z.ZodSchema)) {
|
|
119
124
|
return false;
|
|
120
|
-
|
|
125
|
+
}
|
|
126
|
+
if (tool.outputSchema && !(tool.outputSchema instanceof z.ZodSchema)) {
|
|
121
127
|
return false;
|
|
128
|
+
}
|
|
122
129
|
return true;
|
|
123
130
|
}
|
|
124
131
|
catch (error) {
|
|
@@ -135,7 +142,7 @@ export function getServerInfo(server) {
|
|
|
135
142
|
description: server.description,
|
|
136
143
|
category: server.category,
|
|
137
144
|
toolCount: Object.keys(server.tools).length,
|
|
138
|
-
capabilities: server.capabilities || []
|
|
145
|
+
capabilities: server.capabilities || [],
|
|
139
146
|
};
|
|
140
147
|
}
|
|
141
148
|
// Types are already exported above via export interface declarations
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MCP Function-Calling Integration
|
|
3
|
+
* Converts MCP tools to AI SDK function definitions and handles function calls
|
|
4
|
+
* Enables true AI function calling with discovered MCP tools
|
|
5
|
+
*/
|
|
6
|
+
import type { Tool } from "ai";
|
|
7
|
+
import type { NeuroLinkMCPTool, ToolResult, NeuroLinkExecutionContext } from "./factory.js";
|
|
8
|
+
/**
|
|
9
|
+
* Convert MCP tool to AI SDK function definition
|
|
10
|
+
*/
|
|
11
|
+
export declare function mcpToolToAISDKTool(tool: NeuroLinkMCPTool, serverId: string): Tool;
|
|
12
|
+
/**
|
|
13
|
+
* Get all available MCP tools as AI SDK function definitions
|
|
14
|
+
*/
|
|
15
|
+
export declare function getAvailableFunctionTools(): Promise<{
|
|
16
|
+
tools: Tool[];
|
|
17
|
+
toolMap: Map<string, {
|
|
18
|
+
serverId: string;
|
|
19
|
+
toolName: string;
|
|
20
|
+
}>;
|
|
21
|
+
}>;
|
|
22
|
+
/**
|
|
23
|
+
* Execute MCP tool from AI function call
|
|
24
|
+
*/
|
|
25
|
+
export declare function executeFunctionCall(functionName: string, parameters: Record<string, unknown>, context?: NeuroLinkExecutionContext): Promise<ToolResult>;
|
|
26
|
+
/**
|
|
27
|
+
* Handle multiple function calls and format results for AI
|
|
28
|
+
*/
|
|
29
|
+
export declare function handleFunctionCalls(functionCalls: Array<{
|
|
30
|
+
name: string;
|
|
31
|
+
parameters: Record<string, unknown>;
|
|
32
|
+
id?: string;
|
|
33
|
+
}>, context?: NeuroLinkExecutionContext): Promise<Array<{
|
|
34
|
+
id?: string;
|
|
35
|
+
result: ToolResult;
|
|
36
|
+
formattedForAI: string;
|
|
37
|
+
}>>;
|
|
38
|
+
/**
|
|
39
|
+
* Create a subset of tools for specific categories or capabilities
|
|
40
|
+
*/
|
|
41
|
+
export declare function getFunctionToolsForCategory(category?: string, maxTools?: number): Promise<{
|
|
42
|
+
tools: Tool[];
|
|
43
|
+
toolMap: Map<string, {
|
|
44
|
+
serverId: string;
|
|
45
|
+
toolName: string;
|
|
46
|
+
}>;
|
|
47
|
+
}>;
|
|
48
|
+
/**
|
|
49
|
+
* Check if function calling is available
|
|
50
|
+
*/
|
|
51
|
+
export declare function isFunctionCallingAvailable(): Promise<boolean>;
|
|
@@ -0,0 +1,510 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MCP Function-Calling Integration
|
|
3
|
+
* Converts MCP tools to AI SDK function definitions and handles function calls
|
|
4
|
+
* Enables true AI function calling with discovered MCP tools
|
|
5
|
+
*/
|
|
6
|
+
import { tool } from "ai";
|
|
7
|
+
import { z } from "zod";
|
|
8
|
+
import { defaultUnifiedRegistry } from "./unified-registry.js";
|
|
9
|
+
import { createExecutionContext } from "./context-manager.js";
|
|
10
|
+
import { mcpLogger } from "./logging.js";
|
|
11
|
+
/**
|
|
12
|
+
* Convert MCP tool to AI SDK function definition
|
|
13
|
+
*/
|
|
14
|
+
export function mcpToolToAISDKTool(tool, serverId) {
|
|
15
|
+
// Create basic JSON Schema for AI SDK
|
|
16
|
+
const parameters = {
|
|
17
|
+
type: "object",
|
|
18
|
+
properties: {},
|
|
19
|
+
required: [],
|
|
20
|
+
};
|
|
21
|
+
// If we have an input schema, try to extract basic information
|
|
22
|
+
if (tool.inputSchema) {
|
|
23
|
+
try {
|
|
24
|
+
// For now, create a simple schema that accepts any object
|
|
25
|
+
// This could be enhanced with proper Zod-to-JSON-Schema conversion
|
|
26
|
+
parameters.properties = {
|
|
27
|
+
// Generic parameter support
|
|
28
|
+
data: {
|
|
29
|
+
type: "object",
|
|
30
|
+
description: "Tool parameters",
|
|
31
|
+
},
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
catch (error) {
|
|
35
|
+
mcpLogger.warn(`[Function-Calling] Failed to convert schema for tool ${tool.name}:`, error);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
return {
|
|
39
|
+
description: tool.description,
|
|
40
|
+
parameters,
|
|
41
|
+
execute: async (args) => {
|
|
42
|
+
// This will be handled by the AI SDK's function calling mechanism
|
|
43
|
+
// We'll implement the actual execution in the provider level
|
|
44
|
+
mcpLogger.debug(`[Function-Calling] AI SDK tool executed: ${serverId}.${tool.name}`, args);
|
|
45
|
+
return {
|
|
46
|
+
success: true,
|
|
47
|
+
message: "Tool execution handled by MCP integration",
|
|
48
|
+
};
|
|
49
|
+
},
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Get all available MCP tools as AI SDK function definitions
|
|
54
|
+
*/
|
|
55
|
+
export async function getAvailableFunctionTools() {
|
|
56
|
+
const functionTag = "getAvailableFunctionTools";
|
|
57
|
+
const tools = [];
|
|
58
|
+
const toolMap = new Map();
|
|
59
|
+
try {
|
|
60
|
+
// Add overall timeout for the entire function
|
|
61
|
+
const overallTimeoutMs = 5000; // 5 seconds max for everything
|
|
62
|
+
let overallTimeoutId;
|
|
63
|
+
const overallTimeoutPromise = new Promise((_, reject) => {
|
|
64
|
+
overallTimeoutId = setTimeout(() => {
|
|
65
|
+
mcpLogger.warn(`[${functionTag}] Overall timeout reached, returning empty tools`);
|
|
66
|
+
reject(new Error("getAvailableFunctionTools overall timeout"));
|
|
67
|
+
}, overallTimeoutMs);
|
|
68
|
+
// CRITICAL FIX: Unref timeout to prevent event loop hanging
|
|
69
|
+
overallTimeoutId.unref();
|
|
70
|
+
});
|
|
71
|
+
const toolsLoadingPromise = (async () => {
|
|
72
|
+
try {
|
|
73
|
+
// Ensure NeuroLink MCP is initialized first
|
|
74
|
+
const { initializeNeuroLinkMCP } = await import("./initialize.js");
|
|
75
|
+
await initializeNeuroLinkMCP();
|
|
76
|
+
// Ensure unified registry is initialized
|
|
77
|
+
await defaultUnifiedRegistry.initialize();
|
|
78
|
+
// Try to activate important servers like filesystem
|
|
79
|
+
mcpLogger.debug(`[${functionTag}] Attempting to activate important servers...`);
|
|
80
|
+
try {
|
|
81
|
+
// Get auto-discovered servers
|
|
82
|
+
const autoServers = defaultUnifiedRegistry.getAutoDiscoveredServers();
|
|
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);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
catch (error) {
|
|
93
|
+
mcpLogger.debug(`[${functionTag}] Error activating servers: ${error}`);
|
|
94
|
+
}
|
|
95
|
+
// Get all tools from unified registry directly
|
|
96
|
+
const allTools = await defaultUnifiedRegistry.listAllTools();
|
|
97
|
+
mcpLogger.debug(`[${functionTag}] Found ${allTools.length} total tools`);
|
|
98
|
+
// Try to activate servers that have "-tools" entries to get real tools
|
|
99
|
+
const serversToActivate = allTools
|
|
100
|
+
.filter((tool) => tool.name.endsWith("-tools") || tool.name.includes("placeholder"))
|
|
101
|
+
.map((tool) => tool.server);
|
|
102
|
+
mcpLogger.debug(`[${functionTag}] Attempting to activate ${serversToActivate.length} servers for real tool discovery`);
|
|
103
|
+
// Activate servers to convert placeholders to real tools
|
|
104
|
+
for (const serverId of [...new Set(serversToActivate)]) {
|
|
105
|
+
try {
|
|
106
|
+
mcpLogger.debug(`[${functionTag}] Activating server: ${serverId}`);
|
|
107
|
+
// 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);
|
|
113
|
+
}
|
|
114
|
+
else {
|
|
115
|
+
mcpLogger.debug(`[${functionTag}] Server entry not found for: ${serverId}`);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
catch (error) {
|
|
119
|
+
mcpLogger.debug(`[${functionTag}] Failed to activate server ${serverId}:`, error);
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
// Get tools again after activation
|
|
123
|
+
const activatedTools = await defaultUnifiedRegistry.listAllTools();
|
|
124
|
+
mcpLogger.debug(`[${functionTag}] Found ${activatedTools.length} total tools after activation`);
|
|
125
|
+
// Filter to get real, individual tools (not placeholder or grouped tools)
|
|
126
|
+
const realTools = activatedTools.filter((toolInfo) => {
|
|
127
|
+
// Skip placeholder tools that weren't activated
|
|
128
|
+
if (toolInfo.name.includes("placeholder") &&
|
|
129
|
+
toolInfo.isImplemented === false) {
|
|
130
|
+
return false;
|
|
131
|
+
}
|
|
132
|
+
// Skip grouped "-tools" entries unless they're the only ones available
|
|
133
|
+
if (toolInfo.name.endsWith("-tools")) {
|
|
134
|
+
// Check if we have individual tools from the same server
|
|
135
|
+
const serverTools = activatedTools.filter((t) => t.server === toolInfo.server &&
|
|
136
|
+
!t.name.endsWith("-tools") &&
|
|
137
|
+
!t.name.includes("placeholder"));
|
|
138
|
+
// If we have individual tools, skip the grouped entry
|
|
139
|
+
if (serverTools.length > 0) {
|
|
140
|
+
return false;
|
|
141
|
+
}
|
|
142
|
+
// Otherwise, include the grouped tool (better than nothing)
|
|
143
|
+
}
|
|
144
|
+
// Include all other real tools
|
|
145
|
+
return true;
|
|
146
|
+
});
|
|
147
|
+
mcpLogger.debug(`[${functionTag}] Filtered to ${realTools.length} real tools from ${activatedTools.length} total`);
|
|
148
|
+
// Process tools and create function definitions
|
|
149
|
+
for (const toolInfo of realTools) {
|
|
150
|
+
try {
|
|
151
|
+
// Check if tool name already includes server info (e.g., from unified registry)
|
|
152
|
+
let functionName;
|
|
153
|
+
let originalFunctionName;
|
|
154
|
+
// 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, "_");
|
|
156
|
+
if (toolInfo.name.includes(sanitizedServerCheck) ||
|
|
157
|
+
toolInfo.name.endsWith("-tools") ||
|
|
158
|
+
toolInfo.name.startsWith("github_com_") ||
|
|
159
|
+
toolInfo.name.length > 50) {
|
|
160
|
+
// Tool name already includes server info, sanitize and shorten it
|
|
161
|
+
let sanitized = toolInfo.name.replace(/[^a-zA-Z0-9_]/g, "_");
|
|
162
|
+
// Shorten long MCP server names
|
|
163
|
+
if (sanitized.startsWith("github_com_modelcontextprotocol_servers_tree_main_src_")) {
|
|
164
|
+
// Replace the long prefix with just 'mcp_'
|
|
165
|
+
sanitized =
|
|
166
|
+
"mcp_" +
|
|
167
|
+
sanitized.substring("github_com_modelcontextprotocol_servers_tree_main_src_"
|
|
168
|
+
.length);
|
|
169
|
+
mcpLogger.debug(`[${functionTag}] Shortened MCP name: ${toolInfo.name} -> ${sanitized}`);
|
|
170
|
+
}
|
|
171
|
+
else if (sanitized.startsWith("github_com_") &&
|
|
172
|
+
sanitized.length > 64) {
|
|
173
|
+
// Shorten other github paths
|
|
174
|
+
const parts = sanitized.split("_");
|
|
175
|
+
// Keep only the meaningful parts (skip github_com)
|
|
176
|
+
sanitized = parts.slice(2).join("_");
|
|
177
|
+
mcpLogger.debug(`[${functionTag}] Shortened github name: ${toolInfo.name} -> ${sanitized}`);
|
|
178
|
+
}
|
|
179
|
+
// If still too long, truncate intelligently
|
|
180
|
+
if (sanitized.length > 64) {
|
|
181
|
+
// Keep the ending part which usually has the actual tool name
|
|
182
|
+
sanitized = sanitized.substring(sanitized.length - 63);
|
|
183
|
+
}
|
|
184
|
+
// Ensure it starts with a letter or underscore (Google AI requirement)
|
|
185
|
+
if (!/^[a-zA-Z_]/.test(sanitized)) {
|
|
186
|
+
sanitized = "_" + sanitized;
|
|
187
|
+
}
|
|
188
|
+
// Final length check after adding prefix
|
|
189
|
+
if (sanitized.length > 64) {
|
|
190
|
+
// For filesystem tools, create a shorter name
|
|
191
|
+
if (sanitized.includes("filesystem")) {
|
|
192
|
+
const toolPart = sanitized.split("_").pop() || "tool";
|
|
193
|
+
sanitized = "fs_" + toolPart;
|
|
194
|
+
}
|
|
195
|
+
else {
|
|
196
|
+
// Generic truncation from the beginning, keeping the end
|
|
197
|
+
sanitized = "_" + sanitized.substring(sanitized.length - 63);
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
functionName = sanitized;
|
|
201
|
+
originalFunctionName = toolInfo.name;
|
|
202
|
+
}
|
|
203
|
+
else {
|
|
204
|
+
// Tool name doesn't include server info, create compound name
|
|
205
|
+
const sanitizedServerName = toolInfo.server.replace(/[^a-zA-Z0-9_]/g, "_");
|
|
206
|
+
const sanitizedToolName = toolInfo.name.replace(/[^a-zA-Z0-9_]/g, "_");
|
|
207
|
+
// Check if it's a filesystem tool from MCP
|
|
208
|
+
if (sanitizedServerName.includes("modelcontextprotocol") &&
|
|
209
|
+
sanitizedServerName.includes("filesystem")) {
|
|
210
|
+
functionName = `mcp_${sanitizedToolName}`;
|
|
211
|
+
}
|
|
212
|
+
else if (sanitizedServerName.length > 40) {
|
|
213
|
+
// For other long server names, use a shortened version
|
|
214
|
+
const serverParts = sanitizedServerName.split("_");
|
|
215
|
+
const shortServer = serverParts.length > 2
|
|
216
|
+
? serverParts.slice(-2).join("_")
|
|
217
|
+
: sanitizedServerName.substring(0, 20);
|
|
218
|
+
functionName = `${shortServer}_${sanitizedToolName}`;
|
|
219
|
+
}
|
|
220
|
+
else {
|
|
221
|
+
functionName = `${sanitizedServerName}_${sanitizedToolName}`;
|
|
222
|
+
}
|
|
223
|
+
// Ensure it starts with a letter or underscore
|
|
224
|
+
if (!/^[a-zA-Z_]/.test(functionName)) {
|
|
225
|
+
functionName = "_" + functionName;
|
|
226
|
+
}
|
|
227
|
+
// Final length check
|
|
228
|
+
if (functionName.length > 64) {
|
|
229
|
+
// Create a very short version
|
|
230
|
+
functionName = `tool_${sanitizedToolName}`;
|
|
231
|
+
if (functionName.length > 64) {
|
|
232
|
+
functionName = sanitizedToolName.substring(0, 63);
|
|
233
|
+
if (!/^[a-zA-Z_]/.test(functionName)) {
|
|
234
|
+
functionName = "_" + functionName.substring(1);
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
originalFunctionName = `${toolInfo.server}.${toolInfo.name}`;
|
|
239
|
+
}
|
|
240
|
+
// Create AI SDK tool using the proper tool() helper
|
|
241
|
+
const aiTool = tool({
|
|
242
|
+
description: toolInfo.description || `Tool from ${toolInfo.server}`,
|
|
243
|
+
parameters: z.object({
|
|
244
|
+
// Create a generic parameter schema for all MCP tools
|
|
245
|
+
input: z
|
|
246
|
+
.unknown()
|
|
247
|
+
.optional()
|
|
248
|
+
.describe("Input parameters for the tool"),
|
|
249
|
+
}),
|
|
250
|
+
execute: async ({ input }) => {
|
|
251
|
+
mcpLogger.debug(`[Function-Calling] AI SDK tool executed: ${functionName}`, { input });
|
|
252
|
+
try {
|
|
253
|
+
// Execute the actual MCP tool
|
|
254
|
+
const result = await executeFunctionCall(functionName, input || {});
|
|
255
|
+
if (result.success) {
|
|
256
|
+
return (result.data || {
|
|
257
|
+
success: true,
|
|
258
|
+
message: "Tool executed successfully",
|
|
259
|
+
});
|
|
260
|
+
}
|
|
261
|
+
else {
|
|
262
|
+
return { error: result.error || "Tool execution failed" };
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
catch (error) {
|
|
266
|
+
mcpLogger.error(`[Function-Calling] Tool execution error: ${functionName}`, error);
|
|
267
|
+
return {
|
|
268
|
+
error: error instanceof Error ? error.message : String(error),
|
|
269
|
+
};
|
|
270
|
+
}
|
|
271
|
+
},
|
|
272
|
+
});
|
|
273
|
+
tools.push(aiTool);
|
|
274
|
+
// Store mapping for execution - CRITICAL: Use sanitized functionName as key
|
|
275
|
+
toolMap.set(functionName, {
|
|
276
|
+
serverId: toolInfo.server,
|
|
277
|
+
toolName: toolInfo.name,
|
|
278
|
+
});
|
|
279
|
+
mcpLogger.debug(`[${functionTag}] Converted tool: ${functionName} (original: ${originalFunctionName})`);
|
|
280
|
+
}
|
|
281
|
+
catch (error) {
|
|
282
|
+
mcpLogger.warn(`[${functionTag}] Failed to convert tool ${toolInfo.name}:`, error);
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
mcpLogger.debug(`[${functionTag}] Converted ${tools.length} tools for function calling`);
|
|
286
|
+
// Log the tool names for debugging
|
|
287
|
+
const toolNames = Array.from(toolMap.keys());
|
|
288
|
+
mcpLogger.debug(`[${functionTag}] Tool names:`, toolNames);
|
|
289
|
+
mcpLogger.debug(`[${functionTag}] First 5 tool names:`, toolNames.slice(0, 5));
|
|
290
|
+
if (overallTimeoutId) {
|
|
291
|
+
clearTimeout(overallTimeoutId);
|
|
292
|
+
}
|
|
293
|
+
return { tools, toolMap };
|
|
294
|
+
}
|
|
295
|
+
catch (error) {
|
|
296
|
+
if (overallTimeoutId) {
|
|
297
|
+
clearTimeout(overallTimeoutId);
|
|
298
|
+
}
|
|
299
|
+
throw error;
|
|
300
|
+
}
|
|
301
|
+
})();
|
|
302
|
+
return await Promise.race([toolsLoadingPromise, overallTimeoutPromise]);
|
|
303
|
+
}
|
|
304
|
+
catch (error) {
|
|
305
|
+
mcpLogger.error(`[${functionTag}] Error getting function tools:`, error);
|
|
306
|
+
return { tools: [], toolMap: new Map() };
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
/**
|
|
310
|
+
* Execute MCP tool from AI function call
|
|
311
|
+
*/
|
|
312
|
+
export async function executeFunctionCall(functionName, parameters, context) {
|
|
313
|
+
const functionTag = "executeFunctionCall";
|
|
314
|
+
try {
|
|
315
|
+
mcpLogger.debug(`[${functionTag}] Executing function call: ${functionName}`, { parameters });
|
|
316
|
+
// Create context if not provided
|
|
317
|
+
let finalContext = context;
|
|
318
|
+
if (!finalContext) {
|
|
319
|
+
finalContext = createExecutionContext({
|
|
320
|
+
sessionId: `function-call-${Date.now()}`,
|
|
321
|
+
userId: "ai-function-caller",
|
|
322
|
+
aiProvider: "function-calling",
|
|
323
|
+
});
|
|
324
|
+
}
|
|
325
|
+
// Parse server and tool name from function name
|
|
326
|
+
// First try underscore format (sanitized), then fallback to dot format
|
|
327
|
+
let parts = functionName.split("_");
|
|
328
|
+
let serverId;
|
|
329
|
+
let toolName;
|
|
330
|
+
if (parts.length >= 2) {
|
|
331
|
+
// Handle underscore format (sanitized names)
|
|
332
|
+
serverId = parts[0];
|
|
333
|
+
toolName = parts.slice(1).join("_"); // Rejoin in case tool name had underscores
|
|
334
|
+
}
|
|
335
|
+
else {
|
|
336
|
+
// Fallback to dot format for backward compatibility
|
|
337
|
+
parts = functionName.split(".");
|
|
338
|
+
if (parts.length === 2) {
|
|
339
|
+
[serverId, toolName] = parts;
|
|
340
|
+
}
|
|
341
|
+
else {
|
|
342
|
+
// Can't parse - try executing as-is through unified registry
|
|
343
|
+
mcpLogger.debug(`[${functionTag}] Cannot parse function name format: ${functionName}, trying unified registry`);
|
|
344
|
+
const result = await defaultUnifiedRegistry.executeTool(functionName, parameters, finalContext);
|
|
345
|
+
return result;
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
// Handle built-in NeuroLink servers directly
|
|
349
|
+
if (serverId === "neurolink-utility" ||
|
|
350
|
+
serverId === "neurolink-ai-core" ||
|
|
351
|
+
serverId === "neurolink_utility" ||
|
|
352
|
+
serverId === "neurolink_ai_core") {
|
|
353
|
+
mcpLogger.debug(`[${functionTag}] Executing built-in tool: ${toolName} from ${serverId}`);
|
|
354
|
+
// Import and execute from default registry
|
|
355
|
+
const { defaultToolRegistry } = await import("./registry.js");
|
|
356
|
+
return await defaultToolRegistry.executeTool(toolName, parameters, finalContext);
|
|
357
|
+
}
|
|
358
|
+
// Handle filesystem server with special activation logic
|
|
359
|
+
if (serverId === "filesystem") {
|
|
360
|
+
mcpLogger.debug(`[${functionTag}] Executing filesystem tool: ${toolName}`);
|
|
361
|
+
try {
|
|
362
|
+
// First, try to execute through unified registry
|
|
363
|
+
const result = await defaultUnifiedRegistry.executeTool(functionName, parameters, finalContext);
|
|
364
|
+
if (result.success) {
|
|
365
|
+
return result;
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
catch {
|
|
369
|
+
mcpLogger.debug(`[${functionTag}] Unified registry execution failed for ${functionName}, trying fallback`);
|
|
370
|
+
}
|
|
371
|
+
// Fallback: Try to trigger activation and retry
|
|
372
|
+
try {
|
|
373
|
+
// Force activation by attempting to activate the filesystem server directly
|
|
374
|
+
// This should convert placeholders to real tools
|
|
375
|
+
await defaultUnifiedRegistry.initialize();
|
|
376
|
+
// Try a few common activation patterns
|
|
377
|
+
const activationAttempts = [
|
|
378
|
+
`${serverId}.list_directory`,
|
|
379
|
+
`${serverId}.${toolName}`,
|
|
380
|
+
toolName,
|
|
381
|
+
];
|
|
382
|
+
for (const attempt of activationAttempts) {
|
|
383
|
+
try {
|
|
384
|
+
const result = await defaultUnifiedRegistry.executeTool(attempt, parameters, finalContext);
|
|
385
|
+
if (result.success) {
|
|
386
|
+
mcpLogger.debug(`[${functionTag}] Filesystem tool executed successfully with: ${attempt}`);
|
|
387
|
+
return result;
|
|
388
|
+
}
|
|
389
|
+
}
|
|
390
|
+
catch {
|
|
391
|
+
// Continue to next attempt
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
// If all attempts fail, return a helpful error
|
|
395
|
+
return {
|
|
396
|
+
success: false,
|
|
397
|
+
error: `Filesystem tool '${toolName}' could not be activated. Available parameters: ${JSON.stringify(parameters)}`,
|
|
398
|
+
metadata: {
|
|
399
|
+
functionName,
|
|
400
|
+
timestamp: Date.now(),
|
|
401
|
+
source: "function-calling-filesystem-fallback",
|
|
402
|
+
},
|
|
403
|
+
};
|
|
404
|
+
}
|
|
405
|
+
catch (fallbackError) {
|
|
406
|
+
mcpLogger.error(`[${functionTag}] Filesystem fallback failed:`, fallbackError);
|
|
407
|
+
return {
|
|
408
|
+
success: false,
|
|
409
|
+
error: `Filesystem tool execution failed: ${fallbackError instanceof Error ? fallbackError.message : String(fallbackError)}`,
|
|
410
|
+
metadata: {
|
|
411
|
+
functionName,
|
|
412
|
+
timestamp: Date.now(),
|
|
413
|
+
source: "function-calling-filesystem-fallback",
|
|
414
|
+
},
|
|
415
|
+
};
|
|
416
|
+
}
|
|
417
|
+
}
|
|
418
|
+
// For other tools, use unified registry
|
|
419
|
+
mcpLogger.debug(`[${functionTag}] Executing through unified registry: ${functionName}`);
|
|
420
|
+
const result = await defaultUnifiedRegistry.executeTool(functionName, parameters, finalContext);
|
|
421
|
+
mcpLogger.debug(`[${functionTag}] Function call completed: ${functionName}`, {
|
|
422
|
+
success: result.success,
|
|
423
|
+
hasData: !!result.data,
|
|
424
|
+
});
|
|
425
|
+
return result;
|
|
426
|
+
}
|
|
427
|
+
catch (error) {
|
|
428
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
429
|
+
mcpLogger.error(`[${functionTag}] Function call failed: ${functionName}`, {
|
|
430
|
+
error: errorMessage,
|
|
431
|
+
});
|
|
432
|
+
return {
|
|
433
|
+
success: false,
|
|
434
|
+
error: errorMessage,
|
|
435
|
+
metadata: {
|
|
436
|
+
functionName,
|
|
437
|
+
timestamp: Date.now(),
|
|
438
|
+
source: "function-calling-integration",
|
|
439
|
+
},
|
|
440
|
+
};
|
|
441
|
+
}
|
|
442
|
+
}
|
|
443
|
+
/**
|
|
444
|
+
* Handle multiple function calls and format results for AI
|
|
445
|
+
*/
|
|
446
|
+
export async function handleFunctionCalls(functionCalls, context) {
|
|
447
|
+
const functionTag = "handleFunctionCalls";
|
|
448
|
+
const results = [];
|
|
449
|
+
mcpLogger.debug(`[${functionTag}] Handling ${functionCalls.length} function calls`);
|
|
450
|
+
for (const call of functionCalls) {
|
|
451
|
+
const result = await executeFunctionCall(call.name, call.parameters, context);
|
|
452
|
+
// Format result for AI consumption
|
|
453
|
+
let formattedForAI = "";
|
|
454
|
+
if (result.success) {
|
|
455
|
+
if (typeof result.data === "string") {
|
|
456
|
+
formattedForAI = result.data;
|
|
457
|
+
}
|
|
458
|
+
else if (result.data) {
|
|
459
|
+
formattedForAI = JSON.stringify(result.data, null, 2);
|
|
460
|
+
}
|
|
461
|
+
else {
|
|
462
|
+
formattedForAI = "Function executed successfully (no data returned)";
|
|
463
|
+
}
|
|
464
|
+
}
|
|
465
|
+
else {
|
|
466
|
+
formattedForAI = `Error: ${result.error || "Function execution failed"}`;
|
|
467
|
+
}
|
|
468
|
+
results.push({
|
|
469
|
+
id: call.id,
|
|
470
|
+
result,
|
|
471
|
+
formattedForAI,
|
|
472
|
+
});
|
|
473
|
+
}
|
|
474
|
+
return results;
|
|
475
|
+
}
|
|
476
|
+
/**
|
|
477
|
+
* Create a subset of tools for specific categories or capabilities
|
|
478
|
+
*/
|
|
479
|
+
export async function getFunctionToolsForCategory(category, maxTools) {
|
|
480
|
+
const { tools, toolMap } = await getAvailableFunctionTools();
|
|
481
|
+
if (!category) {
|
|
482
|
+
return maxTools
|
|
483
|
+
? {
|
|
484
|
+
tools: tools.slice(0, maxTools),
|
|
485
|
+
toolMap,
|
|
486
|
+
}
|
|
487
|
+
: { tools, toolMap };
|
|
488
|
+
}
|
|
489
|
+
// Filter by category (simplified - just include all for now)
|
|
490
|
+
const filteredTools = tools;
|
|
491
|
+
return maxTools
|
|
492
|
+
? {
|
|
493
|
+
tools: filteredTools.slice(0, maxTools),
|
|
494
|
+
toolMap,
|
|
495
|
+
}
|
|
496
|
+
: { tools: filteredTools, toolMap };
|
|
497
|
+
}
|
|
498
|
+
/**
|
|
499
|
+
* Check if function calling is available
|
|
500
|
+
*/
|
|
501
|
+
export async function isFunctionCallingAvailable() {
|
|
502
|
+
try {
|
|
503
|
+
const { tools } = await getAvailableFunctionTools();
|
|
504
|
+
return tools.length > 0;
|
|
505
|
+
}
|
|
506
|
+
catch (error) {
|
|
507
|
+
mcpLogger.warn("[isFunctionCallingAvailable] Failed to check availability:", error);
|
|
508
|
+
return false;
|
|
509
|
+
}
|
|
510
|
+
}
|