@agentscope-ai/agentscope 0.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (136) hide show
  1. package/dist/agent/index.d.mts +234 -0
  2. package/dist/agent/index.d.ts +234 -0
  3. package/dist/agent/index.js +1412 -0
  4. package/dist/agent/index.js.map +1 -0
  5. package/dist/agent/index.mjs +1375 -0
  6. package/dist/agent/index.mjs.map +1 -0
  7. package/dist/base-BOx3UzOl.d.mts +41 -0
  8. package/dist/base-BoIps2RL.d.ts +41 -0
  9. package/dist/base-C7jwyH4Z.d.mts +52 -0
  10. package/dist/base-Cwi4bjze.d.ts +127 -0
  11. package/dist/base-DYlBMCy_.d.mts +127 -0
  12. package/dist/base-NX-knWOv.d.ts +52 -0
  13. package/dist/block-VsnHrllL.d.mts +48 -0
  14. package/dist/block-VsnHrllL.d.ts +48 -0
  15. package/dist/event/index.d.mts +181 -0
  16. package/dist/event/index.d.ts +181 -0
  17. package/dist/event/index.js +58 -0
  18. package/dist/event/index.js.map +1 -0
  19. package/dist/event/index.mjs +33 -0
  20. package/dist/event/index.mjs.map +1 -0
  21. package/dist/formatter/index.d.mts +187 -0
  22. package/dist/formatter/index.d.ts +187 -0
  23. package/dist/formatter/index.js +647 -0
  24. package/dist/formatter/index.js.map +1 -0
  25. package/dist/formatter/index.mjs +616 -0
  26. package/dist/formatter/index.mjs.map +1 -0
  27. package/dist/index-BTJDlKvQ.d.mts +195 -0
  28. package/dist/index-BcatlwXQ.d.ts +195 -0
  29. package/dist/index-CAxQAkiP.d.mts +21 -0
  30. package/dist/index-CAxQAkiP.d.ts +21 -0
  31. package/dist/mcp/index.d.mts +9 -0
  32. package/dist/mcp/index.d.ts +9 -0
  33. package/dist/mcp/index.js +432 -0
  34. package/dist/mcp/index.js.map +1 -0
  35. package/dist/mcp/index.mjs +408 -0
  36. package/dist/mcp/index.mjs.map +1 -0
  37. package/dist/message/index.d.mts +10 -0
  38. package/dist/message/index.d.ts +10 -0
  39. package/dist/message/index.js +67 -0
  40. package/dist/message/index.js.map +1 -0
  41. package/dist/message/index.mjs +37 -0
  42. package/dist/message/index.mjs.map +1 -0
  43. package/dist/message-CkN21KaY.d.mts +99 -0
  44. package/dist/message-CzLeTlua.d.ts +99 -0
  45. package/dist/model/index.d.mts +377 -0
  46. package/dist/model/index.d.ts +377 -0
  47. package/dist/model/index.js +1880 -0
  48. package/dist/model/index.js.map +1 -0
  49. package/dist/model/index.mjs +1849 -0
  50. package/dist/model/index.mjs.map +1 -0
  51. package/dist/storage/index.d.mts +68 -0
  52. package/dist/storage/index.d.ts +68 -0
  53. package/dist/storage/index.js +250 -0
  54. package/dist/storage/index.js.map +1 -0
  55. package/dist/storage/index.mjs +212 -0
  56. package/dist/storage/index.mjs.map +1 -0
  57. package/dist/tool/index.d.mts +311 -0
  58. package/dist/tool/index.d.ts +311 -0
  59. package/dist/tool/index.js +1494 -0
  60. package/dist/tool/index.js.map +1 -0
  61. package/dist/tool/index.mjs +1447 -0
  62. package/dist/tool/index.mjs.map +1 -0
  63. package/dist/toolkit-CEpulFi0.d.ts +99 -0
  64. package/dist/toolkit-CGEZSZPa.d.mts +99 -0
  65. package/jest.config.js +11 -0
  66. package/package.json +92 -0
  67. package/src/_utils/common.ts +104 -0
  68. package/src/_utils/index.ts +1 -0
  69. package/src/agent/agent-base.ts +0 -0
  70. package/src/agent/agent.test.ts +1028 -0
  71. package/src/agent/agent.ts +1032 -0
  72. package/src/agent/index.ts +2 -0
  73. package/src/agent/interfaces.ts +23 -0
  74. package/src/agent/test-compression.ts +72 -0
  75. package/src/event/index.ts +250 -0
  76. package/src/formatter/base.ts +133 -0
  77. package/src/formatter/dashscope-chat-formatter.test.ts +372 -0
  78. package/src/formatter/dashscope-chat-formatter.ts +163 -0
  79. package/src/formatter/deepseek-chat-formatter.ts +130 -0
  80. package/src/formatter/index.ts +5 -0
  81. package/src/formatter/ollama-chat-formatter.ts +67 -0
  82. package/src/formatter/openai-chat-formatter.test.ts +263 -0
  83. package/src/formatter/openai-chat-formatter.ts +301 -0
  84. package/src/formatter/openai.md +767 -0
  85. package/src/mcp/base.ts +114 -0
  86. package/src/mcp/http.test.ts +303 -0
  87. package/src/mcp/http.ts +224 -0
  88. package/src/mcp/index.ts +2 -0
  89. package/src/mcp/stdio.test.ts +91 -0
  90. package/src/mcp/stdio.ts +119 -0
  91. package/src/message/block.ts +60 -0
  92. package/src/message/enums.ts +4 -0
  93. package/src/message/index.ts +12 -0
  94. package/src/message/message.test.ts +80 -0
  95. package/src/message/message.ts +131 -0
  96. package/src/model/base.ts +226 -0
  97. package/src/model/dashscope-model.test.ts +335 -0
  98. package/src/model/dashscope-model.ts +441 -0
  99. package/src/model/deepseek-model.test.ts +279 -0
  100. package/src/model/deepseek-model.ts +401 -0
  101. package/src/model/index.ts +7 -0
  102. package/src/model/ollama-model.test.ts +307 -0
  103. package/src/model/ollama-model.ts +356 -0
  104. package/src/model/openai-model.ts +327 -0
  105. package/src/model/response.ts +22 -0
  106. package/src/model/usage.ts +12 -0
  107. package/src/storage/base.ts +52 -0
  108. package/src/storage/file-system.test.ts +587 -0
  109. package/src/storage/file-system.ts +269 -0
  110. package/src/storage/index.ts +2 -0
  111. package/src/tool/base.ts +23 -0
  112. package/src/tool/bash.test.ts +174 -0
  113. package/src/tool/bash.ts +152 -0
  114. package/src/tool/edit.test.ts +83 -0
  115. package/src/tool/edit.ts +95 -0
  116. package/src/tool/glob.test.ts +63 -0
  117. package/src/tool/glob.ts +166 -0
  118. package/src/tool/grep.test.ts +74 -0
  119. package/src/tool/grep.ts +256 -0
  120. package/src/tool/index.ts +10 -0
  121. package/src/tool/read.test.ts +77 -0
  122. package/src/tool/read.ts +117 -0
  123. package/src/tool/response.ts +82 -0
  124. package/src/tool/task.test.ts +299 -0
  125. package/src/tool/task.ts +399 -0
  126. package/src/tool/toolkit.test.ts +636 -0
  127. package/src/tool/toolkit.ts +601 -0
  128. package/src/tool/write.test.ts +52 -0
  129. package/src/tool/write.ts +57 -0
  130. package/src/type/index.ts +52 -0
  131. package/tsconfig.build.json +4 -0
  132. package/tsconfig.cjs.json +11 -0
  133. package/tsconfig.esm.json +10 -0
  134. package/tsconfig.json +14 -0
  135. package/tsup.config.ts +20 -0
  136. package/typedoc.json +52 -0
