@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.
- package/dist/InputPrompt.d.ts +13 -0
- package/dist/InputPrompt.js +188 -0
- package/dist/MultilineInput.d.ts +13 -0
- package/dist/MultilineInput.js +154 -0
- package/dist/MultilineTextInput.d.ts +11 -0
- package/dist/MultilineTextInput.js +97 -0
- package/dist/PasteAwareInput.d.ts +13 -0
- package/dist/PasteAwareInput.js +183 -0
- package/dist/SimpleMultilineInput.d.ts +11 -0
- package/dist/SimpleMultilineInput.js +125 -0
- package/dist/app.d.ts +1 -5
- package/dist/app.js +291 -186
- package/dist/cli.js +2 -5
- package/dist/commands.d.ts +15 -30
- package/dist/commands.js +308 -568
- package/dist/components/AsciiLogo.d.ts +2 -0
- package/dist/components/AsciiLogo.js +7 -0
- package/dist/components/Footer.d.ts +5 -0
- package/dist/components/Footer.js +19 -0
- package/dist/components/InputPrompt.d.ts +13 -0
- package/dist/components/InputPrompt.js +188 -0
- package/dist/components/Messages.d.ts +21 -0
- package/dist/components/Messages.js +80 -0
- package/dist/components/ServerStatus.d.ts +7 -0
- package/dist/components/ServerStatus.js +36 -0
- package/dist/components/Spinner.d.ts +16 -0
- package/dist/components/Spinner.js +63 -0
- package/dist/components/ToolStatus.d.ts +8 -0
- package/dist/components/ToolStatus.js +33 -0
- package/dist/components/textInput.d.ts +1 -0
- package/dist/components/textInput.js +1 -0
- package/dist/logger.d.ts +10 -0
- package/dist/logger.js +48 -0
- package/dist/mcp-service.d.ts +5 -4
- package/dist/mcp-service.js +98 -207
- package/dist/services/agent-service.d.ts +56 -0
- package/dist/services/agent-service.js +203 -0
- package/dist/services/cli-service.d.ts +132 -0
- package/dist/services/cli-service.js +591 -0
- package/dist/services/index.d.ts +4 -0
- package/dist/services/index.js +4 -0
- package/dist/services/llm-service.d.ts +174 -0
- package/dist/services/llm-service.js +567 -0
- package/dist/services/mcp-config-service.d.ts +69 -0
- package/dist/services/mcp-config-service.js +426 -0
- package/dist/services/mcp-service.d.ts +1 -0
- package/dist/services/mcp-service.js +1 -0
- package/dist/services/utility-service.d.ts +47 -0
- package/dist/services/utility-service.js +208 -0
- package/dist/storage.js +4 -4
- package/dist/types.d.ts +30 -0
- package/dist/types.js +1 -0
- package/package.json +22 -8
- package/readme.md +68 -39
package/dist/mcp-service.js
CHANGED
|
@@ -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(
|
|
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
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
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
|
|
131
|
-
|
|
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 +=
|
|
232
|
-
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
335
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
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:
|
|
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
|
+
}
|