@mcp-use/cli 1.0.0 → 1.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 (54) hide show
  1. package/dist/InputPrompt.d.ts +13 -0
  2. package/dist/InputPrompt.js +188 -0
  3. package/dist/MultilineInput.d.ts +13 -0
  4. package/dist/MultilineInput.js +154 -0
  5. package/dist/MultilineTextInput.d.ts +11 -0
  6. package/dist/MultilineTextInput.js +97 -0
  7. package/dist/PasteAwareInput.d.ts +13 -0
  8. package/dist/PasteAwareInput.js +183 -0
  9. package/dist/SimpleMultilineInput.d.ts +11 -0
  10. package/dist/SimpleMultilineInput.js +125 -0
  11. package/dist/app.d.ts +1 -5
  12. package/dist/app.js +291 -186
  13. package/dist/cli.js +2 -5
  14. package/dist/commands.d.ts +15 -30
  15. package/dist/commands.js +308 -568
  16. package/dist/components/AsciiLogo.d.ts +2 -0
  17. package/dist/components/AsciiLogo.js +7 -0
  18. package/dist/components/Footer.d.ts +5 -0
  19. package/dist/components/Footer.js +19 -0
  20. package/dist/components/InputPrompt.d.ts +13 -0
  21. package/dist/components/InputPrompt.js +188 -0
  22. package/dist/components/Messages.d.ts +21 -0
  23. package/dist/components/Messages.js +80 -0
  24. package/dist/components/ServerStatus.d.ts +7 -0
  25. package/dist/components/ServerStatus.js +36 -0
  26. package/dist/components/Spinner.d.ts +16 -0
  27. package/dist/components/Spinner.js +63 -0
  28. package/dist/components/ToolStatus.d.ts +8 -0
  29. package/dist/components/ToolStatus.js +33 -0
  30. package/dist/components/textInput.d.ts +1 -0
  31. package/dist/components/textInput.js +1 -0
  32. package/dist/logger.d.ts +10 -0
  33. package/dist/logger.js +48 -0
  34. package/dist/mcp-service.d.ts +5 -4
  35. package/dist/mcp-service.js +98 -207
  36. package/dist/services/agent-service.d.ts +56 -0
  37. package/dist/services/agent-service.js +203 -0
  38. package/dist/services/cli-service.d.ts +132 -0
  39. package/dist/services/cli-service.js +591 -0
  40. package/dist/services/index.d.ts +4 -0
  41. package/dist/services/index.js +4 -0
  42. package/dist/services/llm-service.d.ts +174 -0
  43. package/dist/services/llm-service.js +567 -0
  44. package/dist/services/mcp-config-service.d.ts +69 -0
  45. package/dist/services/mcp-config-service.js +426 -0
  46. package/dist/services/mcp-service.d.ts +1 -0
  47. package/dist/services/mcp-service.js +1 -0
  48. package/dist/services/utility-service.d.ts +47 -0
  49. package/dist/services/utility-service.js +208 -0
  50. package/dist/storage.js +4 -4
  51. package/dist/types.d.ts +30 -0
  52. package/dist/types.js +1 -0
  53. package/package.json +22 -8
  54. package/readme.md +68 -39
@@ -1,6 +1,7 @@
1
1
  import { MCPAgent, MCPClient } from 'mcp-use';
2
2
  import { config } from 'dotenv';
3
3
  import { CommandHandler } from './commands.js';
4
+ import { Logger } from './logger.js';
4
5
  // Load environment variables
5
6
  config();
6
7
  export class MCPService {
@@ -30,163 +31,48 @@ export class MCPService {
30
31
  value: null
31
32
  });
32
33
  }