@@ -0,0 +1,114 @@
1
+ import { Client } from '@modelcontextprotocol/sdk/client/index.js';
2
+ import { CallToolRequest, CallToolResultSchema } from '@modelcontextprotocol/sdk/types.js';
3
+ import z from 'zod';
4
+
5
+ import { Tool, ToolResponse } from '../tool';
6
+ import { createToolResponse } from '../tool/response';
7
+ import { ToolInputSchema } from '../type';
8
+
9
+ /**
10
+ * Type definition for getting a client instance
11
+ */
12
+ type GetClient = () => Promise<Client>;
13
+
14
+ /**
15
+ * Type definition for releasing a client instance
16
+ */
17
+ type ReleaseClient = (client: Client) => Promise<void>;
18
+
19
+ /**
20
+ * MCPTool class that wraps an MCP tool and provides a callable interface
21
+ */
22
+ export class MCPTool implements Tool {
23
+ name: string;
24
+ description: string;
25
+ inputSchema: z.ZodObject | ToolInputSchema;
26
+ requireUserConfirm = false;
27
+ call: (input: Record<string, unknown>) => Promise<ToolResponse>;
28
+
29
+ private getClient: GetClient;
30
+ private releaseClient: ReleaseClient;
31
+
32
+ /**
33
+ * Initialize an MCPTool instance
34
+ * @param root0
35
+ * @param root0.name
36
+ * @param root0.description
37
+ * @param root0.inputSchema
38
+ * @param root0.getClient
39
+ * @param root0.releaseClient
40
+ */
41
+ constructor({
42
+ name,
43
+ description,
44
+ inputSchema,
45
+ getClient,
46
+ releaseClient,
47
+ }: {
48
+ name: string;
49
+ description: string;
50
+ inputSchema: z.ZodObject | ToolInputSchema;
51
+ getClient: GetClient;
52
+ releaseClient: ReleaseClient;
53
+ }) {
54
+ this.name = name;
55
+ this.description = description;
56
+ this.inputSchema = inputSchema;
57
+ this.getClient = getClient;
58
+ this.releaseClient = releaseClient;
59
+ this.call = this._call.bind(this);
60
+ }
61
+
62
+ /**
63
+ * Call the MCP tool with the specified input arguments. This method sends a request to the MCP server to execute
64
+ * the tool and returns the result as a ToolResponse.
65
+ *
66
+ * @param arguments
67
+ * @param input
68
+ * @returns A ToolResponse object containing the result of the tool execution, or an error message if the call fails.
69
+ */
70
+ async _call(input: Record<string, unknown>) {
71
+ const client = await this.getClient();
72
+ try {
73
+ const request: CallToolRequest = {
74
+ method: 'tools/call',
75
+ params: {
76
+ name: this.name,
77
+ arguments: input,
78
+ },
79
+ };
80
+ const result = await client.request(request, CallToolResultSchema);
81
+
82
+ const content: ToolResponse['content'] = [];
83
+ result.content.forEach(item => {
84
+ if (item.type === 'text') {
85
+ content.push({ type: 'text', text: item.text, id: crypto.randomUUID() });
86
+ } else if (item.type === 'image' || item.type === 'audio') {
87
+ content.push({
88
+ id: crypto.randomUUID(),
89
+ type: 'data',
90
+ source: { type: 'base64', mediaType: item.mimeType, data: item.data },
91
+ });
92
+ } else {
93
+ console.warn(
94
+ `Unsupported content type '${item.type}' in tool result, skipping...`
95
+ );
96
+ }
97
+ });
98
+ return createToolResponse({ content, state: 'success' });
99
+ } catch (error) {
100
+ return createToolResponse({
101
+ content: [
102
+ {
103
+ id: crypto.randomUUID(),
104
+ type: 'text',
105
+ text: `Error calling tool '${this.name}': ${error}`,
106
+ },
107
+ ],
108
+ state: 'error',
109
+ });
110
+ } finally {
111
+ await this.releaseClient(client);
112
+ }
113
+ }
114
+ }
@@ -0,0 +1,303 @@
1
+ import * as http from 'http';
2
+
3
+ import { HTTPMCPClient } from './http';
4
+ import { Toolkit, ToolResponse } from '../tool';
5
+
6
+ /**
7
+ * Creates a minimal MCP HTTP server for testing purposes.
8
+ *
9
+ * @param port - The port number to listen on
10
+ * @returns An HTTP server instance
11
+ */
12
+ function createTestMCPServer(port: number): http.Server {
13
+ const sessions = new Map<string, Record<string, unknown>>();
14
+ let sessionCounter = 0;
15
+
16
+ const server = http.createServer(async (req, res) => {
17
+ // Handle CORS
18
+ res.setHeader('Access-Control-Allow-Origin', '*');
19
+ res.setHeader('Access-Control-Allow-Methods', 'GET, POST, DELETE, OPTIONS');
20
+ res.setHeader('Access-Control-Allow-Headers', 'Content-Type, Mcp-Session-Id');
21
+
22
+ if (req.method === 'OPTIONS') {
23
+ res.writeHead(200);
24
+ res.end();
25
+ return;
26
+ }
27
+
28
+ let body = '';
29
+ req.on('data', chunk => {
30
+ body += chunk.toString();
31
+ });
32
+
33
+ req.on('end', async () => {
34
+ try {
35
+ const message = JSON.parse(body);
36
+ let response: Record<string, unknown>;
37
+
38
+ switch (message.method) {
39
+ case 'initialize': {
40
+ sessionCounter++;
41
+ const sessionId = `session-${sessionCounter}`;
42
+ sessions.set(sessionId, {});
43
+ response = {
44
+ jsonrpc: '2.0',
45
+ id: message.id,
46
+ result: {
47
+ protocolVersion: '2024-11-05',
48
+ capabilities: { tools: {} },
49
+ serverInfo: {
50
+ name: 'test-mcp-server',
51
+ version: '1.0.0',
52
+ },
53
+ sessionId,
54
+ },
55
+ };
56
+ break;
57
+ }
58
+
59
+ case 'tools/list': {
60
+ response = {
61
+ jsonrpc: '2.0',
62
+ id: message.id,
63
+ result: {
64
+ tools: [
65
+ {
66
+ name: 'add',
67
+ description: 'Adds two numbers together',
68
+ inputSchema: {
69
+ type: 'object',
70
+ properties: {
71
+ a: {
72
+ type: 'number',
73
+ description: 'First number',
74
+ },
75
+ b: {
76
+ type: 'number',
77
+ description: 'Second number',
78
+ },
79
+ },
80
+ required: ['a', 'b'],
81
+ },
82
+ },
83
+ ],
84
+ },
85
+ };
86
+ break;
87
+ }
88
+
89
+ case 'tools/call': {
90
+ if (message.params.name === 'add') {
91
+ const { a, b } = message.params.arguments;
92
+ const result = a + b;
93
+ response = {
94
+ jsonrpc: '2.0',
95
+ id: message.id,
96
+ result: {
97
+ content: [
98
+ {
99
+ type: 'text',
100
+ text: `Result: ${a} + ${b} = ${result}`,
101
+ },
102
+ ],
103
+ },
104
+ };
105
+ } else {
106
+ response = {
107
+ jsonrpc: '2.0',
108
+ id: message.id,
109
+ error: {
110
+ code: -32601,
111
+ message: 'Tool not found',
112
+ },
113
+ };
114
+ }
115
+ break;
116
+ }
117
+
118
+ default: {
119
+ response = {
120
+ jsonrpc: '2.0',
121
+ id: message.id,
122
+ error: {
123
+ code: -32601,
124
+ message: 'Method not found',
125
+ },
126
+ };
127
+ }
128
+ }
129
+
130
+ res.writeHead(200, { 'Content-Type': 'application/json' });
131
+ res.end(JSON.stringify(response));
132
+ } catch {
133
+ res.writeHead(400, { 'Content-Type': 'application/json' });
134
+ res.end(
135
+ JSON.stringify({
136
+ jsonrpc: '2.0',
137
+ id: null,
138
+ error: {
139
+ code: -32700,
140
+ message: 'Parse error',
141
+ },
142
+ })
143
+ );
144
+ }
145
+ });
146
+ });
147
+
148
+ server.listen(port);
149
+ return server;
150
+ }
151
+
152
+ describe('HTTPStatefulMCPClient', () => {
153
+ const TEST_PORT = 13579;
154
+ const TEST_URL = `http://localhost:${TEST_PORT}/mcp`;
155
+ let testServer: http.Server;
156
+
157
+ beforeAll(() => {
158
+ testServer = createTestMCPServer(TEST_PORT);
159
+ });
160
+
161
+ afterAll(done => {
162
+ testServer.close(done);
163
+ });
164
+
165
+ test('Create HTTP MCP client, list and execute tools', async () => {
166
+ const client = new HTTPMCPClient({
167
+ name: 'test-mcp-server',
168
+ transportType: 'streamable-http',
169
+ url: TEST_URL,
170
+ stateful: true,
171
+ });
172
+ await client.connect();
173
+
174
+ const tools = await client.listTools();
175
+ expect(tools.length).toBeGreaterThan(0);
176
+
177
+ const func = await client.getCallableFunction({ name: 'add' });
178
+ const res = await func.call({ a: 5, b: 3 });
179
+ expect(res.content.length).toBeGreaterThan(0);
180
+ expect(res.content[0].type).toBe('text');
181
+ if (res.content[0].type === 'text') {
182
+ expect(res.content[0].text).toContain('8');
183
+ }
184
+
185
+ await client.close();
186
+
187
+ // Try to reconnect and list tools again
188
+ await client.connect();
189
+ const tools2 = await client.listTools();
190
+ expect(tools2.length).toBeGreaterThan(0);
191
+
192
+ await client.close();
193
+ }, 10000);
194
+
195
+ test('Test toolkit works with HTTPStatefulMCPClient', async () => {
196
+ const client = new HTTPMCPClient({
197
+ name: 'test-mcp-server',
198
+ transportType: 'streamable-http',
199
+ url: TEST_URL,
200
+ stateful: true,
201
+ });
202
+ await client.connect();
203
+
204
+ const toolkit = new Toolkit();
205
+ await toolkit.registerMCPClient({ client, enabledTools: ['add'] });
206
+
207
+ const schema = toolkit.getJSONSchemas();
208
+ expect(schema.length).toBe(2);
209
+ expect(schema[1].type).toBe('function');
210
+ expect(schema[1].function.name).toBe('add');
211
+ expect(schema[1].function.parameters).toBeDefined();
212
+
213
+ const res = toolkit.callToolFunction({
214
+ id: '123',
215
+ name: 'add',
216
+ type: 'tool_call',
217
+ input: `{"a": 10, "b": 20}`,
218
+ });
219
+ for await (const item of res) {
220
+ expect(item.content.length).toBeGreaterThan(0);
221
+ expect(item.content[0].type).toBe('text');
222
+ if (item.content[0].type === 'text') {
223
+ expect(item.content[0].text).toContain('30');
224
+ }
225
+ }
226
+
227
+ await client.close();
228
+ }, 10000);
229
+ });
230
+
231
+ describe('HTTPStatelessMCPClient', () => {
232
+ const TEST_PORT = 13580;
233
+ const TEST_URL = `http://localhost:${TEST_PORT}/mcp`;
234
+ let testServer: http.Server;
235
+
236
+ beforeAll(() => {
237
+ testServer = createTestMCPServer(TEST_PORT);
238
+ });
239
+
240
+ afterAll(done => {
241
+ testServer.close(done);
242
+ });
243
+
244
+ test('Create stateless HTTP MCP client, list and execute tools without explicit connect/close', async () => {
245
+ const client = new HTTPMCPClient({
246
+ name: 'test-mcp-server',
247
+ transportType: 'streamable-http',
248
+ url: TEST_URL,
249
+ stateful: false,
250
+ });
251
+
252
+ // connect() and close() are no-ops for stateless clients
253
+ await client.connect();
254
+
255
+ const tools = await client.listTools();
256
+ expect(tools.length).toBeGreaterThan(0);
257
+
258
+ const func = await client.getCallableFunction({ name: 'add' });
259
+ const res = await func.call({ a: 7, b: 13 });
260
+ expect(res.content.length).toBeGreaterThan(0);
261
+ expect(res.content[0].type).toBe('text');
262
+ if (res.content[0].type === 'text') {
263
+ expect(res.content[0].text).toContain('20');
264
+ }
265
+
266
+ await client.close();
267
+ }, 10000);
268
+
269
+ test('Test toolkit works with HTTPStatelessMCPClient', async () => {
270
+ const client = new HTTPMCPClient({
271
+ name: 'test-mcp-server',
272
+ transportType: 'streamable-http',
273
+ url: TEST_URL,
274
+ stateful: false,
275
+ });
276
+
277
+ const toolkit = new Toolkit();
278
+ await toolkit.registerMCPClient({ client, enabledTools: ['add'] });
279
+
280
+ const schema = toolkit.getJSONSchemas();
281
+ expect(schema.length).toBe(2);
282
+ expect(schema[1].type).toBe('function');
283
+ expect(schema[1].function.name).toBe('add');
284
+ expect(schema[1].function.parameters).toBeDefined();
285
+
286
+ const res = toolkit.callToolFunction({
287
+ id: '123',
288
+ name: 'add',
289
+ type: 'tool_call',
290
+ input: `{"a": 15, "b": 25}`,
291
+ });
292
+ const collectedRes: ToolResponse[] = [];
293
+ for await (const item of res) {
294
+ collectedRes.push(item);
295
+ expect(item.content.length).toBeGreaterThan(0);
296
+ expect(item.content[0].type).toBe('text');
297
+ if (item.content[0].type === 'text') {
298
+ expect(item.content[0].text).toContain('40');
299
+ }
300
+ }
301
+ expect(collectedRes.length).toBe(1);
302
+ }, 10000);
303
+ });
@@ -0,0 +1,224 @@
1
+ import { Client } from '@modelcontextprotocol/sdk/client/index.js';
2
+ import {
3
+ SSEClientTransport,
4
+ SSEClientTransportOptions,
5
+ } from '@modelcontextprotocol/sdk/client/sse.js';
6
+ import { StreamableHTTPClientTransport } from '@modelcontextprotocol/sdk/client/streamableHttp.js';
7
+ import { StreamableHTTPClientTransportOptions } from '@modelcontextprotocol/sdk/client/streamableHttp.js';
8
+ import type { RequestOptions } from '@modelcontextprotocol/sdk/shared/protocol.js';
9
+ import { ListToolsRequest, ListToolsResultSchema, Tool } from '@modelcontextprotocol/sdk/types.js';
10
+
11
+ import { MCPTool } from './base';
12
+
13
+ /**
14
+ * The HTTP MCP client class that connects to an MCP server using either Streamable HTTP or Server-Sent Events (SSE)
15
+ * transport.
16
+ * Note the client is stateful, meaning that developers should manually call the `connect()` and `close()` methods to
17
+ * manage the connection lifecycle.
18
+ */
19
+ export class HTTPMCPClient {
20
+ name: string;
21
+ private requestOptions?: RequestOptions;
22
+ private client?: Client;
23
+ private transport?: StreamableHTTPClientTransport | SSEClientTransport;
24
+ private transportType: 'streamable-http' | 'sse';
25
+ private url: string;
26
+ private transportOpts?: StreamableHTTPClientTransportOptions | SSEClientTransportOptions;
27
+ private stateful: boolean;
28
+
29
+ /**
30
+ * Initialize the HTTPStatefulMCPClient with the specified transport type, URL, and options.
31
+ *
32
+ * @param root0
33
+ * @param root0.name
34
+ * @param root0.transportType
35
+ * @param root0.url
36
+ * @param root0.stateful
37
+ * @param root0.transportOpts
38
+ * @param root0.requestOptions
39
+ */
40
+ constructor({
41
+ name,
42
+ transportType,
43
+ url,
44
+ stateful = true,
45
+ transportOpts,
46
+ requestOptions,
47
+ }: {
48
+ name: string;
49
+ transportType: 'streamable-http' | 'sse';
50
+ url: string;
51
+ stateful?: boolean;
52
+ transportOpts?: StreamableHTTPClientTransportOptions | SSEClientTransportOptions;
53
+ requestOptions?: RequestOptions;
54
+ }) {
55
+ this.name = name;
56
+ this.transportType = transportType;
57
+ this.transportOpts = transportOpts;
58
+ this.requestOptions = requestOptions;
59
+ this.url = url;
60
+ this.stateful = stateful;
61
+ }
62
+
63
+ /**
64
+ * Connect to the MCP server with the specified transport and URL. This method must be called before making any
65
+ * requests to the server.
66
+ */
67
+ async connect() {
68
+ if (!this.stateful) {
69
+ console.log(
70
+ `MCP client '${this.name}' initialized with stateful=false will connect and close the connection automatically for each request, no need to call 'connect()' method explicitly.`
71
+ );
72
+ } else {
73
+ await this._connect();
74
+ }
75
+ }
76
+
77
+ /**
78
+ * The internal method to establish the connection to the MCP server. It initializes the appropriate transport
79
+ * based on the specified transport type and creates a new Client instance to manage the connection and requests.
80
+ */
81
+ protected async _connect() {
82
+ const baseUrl = new URL(this.url);
83
+ if (this.transportType === 'streamable-http') {
84
+ this.transport = new StreamableHTTPClientTransport(baseUrl, this.transportOpts);
85
+ } else {
86
+ this.transport = new SSEClientTransport(baseUrl, this.transportOpts);
87
+ }
88
+ this.client = new Client({
89
+ name: this.name,
90
+ version: '1.0.0',
91
+ });
92
+ await this.client.connect(this.transport, this.requestOptions);
93
+ console.log(`MCP client '${this.name}' is connected`);
94
+ }
95
+
96
+ /**
97
+ * List all tools available on the MCP server.
98
+ *
99
+ * @returns An array of MCPTool instances representing the tools available on the server.
100
+ */
101
+ async listTools(): Promise<MCPTool[]> {
102
+ let listClient: Client;
103
+
104
+ if (this.stateful) {
105
+ if (!this.client) {
106
+ throw new Error(
107
+ `Client not initialized, call 'connect()' method first for the MCP client named '${this.name}'`
108
+ );
109
+ }
110
+ listClient = this.client;
111
+ } else {
112
+ listClient = await this._createClient();
113
+ }
114
+
115
+ try {
116
+ const toolsRequest: ListToolsRequest = {
117
+ method: 'tools/list',
118
+ params: {},
119
+ };
120
+
121
+ const toolsResult = await listClient.request(toolsRequest, ListToolsResultSchema);
122
+ if (toolsResult.tools === undefined) {
123
+ return [];
124
+ }
125
+
126
+ return toolsResult.tools.map((tool: Tool) => {
127
+ if (this.stateful) {
128
+ return new MCPTool({
129
+ name: tool.name,
130
+ description: tool.description || '',
131
+ inputSchema: tool.inputSchema,
132
+ getClient: async () => this.client!,
133
+ releaseClient: async () => {},
134
+ });
135
+ } else {
136
+ return new MCPTool({
137
+ name: tool.name,
138
+ description: tool.description || '',
139
+ inputSchema: tool.inputSchema,
140
+ getClient: () => this._createClient(),
141
+ releaseClient: async (c: Client) => {
142
+ await c.close();
143
+ },
144
+ });
145
+ }
146
+ });
147
+ } finally {
148
+ if (!this.stateful) {
149
+ await listClient.close();
150
+ }
151
+ }
152
+ }
153
+
154
+ /**
155
+ * Close the connection to the MCP server and clean up any resources used by the client.
156
+ */
157
+ async close() {
158
+ if (!this.stateful) {
159
+ console.log(
160
+ `MCP client '${this.name}' initialized with stateful=false will connect and close the connection automatically for each request, no need to call 'close()' method explicitly.`
161
+ );
162
+ } else {
163
+ await this._close();
164
+ }
165
+ }
166
+
167
+ /**
168
+ * The internal method to close the connection to the MCP server.
169
+ */
170
+ protected async _close() {
171
+ try {
172
+ await this.client?.close();
173
+ } finally {
174
+ console.log(`MCP client '${this.name} is closed.'`);
175
+ this.client = undefined;
176
+ this.transport = undefined;
177
+ }
178
+ }
179
+
180
+ /**
181
+ * Create a new client instance without storing it in this.client.
182
+ * Used for stateless operations where each request needs its own client.
183
+ * @returns A new connected Client instance
184
+ */
185
+ protected async _createClient(): Promise<Client> {
186
+ const baseUrl = new URL(this.url);
187
+ const transport =
188
+ this.transportType === 'streamable-http'
189
+ ? new StreamableHTTPClientTransport(baseUrl, this.transportOpts)
190
+ : new SSEClientTransport(baseUrl, this.transportOpts);
191
+
192
+ const client = new Client({
193
+ name: this.name,
194
+ version: '1.0.0',
195
+ });
196
+ await client.connect(transport, this.requestOptions);
197
+ return client;
198
+ }
199
+
200
+ /**
201
+ * Get a callable function for a specific tool by its name.
202
+ * @param root0
203
+ * @param root0.name
204
+ * @returns An instance of MCPTool that can be called to execute the tool's functionality.
205
+ */
206
+ async getCallableFunction({ name }: { name: string }) {
207
+ if (this.stateful && !this.client) {
208
+ throw new Error(
209
+ `Client not initialized, call 'connect()' method first for the MCP client named '${this.name}'`
210
+ );
211
+ }
212
+
213
+ const tools = await this.listTools();
214
+ const targetTool = tools.find(tool => tool.name === name);
215
+
216
+ if (!targetTool) {
217
+ throw new Error(
218
+ `Tool '${name}' not found in MCP server '${this.name}'. Available tools: ${tools.map(t => t.name).join(', ')}`
219
+ );
220
+ }
221
+
222
+ return targetTool;
223
+ }
224
+ }
@@ -0,0 +1,2 @@
1
+ export * from './http';
2
+ export * from './stdio';