@mcp-use/cli 1.0.0

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.
@@ -0,0 +1,44 @@
1
+ import { CommandResult } from './commands.js';
2
+ export interface MCPMessage {
3
+ id: string;
4
+ role: 'user' | 'assistant';
5
+ content: string;
6
+ timestamp: Date;
7
+ }
8
+ export interface MCPToolCall {
9
+ id: string;
10
+ role: 'tool';
11
+ tool_name: string;
12
+ tool_input: Record<string, any>;
13
+ tool_output: Record<string, any>;
14
+ }
15
+ export declare class MCPService {
16
+ private agent;
17
+ private isInitialized;
18
+ private commandHandler;
19
+ private client;
20
+ initialize(config?: any): Promise<void>;
21
+ private initializeAgent;
22
+ private reinitializeWithNewServers;
23
+ sendMessage(message: string, isApiKeyInput?: boolean, pendingProvider?: string, pendingModel?: string, isServerConfigInput?: boolean, serverConfigStep?: string, serverConfig?: any): Promise<{
24
+ response: string;
25
+ toolCalls: MCPToolCall[];
26
+ isCommand?: boolean;
27
+ commandResult?: CommandResult;
28
+ }>;
29
+ private getExampleModel;
30
+ streamMessage(message: string): AsyncGenerator<{
31
+ content?: string;
32
+ toolCall?: MCPToolCall;
33
+ done: boolean;
34
+ }>;
35
+ isReady(): boolean;
36
+ getCurrentModel(): string;
37
+ getConfiguredServers(): string[];
38
+ getConnectedServers(): string[];
39
+ getAvailableTools(): Promise<{
40
+ tools: any[];
41
+ error?: string;
42
+ }>;
43
+ }
44
+ export declare const mcpService: MCPService;
@@ -0,0 +1,436 @@
1
+ import { MCPAgent, MCPClient } from 'mcp-use';
2
+ import { config } from 'dotenv';
3
+ import { CommandHandler } from './commands.js';
4
+ // Load environment variables
5
+ config();
6
+ export class MCPService {
7
+ constructor() {
8
+ Object.defineProperty(this, "agent", {
9
+ enumerable: true,
10
+ configurable: true,
11
+ writable: true,
12
+ value: null
13
+ });
14
+ Object.defineProperty(this, "isInitialized", {
15
+ enumerable: true,
16
+ configurable: true,
17
+ writable: true,
18
+ value: false
19
+ });
20
+ Object.defineProperty(this, "commandHandler", {
21
+ enumerable: true,
22
+ configurable: true,
23
+ writable: true,
24
+ value: new CommandHandler()
25
+ });
26
+ Object.defineProperty(this, "client", {
27
+ enumerable: true,
28
+ configurable: true,
29
+ writable: true,
30
+ value: null
31
+ });
32
+ }
33
+ async initialize(config) {
34
+ if (this.isInitialized)
35
+ 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
+ }
71
+ }
72
+ 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
+ }
129
+ }
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
+ }
176
+ }
177
+ async sendMessage(message, isApiKeyInput, pendingProvider, pendingModel, isServerConfigInput, serverConfigStep, serverConfig) {
178
+ // Handle server configuration input
179
+ if (isServerConfigInput && serverConfigStep) {
180
+ 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
+ return {
186
+ response: commandResult.message,
187
+ toolCalls: [],
188
+ isCommand: true,
189
+ commandResult
190
+ };
191
+ }
192
+ // Handle API key input
193
+ if (isApiKeyInput && pendingProvider && pendingModel) {
194
+ const commandResult = this.commandHandler.handleApiKeyInput(message.trim(), pendingProvider, pendingModel);
195
+ // If successful, reinitialize the agent
196
+ if (commandResult.data?.llmConfig) {
197
+ await this.initializeAgent();
198
+ }
199
+ return {
200
+ response: commandResult.message,
201
+ toolCalls: [],
202
+ isCommand: true,
203
+ commandResult
204
+ };
205
+ }
206
+ // Check if it's a slash command
207
+ if (this.commandHandler.isCommand(message)) {
208
+ try {
209
+ const commandResult = await this.commandHandler.handleCommand(message);
210
+ // Handle special commands that need MCP service interaction
211
+ if (commandResult.data?.checkTools) {
212
+ const toolsResult = await this.getAvailableTools();
213
+ let toolsMessage = '🔧 Available MCP Tools:\n\n';
214
+ if (toolsResult.error) {
215
+ toolsMessage += `❌ Error: ${toolsResult.error}\n\n`;
216
+ toolsMessage += '💡 This might indicate:\n';
217
+ toolsMessage += '• MCP servers failed to start\n';
218
+ toolsMessage += '• Agent fell back to default LLM tools\n';
219
+ toolsMessage += '• Connection issues with configured servers\n\n';
220
+ toolsMessage += 'Check console logs for more details.';
221
+ }
222
+ else if (toolsResult.tools.length === 0) {
223
+ toolsMessage += '❌ No MCP tools found\n\n';
224
+ toolsMessage += '💡 This suggests:\n';
225
+ toolsMessage += '• MCP servers failed to start or connect\n';
226
+ toolsMessage += '• Agent fell back to default LangChain tools\n';
227
+ toolsMessage += '• Server packages may not be installed\n\n';
228
+ toolsMessage += '🔍 Debug steps:\n';
229
+ toolsMessage += '1. Check console logs for errors\n';
230
+ 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.';
233
+ }
234
+ else {
235
+ toolsMessage += `✅ Found ${toolsResult.tools.length} MCP tools:\n\n`;
236
+ toolsResult.tools.forEach((tool, index) => {
237
+ toolsMessage += `${index + 1}. **${tool.name || 'Unknown'}**`;
238
+ if (tool.description) {
239
+ toolsMessage += `: ${tool.description}`;
240
+ }
241
+ toolsMessage += '\n';
242
+ });
243
+ }
244
+ return {
245
+ response: toolsMessage,
246
+ toolCalls: [],
247
+ isCommand: true,
248
+ commandResult: { type: 'info', message: toolsMessage }
249
+ };
250
+ }
251
+ // If the command changed the LLM config, reinitialize the agent
252
+ if (commandResult.data?.llmConfig) {
253
+ await this.initializeAgent();
254
+ }
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
+ return {
261
+ response: commandResult.message,
262
+ toolCalls: [],
263
+ isCommand: true,
264
+ commandResult
265
+ };
266
+ }
267
+ catch (error) {
268
+ return {
269
+ response: `Command error: ${error instanceof Error ? error.message : 'Unknown error'}`,
270
+ toolCalls: [],
271
+ isCommand: true,
272
+ commandResult: { type: 'error', message: 'Command failed' }
273
+ };
274
+ }
275
+ }
276
+ if (!this.agent) {
277
+ const availableProviders = this.commandHandler.getAvailableProviders();
278
+ if (availableProviders.length === 0) {
279
+ return {
280
+ response: `🤖 Choose a model to get started!\n\nTry one of these popular options:\n• /model openai gpt-4o-mini\n• /model anthropic claude-3-5-sonnet-20241022\n• /model google gemini-1.5-pro\n\nThe CLI will help you set up the API key when needed.\nUse /models to see all available models.`,
281
+ toolCalls: [],
282
+ };
283
+ }
284
+ else {
285
+ const firstProvider = availableProviders[0];
286
+ const exampleModel = firstProvider ? this.getExampleModel(firstProvider) : 'model-name';
287
+ return {
288
+ response: `🔧 No model selected.\n\nAvailable providers: ${availableProviders.join(', ')}\n\nUse /model <provider> <model> to get started.\n\nExample: /model ${firstProvider} ${exampleModel}`,
289
+ toolCalls: [],
290
+ };
291
+ }
292
+ }
293
+ try {
294
+ const result = await this.agent.run(message);
295
+ // Parse the result to extract tool calls
296
+ // Note: This is a simplified example - you may need to adjust based on actual mcp-use response format
297
+ const toolCalls = [];
298
+ // Extract tool calls from the result if available
299
+ // This would depend on how mcp-use exposes tool execution details
300
+ return {
301
+ response: result || 'No response received',
302
+ toolCalls,
303
+ };
304
+ }
305
+ catch (error) {
306
+ console.error('Error sending message to MCP agent:', error);
307
+ throw error;
308
+ }
309
+ }
310
+ getExampleModel(provider) {
311
+ const examples = {
312
+ openai: 'gpt-4o-mini',
313
+ anthropic: 'claude-3-5-sonnet-20241022',
314
+ google: 'gemini-1.5-pro',
315
+ mistral: 'mistral-large-latest'
316
+ };
317
+ return examples[provider] || 'model-name';
318
+ }
319
+ async *streamMessage(message) {
320
+ if (!this.agent) {
321
+ throw new Error('MCP service not initialized');
322
+ }
323
+ try {
324
+ // MCPAgent doesn't support streaming in the current version
325
+ // Fallback to non-streaming
326
+ const result = await this.sendMessage(message);
327
+ yield { content: result.response, done: false };
328
+ for (const toolCall of result.toolCalls) {
329
+ yield { toolCall, done: false };
330
+ }
331
+ yield { done: true };
332
+ }
333
+ catch (error) {
334
+ console.error('Error streaming message:', error);
335
+ yield { content: `Error: ${error instanceof Error ? error.message : 'Unknown error'}`, done: true };
336
+ }
337
+ }
338
+ isReady() {
339
+ return this.isInitialized && this.agent !== null;
340
+ }
341
+ getCurrentModel() {
342
+ const config = this.commandHandler.getCurrentConfig();
343
+ if (!config) {
344
+ const availableProviders = this.commandHandler.getAvailableProviders();
345
+ if (availableProviders.length === 0) {
346
+ return 'No API keys configured';
347
+ }
348
+ return 'No model selected';
349
+ }
350
+ return `${config.provider}/${config.model}`;
351
+ }
352
+ getConfiguredServers() {
353
+ const storedConfig = this.commandHandler.getCurrentStoredConfig();
354
+ const storedServers = storedConfig.mcpServers || {};
355
+ const sessionServers = this.commandHandler.getSessionServers();
356
+ // Always include filesystem as it's the default
357
+ const servers = ['filesystem'];
358
+ // Add persistent servers (avoid duplicates)
359
+ const persistentCustomServers = Object.keys(storedServers).filter(name => name !== 'filesystem');
360
+ servers.push(...persistentCustomServers);
361
+ // Add session servers (avoid duplicates)
362
+ const sessionCustomServers = Object.keys(sessionServers).filter(name => name !== 'filesystem' && !persistentCustomServers.includes(name));
363
+ servers.push(...sessionCustomServers);
364
+ return servers;
365
+ }
366
+ getConnectedServers() {
367
+ 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
+ const connectedCustomServers = Object.keys(sessionServers);
372
+ servers.push(...connectedCustomServers);
373
+ return servers;
374
+ }
375
+ async getAvailableTools() {
376
+ if (!this.agent) {
377
+ return { tools: [], error: 'No agent initialized' };
378
+ }
379
+ try {
380
+ // Try to access the MCP client directly to get available tools
381
+ 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
+ }
403
+ }
404
+ }
405
+ if (allTools.length > 0) {
406
+ return { tools: allTools };
407
+ }
408
+ }
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' };
425
+ }
426
+ }
427
+ catch (error) {
428
+ return {
429
+ tools: [],
430
+ error: `Failed to get tools: ${error instanceof Error ? error.message : 'Unknown error'}`
431
+ };
432
+ }
433
+ }
434
+ }
435
+ // Export a singleton instance
436
+ export const mcpService = new MCPService();
@@ -0,0 +1,24 @@
1
+ export interface StoredConfig {
2
+ apiKeys: Record<string, string>;
3
+ lastModel?: {
4
+ provider: string;
5
+ model: string;
6
+ temperature?: number;
7
+ maxTokens?: number;
8
+ };
9
+ mcpServers?: Record<string, {
10
+ command: string;
11
+ args?: string[];
12
+ env?: Record<string, string>;
13
+ }>;
14
+ }
15
+ export declare class SecureStorage {
16
+ private static getKey;
17
+ private static encrypt;
18
+ private static decrypt;
19
+ static ensureConfigDir(): void;
20
+ static loadConfig(): StoredConfig;
21
+ static saveConfig(config: StoredConfig): void;
22
+ static clearConfig(): void;
23
+ static getConfigPath(): string;
24
+ }
@@ -0,0 +1,108 @@
1
+ import { scryptSync, randomBytes, createCipheriv, createDecipheriv } from 'node:crypto';
2
+ import { readFileSync, writeFileSync, existsSync, mkdirSync } from 'node:fs';
3
+ import { join } from 'node:path';
4
+ import { homedir } from 'node:os';
5
+ const CONFIG_DIR = join(homedir(), '.mcp-use-cli');
6
+ const CONFIG_FILE = join(CONFIG_DIR, 'config.json');
7
+ const SALT = 'mcp-use-cli-salt'; // In production, this should be more secure
8
+ export class SecureStorage {
9
+ static getKey() {
10
+ return scryptSync('mcp-use-cli-encryption-key', SALT, 32);
11
+ }
12
+ static encrypt(text) {
13
+ try {
14
+ const iv = randomBytes(16);
15
+ const key = this.getKey();
16
+ const cipher = createCipheriv('aes-256-cbc', key, iv);
17
+ let encrypted = cipher.update(text, 'utf8', 'hex');
18
+ encrypted += cipher.final('hex');
19
+ return iv.toString('hex') + ':' + encrypted;
20
+ }
21
+ catch (error) {
22
+ console.error('Encryption error:', error);
23
+ return text; // Fallback to plaintext if encryption fails
24
+ }
25
+ }
26
+ static decrypt(encryptedText) {
27
+ try {
28
+ const parts = encryptedText.split(':');
29
+ if (parts.length !== 2 || !parts[0] || !parts[1]) {
30
+ // Old format or plaintext, return as-is
31
+ return encryptedText;
32
+ }
33
+ const iv = Buffer.from(parts[0], 'hex');
34
+ const encryptedData = parts[1];
35
+ const key = this.getKey();
36
+ const decipher = createDecipheriv('aes-256-cbc', key, iv);
37
+ let decrypted = decipher.update(encryptedData, 'hex', 'utf8');
38
+ decrypted += decipher.final('utf8');
39
+ return decrypted;
40
+ }
41
+ catch (error) {
42
+ console.error('Decryption error:', error);
43
+ return encryptedText; // Fallback to return as-is if decryption fails
44
+ }
45
+ }
46
+ static ensureConfigDir() {
47
+ if (!existsSync(CONFIG_DIR)) {
48
+ mkdirSync(CONFIG_DIR, { recursive: true });
49
+ }
50
+ }
51
+ static loadConfig() {
52
+ this.ensureConfigDir();
53
+ if (!existsSync(CONFIG_FILE)) {
54
+ return { apiKeys: {} };
55
+ }
56
+ try {
57
+ const configData = readFileSync(CONFIG_FILE, 'utf8');
58
+ const parsed = JSON.parse(configData);
59
+ // Decrypt API keys
60
+ const decryptedApiKeys = {};
61
+ for (const [key, encryptedValue] of Object.entries(parsed.apiKeys || {})) {
62
+ if (typeof encryptedValue === 'string') {
63
+ decryptedApiKeys[key] = this.decrypt(encryptedValue);
64
+ }
65
+ }
66
+ return {
67
+ ...parsed,
68
+ apiKeys: decryptedApiKeys
69
+ };
70
+ }
71
+ catch (error) {
72
+ console.error('Error loading config:', error);
73
+ return { apiKeys: {} };
74
+ }
75
+ }
76
+ static saveConfig(config) {
77
+ this.ensureConfigDir();
78
+ try {
79
+ // Encrypt API keys before saving
80
+ const encryptedApiKeys = {};
81
+ for (const [key, value] of Object.entries(config.apiKeys)) {
82
+ encryptedApiKeys[key] = this.encrypt(value);
83
+ }
84
+ const configToSave = {
85
+ ...config,
86
+ apiKeys: encryptedApiKeys
87
+ };
88
+ writeFileSync(CONFIG_FILE, JSON.stringify(configToSave, null, 2), 'utf8');
89
+ }
90
+ catch (error) {
91
+ console.error('Error saving config:', error);
92
+ }
93
+ }
94
+ static clearConfig() {
95
+ this.ensureConfigDir();
96
+ try {
97
+ if (existsSync(CONFIG_FILE)) {
98
+ writeFileSync(CONFIG_FILE, JSON.stringify({ apiKeys: {} }, null, 2), 'utf8');
99
+ }
100
+ }
101
+ catch (error) {
102
+ console.error('Error clearing config:', error);
103
+ }
104
+ }
105
+ static getConfigPath() {
106
+ return CONFIG_FILE;
107
+ }
108
+ }