33
- async initialize(config) {
34
- if (this.isInitialized)
34
+ async initialize() {
35
+ if (this.isInitialized) {
35
36
  return;
36
- try {
37
- // Load servers from persistent storage and session
38
- const storedConfig = this.commandHandler.getCurrentStoredConfig();
39
- const storedServers = storedConfig.mcpServers || {};
40
- const sessionServers = this.commandHandler.getSessionServers();
41
- // Default filesystem server
42
- const defaultFilesystemServer = {
43
- "command": "npx",
44
- "args": ["-y", "@modelcontextprotocol/server-filesystem", "/tmp"],
45
- "env": {}
46
- };
47
- // Merge stored servers, session servers with default (session servers override persistent ones)
48
- const servers = {
49
- "filesystem": defaultFilesystemServer,
50
- ...storedServers,
51
- ...sessionServers
52
- };
53
- const defaultConfig = {
54
- "servers": servers
55
- };
56
- const mcpConfig = config || defaultConfig;
57
- // Initialize MCP client with logging
58
- console.log('Initializing MCP client with config:', JSON.stringify(mcpConfig, null, 2));
59
- this.client = MCPClient.fromDict(mcpConfig);
60
- console.log('MCP client created successfully');
61
- // Only initialize agent if we have a configured LLM
62
- if (this.commandHandler.isAnyProviderAvailable() && this.commandHandler.getCurrentConfig()) {
63
- await this.initializeAgent();
64
- }
65
- this.isInitialized = true;
66
- }
67
- catch (error) {
68
- console.error('Failed to initialize MCP service:', error);
69
- throw error;
70
37
  }
38
+ await this.initializeAgent();
39
+ this.isInitialized = true;
71
40
  }
72
41
  async initializeAgent() {
73
- if (!this.client) {
74
- throw new Error('MCP client not initialized');
75
- }
76
- try {
77
- // Create LLM using command handler
78
- console.log('Creating LLM for agent...');
79
- const llm = this.commandHandler.createLLM();
80
- console.log('LLM created successfully');
81
- // Create agent
82
- console.log('Creating MCPAgent...');
83
- this.agent = new MCPAgent({
84
- llm,
85
- client: this.client,
86
- maxSteps: 20,
87
- });
88
- console.log('MCPAgent created successfully');
89
- // Initialize the agent
90
- console.log('Initializing MCP agent with servers...');
91
- await this.agent.initialize();
92
- console.log('MCP agent initialized successfully');
93
- // Wait a bit for servers to start up
94
- console.log('Waiting for servers to start...');
95
- await new Promise(resolve => setTimeout(resolve, 2000));
96
- // Log available tools for debugging
97
- try {
98
- console.log('Checking for available tools...');
99
- const toolsResult = await this.getAvailableTools();
100
- if (toolsResult.tools.length > 0) {
101
- console.log('✅ Available MCP tools:', toolsResult.tools.map((t) => t.name || 'unnamed').join(', '));
102
- }
103
- else {
104
- console.log('❌ No MCP tools found:', toolsResult.error || 'Unknown reason');
105
- // Try to get more info about the client state
106
- console.log('Client details:', this.client);
107
- const clientAny = this.client;
108
- if (clientAny.servers) {
109
- console.log('Client servers:', Object.keys(clientAny.servers));
110
- for (const [name, server] of Object.entries(clientAny.servers)) {
111
- console.log(`Server ${name}:`, server);
112
- }
113
- }
114
- }
115
- }
116
- catch (e) {
117
- console.log('❌ Error checking MCP tools:', e);
118
- }
119
- }
120
- catch (error) {
121
- console.error('❌ Failed to initialize agent:', error);
122
- console.error('Error details:', error);
123
- // Try to get more specific error info
124
- if (error instanceof Error) {
125
- console.error('Error stack:', error.stack);
126
- }
127
- throw error;
128
- }
42
+ const sessionServers = this.commandHandler.getSessionServers();
43
+ const llm = this.commandHandler.createLLM();
44
+ const config = {
45
+ mcpServers: {
46
+ ...sessionServers,
47
+ },
48
+ };
49
+ Logger.info('Initializing MCP client with config', { config });
50
+ const client = new MCPClient(config);
51
+ // Create agent with memory_enabled=true
52
+ const agent = new MCPAgent({
53
+ llm,
54
+ client,
55
+ maxSteps: 15,
56
+ memoryEnabled: true, // Enable built-in conversation memory
57
+ });
58
+ Logger.info('Initializing MCP agent', { agent });
59
+ await agent.initialize();
60
+ Logger.info('MCP agent initialized', { agent });
61
+ this.agent = agent;
62
+ this.client = client;
129
63
  }
130
- async reinitializeWithNewServers() {
131
- try {
132
- console.log('🔄 Reinitializing agent with new servers...');
133
- // Get updated server configuration
134
- const storedConfig = this.commandHandler.getCurrentStoredConfig();
135
- const storedServers = storedConfig.mcpServers || {};
136
- const sessionServers = this.commandHandler.getSessionServers();
137
- console.log('Stored servers:', Object.keys(storedServers));
138
- console.log('Session servers:', Object.keys(sessionServers));
139
- // Default filesystem server
140
- const defaultFilesystemServer = {
141
- "command": "npx",
142
- "args": ["-y", "@modelcontextprotocol/server-filesystem", "/tmp"],
143
- "env": {}
144
- };
145
- // Merge stored servers, session servers, with default (session servers override persistent ones)
146
- const servers = {
147
- "filesystem": defaultFilesystemServer,
148
- ...storedServers,
149
- ...sessionServers
150
- };
151
- console.log('Final server configuration:', Object.keys(servers));
152
- const newConfig = {
153
- "servers": servers
154
- };
155
- // Reinitialize MCP client with new configuration
156
- console.log('Reinitializing MCP client with new config:', JSON.stringify(newConfig, null, 2));
157
- this.client = MCPClient.fromDict(newConfig);
158
- console.log('MCP client reinitialized successfully');
159
- // If we have an agent configured, reinitialize it with the new client
160
- if (this.commandHandler.isAnyProviderAvailable() && this.commandHandler.getCurrentConfig()) {
161
- console.log('Reinitializing agent...');
162
- await this.initializeAgent();
163
- console.log('✅ Agent reinitialized successfully');
164
- }
165
- else {
166
- console.log('⚠️ No LLM configured, skipping agent initialization');
167
- }
168
- }
169
- catch (error) {
170
- console.error('❌ Failed to reinitialize with new servers:', error);
171
- if (error instanceof Error) {
172
- console.error('Error stack:', error.stack);
173
- }
174
- // Don't throw here, just log - the old agent should still work
175
- }
64
+ async refreshAgent() {
65
+ await this.initializeAgent();
176
66
  }
177
67
  async sendMessage(message, isApiKeyInput, pendingProvider, pendingModel, isServerConfigInput, serverConfigStep, serverConfig) {
178
68
  // Handle server configuration input
179
69
  if (isServerConfigInput && serverConfigStep) {
180
70
  const commandResult = this.commandHandler.handleServerConfigInput(message.trim(), serverConfigStep, serverConfig);
181
- // If servers were added successfully, reinitialize the agent
182
- if (commandResult.data?.serversAdded || commandResult.data?.serverAdded) {
183
- await this.reinitializeWithNewServers();
184
- }
185
71
  return {
186
72
  response: commandResult.message,
187
73
  toolCalls: [],
188
74
  isCommand: true,
189
- commandResult
75
+ commandResult,
190
76
  };
191
77
  }
192
78
  // Handle API key input
@@ -200,7 +86,7 @@ export class MCPService {
200
86
  response: commandResult.message,
201
87
  toolCalls: [],
202
88
  isCommand: true,
203
- commandResult
89
+ commandResult,
204
90
  };
205
91
  }
206
92
  // Check if it's a slash command
@@ -228,8 +114,10 @@ export class MCPService {
228
114
  toolsMessage += '🔍 Debug steps:\n';
229
115
  toolsMessage += '1. Check console logs for errors\n';
230
116
  toolsMessage += '2. Test server manually: /test-server <name>\n';
231
- toolsMessage += '3. Ask agent "Which tools do you have?" to see fallback tools\n\n';
232
- toolsMessage += '⚠️ If you see Wolfram/Wikipedia tools, MCP integration failed completely.';
117
+ toolsMessage +=
118
+ '3. Ask agent "Which tools do you have?" to see fallback tools\n\n';
119
+ toolsMessage +=
120
+ '⚠️ If you see Wolfram/Wikipedia tools, MCP integration failed completely.';
233
121
  }
234
122
  else {
235
123
  toolsMessage += `✅ Found ${toolsResult.tools.length} MCP tools:\n\n`;
@@ -245,23 +133,18 @@ export class MCPService {
245
133
  response: toolsMessage,
246
134
  toolCalls: [],
247
135
  isCommand: true,
248
- commandResult: { type: 'info', message: toolsMessage }
136
+ commandResult: { type: 'info', message: toolsMessage },
249
137
  };
250
138
  }
251
139
  // If the command changed the LLM config, reinitialize the agent
252
140
  if (commandResult.data?.llmConfig) {
253
141
  await this.initializeAgent();
254
142
  }
255
- // If servers were added, connected, or disconnected, reinitialize the agent
256
- if (commandResult.data?.serversAdded || commandResult.data?.serverAdded ||
257
- commandResult.data?.serverConnected || commandResult.data?.serverDisconnected) {
258
- await this.reinitializeWithNewServers();
259
- }
260
143
  return {
261
144
  response: commandResult.message,
262
145
  toolCalls: [],
263
146
  isCommand: true,
264
- commandResult
147
+ commandResult,
265
148
  };
266
149
  }
267
150
  catch (error) {
@@ -269,7 +152,7 @@ export class MCPService {
269
152
  response: `Command error: ${error instanceof Error ? error.message : 'Unknown error'}`,
270
153
  toolCalls: [],
271
154
  isCommand: true,
272
- commandResult: { type: 'error', message: 'Command failed' }
155
+ commandResult: { type: 'error', message: 'Command failed' },
273
156
  };
274
157
  }
275
158
  }
@@ -283,7 +166,9 @@ export class MCPService {
283
166
  }
284
167
  else {
285
168
  const firstProvider = availableProviders[0];
286
- const exampleModel = firstProvider ? this.getExampleModel(firstProvider) : 'model-name';
169
+ const exampleModel = firstProvider
170
+ ? this.getExampleModel(firstProvider)
171
+ : 'model-name';
287
172
  return {
288
173
  response: `🔧 No model selected.\n\nAvailable providers: ${availableProviders.join(', ')}\n\nUse /model <provider> <model> to get started.\n\nExample: /model ${firstProvider} ${exampleModel}`,
289
174
  toolCalls: [],
@@ -303,7 +188,10 @@ export class MCPService {
303
188
  };
304
189
  }
305
190
  catch (error) {
306
- console.error('Error sending message to MCP agent:', error);
191
+ Logger.error('Error sending message to MCP agent', {
192
+ error: error instanceof Error ? error.message : 'Unknown error',
193
+ stack: error instanceof Error ? error.stack : undefined,
194
+ });
307
195
  throw error;
308
196
  }
309
197
  }
@@ -312,7 +200,7 @@ export class MCPService {
312
200
  openai: 'gpt-4o-mini',
313
201
  anthropic: 'claude-3-5-sonnet-20241022',
314
202
  google: 'gemini-1.5-pro',
315
- mistral: 'mistral-large-latest'
203
+ mistral: 'mistral-large-latest',
316
204
  };
317
205
  return examples[provider] || 'model-name';
318
206
  }
