wave-agent-sdk 0.0.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 (170) hide show
  1. package/README.md +32 -0
  2. package/dist/agent.d.ts +96 -0
  3. package/dist/agent.d.ts.map +1 -0
  4. package/dist/agent.js +286 -0
  5. package/dist/hooks/executor.d.ts +56 -0
  6. package/dist/hooks/executor.d.ts.map +1 -0
  7. package/dist/hooks/executor.js +312 -0
  8. package/dist/hooks/index.d.ts +17 -0
  9. package/dist/hooks/index.d.ts.map +1 -0
  10. package/dist/hooks/index.js +14 -0
  11. package/dist/hooks/manager.d.ts +90 -0
  12. package/dist/hooks/manager.d.ts.map +1 -0
  13. package/dist/hooks/manager.js +395 -0
  14. package/dist/hooks/matcher.d.ts +49 -0
  15. package/dist/hooks/matcher.d.ts.map +1 -0
  16. package/dist/hooks/matcher.js +147 -0
  17. package/dist/hooks/settings.d.ts +46 -0
  18. package/dist/hooks/settings.d.ts.map +1 -0
  19. package/dist/hooks/settings.js +100 -0
  20. package/dist/hooks/types.d.ts +80 -0
  21. package/dist/hooks/types.d.ts.map +1 -0
  22. package/dist/hooks/types.js +59 -0
  23. package/dist/index.d.ts +16 -0
  24. package/dist/index.d.ts.map +1 -0
  25. package/dist/index.js +20 -0
  26. package/dist/managers/aiManager.d.ts +61 -0
  27. package/dist/managers/aiManager.d.ts.map +1 -0
  28. package/dist/managers/aiManager.js +415 -0
  29. package/dist/managers/backgroundBashManager.d.ts +27 -0
  30. package/dist/managers/backgroundBashManager.d.ts.map +1 -0
  31. package/dist/managers/backgroundBashManager.js +166 -0
  32. package/dist/managers/bashManager.d.ts +20 -0
  33. package/dist/managers/bashManager.d.ts.map +1 -0
  34. package/dist/managers/bashManager.js +66 -0
  35. package/dist/managers/mcpManager.d.ts +63 -0
  36. package/dist/managers/mcpManager.d.ts.map +1 -0
  37. package/dist/managers/mcpManager.js +378 -0
  38. package/dist/managers/messageManager.d.ts +85 -0
  39. package/dist/managers/messageManager.d.ts.map +1 -0
  40. package/dist/managers/messageManager.js +265 -0
  41. package/dist/managers/skillManager.d.ts +59 -0
  42. package/dist/managers/skillManager.d.ts.map +1 -0
  43. package/dist/managers/skillManager.js +317 -0
  44. package/dist/managers/slashCommandManager.d.ts +77 -0
  45. package/dist/managers/slashCommandManager.d.ts.map +1 -0
  46. package/dist/managers/slashCommandManager.js +208 -0
  47. package/dist/managers/toolManager.d.ts +23 -0
  48. package/dist/managers/toolManager.d.ts.map +1 -0
  49. package/dist/managers/toolManager.js +79 -0
  50. package/dist/services/aiService.d.ts +28 -0
  51. package/dist/services/aiService.d.ts.map +1 -0
  52. package/dist/services/aiService.js +180 -0
  53. package/dist/services/memory.d.ts +8 -0
  54. package/dist/services/memory.d.ts.map +1 -0
  55. package/dist/services/memory.js +128 -0
  56. package/dist/services/session.d.ts +54 -0
  57. package/dist/services/session.d.ts.map +1 -0
  58. package/dist/services/session.js +196 -0
  59. package/dist/tools/bashTool.d.ts +14 -0
  60. package/dist/tools/bashTool.d.ts.map +1 -0
  61. package/dist/tools/bashTool.js +351 -0
  62. package/dist/tools/deleteFileTool.d.ts +6 -0
  63. package/dist/tools/deleteFileTool.d.ts.map +1 -0
  64. package/dist/tools/deleteFileTool.js +67 -0
  65. package/dist/tools/editTool.d.ts +6 -0
  66. package/dist/tools/editTool.d.ts.map +1 -0
  67. package/dist/tools/editTool.js +168 -0
  68. package/dist/tools/globTool.d.ts +6 -0
  69. package/dist/tools/globTool.d.ts.map +1 -0
  70. package/dist/tools/globTool.js +113 -0
  71. package/dist/tools/grepTool.d.ts +6 -0
  72. package/dist/tools/grepTool.d.ts.map +1 -0
  73. package/dist/tools/grepTool.js +268 -0
  74. package/dist/tools/lsTool.d.ts +6 -0
  75. package/dist/tools/lsTool.d.ts.map +1 -0
  76. package/dist/tools/lsTool.js +160 -0
  77. package/dist/tools/multiEditTool.d.ts +6 -0
  78. package/dist/tools/multiEditTool.d.ts.map +1 -0
  79. package/dist/tools/multiEditTool.js +222 -0
  80. package/dist/tools/readTool.d.ts +6 -0
  81. package/dist/tools/readTool.d.ts.map +1 -0
  82. package/dist/tools/readTool.js +136 -0
  83. package/dist/tools/types.d.ts +35 -0
  84. package/dist/tools/types.d.ts.map +1 -0
  85. package/dist/tools/types.js +4 -0
  86. package/dist/tools/writeTool.d.ts +6 -0
  87. package/dist/tools/writeTool.d.ts.map +1 -0
  88. package/dist/tools/writeTool.js +138 -0
  89. package/dist/types.d.ts +212 -0
  90. package/dist/types.d.ts.map +1 -0
  91. package/dist/types.js +13 -0
  92. package/dist/utils/bashHistory.d.ts +46 -0
  93. package/dist/utils/bashHistory.d.ts.map +1 -0
  94. package/dist/utils/bashHistory.js +236 -0
  95. package/dist/utils/commandArgumentParser.d.ts +34 -0
  96. package/dist/utils/commandArgumentParser.d.ts.map +1 -0
  97. package/dist/utils/commandArgumentParser.js +123 -0
  98. package/dist/utils/constants.d.ts +27 -0
  99. package/dist/utils/constants.d.ts.map +1 -0
  100. package/dist/utils/constants.js +28 -0
  101. package/dist/utils/convertMessagesForAPI.d.ts +9 -0
  102. package/dist/utils/convertMessagesForAPI.d.ts.map +1 -0
  103. package/dist/utils/convertMessagesForAPI.js +189 -0
  104. package/dist/utils/customCommands.d.ts +14 -0
  105. package/dist/utils/customCommands.d.ts.map +1 -0
  106. package/dist/utils/customCommands.js +71 -0
  107. package/dist/utils/fileFilter.d.ts +26 -0
  108. package/dist/utils/fileFilter.d.ts.map +1 -0
  109. package/dist/utils/fileFilter.js +177 -0
  110. package/dist/utils/markdownParser.d.ts +27 -0
  111. package/dist/utils/markdownParser.d.ts.map +1 -0
  112. package/dist/utils/markdownParser.js +109 -0
  113. package/dist/utils/mcpUtils.d.ts +24 -0
  114. package/dist/utils/mcpUtils.d.ts.map +1 -0
  115. package/dist/utils/mcpUtils.js +51 -0
  116. package/dist/utils/messageOperations.d.ts +118 -0
  117. package/dist/utils/messageOperations.d.ts.map +1 -0
  118. package/dist/utils/messageOperations.js +334 -0
  119. package/dist/utils/path.d.ts +25 -0
  120. package/dist/utils/path.d.ts.map +1 -0
  121. package/dist/utils/path.js +109 -0
  122. package/dist/utils/skillParser.d.ts +18 -0
  123. package/dist/utils/skillParser.d.ts.map +1 -0
  124. package/dist/utils/skillParser.js +147 -0
  125. package/dist/utils/stringUtils.d.ts +13 -0
  126. package/dist/utils/stringUtils.d.ts.map +1 -0
  127. package/dist/utils/stringUtils.js +44 -0
  128. package/package.json +51 -0
  129. package/src/agent.ts +405 -0
  130. package/src/hooks/executor.ts +440 -0
  131. package/src/hooks/index.ts +52 -0
  132. package/src/hooks/manager.ts +618 -0
  133. package/src/hooks/matcher.ts +187 -0
  134. package/src/hooks/settings.ts +129 -0
  135. package/src/hooks/types.ts +169 -0
  136. package/src/index.ts +24 -0
  137. package/src/managers/aiManager.ts +573 -0
  138. package/src/managers/backgroundBashManager.ts +203 -0
  139. package/src/managers/bashManager.ts +97 -0
  140. package/src/managers/mcpManager.ts +493 -0
  141. package/src/managers/messageManager.ts +415 -0
  142. package/src/managers/skillManager.ts +404 -0
  143. package/src/managers/slashCommandManager.ts +293 -0
  144. package/src/managers/toolManager.ts +106 -0
  145. package/src/services/aiService.ts +252 -0
  146. package/src/services/memory.ts +149 -0
  147. package/src/services/session.ts +265 -0
  148. package/src/tools/bashTool.ts +402 -0
  149. package/src/tools/deleteFileTool.ts +81 -0
  150. package/src/tools/editTool.ts +192 -0
  151. package/src/tools/globTool.ts +135 -0
  152. package/src/tools/grepTool.ts +326 -0
  153. package/src/tools/lsTool.ts +187 -0
  154. package/src/tools/multiEditTool.ts +268 -0
  155. package/src/tools/readTool.ts +165 -0
  156. package/src/tools/types.ts +47 -0
  157. package/src/tools/writeTool.ts +163 -0
  158. package/src/types.ts +260 -0
  159. package/src/utils/bashHistory.ts +303 -0
  160. package/src/utils/commandArgumentParser.ts +153 -0
  161. package/src/utils/constants.ts +37 -0
  162. package/src/utils/convertMessagesForAPI.ts +236 -0
  163. package/src/utils/customCommands.ts +85 -0
  164. package/src/utils/fileFilter.ts +202 -0
  165. package/src/utils/markdownParser.ts +156 -0
  166. package/src/utils/mcpUtils.ts +81 -0
  167. package/src/utils/messageOperations.ts +506 -0
  168. package/src/utils/path.ts +118 -0
  169. package/src/utils/skillParser.ts +188 -0
  170. package/src/utils/stringUtils.ts +50 -0
