@mcp-ts/sdk 1.3.6 → 1.3.7
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/dist/adapters/agui-adapter.d.mts +1 -1
- package/dist/adapters/agui-adapter.d.ts +1 -1
- package/dist/adapters/agui-adapter.js +2 -2
- package/dist/adapters/agui-adapter.js.map +1 -1
- package/dist/adapters/agui-adapter.mjs +2 -2
- package/dist/adapters/agui-adapter.mjs.map +1 -1
- package/dist/adapters/agui-middleware.d.mts +1 -1
- package/dist/adapters/agui-middleware.d.ts +1 -1
- package/dist/adapters/agui-middleware.js.map +1 -1
- package/dist/adapters/agui-middleware.mjs.map +1 -1
- package/dist/adapters/ai-adapter.d.mts +1 -1
- package/dist/adapters/ai-adapter.d.ts +1 -1
- package/dist/adapters/ai-adapter.js +1 -1
- package/dist/adapters/ai-adapter.js.map +1 -1
- package/dist/adapters/ai-adapter.mjs +1 -1
- package/dist/adapters/ai-adapter.mjs.map +1 -1
- package/dist/adapters/langchain-adapter.d.mts +1 -1
- package/dist/adapters/langchain-adapter.d.ts +1 -1
- package/dist/adapters/langchain-adapter.js +1 -1
- package/dist/adapters/langchain-adapter.js.map +1 -1
- package/dist/adapters/langchain-adapter.mjs +1 -1
- package/dist/adapters/langchain-adapter.mjs.map +1 -1
- package/dist/adapters/mastra-adapter.d.mts +1 -1
- package/dist/adapters/mastra-adapter.d.ts +1 -1
- package/dist/adapters/mastra-adapter.js +1 -1
- package/dist/adapters/mastra-adapter.js.map +1 -1
- package/dist/adapters/mastra-adapter.mjs +1 -1
- package/dist/adapters/mastra-adapter.mjs.map +1 -1
- package/dist/index.d.mts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +134 -71
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +134 -71
- package/dist/index.mjs.map +1 -1
- package/dist/{multi-session-client-BYLarghq.d.ts → multi-session-client-CHE8QpVE.d.ts} +75 -5
- package/dist/{multi-session-client-CzhMkE0k.d.mts → multi-session-client-CQsRbxYI.d.mts} +75 -5
- package/dist/server/index.d.mts +1 -1
- package/dist/server/index.d.ts +1 -1
- package/dist/server/index.js +134 -71
- package/dist/server/index.js.map +1 -1
- package/dist/server/index.mjs +134 -71
- package/dist/server/index.mjs.map +1 -1
- package/dist/shared/index.js +10 -2
- package/dist/shared/index.js.map +1 -1
- package/dist/shared/index.mjs +10 -2
- package/dist/shared/index.mjs.map +1 -1
- package/package.json +2 -2
- package/src/adapters/agui-adapter.ts +222 -222
- package/src/adapters/ai-adapter.ts +115 -115
- package/src/adapters/langchain-adapter.ts +127 -127
- package/src/adapters/mastra-adapter.ts +126 -126
- package/src/server/mcp/multi-session-client.ts +135 -39
- package/src/server/storage/file-backend.ts +3 -16
- package/src/server/storage/index.ts +1 -0
- package/src/server/storage/memory-backend.ts +3 -16
- package/src/server/storage/redis-backend.ts +3 -16
- package/src/server/storage/sqlite-backend.ts +2 -6
- package/src/server/storage/supabase-backend.ts +2 -1
- package/src/shared/utils.ts +22 -0
|
@@ -1,115 +1,115 @@
|
|
|
1
|
-
import { MCPClient } from '../server/mcp/oauth-client';
|
|
2
|
-
import { MultiSessionClient } from '../server/mcp/multi-session-client';
|
|
3
|
-
import type { JSONSchema7 } from 'json-schema';
|
|
4
|
-
import type { ToolSet } from 'ai';
|
|
5
|
-
|
|
6
|
-
export interface AIAdapterOptions {
|
|
7
|
-
/**
|
|
8
|
-
* Prefix for tool names to avoid collision with other tools.
|
|
9
|
-
* Defaults to the client's serverId.
|
|
10
|
-
*/
|
|
11
|
-
prefix?: string;
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
/**
|
|
15
|
-
* Adapter to use MCP tools with the Vercel AI SDK.
|
|
16
|
-
*/
|
|
17
|
-
export class AIAdapter {
|
|
18
|
-
private jsonSchema: typeof import('ai').jsonSchema | undefined;
|
|
19
|
-
|
|
20
|
-
constructor(
|
|
21
|
-
private client: MCPClient | MultiSessionClient,
|
|
22
|
-
private options: AIAdapterOptions = {}
|
|
23
|
-
) { }
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
/**
|
|
28
|
-
* Lazy-loads the jsonSchema function from the AI SDK.
|
|
29
|
-
*/
|
|
30
|
-
private async ensureJsonSchema() {
|
|
31
|
-
if (!this.jsonSchema) {
|
|
32
|
-
const { jsonSchema } = await import('ai');
|
|
33
|
-
this.jsonSchema = jsonSchema;
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
private async transformTools(client: MCPClient): Promise<ToolSet> {
|
|
38
|
-
// Safe check for isConnected method (duck typing for bundler compatibility)
|
|
39
|
-
const isConnected = typeof client.isConnected === 'function'
|
|
40
|
-
? client.isConnected()
|
|
41
|
-
: false;
|
|
42
|
-
|
|
43
|
-
if (!isConnected) {
|
|
44
|
-
return {};
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
const result = await client.listTools();
|
|
48
|
-
|
|
49
|
-
// @ts-ignore: ToolSet type inference can be tricky with dynamic imports
|
|
50
|
-
return Object.fromEntries(
|
|
51
|
-
result.tools.map((tool) => {
|
|
52
|
-
// Safe access to getServerId
|
|
53
|
-
const serverId = typeof client.getServerId === 'function'
|
|
54
|
-
? client.getServerId()
|
|
55
|
-
: undefined;
|
|
56
|
-
const prefix = this.options.prefix ?? serverId?.replace(/-/g, '') ?? 'mcp';
|
|
57
|
-
return [
|
|
58
|
-
`tool_${prefix}_${tool.name}`,
|
|
59
|
-
{
|
|
60
|
-
description: tool.description,
|
|
61
|
-
inputSchema: this.jsonSchema!(tool.inputSchema as JSONSchema7),
|
|
62
|
-
execute: async (args: any) => {
|
|
63
|
-
try {
|
|
64
|
-
const response = await client.callTool(tool.name, args);
|
|
65
|
-
return response;
|
|
66
|
-
} catch (error) {
|
|
67
|
-
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
68
|
-
throw new Error(`Tool execution failed: ${errorMessage}`);
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
];
|
|
73
|
-
})
|
|
74
|
-
);
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
/**
|
|
78
|
-
* Fetches tools from the client(s) and converts them to AI SDK tools.
|
|
79
|
-
*/
|
|
80
|
-
async getTools(): Promise<ToolSet> {
|
|
81
|
-
await this.ensureJsonSchema();
|
|
82
|
-
|
|
83
|
-
// Use duck typing instead of instanceof to handle module bundling issues
|
|
84
|
-
// MultiSessionClient has getClients(), MCPClient does not
|
|
85
|
-
const isMultiSession = typeof (this.client as any).getClients === 'function';
|
|
86
|
-
const clients = isMultiSession
|
|
87
|
-
? (this.client as MultiSessionClient).getClients()
|
|
88
|
-
: [this.client as MCPClient];
|
|
89
|
-
|
|
90
|
-
const results = await Promise.all(
|
|
91
|
-
clients.map(async (client) => {
|
|
92
|
-
try {
|
|
93
|
-
return await this.transformTools(client);
|
|
94
|
-
} catch (error) {
|
|
95
|
-
// For multi-client, we log and continue.
|
|
96
|
-
// This is safer than throwing.
|
|
97
|
-
const serverId = typeof client.getServerId === 'function'
|
|
98
|
-
? client.getServerId() ?? 'unknown'
|
|
99
|
-
: 'unknown';
|
|
100
|
-
console.error(`[AIAdapter] Failed to fetch tools from ${serverId}:`, error);
|
|
101
|
-
return {};
|
|
102
|
-
}
|
|
103
|
-
})
|
|
104
|
-
);
|
|
105
|
-
|
|
106
|
-
return results.reduce((acc, tools) => ({ ...acc, ...tools }), {});
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
/**
|
|
110
|
-
* Convenience static method to fetch tools in a single line.
|
|
111
|
-
*/
|
|
112
|
-
static async getTools(client: MCPClient | MultiSessionClient, options: AIAdapterOptions = {}): Promise<ToolSet> {
|
|
113
|
-
return new AIAdapter(client, options).getTools();
|
|
114
|
-
}
|
|
115
|
-
}
|
|
1
|
+
import { MCPClient } from '../server/mcp/oauth-client';
|
|
2
|
+
import { MultiSessionClient } from '../server/mcp/multi-session-client';
|
|
3
|
+
import type { JSONSchema7 } from 'json-schema';
|
|
4
|
+
import type { ToolSet } from 'ai';
|
|
5
|
+
|
|
6
|
+
export interface AIAdapterOptions {
|
|
7
|
+
/**
|
|
8
|
+
* Prefix for tool names to avoid collision with other tools.
|
|
9
|
+
* Defaults to the client's serverId.
|
|
10
|
+
*/
|
|
11
|
+
prefix?: string;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Adapter to use MCP tools with the Vercel AI SDK.
|
|
16
|
+
*/
|
|
17
|
+
export class AIAdapter {
|
|
18
|
+
private jsonSchema: typeof import('ai').jsonSchema | undefined;
|
|
19
|
+
|
|
20
|
+
constructor(
|
|
21
|
+
private client: MCPClient | MultiSessionClient,
|
|
22
|
+
private options: AIAdapterOptions = {}
|
|
23
|
+
) { }
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Lazy-loads the jsonSchema function from the AI SDK.
|
|
29
|
+
*/
|
|
30
|
+
private async ensureJsonSchema() {
|
|
31
|
+
if (!this.jsonSchema) {
|
|
32
|
+
const { jsonSchema } = await import('ai');
|
|
33
|
+
this.jsonSchema = jsonSchema;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
private async transformTools(client: MCPClient): Promise<ToolSet> {
|
|
38
|
+
// Safe check for isConnected method (duck typing for bundler compatibility)
|
|
39
|
+
const isConnected = typeof client.isConnected === 'function'
|
|
40
|
+
? client.isConnected()
|
|
41
|
+
: false;
|
|
42
|
+
|
|
43
|
+
if (!isConnected) {
|
|
44
|
+
return {};
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
const result = await client.listTools();
|
|
48
|
+
|
|
49
|
+
// @ts-ignore: ToolSet type inference can be tricky with dynamic imports
|
|
50
|
+
return Object.fromEntries(
|
|
51
|
+
result.tools.map((tool) => {
|
|
52
|
+
// Safe access to getServerId
|
|
53
|
+
const serverId = typeof client.getServerId === 'function'
|
|
54
|
+
? client.getServerId()
|
|
55
|
+
: undefined;
|
|
56
|
+
const prefix = this.options.prefix ?? serverId?.replace(/-/g, '').substring(0, 8) ?? 'mcp';
|
|
57
|
+
return [
|
|
58
|
+
`tool_${prefix}_${tool.name}`,
|
|
59
|
+
{
|
|
60
|
+
description: tool.description,
|
|
61
|
+
inputSchema: this.jsonSchema!(tool.inputSchema as JSONSchema7),
|
|
62
|
+
execute: async (args: any) => {
|
|
63
|
+
try {
|
|
64
|
+
const response = await client.callTool(tool.name, args);
|
|
65
|
+
return response;
|
|
66
|
+
} catch (error) {
|
|
67
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
68
|
+
throw new Error(`Tool execution failed: ${errorMessage}`);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
];
|
|
73
|
+
})
|
|
74
|
+
);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Fetches tools from the client(s) and converts them to AI SDK tools.
|
|
79
|
+
*/
|
|
80
|
+
async getTools(): Promise<ToolSet> {
|
|
81
|
+
await this.ensureJsonSchema();
|
|
82
|
+
|
|
83
|
+
// Use duck typing instead of instanceof to handle module bundling issues
|
|
84
|
+
// MultiSessionClient has getClients(), MCPClient does not
|
|
85
|
+
const isMultiSession = typeof (this.client as any).getClients === 'function';
|
|
86
|
+
const clients = isMultiSession
|
|
87
|
+
? (this.client as MultiSessionClient).getClients()
|
|
88
|
+
: [this.client as MCPClient];
|
|
89
|
+
|
|
90
|
+
const results = await Promise.all(
|
|
91
|
+
clients.map(async (client) => {
|
|
92
|
+
try {
|
|
93
|
+
return await this.transformTools(client);
|
|
94
|
+
} catch (error) {
|
|
95
|
+
// For multi-client, we log and continue.
|
|
96
|
+
// This is safer than throwing.
|
|
97
|
+
const serverId = typeof client.getServerId === 'function'
|
|
98
|
+
? client.getServerId() ?? 'unknown'
|
|
99
|
+
: 'unknown';
|
|
100
|
+
console.error(`[AIAdapter] Failed to fetch tools from ${serverId}:`, error);
|
|
101
|
+
return {};
|
|
102
|
+
}
|
|
103
|
+
})
|
|
104
|
+
);
|
|
105
|
+
|
|
106
|
+
return results.reduce((acc, tools) => ({ ...acc, ...tools }), {});
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* Convenience static method to fetch tools in a single line.
|
|
111
|
+
*/
|
|
112
|
+
static async getTools(client: MCPClient | MultiSessionClient, options: AIAdapterOptions = {}): Promise<ToolSet> {
|
|
113
|
+
return new AIAdapter(client, options).getTools();
|
|
114
|
+
}
|
|
115
|
+
}
|
|
@@ -1,127 +1,127 @@
|
|
|
1
|
-
import { MCPClient } from '../server/mcp/oauth-client';
|
|
2
|
-
import { MultiSessionClient } from '../server/mcp/multi-session-client';
|
|
3
|
-
import type { DynamicStructuredTool, StructuredTool } from '@langchain/core/tools';
|
|
4
|
-
import type { z } from 'zod';
|
|
5
|
-
|
|
6
|
-
export interface LangChainAdapterOptions {
|
|
7
|
-
/**
|
|
8
|
-
* Prefix for tool names to avoid collision with other tools.
|
|
9
|
-
* Defaults to the client's serverId.
|
|
10
|
-
*/
|
|
11
|
-
prefix?: string;
|
|
12
|
-
|
|
13
|
-
/**
|
|
14
|
-
* Whether to simplify error messages returned to the LLM.
|
|
15
|
-
* If true, returns "Error: <message>" string instead of throwing.
|
|
16
|
-
* @default false
|
|
17
|
-
*/
|
|
18
|
-
simplifyErrors?: boolean;
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
/**
|
|
22
|
-
* Adapter to use MCP tools within LangChain/LangGraph agents.
|
|
23
|
-
*/
|
|
24
|
-
export class LangChainAdapter {
|
|
25
|
-
private DynamicStructuredTool: typeof DynamicStructuredTool | undefined;
|
|
26
|
-
private z: typeof z | undefined;
|
|
27
|
-
|
|
28
|
-
constructor(
|
|
29
|
-
private client: MCPClient | MultiSessionClient,
|
|
30
|
-
private options: LangChainAdapterOptions = {}
|
|
31
|
-
) { }
|
|
32
|
-
|
|
33
|
-
/**
|
|
34
|
-
* Lazy-loads LangChain and Zod dependencies
|
|
35
|
-
*/
|
|
36
|
-
private async ensureDependencies() {
|
|
37
|
-
if (!this.DynamicStructuredTool) {
|
|
38
|
-
try {
|
|
39
|
-
const langchain = await import('@langchain/core/tools');
|
|
40
|
-
this.DynamicStructuredTool = langchain.DynamicStructuredTool;
|
|
41
|
-
|
|
42
|
-
const zod = await import('zod');
|
|
43
|
-
this.z = zod.z;
|
|
44
|
-
} catch (error) {
|
|
45
|
-
throw new Error(
|
|
46
|
-
'LangChain dependencies not installed. Install with:\n' +
|
|
47
|
-
' npm install @langchain/core zod'
|
|
48
|
-
);
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
private async transformTools(client: MCPClient): Promise<StructuredTool[]> {
|
|
54
|
-
if (!client.isConnected()) {
|
|
55
|
-
return [];
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
await this.ensureDependencies();
|
|
59
|
-
|
|
60
|
-
const result = await client.listTools();
|
|
61
|
-
const prefix = this.options.prefix ?? client.getServerId() ?? 'mcp';
|
|
62
|
-
|
|
63
|
-
return result.tools.map((tool) => {
|
|
64
|
-
// In a real implementation, you would use a library like 'json-schema-to-zod'
|
|
65
|
-
const schema = this.jsonSchemaToZod(tool.inputSchema);
|
|
66
|
-
|
|
67
|
-
return new this.DynamicStructuredTool!({
|
|
68
|
-
name: `${prefix}_${tool.name}`,
|
|
69
|
-
description: tool.description || `Tool ${tool.name}`,
|
|
70
|
-
schema: schema,
|
|
71
|
-
func: async (args: any) => {
|
|
72
|
-
try {
|
|
73
|
-
return await client.callTool(tool.name, args);
|
|
74
|
-
} catch (error: any) {
|
|
75
|
-
if (this.options.simplifyErrors) {
|
|
76
|
-
return `Error: ${error.message}`;
|
|
77
|
-
}
|
|
78
|
-
throw error;
|
|
79
|
-
}
|
|
80
|
-
},
|
|
81
|
-
});
|
|
82
|
-
});
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
private jsonSchemaToZod(schema: any): z.ZodType<any> {
|
|
86
|
-
try {
|
|
87
|
-
const { parseSchema } = require('json-schema-to-zod');
|
|
88
|
-
const zodSchemaString = parseSchema(schema);
|
|
89
|
-
// eslint-disable-next-line
|
|
90
|
-
return new Function('z', 'return ' + zodSchemaString)(this.z);
|
|
91
|
-
} catch (error) {
|
|
92
|
-
// Fallback: Accept any object if conversion fails
|
|
93
|
-
console.warn('[LangChainAdapter] Failed to convert JSON Schema to Zod, using fallback:', error);
|
|
94
|
-
return this.z!.record(this.z!.any()).optional().describe("Dynamic Input");
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
/**
|
|
99
|
-
* Fetches tools from the MCP server and converts them to LangChain StructuredTools.
|
|
100
|
-
*/
|
|
101
|
-
async getTools(): Promise<StructuredTool[]> {
|
|
102
|
-
// Use duck typing instead of instanceof to handle module bundling issues
|
|
103
|
-
const isMultiSession = typeof (this.client as any).getClients === 'function';
|
|
104
|
-
const clients = isMultiSession
|
|
105
|
-
? (this.client as MultiSessionClient).getClients()
|
|
106
|
-
: [this.client as MCPClient];
|
|
107
|
-
|
|
108
|
-
const results = await Promise.all(
|
|
109
|
-
clients.map(async (client) => {
|
|
110
|
-
try {
|
|
111
|
-
return await this.transformTools(client);
|
|
112
|
-
} catch (error) {
|
|
113
|
-
console.error(`[LangChainAdapter] Failed to fetch tools from ${client.getServerId()}:`, error);
|
|
114
|
-
return [];
|
|
115
|
-
}
|
|
116
|
-
})
|
|
117
|
-
);
|
|
118
|
-
return results.flat();
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
/**
|
|
122
|
-
* Convenience static method to fetch tools in a single line.
|
|
123
|
-
*/
|
|
124
|
-
static async getTools(client: MCPClient | MultiSessionClient, options: LangChainAdapterOptions = {}): Promise<StructuredTool[]> {
|
|
125
|
-
return new LangChainAdapter(client, options).getTools();
|
|
126
|
-
}
|
|
127
|
-
}
|
|
1
|
+
import { MCPClient } from '../server/mcp/oauth-client';
|
|
2
|
+
import { MultiSessionClient } from '../server/mcp/multi-session-client';
|
|
3
|
+
import type { DynamicStructuredTool, StructuredTool } from '@langchain/core/tools';
|
|
4
|
+
import type { z } from 'zod';
|
|
5
|
+
|
|
6
|
+
export interface LangChainAdapterOptions {
|
|
7
|
+
/**
|
|
8
|
+
* Prefix for tool names to avoid collision with other tools.
|
|
9
|
+
* Defaults to the client's serverId.
|
|
10
|
+
*/
|
|
11
|
+
prefix?: string;
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Whether to simplify error messages returned to the LLM.
|
|
15
|
+
* If true, returns "Error: <message>" string instead of throwing.
|
|
16
|
+
* @default false
|
|
17
|
+
*/
|
|
18
|
+
simplifyErrors?: boolean;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Adapter to use MCP tools within LangChain/LangGraph agents.
|
|
23
|
+
*/
|
|
24
|
+
export class LangChainAdapter {
|
|
25
|
+
private DynamicStructuredTool: typeof DynamicStructuredTool | undefined;
|
|
26
|
+
private z: typeof z | undefined;
|
|
27
|
+
|
|
28
|
+
constructor(
|
|
29
|
+
private client: MCPClient | MultiSessionClient,
|
|
30
|
+
private options: LangChainAdapterOptions = {}
|
|
31
|
+
) { }
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Lazy-loads LangChain and Zod dependencies
|
|
35
|
+
*/
|
|
36
|
+
private async ensureDependencies() {
|
|
37
|
+
if (!this.DynamicStructuredTool) {
|
|
38
|
+
try {
|
|
39
|
+
const langchain = await import('@langchain/core/tools');
|
|
40
|
+
this.DynamicStructuredTool = langchain.DynamicStructuredTool;
|
|
41
|
+
|
|
42
|
+
const zod = await import('zod');
|
|
43
|
+
this.z = zod.z;
|
|
44
|
+
} catch (error) {
|
|
45
|
+
throw new Error(
|
|
46
|
+
'LangChain dependencies not installed. Install with:\n' +
|
|
47
|
+
' npm install @langchain/core zod'
|
|
48
|
+
);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
private async transformTools(client: MCPClient): Promise<StructuredTool[]> {
|
|
54
|
+
if (!client.isConnected()) {
|
|
55
|
+
return [];
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
await this.ensureDependencies();
|
|
59
|
+
|
|
60
|
+
const result = await client.listTools();
|
|
61
|
+
const prefix = this.options.prefix ?? client.getServerId()?.replace(/-/g, '').substring(0, 8) ?? 'mcp';
|
|
62
|
+
|
|
63
|
+
return result.tools.map((tool) => {
|
|
64
|
+
// In a real implementation, you would use a library like 'json-schema-to-zod'
|
|
65
|
+
const schema = this.jsonSchemaToZod(tool.inputSchema);
|
|
66
|
+
|
|
67
|
+
return new this.DynamicStructuredTool!({
|
|
68
|
+
name: `${prefix}_${tool.name}`,
|
|
69
|
+
description: tool.description || `Tool ${tool.name}`,
|
|
70
|
+
schema: schema,
|
|
71
|
+
func: async (args: any) => {
|
|
72
|
+
try {
|
|
73
|
+
return await client.callTool(tool.name, args);
|
|
74
|
+
} catch (error: any) {
|
|
75
|
+
if (this.options.simplifyErrors) {
|
|
76
|
+
return `Error: ${error.message}`;
|
|
77
|
+
}
|
|
78
|
+
throw error;
|
|
79
|
+
}
|
|
80
|
+
},
|
|
81
|
+
});
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
private jsonSchemaToZod(schema: any): z.ZodType<any> {
|
|
86
|
+
try {
|
|
87
|
+
const { parseSchema } = require('json-schema-to-zod');
|
|
88
|
+
const zodSchemaString = parseSchema(schema);
|
|
89
|
+
// eslint-disable-next-line
|
|
90
|
+
return new Function('z', 'return ' + zodSchemaString)(this.z);
|
|
91
|
+
} catch (error) {
|
|
92
|
+
// Fallback: Accept any object if conversion fails
|
|
93
|
+
console.warn('[LangChainAdapter] Failed to convert JSON Schema to Zod, using fallback:', error);
|
|
94
|
+
return this.z!.record(this.z!.any()).optional().describe("Dynamic Input");
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Fetches tools from the MCP server and converts them to LangChain StructuredTools.
|
|
100
|
+
*/
|
|
101
|
+
async getTools(): Promise<StructuredTool[]> {
|
|
102
|
+
// Use duck typing instead of instanceof to handle module bundling issues
|
|
103
|
+
const isMultiSession = typeof (this.client as any).getClients === 'function';
|
|
104
|
+
const clients = isMultiSession
|
|
105
|
+
? (this.client as MultiSessionClient).getClients()
|
|
106
|
+
: [this.client as MCPClient];
|
|
107
|
+
|
|
108
|
+
const results = await Promise.all(
|
|
109
|
+
clients.map(async (client) => {
|
|
110
|
+
try {
|
|
111
|
+
return await this.transformTools(client);
|
|
112
|
+
} catch (error) {
|
|
113
|
+
console.error(`[LangChainAdapter] Failed to fetch tools from ${client.getServerId()}:`, error);
|
|
114
|
+
return [];
|
|
115
|
+
}
|
|
116
|
+
})
|
|
117
|
+
);
|
|
118
|
+
return results.flat();
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* Convenience static method to fetch tools in a single line.
|
|
123
|
+
*/
|
|
124
|
+
static async getTools(client: MCPClient | MultiSessionClient, options: LangChainAdapterOptions = {}): Promise<StructuredTool[]> {
|
|
125
|
+
return new LangChainAdapter(client, options).getTools();
|
|
126
|
+
}
|
|
127
|
+
}
|