@@ -331,8 +219,14 @@ export class MCPService {
331
219
  yield { done: true };
332
220
  }
333
221
  catch (error) {
334
- console.error('Error streaming message:', error);
335
- yield { content: `Error: ${error instanceof Error ? error.message : 'Unknown error'}`, done: true };
222
+ Logger.error('Error streaming message:', {
223
+ error: error instanceof Error ? error.message : 'Unknown error',
224
+ stack: error instanceof Error ? error.stack : undefined,
225
+ });
226
+ yield {
227
+ content: `Error: ${error instanceof Error ? error.message : 'Unknown error'}`,
228
+ done: true,
229
+ };
336
230
  }
337
231
  }
338
232
  isReady() {
@@ -365,71 +259,68 @@ export class MCPService {
365
259
  }
366
260
  getConnectedServers() {
367
261
  const sessionServers = this.commandHandler.getSessionServers();
368
- // Always include filesystem as it's built-in and always connected
369
- const servers = ['filesystem'];
370
- // Add only connected servers (those in sessionServers)
371
262
  const connectedCustomServers = Object.keys(sessionServers);
372
- servers.push(...connectedCustomServers);
373
- return servers;
263
+ return connectedCustomServers;
374
264
  }
375
265
  async getAvailableTools() {
266
+ Logger.debug('Getting available tools - starting check');
376
267
  if (!this.agent) {
377
- return { tools: [], error: 'No agent initialized' };
268
+ const error = 'No agent initialized';
269
+ Logger.warn('Tools check failed - no agent', { error });
270
+ return { tools: [], error };
378
271
  }
379
272
  try {
380
- // Try to access the MCP client directly to get available tools
381
273
  if (this.client) {
382
- // Try to call listTools on the client
383
- const clientAny = this.client;
384
- if (typeof clientAny.listTools === 'function') {
385
- const tools = await clientAny.listTools();
386
- return { tools: tools || [] };
387
- }
388
- // Try to access servers and their tools
389
- if (clientAny.servers) {
390
- const allTools = [];
391
- for (const [serverName, server] of Object.entries(clientAny.servers)) {
392
- const serverAny = server;
393
- if (serverAny.listTools && typeof serverAny.listTools === 'function') {
394
- try {
395
- const serverTools = await serverAny.listTools();
396
- if (Array.isArray(serverTools)) {
397
- allTools.push(...serverTools.map(tool => ({ ...tool, server: serverName })));
398
- }
399
- }
400
- catch (e) {
401
- console.log(`Failed to get tools from server ${serverName}:`, e);
402
- }
274
+ Logger.debug('Checking client for tools', {
275
+ clientType: this.client.constructor.name,
276
+ clientKeys: Object.keys(this.client),
277
+ });
278
+ let allTools = [];
279
+ // Iterate through sessions
280
+ for (const [sessionName, session] of Object.entries(this.client.getAllActiveSessions())) {
281
+ Logger.debug(`Checking session: ${sessionName}`, {
282
+ sessionType: typeof session,
283
+ sessionConstructor: session?.constructor?.name,
284
+ sessionKeys: session ? Object.keys(session) : [],
285
+ });
286
+ // Try to get tools from connector
287
+ if (session.connector) {
288
+ Logger.debug(`Checking connector in session ${sessionName}`, {
289
+ connectorType: typeof session.connector,
290
+ connectorConstructor: session.connector?.constructor?.name,
291
+ connectorKeys: session.connector
292
+ ? Object.keys(session.connector)
293
+ : [],
294
+ });
295
+ if (session.connector.tools &&
296
+ Array.isArray(session.connector.tools)) {
297
+ Logger.debug(`Found tools in connector for session ${sessionName}`, {
298
+ toolCount: session.connector.tools.length,
299
+ tools: session.connector.tools,
300
+ });
301
+ allTools.push(...session.connector.tools.map((tool) => ({
302
+ ...tool,
303
+ session: sessionName,
304
+ })));
403
305
  }
404
306
  }
405
- if (allTools.length > 0) {
406
- return { tools: allTools };
407
- }
408
307
  }
409
- }
410
- // Try the agent directly (with type assertions to avoid TS errors)
411
- const agentAny = this.agent;
412
- if (typeof agentAny.listTools === 'function') {
413
- const tools = await agentAny.listTools();
414
- return { tools: tools || [] };
415
- }
416
- else if (typeof agentAny.getTools === 'function') {
417
- const tools = await agentAny.getTools();
418
- return { tools: tools || [] };
419
- }
420
- else if (agentAny.tools) {
421
- return { tools: agentAny.tools || [] };
422
- }
423
- else {
424
- return { tools: [], error: 'Agent and client do not expose tool listing functionality' };
308
+ return { tools: allTools };
425
309
  }
426
310
  }
427
311
  catch (error) {
312
+ const errorMsg = `Failed to get tools: ${error instanceof Error ? error.message : 'Unknown error'}`;
313
+ Logger.error('Tools check failed with exception', {
314
+ error: errorMsg,
315
+ stack: error instanceof Error ? error.stack : undefined,
316
+ });
428
317
  return {
429
318
  tools: [],
430
- error: `Failed to get tools: ${error instanceof Error ? error.message : 'Unknown error'}`
319
+ error: errorMsg,
431
320
  };
432
321
  }
322
+ // Default return if client doesn't exist
323
+ return { tools: [], error: 'No client available' };
433
324
  }
434
325
  }
435
326
  // Export a singleton instance
@@ -0,0 +1,56 @@
1
+ import type { Tool } from '@modelcontextprotocol/sdk/types.js';
2
+ import type { ToolCall, CommandResult } from '../types.js';
3
+ import { LLMService } from './llm-service.js';
4
+ export interface AgentServiceDeps {
5
+ llmService: LLMService;
6
+ }
7
+ export declare class AgentService {
8
+ private agent;
9
+ private client;
10
+ private llmService;
11
+ constructor(deps: AgentServiceDeps);
12
+ isReady(): boolean;
13
+ sendMessage(message: string): AsyncGenerator<{
14
+ response?: string;
15
+ toolCalls?: ToolCall[];
16
+ thought?: string;
17
+ }>;
18
+ getAvailableTools(): Promise<{
19
+ tools: Tool[];
20
+ error?: string;
21
+ }>;
22
+ /**
23
+ * Handles the /tools command to list available MCP tools.
24
+ * @returns A CommandResult indicating that tools should be checked
25
+ */
26
+ handleListToolsCommand(): CommandResult;
27
+ /**
28
+ * Gets all active MCP sessions.
29
+ * @returns Object with session names as keys
30
+ */
31
+ getActiveSessions(): Record<string, any>;
32
+ /**
33
+ * Checks if a specific server is connected.
34
+ * @param serverName - Name of the server to check
35
+ * @returns True if the server is connected
36
+ */
37
+ isServerConnected(serverName: string): boolean;
38
+ /**
39
+ * Gets the list of connected server names.
40
+ * @returns Array of connected server names
41
+ */
42
+ getConnectedServerNames(): string[];
43
+ /**
44
+ * Connects a new MCP server without reinitializing the entire agent.
45
+ * @param serverName - Name of the server to connect
46
+ * @param serverConfig - Configuration for the server
47
+ * @returns Promise that resolves when connected
48
+ */
49
+ connectServer(serverName: string, serverConfig: any): Promise<void>;
50
+ /**
51
+ * Disconnects an MCP server without reinitializing the entire agent.
52
+ * @param serverName - Name of the server to disconnect
53
+ * @returns Promise that resolves when disconnected
54
+ */
55
+ disconnectServer(serverName: string): Promise<void>;
56
+ }
@@ -0,0 +1,203 @@
1
+ import { MCPAgent, MCPClient } from 'mcp-use';
2
+ import { Logger } from '../logger.js';
3
+ export class AgentService {
4
+ constructor(deps) {
5
+ Object.defineProperty(this, "agent", {
6
+ enumerable: true,
7
+ configurable: true,
8
+ writable: true,
9
+ value: null
10
+ });
11
+ Object.defineProperty(this, "client", {
12
+ enumerable: true,
13
+ configurable: true,
14
+ writable: true,
15
+ value: null
16
+ });
17
+ Object.defineProperty(this, "llmService", {
18
+ enumerable: true,
19
+ configurable: true,
20
+ writable: true,
21
+ value: void 0
22
+ });
23
+ this.llmService = deps.llmService;
24
+ this.client = new MCPClient({});
25
+ this.agent = new MCPAgent({
26
+ llm: this.llmService.createLLM(),
27
+ client: this.client,
28
+ maxSteps: 15,
29
+ memoryEnabled: true, // Enable built-in conversation memory
30
+ });
31
+ }
32
+ isReady() {
33
+ return this.agent !== null;
34
+ }
35
+ async *sendMessage(message) {
36
+ if (!this.agent) {
37
+ throw new Error('Agent not initialized');
38
+ }
39
+ try {
40
+ // The stream method yields AgentSteps for each tool call and returns the final string response.
41
+ const generator = this.agent.stream(message);
42
+ let result = await generator.next();
43
+ while (!result.done) {
44
+ const agentStep = result.value; // This is of type AgentStep
45
+ if (agentStep.action) {
46
+ // The 'log' contains the "Thought:" part.
47
+ if (agentStep.action.log) {
48
+ yield { thought: agentStep.action.log };
49
+ }
50
+ // Map AgentStep to our internal ToolCall type
51
+ const toolCall = {
52
+ id: `${agentStep.action.tool}-${Date.now()}`, // Create a simple unique ID
53
+ role: 'tool',
54
+ tool_name: agentStep.action.tool,
55
+ tool_input: agentStep.action.toolInput,
56
+ tool_output: agentStep.observation,
57
+ };
58
+ yield { toolCalls: [toolCall] };
59
+ }
60
+ result = await generator.next();
61
+ }
62
+ // When the generator is done, the final response is in result.value
63
+ const finalResponse = result.value;
64
+ if (finalResponse) {
65
+ yield { response: finalResponse };
66
+ }
67
+ }
68
+ catch (error) {
69
+ Logger.error('Error sending message to MCP agent', {
70
+ error: error instanceof Error ? error.message : 'Unknown error',
71
+ stack: error instanceof Error ? error.stack : undefined,
72
+ });
73
+ throw error;
74
+ }
75
+ }
76
+ async getAvailableTools() {
77
+ Logger.debug('Getting available tools - starting check');
78
+ if (!this.client) {
79
+ const error = 'No agent/client initialized';
80
+ Logger.warn('Tools check failed - no client', { error });
81
+ return { tools: [], error };
82
+ }
83
+ try {
84
+ let allTools = [];
85
+ const sessions = this.client.getAllActiveSessions();
86
+ for (const [sessionName, session] of Object.entries(sessions)) {
87
+ if (session.connector?.tools &&
88
+ Array.isArray(session.connector.tools)) {
89
+ Logger.debug(`Found tools in connector for session ${sessionName}`, {
90
+ toolCount: session.connector.tools.length,
91
+ });
92
+ const sessionTools = session.connector.tools.map((tool) => ({
93
+ ...tool,
94
+ session: sessionName,
95
+ }));
96
+ allTools.push(...sessionTools);
97
+ }
98
+ }
99
+ return { tools: allTools };
100
+ }
101
+ catch (error) {
102
+ const errorMsg = `Failed to get tools: ${error instanceof Error ? error.message : 'Unknown error'}`;
103
+ Logger.error('Tools check failed with exception', {
104
+ error: errorMsg,
105
+ stack: error instanceof Error ? error.stack : undefined,
106
+ });
107
+ return {
108
+ tools: [],
109
+ error: errorMsg,
110
+ };
111
+ }
112
+ }
113
+ /**
114
+ * Handles the /tools command to list available MCP tools.
115
+ * @returns A CommandResult indicating that tools should be checked
116
+ */
117
+ handleListToolsCommand() {
118
+ return {
119
+ type: 'info',
120
+ message: '🔧 Checking available MCP tools...\n\nThis command will show tools available from connected MCP servers.\nNote: This requires the MCP service to provide tool listing functionality.',
121
+ data: { checkTools: true },
122
+ };
123
+ }
124
+ /**
125
+ * Gets all active MCP sessions.
126
+ * @returns Object with session names as keys
127
+ */
128
+ getActiveSessions() {
129
+ if (!this.client) {
130
+ return {};
131
+ }
132
+ try {
133
+ return this.client.getAllActiveSessions();
134
+ }
135
+ catch (error) {
136
+ Logger.error('Failed to get active sessions', {
137
+ error: error instanceof Error ? error.message : 'Unknown error',
138
+ });
139
+ return {};
140
+ }
141
+ }
142
+ /**
143
+ * Checks if a specific server is connected.
144
+ * @param serverName - Name of the server to check
145
+ * @returns True if the server is connected
146
+ */
147
+ isServerConnected(serverName) {
148
+ const sessions = this.getActiveSessions();
149
+ return !!sessions[serverName];
150
+ }
151
+ /**
152
+ * Gets the list of connected server names.
153
+ * @returns Array of connected server names
154
+ */
155
+ getConnectedServerNames() {
156
+ return Object.keys(this.getActiveSessions());
157
+ }
158
+ /**
159
+ * Connects a new MCP server without reinitializing the entire agent.
160
+ * @param serverName - Name of the server to connect
161
+ * @param serverConfig - Configuration for the server
162
+ * @returns Promise that resolves when connected
163
+ */
164
+ async connectServer(serverName, serverConfig) {
165
+ if (!this.agent || !this.client) {
166
+ throw new Error('Agent not initialized');
167
+ }
168
+ if (this.isServerConnected(serverName)) {
169
+ throw new Error(`Server "${serverName}" is already connected`);
170
+ }
171
+ Logger.info('Connecting to server', serverName);
172
+ const currentConfig = this.client.getConfig();
173
+ const newConfig = {
174
+ mcpServers: {
175
+ ...currentConfig["mcpServers"],
176
+ [serverName]: serverConfig,
177
+ }
178
+ };
179
+ this.client = new MCPClient(newConfig);
180
+ this.agent = new MCPAgent({
181
+ llm: this.llmService.createLLM(),
182
+ client: this.client,
183
+ maxSteps: 30,
184
+ memoryEnabled: true, // Enable built-in conversation memory
185
+ });
186
+ await this.agent?.initialize();
187
+ }
188
+ /**
189
+ * Disconnects an MCP server without reinitializing the entire agent.
190
+ * @param serverName - Name of the server to disconnect
191
+ * @returns Promise that resolves when disconnected
192
+ */
193
+ async disconnectServer(serverName) {
194
+ if (!this.agent || !this.client) {
195
+ throw new Error('Agent not initialized');
196
+ }
197
+ if (!this.isServerConnected(serverName)) {
198
+ throw new Error(`Server "${serverName}" is not connected`);
199
+ }
200
+ this.client?.removeServer(serverName);
201
+ this.agent?.initialize();
202
+ }
203
+ }