@@ -0,0 +1,493 @@
1
+ import { promises as fs } from "fs";
2
+ import { join } from "path";
3
+ import { Client } from "@modelcontextprotocol/sdk/client/index.js";
4
+ import { StdioClientTransport } from "@modelcontextprotocol/sdk/client/stdio.js";
5
+ import { ChatCompletionFunctionTool } from "openai/resources.js";
6
+ import { createMcpToolPlugin, findToolServer } from "@/utils/mcpUtils.js";
7
+ import type { ToolPlugin, ToolResult, ToolContext } from "../tools/types.js";
8
+ import type {
9
+ Logger,
10
+ McpServerConfig,
11
+ McpConfig,
12
+ McpTool,
13
+ McpServerStatus,
14
+ } from "../types.js";
15
+
16
+ interface McpConnection {
17
+ client: Client;
18
+ transport: StdioClientTransport;
19
+ process: null; // StdioClientTransport manages process internally
20
+ }
21
+
22
+ export interface McpManagerCallbacks {
23
+ onServersChange?: (servers: McpServerStatus[]) => void;
24
+ }
25
+
26
+ export interface McpManagerOptions {
27
+ callbacks?: McpManagerCallbacks;
28
+ logger?: Logger;
29
+ }
30
+
31
+ export class McpManager {
32
+ private config: McpConfig | null = null;
33
+ private servers: Map<string, McpServerStatus> = new Map();
34
+ private connections: Map<string, McpConnection> = new Map();
35
+ private configPath: string = "";
36
+ private workdir: string = "";
37
+ private callbacks: McpManagerCallbacks;
38
+ private logger?: Logger;
39
+
40
+ constructor(options: McpManagerOptions = {}) {
41
+ this.callbacks = options.callbacks || {};
42
+ this.logger = options.logger;
43
+ }
44
+
45
+ /**
46
+ * Initialize MCP manager with working directory and optionally auto-connect
47
+ */
48
+ async initialize(
49
+ workdir: string,
50
+ autoConnect: boolean = false,
51
+ ): Promise<void> {
52
+ this.configPath = join(workdir, ".mcp.json");
53
+ this.workdir = workdir;
54
+
55
+ if (autoConnect) {
56
+ this.logger?.info("Initializing MCP servers...");
57
+
58
+ // Ensure MCP configuration is loaded
59
+ const config = await this.ensureConfigLoaded();
60
+
61
+ if (config && config.mcpServers) {
62
+ // Connect to all configured servers
63
+ const connectionPromises = Object.keys(config.mcpServers).map(
64
+ async (serverName) => {
65
+ try {
66
+ this.logger?.info(`Connecting to MCP server: ${serverName}`);
67
+ const success = await this.connectServer(serverName);
68
+ if (success) {
69
+ this.logger?.info(
70
+ `Successfully connected to MCP server: ${serverName}`,
71
+ );
72
+ } else {
73
+ this.logger?.warn(
74
+ `Failed to connect to MCP server: ${serverName}`,
75
+ );
76
+ }
77
+ } catch {
78
+ this.logger?.error(
79
+ `Error connecting to MCP server ${serverName}`,
80
+ );
81
+ }
82
+ },
83
+ );
84
+
85
+ // Wait for all connection attempts to complete
86
+ await Promise.all(connectionPromises);
87
+ }
88
+
89
+ this.logger?.info("MCP servers initialization completed");
90
+ // Trigger state change callback after initialization
91
+ this.callbacks.onServersChange?.(this.getAllServers());
92
+ }
93
+ }
94
+
95
+ async ensureConfigLoaded(): Promise<McpConfig | null> {
96
+ if (!this.config) {
97
+ return this.loadConfig();
98
+ }
99
+ return this.config;
100
+ }
101
+
102
+ async loadConfig(): Promise<McpConfig | null> {
103
+ if (!this.configPath) {
104
+ this.logger?.warn("MCP config path not set. Call initialize() first.");
105
+ return null;
106
+ }
107
+
108
+ try {
109
+ const configContent = await fs.readFile(this.configPath, "utf-8");
110
+ this.config = JSON.parse(configContent);
111
+
112
+ // Initialize server statuses (preserve existing status for already known servers)
113
+ if (this.config) {
114
+ for (const [name, config] of Object.entries(this.config.mcpServers)) {
115
+ const existingServer = this.servers.get(name);
116
+
117
+ if (existingServer) {
118
+ // Update config but preserve status and other runtime info
119
+ this.servers.set(name, {
120
+ ...existingServer,
121
+ config, // Update config in case it changed
122
+ });
123
+ } else {
124
+ // New server, initialize with disconnected status
125
+ this.servers.set(name, {
126
+ name,
127
+ config,
128
+ status: "disconnected",
129
+ });
130
+ }
131
+ }
132
+ }
133
+
134
+ return this.config;
135
+ } catch (error) {
136
+ // Only log error if it's not a "file not found" error
137
+ if ((error as NodeJS.ErrnoException).code !== "ENOENT") {
138
+ this.logger?.error("Failed to load .mcp.json:", error);
139
+ }
140
+ return null;
141
+ }
142
+ }
143
+
144
+ async saveConfig(config: McpConfig): Promise<boolean> {
145
+ try {
146
+ await fs.writeFile(this.configPath, JSON.stringify(config, null, 2));
147
+ this.config = config;
148
+ return true;
149
+ } catch (error) {
150
+ this.logger?.error("Failed to save .mcp.json:", error);
151
+ return false;
152
+ }
153
+ }
154
+
155
+ getConfig(): McpConfig | null {
156
+ return this.config;
157
+ }
158
+
159
+ getAllServers(): McpServerStatus[] {
160
+ return Array.from(this.servers.values());
161
+ }
162
+
163
+ getServer(name: string): McpServerStatus | undefined {
164
+ return this.servers.get(name);
165
+ }
166
+
167
+ updateServerStatus(name: string, updates: Partial<McpServerStatus>): void {
168
+ const server = this.servers.get(name);
169
+ if (server) {
170
+ this.servers.set(name, { ...server, ...updates });
171
+ // Trigger state change callback
172
+ this.callbacks.onServersChange?.(this.getAllServers());
173
+ }
174
+ }
175
+
176
+ addServer(name: string, config: McpServerConfig): boolean {
177
+ if (this.servers.has(name)) {
178
+ return false;
179
+ }
180
+
181
+ const newServer: McpServerStatus = {
182
+ name,
183
+ config,
184
+ status: "disconnected",
185
+ };
186
+
187
+ this.servers.set(name, newServer);
188
+
189
+ // Update config
190
+ if (this.config) {
191
+ this.config.mcpServers[name] = config;
192
+ } else {
193
+ this.config = {
194
+ mcpServers: { [name]: config },
195
+ };
196
+ }
197
+
198
+ return true;
199
+ }
200
+
201
+ removeServer(name: string): boolean {
202
+ // Disconnect if connected
203
+ if (this.connections.has(name)) {
204
+ this.disconnectServer(name);
205
+ }
206
+
207
+ const removed = this.servers.delete(name);
208
+
209
+ if (removed && this.config) {
210
+ delete this.config.mcpServers[name];
211
+ }
212
+
213
+ return removed;
214
+ }
215
+
216
+ // Real MCP connection implementation
217
+ async connectServer(name: string): Promise<boolean> {
218
+ const server = this.servers.get(name);
219
+ if (!server) return false;
220
+
221
+ // Already connected
222
+ if (this.connections.has(name)) return true;
223
+
224
+ this.updateServerStatus(name, { status: "connecting" });
225
+
226
+ try {
227
+ // Create transport - it will manage the process
228
+ const transport = new StdioClientTransport({
229
+ command: server.config.command,
230
+ args: server.config.args || [],
231
+ env: server.config.env || {},
232
+ cwd: this.workdir, // Use the agent's workdir as the process working directory
233
+ });
234
+
235
+ // Create client
236
+ const client = new Client(
237
+ {
238
+ name: "wave-code",
239
+ version: "1.0.0",
240
+ },
241
+ {
242
+ capabilities: {
243
+ tools: {},
244
+ },
245
+ },
246
+ );
247
+
248
+ // Handle transport errors
249
+ transport.onerror = (error: Error) => {
250
+ this.logger?.error(`MCP Server ${name} transport error:`, error);
251
+ this.updateServerStatus(name, {
252
+ status: "error",
253
+ error: error.message,
254
+ });
255
+ };
256
+
257
+ transport.onclose = () => {
258
+ this.logger?.info(`MCP Server ${name} transport closed`);
259
+ this.connections.delete(name);
260
+ this.updateServerStatus(name, {
261
+ status: "disconnected",
262
+ tools: [],
263
+ toolCount: 0,
264
+ });
265
+ };
266
+
267
+ // Connect to transport
268
+ await client.connect(transport);
269
+
270
+ // List available tools
271
+ const toolsResponse = await client.listTools();
272
+
273
+ const tools: McpTool[] =
274
+ toolsResponse.tools?.map((tool) => ({
275
+ name: tool.name,
276
+ description: tool.description,
277
+ inputSchema: tool.inputSchema,
278
+ })) || [];
279
+
280
+ // Store connection (we don't have direct process access with StdioClientTransport)
281
+ this.connections.set(name, {
282
+ client,
283
+ transport,
284
+ process: null, // StdioClientTransport manages the process internally
285
+ });
286
+
287
+ // Update status
288
+ this.updateServerStatus(name, {
289
+ status: "connected",
290
+ tools,
291
+ toolCount: tools.length,
292
+ capabilities: ["tools"],
293
+ lastConnected: Date.now(),
294
+ error: undefined,
295
+ });
296
+
297
+ return true;
298
+ } catch (error) {
299
+ this.logger?.error(`Failed to connect to MCP server ${name}:`, error);
300
+ // updateServerStatus will trigger the callback
301
+ this.updateServerStatus(name, {
302
+ status: "error",
303
+ error: error instanceof Error ? error.message : String(error),
304
+ });
305
+ return false;
306
+ }
307
+ }
308
+
309
+ async disconnectServer(name: string): Promise<boolean> {
310
+ const connection = this.connections.get(name);
311
+ if (!connection) return false;
312
+
313
+ try {
314
+ // Close client connection and transport
315
+ await connection.client.close();
316
+ await connection.transport.close();
317
+
318
+ // Remove connection
319
+ this.connections.delete(name);
320
+
321
+ // updateServerStatus will trigger the callback
322
+ this.updateServerStatus(name, {
323
+ status: "disconnected",
324
+ tools: [],
325
+ toolCount: 0,
326
+ });
327
+
328
+ return true;
329
+ } catch (error) {
330
+ this.logger?.error(`Error disconnecting from MCP server ${name}:`, error);
331
+ return false;
332
+ }
333
+ }
334
+
335
+ // Get all tools from connected servers
336
+ getAllConnectedTools(): McpTool[] {
337
+ const allTools: McpTool[] = [];
338
+ for (const server of this.servers.values()) {
339
+ if (server.status === "connected" && server.tools) {
340
+ allTools.push(...server.tools);
341
+ }
342
+ }
343
+ return allTools;
344
+ }
345
+
346
+ // Execute MCP tool
347
+ async executeMcpTool(
348
+ toolName: string,
349
+ args: Record<string, unknown>,
350
+ ): Promise<{
351
+ success: boolean;
352
+ content: string;
353
+ serverName?: string;
354
+ images?: Array<{ data: string; mediaType?: string }>;
355
+ }> {
356
+ // Find which server has this tool
357
+ for (const [serverName, server] of this.servers.entries()) {
358
+ if (server.status === "connected" && server.tools) {
359
+ const tool = server.tools.find((t) => t.name === toolName);
360
+ if (tool) {
361
+ const connection = this.connections.get(serverName);
362
+ if (connection) {
363
+ try {
364
+ const result = await connection.client.callTool({
365
+ name: toolName,
366
+ arguments: args,
367
+ });
368
+
369
+ // Separate text content and image data
370
+ const textContent: string[] = [];
371
+ const images: Array<{ data: string; mediaType?: string }> = [];
372
+
373
+ if (Array.isArray(result.content)) {
374
+ result.content.forEach(
375
+ (c: {
376
+ type: string;
377
+ text?: string;
378
+ data?: string;
379
+ resource?: { uri: string };
380
+ [key: string]: unknown;
381
+ }) => {
382
+ if (c.type === "text") {
383
+ textContent.push(c.text || "");
384
+ } else if (c.type === "image" && c.data) {
385
+ images.push({
386
+ data: c.data,
387
+ mediaType: "image/png", // Default to PNG, can be adjusted according to actual situation
388
+ });
389
+ } else if (c.type === "resource") {
390
+ textContent.push(`[Resource: ${c.resource?.uri || ""}]`);
391
+ } else {
392
+ textContent.push(JSON.stringify(c));
393
+ }
394
+ },
395
+ );
396
+ } else if (result.content) {
397
+ textContent.push(String(result.content));
398
+ }
399
+
400
+ return {
401
+ success: true,
402
+ content:
403
+ textContent.length > 0
404
+ ? textContent.join("\n")
405
+ : "No content",
406
+ images: images.length > 0 ? images : undefined,
407
+ serverName,
408
+ };
409
+ } catch (error) {
410
+ throw new Error(
411
+ `Tool execution failed: ${error instanceof Error ? error.message : String(error)}`,
412
+ );
413
+ }
414
+ }
415
+ }
416
+ }
417
+ }
418
+
419
+ throw new Error(`Tool ${toolName} not found on any connected MCP server`);
420
+ }
421
+
422
+ // Cleanup all connections
423
+ async cleanup(): Promise<void> {
424
+ const disconnectPromises = Array.from(this.connections.keys()).map((name) =>
425
+ this.disconnectServer(name),
426
+ );
427
+ await Promise.all(disconnectPromises);
428
+ }
429
+
430
+ // ========== Tools Registry Methods ==========
431
+
432
+ /**
433
+ * Get all currently available MCP tools as plugins
434
+ */
435
+ getMcpToolPlugins(): ToolPlugin[] {
436
+ const mcpTools = new Map<string, ToolPlugin>();
437
+
438
+ // Get all connected MCP tools
439
+ const connectedTools = this.getAllConnectedTools();
440
+ const servers = this.getAllServers();
441
+
442
+ // Find server name for each tool and create plugins
443
+ for (const tool of connectedTools) {
444
+ // Find which server this tool belongs to
445
+ const server = findToolServer(tool.name, servers);
446
+
447
+ if (server) {
448
+ const plugin = createMcpToolPlugin(tool, server.name, (name, args) =>
449
+ this.executeMcpTool(name, args),
450
+ );
451
+ mcpTools.set(tool.name, plugin);
452
+ }
453
+ }
454
+
455
+ return Array.from(mcpTools.values());
456
+ }
457
+
458
+ /**
459
+ * Get all currently available MCP tools as OpenAI function tools
460
+ */
461
+ getMcpToolsConfig(): ChatCompletionFunctionTool[] {
462
+ return this.getMcpToolPlugins().map((tool) => tool.config);
463
+ }
464
+
465
+ /**
466
+ * Execute an MCP tool by name (registry version)
467
+ */
468
+ async executeMcpToolByRegistry(
469
+ name: string,
470
+ args: Record<string, unknown>,
471
+ context: ToolContext,
472
+ ): Promise<ToolResult> {
473
+ const plugins = this.getMcpToolPlugins();
474
+ const tool = plugins.find((plugin) => plugin.name === name);
475
+
476
+ if (!tool) {
477
+ return {
478
+ success: false,
479
+ content: "",
480
+ error: `MCP tool '${name}' not found or server disconnected`,
481
+ };
482
+ }
483
+ return tool.execute(args, context);
484
+ }
485
+
486
+ /**
487
+ * Check if a tool name belongs to an MCP tool
488
+ */
489
+ isMcpTool(name: string): boolean {
490
+ const connectedTools = this.getAllConnectedTools();
491
+ return connectedTools.some((tool) => tool.name === name);
492
+ }
493
+ }