@lanonasis/cli 3.6.5 ā 3.7.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.
- package/README.md +19 -2
- package/dist/commands/api-keys.d.ts +2 -1
- package/dist/commands/api-keys.js +73 -78
- package/dist/commands/auth.js +244 -177
- package/dist/commands/completion.js +31 -39
- package/dist/commands/config.js +162 -201
- package/dist/commands/enhanced-memory.js +11 -17
- package/dist/commands/guide.js +79 -88
- package/dist/commands/init.js +14 -20
- package/dist/commands/mcp.d.ts +10 -0
- package/dist/commands/mcp.js +215 -156
- package/dist/commands/memory.js +77 -83
- package/dist/commands/organization.js +15 -21
- package/dist/commands/topics.js +52 -58
- package/dist/core/achievements.js +19 -26
- package/dist/core/architecture.js +42 -59
- package/dist/core/dashboard.js +71 -81
- package/dist/core/error-handler.js +30 -39
- package/dist/core/power-mode.js +46 -53
- package/dist/core/progress.js +35 -44
- package/dist/core/welcome.js +56 -64
- package/dist/enhanced-cli.js +49 -58
- package/dist/index-simple.js +75 -113
- package/dist/index.js +64 -69
- package/dist/mcp/access-control.js +13 -17
- package/dist/mcp/client/enhanced-client.js +17 -28
- package/dist/mcp/enhanced-server.js +10 -14
- package/dist/mcp/logger.js +3 -7
- package/dist/mcp/memory-state.js +13 -17
- package/dist/mcp/schemas/tool-schemas.d.ts +16 -16
- package/dist/mcp/schemas/tool-schemas.js +122 -126
- package/dist/mcp/server/lanonasis-server.js +66 -57
- package/dist/mcp/transports/transport-manager.js +18 -25
- package/dist/mcp/vector-store.js +6 -10
- package/dist/mcp-server.js +23 -27
- package/dist/utils/api.js +21 -27
- package/dist/utils/config.d.ts +2 -1
- package/dist/utils/config.js +65 -78
- package/dist/utils/formatting.js +6 -14
- package/dist/utils/hash-utils.d.ts +23 -0
- package/dist/utils/hash-utils.js +37 -0
- package/dist/utils/mcp-client.js +76 -117
- package/package.json +36 -5
package/dist/commands/mcp.js
CHANGED
|
@@ -1,17 +1,21 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
};
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
1
|
+
import chalk from 'chalk';
|
|
2
|
+
import ora from 'ora';
|
|
3
|
+
import { table } from 'table';
|
|
4
|
+
import { getMCPClient } from '../utils/mcp-client.js';
|
|
5
|
+
import { EnhancedMCPClient } from '../mcp/client/enhanced-client.js';
|
|
6
|
+
import { CLIConfig } from '../utils/config.js';
|
|
7
|
+
import WebSocket from 'ws';
|
|
8
|
+
/**
|
|
9
|
+
* Register MCP-related CLI commands (mcp and mcp-server) on a Commander program.
|
|
10
|
+
*
|
|
11
|
+
* Adds commands and subcommands for MCP server initialization, connection management,
|
|
12
|
+
* status reporting, tool listing and invocation, memory create/search operations,
|
|
13
|
+
* preference configuration, and diagnostic routines, wiring each command to its
|
|
14
|
+
* corresponding action handlers.
|
|
15
|
+
*
|
|
16
|
+
* @param program - Commander program instance to extend with MCP commands
|
|
17
|
+
*/
|
|
18
|
+
export function mcpCommands(program) {
|
|
15
19
|
const mcp = program
|
|
16
20
|
.command('mcp')
|
|
17
21
|
.description('MCP (Model Context Protocol) server operations');
|
|
@@ -22,35 +26,35 @@ function mcpCommands(program) {
|
|
|
22
26
|
mcpServer.command('init')
|
|
23
27
|
.description('Initialize MCP server configuration')
|
|
24
28
|
.action(async () => {
|
|
25
|
-
console.log(
|
|
29
|
+
console.log(chalk.cyan('š Initializing MCP Server Configuration'));
|
|
26
30
|
console.log('');
|
|
27
|
-
const config = new
|
|
31
|
+
const config = new CLIConfig();
|
|
28
32
|
const isAuthenticated = !!config.get('token');
|
|
29
33
|
if (isAuthenticated) {
|
|
30
|
-
console.log(
|
|
34
|
+
console.log(chalk.green('ā Authenticated - Using remote MCP mode'));
|
|
31
35
|
console.log(' Your memory operations will use mcp.lanonasis.com');
|
|
32
36
|
console.log(' with real-time SSE updates enabled');
|
|
33
37
|
}
|
|
34
38
|
else {
|
|
35
|
-
console.log(
|
|
39
|
+
console.log(chalk.yellow('ā ļø Not authenticated - Using local MCP mode'));
|
|
36
40
|
console.log(' Run "lanonasis auth login" to enable remote mode');
|
|
37
41
|
}
|
|
38
42
|
console.log('');
|
|
39
|
-
console.log(
|
|
43
|
+
console.log(chalk.cyan('Available MCP Commands:'));
|
|
40
44
|
console.log(' lanonasis mcp connect # Auto-connect to best mode');
|
|
41
45
|
console.log(' lanonasis mcp connect -r # Force remote mode');
|
|
42
46
|
console.log(' lanonasis mcp connect -l # Force local mode');
|
|
43
47
|
console.log(' lanonasis mcp status # Check connection status');
|
|
44
48
|
console.log(' lanonasis mcp tools # List available tools');
|
|
45
49
|
console.log('');
|
|
46
|
-
console.log(
|
|
50
|
+
console.log(chalk.cyan('Memory operations are MCP-powered by default!'));
|
|
47
51
|
// Auto-connect to MCP
|
|
48
|
-
const spinner = (
|
|
52
|
+
const spinner = ora('Auto-connecting to MCP...').start();
|
|
49
53
|
try {
|
|
50
|
-
const client =
|
|
54
|
+
const client = getMCPClient();
|
|
51
55
|
const connected = await client.connect({ useRemote: isAuthenticated });
|
|
52
56
|
if (connected) {
|
|
53
|
-
spinner.succeed(
|
|
57
|
+
spinner.succeed(chalk.green(`Connected to ${isAuthenticated ? 'remote' : 'local'} MCP server`));
|
|
54
58
|
process.exit(0);
|
|
55
59
|
}
|
|
56
60
|
else {
|
|
@@ -73,8 +77,8 @@ function mcpCommands(program) {
|
|
|
73
77
|
.option('-u, --url <url>', 'Remote/WebSocket server URL')
|
|
74
78
|
.option('--local-args <args>', 'Extra args for local server (e.g., "--stdio --port 3001")')
|
|
75
79
|
.action(async (options) => {
|
|
76
|
-
const spinner = (
|
|
77
|
-
const config = new
|
|
80
|
+
const spinner = ora('Connecting to MCP server...').start();
|
|
81
|
+
const config = new CLIConfig();
|
|
78
82
|
try {
|
|
79
83
|
let connectionMode;
|
|
80
84
|
// Determine connection mode - WebSocket takes precedence over remote and local
|
|
@@ -88,8 +92,9 @@ function mcpCommands(program) {
|
|
|
88
92
|
connectionMode = 'local';
|
|
89
93
|
}
|
|
90
94
|
else {
|
|
91
|
-
// Default to
|
|
92
|
-
|
|
95
|
+
// Default to websocket (production mode) for all users
|
|
96
|
+
// Local mode should only be used explicitly for development
|
|
97
|
+
connectionMode = 'websocket';
|
|
93
98
|
}
|
|
94
99
|
// Save preferences
|
|
95
100
|
config.set('mcpConnectionMode', connectionMode);
|
|
@@ -106,7 +111,7 @@ function mcpCommands(program) {
|
|
|
106
111
|
}
|
|
107
112
|
let connected = false;
|
|
108
113
|
// Use Enhanced MCP Client for better connection handling
|
|
109
|
-
const enhancedClient = new
|
|
114
|
+
const enhancedClient = new EnhancedMCPClient();
|
|
110
115
|
if (options.url) {
|
|
111
116
|
// Connect to specific URL (WebSocket or remote)
|
|
112
117
|
const serverConfig = {
|
|
@@ -117,14 +122,14 @@ function mcpCommands(program) {
|
|
|
117
122
|
};
|
|
118
123
|
connected = await enhancedClient.connectSingle(serverConfig);
|
|
119
124
|
if (connected) {
|
|
120
|
-
spinner.succeed(
|
|
125
|
+
spinner.succeed(chalk.green(`Connected to MCP server at ${options.url}`));
|
|
121
126
|
process.exit(0);
|
|
122
127
|
return;
|
|
123
128
|
}
|
|
124
129
|
}
|
|
125
130
|
else {
|
|
126
131
|
// Fall back to old client for local connections
|
|
127
|
-
const client =
|
|
132
|
+
const client = getMCPClient();
|
|
128
133
|
const localArgs = typeof options.localArgs === 'string' && options.localArgs.trim().length > 0
|
|
129
134
|
? options.localArgs.split(' ').map((s) => s.trim()).filter(Boolean)
|
|
130
135
|
: undefined;
|
|
@@ -136,15 +141,15 @@ function mcpCommands(program) {
|
|
|
136
141
|
});
|
|
137
142
|
}
|
|
138
143
|
if (connected) {
|
|
139
|
-
spinner.succeed(
|
|
144
|
+
spinner.succeed(chalk.green(`Connected to MCP server in ${connectionMode} mode`));
|
|
140
145
|
process.exit(0);
|
|
141
146
|
if (connectionMode === 'remote') {
|
|
142
|
-
console.log(
|
|
143
|
-
console.log(
|
|
147
|
+
console.log(chalk.cyan('ā¹ļø Using remote MCP via mcp.lanonasis.com'));
|
|
148
|
+
console.log(chalk.cyan('š” SSE endpoint active for real-time updates'));
|
|
144
149
|
}
|
|
145
150
|
else if (connectionMode === 'websocket') {
|
|
146
|
-
console.log(
|
|
147
|
-
console.log(
|
|
151
|
+
console.log(chalk.cyan('ā¹ļø Using enterprise WebSocket MCP server'));
|
|
152
|
+
console.log(chalk.cyan('š” WebSocket connection active with auto-reconnect'));
|
|
148
153
|
}
|
|
149
154
|
}
|
|
150
155
|
else {
|
|
@@ -161,47 +166,95 @@ function mcpCommands(program) {
|
|
|
161
166
|
mcp.command('disconnect')
|
|
162
167
|
.description('Disconnect from MCP server')
|
|
163
168
|
.action(async () => {
|
|
164
|
-
const client =
|
|
169
|
+
const client = getMCPClient();
|
|
165
170
|
await client.disconnect();
|
|
166
|
-
console.log(
|
|
171
|
+
console.log(chalk.green('ā Disconnected from MCP server'));
|
|
167
172
|
});
|
|
168
173
|
// Status command
|
|
169
174
|
mcp.command('status')
|
|
170
175
|
.description('Show MCP connection status')
|
|
171
176
|
.action(async () => {
|
|
172
|
-
const client =
|
|
177
|
+
const client = getMCPClient();
|
|
173
178
|
// Reload config from disk to get latest preference
|
|
174
179
|
await client.init();
|
|
175
180
|
const status = client.getConnectionStatus();
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
181
|
+
// Also perform a lightweight live health check against the MCP HTTP endpoint
|
|
182
|
+
const config = new CLIConfig();
|
|
183
|
+
await config.init();
|
|
184
|
+
let healthLabel = chalk.gray('Unknown');
|
|
185
|
+
let healthDetails;
|
|
186
|
+
try {
|
|
187
|
+
const axios = (await import('axios')).default;
|
|
188
|
+
// Derive MCP health URL from discovered REST base (e.g. https://mcp.lanonasis.com/api/v1 -> https://mcp.lanonasis.com/health)
|
|
189
|
+
const restUrl = config.getMCPRestUrl();
|
|
190
|
+
const rootBase = restUrl.replace(/\/api\/v1$/, '');
|
|
191
|
+
const healthUrl = `${rootBase}/health`;
|
|
192
|
+
const token = config.getToken();
|
|
193
|
+
const vendorKey = config.getVendorKey();
|
|
194
|
+
const headers = {};
|
|
195
|
+
if (vendorKey) {
|
|
196
|
+
headers['X-API-Key'] = vendorKey;
|
|
197
|
+
headers['X-Auth-Method'] = 'vendor_key';
|
|
198
|
+
}
|
|
199
|
+
else if (token) {
|
|
200
|
+
headers['Authorization'] = `Bearer ${token}`;
|
|
201
|
+
headers['X-Auth-Method'] = 'jwt';
|
|
202
|
+
}
|
|
203
|
+
const response = await axios.get(healthUrl, {
|
|
204
|
+
headers,
|
|
205
|
+
timeout: 5000
|
|
206
|
+
});
|
|
207
|
+
const overallStatus = String(response.data?.status ?? '').toLowerCase();
|
|
208
|
+
const ok = response.status === 200 && (!overallStatus || overallStatus === 'healthy');
|
|
209
|
+
if (ok) {
|
|
210
|
+
healthLabel = chalk.green('Reachable');
|
|
211
|
+
}
|
|
212
|
+
else {
|
|
213
|
+
healthLabel = chalk.yellow('Degraded');
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
catch (error) {
|
|
217
|
+
healthLabel = chalk.red('Unreachable');
|
|
218
|
+
if (error instanceof Error) {
|
|
219
|
+
healthDetails = error.message;
|
|
220
|
+
}
|
|
221
|
+
else if (error !== null && error !== undefined) {
|
|
222
|
+
healthDetails = String(error);
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
console.log(chalk.cyan('\nš MCP Connection Status'));
|
|
226
|
+
console.log(chalk.cyan('========================'));
|
|
227
|
+
console.log(`Status: ${status.connected ? chalk.green('Connected') : chalk.red('Disconnected')}`);
|
|
179
228
|
// Display mode with proper labels
|
|
180
229
|
let modeDisplay;
|
|
181
230
|
switch (status.mode) {
|
|
182
231
|
case 'websocket':
|
|
183
|
-
modeDisplay =
|
|
232
|
+
modeDisplay = chalk.blue('WebSocket');
|
|
184
233
|
break;
|
|
185
234
|
case 'remote':
|
|
186
|
-
modeDisplay =
|
|
235
|
+
modeDisplay = chalk.blue('Remote (HTTP/SSE)');
|
|
187
236
|
break;
|
|
188
237
|
case 'local':
|
|
189
|
-
modeDisplay =
|
|
238
|
+
modeDisplay = chalk.yellow('Local (stdio)');
|
|
190
239
|
break;
|
|
191
240
|
default:
|
|
192
|
-
modeDisplay =
|
|
241
|
+
modeDisplay = chalk.gray(status.mode);
|
|
193
242
|
}
|
|
194
243
|
console.log(`Mode: ${modeDisplay}`);
|
|
195
244
|
console.log(`Server: ${status.server}`);
|
|
245
|
+
console.log(`Health: ${healthLabel}`);
|
|
246
|
+
if (healthDetails && process.env.CLI_VERBOSE === 'true') {
|
|
247
|
+
console.log(chalk.gray(`Health details: ${healthDetails}`));
|
|
248
|
+
}
|
|
196
249
|
if (status.connected) {
|
|
197
250
|
if (status.mode === 'remote') {
|
|
198
|
-
console.log(`\n${
|
|
251
|
+
console.log(`\n${chalk.cyan('Features:')}`);
|
|
199
252
|
console.log('⢠Real-time updates via SSE');
|
|
200
253
|
console.log('⢠Authenticated API access');
|
|
201
254
|
console.log('⢠MCP-compatible tool interface');
|
|
202
255
|
}
|
|
203
256
|
else if (status.mode === 'websocket') {
|
|
204
|
-
console.log(`\n${
|
|
257
|
+
console.log(`\n${chalk.cyan('Features:')}`);
|
|
205
258
|
console.log('⢠Bi-directional real-time communication');
|
|
206
259
|
console.log('⢠Authenticated WebSocket connection');
|
|
207
260
|
console.log('⢠Production-ready MCP server');
|
|
@@ -212,29 +265,29 @@ function mcpCommands(program) {
|
|
|
212
265
|
mcp.command('tools')
|
|
213
266
|
.description('List available MCP tools')
|
|
214
267
|
.action(async () => {
|
|
215
|
-
const spinner = (
|
|
268
|
+
const spinner = ora('Fetching available tools...').start();
|
|
216
269
|
try {
|
|
217
|
-
const client =
|
|
270
|
+
const client = getMCPClient();
|
|
218
271
|
if (!client.isConnectedToServer()) {
|
|
219
272
|
spinner.info('Not connected. Attempting auto-connect...');
|
|
220
|
-
const config = new
|
|
273
|
+
const config = new CLIConfig();
|
|
221
274
|
const useRemote = !!config.get('token');
|
|
222
275
|
await client.connect({ useRemote });
|
|
223
276
|
}
|
|
224
277
|
const tools = await client.listTools();
|
|
225
278
|
spinner.succeed('Tools fetched successfully');
|
|
226
|
-
console.log(
|
|
227
|
-
console.log(
|
|
279
|
+
console.log(chalk.cyan('\nš§ Available MCP Tools'));
|
|
280
|
+
console.log(chalk.cyan('====================='));
|
|
228
281
|
const tableData = [
|
|
229
|
-
[
|
|
282
|
+
[chalk.bold('Tool Name'), chalk.bold('Description')]
|
|
230
283
|
];
|
|
231
284
|
tools.forEach(tool => {
|
|
232
285
|
tableData.push([
|
|
233
|
-
|
|
286
|
+
chalk.green(tool.name),
|
|
234
287
|
tool.description
|
|
235
288
|
]);
|
|
236
289
|
});
|
|
237
|
-
console.log(
|
|
290
|
+
console.log(table(tableData, {
|
|
238
291
|
border: {
|
|
239
292
|
topBody: 'ā',
|
|
240
293
|
topJoin: 'ā¬',
|
|
@@ -265,12 +318,12 @@ function mcpCommands(program) {
|
|
|
265
318
|
.argument('<tool>', 'Tool name to call')
|
|
266
319
|
.option('-a, --args <json>', 'Tool arguments as JSON')
|
|
267
320
|
.action(async (toolName, options) => {
|
|
268
|
-
const spinner = (
|
|
321
|
+
const spinner = ora(`Calling tool: ${toolName}...`).start();
|
|
269
322
|
try {
|
|
270
|
-
const client =
|
|
323
|
+
const client = getMCPClient();
|
|
271
324
|
if (!client.isConnectedToServer()) {
|
|
272
325
|
spinner.info('Not connected. Attempting auto-connect...');
|
|
273
|
-
const config = new
|
|
326
|
+
const config = new CLIConfig();
|
|
274
327
|
const useRemote = !!config.get('token');
|
|
275
328
|
await client.connect({ useRemote });
|
|
276
329
|
}
|
|
@@ -286,7 +339,7 @@ function mcpCommands(program) {
|
|
|
286
339
|
}
|
|
287
340
|
const result = await client.callTool(toolName, args);
|
|
288
341
|
spinner.succeed(`Tool ${toolName} executed successfully`);
|
|
289
|
-
console.log(
|
|
342
|
+
console.log(chalk.cyan('\nš¤ Tool Result:'));
|
|
290
343
|
console.log(JSON.stringify(result, null, 2));
|
|
291
344
|
}
|
|
292
345
|
catch (error) {
|
|
@@ -304,12 +357,12 @@ function mcpCommands(program) {
|
|
|
304
357
|
.option('-T, --type <type>', 'Memory type', 'context')
|
|
305
358
|
.option('--tags <tags>', 'Comma-separated tags')
|
|
306
359
|
.action(async (options) => {
|
|
307
|
-
const spinner = (
|
|
360
|
+
const spinner = ora('Creating memory via MCP...').start();
|
|
308
361
|
try {
|
|
309
|
-
const client =
|
|
362
|
+
const client = getMCPClient();
|
|
310
363
|
if (!client.isConnectedToServer()) {
|
|
311
364
|
spinner.info('Not connected. Attempting auto-connect...');
|
|
312
|
-
const config = new
|
|
365
|
+
const config = new CLIConfig();
|
|
313
366
|
const useRemote = !!config.get('token');
|
|
314
367
|
await client.connect({ useRemote });
|
|
315
368
|
}
|
|
@@ -320,8 +373,8 @@ function mcpCommands(program) {
|
|
|
320
373
|
tags: options.tags ? options.tags.split(',').map((t) => t.trim()) : []
|
|
321
374
|
});
|
|
322
375
|
spinner.succeed('Memory created successfully');
|
|
323
|
-
console.log(
|
|
324
|
-
console.log(`ID: ${
|
|
376
|
+
console.log(chalk.green('\nā Memory created'));
|
|
377
|
+
console.log(`ID: ${chalk.cyan(result.id)}`);
|
|
325
378
|
console.log(`Title: ${result.title}`);
|
|
326
379
|
console.log(`Type: ${result.memory_type}`);
|
|
327
380
|
}
|
|
@@ -336,12 +389,12 @@ function mcpCommands(program) {
|
|
|
336
389
|
.option('-l, --limit <number>', 'Maximum results', '10')
|
|
337
390
|
.option('-t, --threshold <number>', 'Similarity threshold (0-1)', '0.7')
|
|
338
391
|
.action(async (query, options) => {
|
|
339
|
-
const spinner = (
|
|
392
|
+
const spinner = ora('Searching memories via MCP...').start();
|
|
340
393
|
try {
|
|
341
|
-
const client =
|
|
394
|
+
const client = getMCPClient();
|
|
342
395
|
if (!client.isConnectedToServer()) {
|
|
343
396
|
spinner.info('Not connected. Attempting auto-connect...');
|
|
344
|
-
const config = new
|
|
397
|
+
const config = new CLIConfig();
|
|
345
398
|
const useRemote = !!config.get('token');
|
|
346
399
|
await client.connect({ useRemote });
|
|
347
400
|
}
|
|
@@ -352,15 +405,15 @@ function mcpCommands(program) {
|
|
|
352
405
|
});
|
|
353
406
|
spinner.succeed(`Found ${results.length} memories`);
|
|
354
407
|
if (results.length === 0) {
|
|
355
|
-
console.log(
|
|
408
|
+
console.log(chalk.yellow('\nNo memories found matching your query'));
|
|
356
409
|
return;
|
|
357
410
|
}
|
|
358
|
-
console.log(
|
|
411
|
+
console.log(chalk.cyan('\nš Search Results:'));
|
|
359
412
|
results.forEach((memory, index) => {
|
|
360
|
-
console.log(`\n${
|
|
361
|
-
console.log(` ID: ${
|
|
362
|
-
console.log(` Type: ${
|
|
363
|
-
console.log(` Score: ${
|
|
413
|
+
console.log(`\n${chalk.bold(`${index + 1}. ${memory.title}`)}`);
|
|
414
|
+
console.log(` ID: ${chalk.gray(memory.id)}`);
|
|
415
|
+
console.log(` Type: ${chalk.blue(memory.memory_type)}`);
|
|
416
|
+
console.log(` Score: ${chalk.green((memory.relevance_score * 100).toFixed(1) + '%')}`);
|
|
364
417
|
console.log(` Content: ${memory.content.substring(0, 100)}...`);
|
|
365
418
|
});
|
|
366
419
|
}
|
|
@@ -372,30 +425,36 @@ function mcpCommands(program) {
|
|
|
372
425
|
// Configure MCP preferences
|
|
373
426
|
mcp.command('config')
|
|
374
427
|
.description('Configure MCP preferences')
|
|
375
|
-
.option('--prefer-
|
|
376
|
-
.option('--prefer-
|
|
428
|
+
.option('--prefer-websocket', 'Prefer WebSocket MCP connection (recommended for production)')
|
|
429
|
+
.option('--prefer-remote', 'Prefer remote MCP server (REST/SSE mode)')
|
|
430
|
+
.option('--prefer-local', 'Prefer local MCP server (development only)')
|
|
377
431
|
.option('--auto', 'Auto-detect best connection mode')
|
|
378
432
|
.action(async (options) => {
|
|
379
|
-
const config = new
|
|
380
|
-
if (options.
|
|
433
|
+
const config = new CLIConfig();
|
|
434
|
+
if (options.preferWebsocket) {
|
|
435
|
+
await config.setAndSave('mcpPreference', 'websocket');
|
|
436
|
+
console.log(chalk.green('ā Set MCP preference to WebSocket (production mode)'));
|
|
437
|
+
}
|
|
438
|
+
else if (options.preferRemote) {
|
|
381
439
|
await config.setAndSave('mcpPreference', 'remote');
|
|
382
|
-
console.log(
|
|
440
|
+
console.log(chalk.green('ā Set MCP preference to remote (REST/SSE mode)'));
|
|
383
441
|
}
|
|
384
442
|
else if (options.preferLocal) {
|
|
385
443
|
await config.setAndSave('mcpPreference', 'local');
|
|
386
|
-
console.log(
|
|
444
|
+
console.log(chalk.green('ā Set MCP preference to local (development only)'));
|
|
387
445
|
}
|
|
388
446
|
else if (options.auto) {
|
|
389
447
|
await config.setAndSave('mcpPreference', 'auto');
|
|
390
|
-
console.log(
|
|
448
|
+
console.log(chalk.green('ā Set MCP preference to auto-detect'));
|
|
391
449
|
}
|
|
392
450
|
else {
|
|
393
451
|
const current = config.get('mcpPreference') || 'auto';
|
|
394
|
-
console.log(`Current MCP preference: ${
|
|
452
|
+
console.log(`Current MCP preference: ${chalk.cyan(current)}`);
|
|
395
453
|
console.log('\nOptions:');
|
|
396
|
-
console.log(' --prefer-
|
|
397
|
-
console.log(' --prefer-
|
|
398
|
-
console.log(' --
|
|
454
|
+
console.log(' --prefer-websocket : Use WebSocket mode (recommended for production)');
|
|
455
|
+
console.log(' --prefer-remote : Use remote REST/SSE mode (alternative)');
|
|
456
|
+
console.log(' --prefer-local : Use local stdio mode (development only)');
|
|
457
|
+
console.log(' --auto : Auto-detect based on configuration (default)');
|
|
399
458
|
}
|
|
400
459
|
});
|
|
401
460
|
// Diagnose MCP connection issues
|
|
@@ -403,10 +462,10 @@ function mcpCommands(program) {
|
|
|
403
462
|
.description('Diagnose MCP connection issues')
|
|
404
463
|
.option('-v, --verbose', 'show detailed diagnostic information')
|
|
405
464
|
.action(async (options) => {
|
|
406
|
-
const config = new
|
|
465
|
+
const config = new CLIConfig();
|
|
407
466
|
await config.init();
|
|
408
|
-
console.log(
|
|
409
|
-
console.log(
|
|
467
|
+
console.log(chalk.blue.bold('š MCP Connection Diagnostic'));
|
|
468
|
+
console.log(chalk.cyan('ā'.repeat(50)));
|
|
410
469
|
console.log();
|
|
411
470
|
const diagnostics = {
|
|
412
471
|
authenticationValid: false,
|
|
@@ -422,64 +481,64 @@ function mcpCommands(program) {
|
|
|
422
481
|
healthCheckPassing: false
|
|
423
482
|
};
|
|
424
483
|
// Step 1: Check authentication status
|
|
425
|
-
console.log(
|
|
484
|
+
console.log(chalk.cyan('1. Authentication Status'));
|
|
426
485
|
const token = config.getToken();
|
|
427
486
|
const vendorKey = config.getVendorKey();
|
|
428
487
|
if (!token && !vendorKey) {
|
|
429
|
-
console.log(
|
|
430
|
-
console.log(
|
|
431
|
-
console.log(
|
|
488
|
+
console.log(chalk.red(' ā No authentication credentials found'));
|
|
489
|
+
console.log(chalk.gray(' ā Run: lanonasis auth login'));
|
|
490
|
+
console.log(chalk.gray(' ā MCP requires authentication for remote access'));
|
|
432
491
|
}
|
|
433
492
|
else {
|
|
434
493
|
try {
|
|
435
494
|
const isValid = await config.validateStoredCredentials();
|
|
436
495
|
diagnostics.authenticationValid = isValid;
|
|
437
496
|
if (isValid) {
|
|
438
|
-
console.log(
|
|
497
|
+
console.log(chalk.green(' ā Authentication credentials are valid'));
|
|
439
498
|
}
|
|
440
499
|
else {
|
|
441
|
-
console.log(
|
|
442
|
-
console.log(
|
|
500
|
+
console.log(chalk.red(' ā Authentication credentials are invalid'));
|
|
501
|
+
console.log(chalk.gray(' ā Run: lanonasis auth login'));
|
|
443
502
|
}
|
|
444
503
|
}
|
|
445
504
|
catch (error) {
|
|
446
|
-
console.log(
|
|
447
|
-
console.log(
|
|
505
|
+
console.log(chalk.yellow(' ā Could not validate authentication'));
|
|
506
|
+
console.log(chalk.gray(` ${error instanceof Error ? error.message : 'Unknown error'}`));
|
|
448
507
|
}
|
|
449
508
|
}
|
|
450
509
|
// Step 2: Test endpoint availability
|
|
451
|
-
console.log(
|
|
452
|
-
const spinner1 = (
|
|
510
|
+
console.log(chalk.cyan('\n2. Endpoint Availability'));
|
|
511
|
+
const spinner1 = ora('Testing MCP endpoints...').start();
|
|
453
512
|
try {
|
|
454
513
|
await config.discoverServices(options.verbose);
|
|
455
514
|
const services = config.get('discoveredServices');
|
|
456
515
|
if (services) {
|
|
457
516
|
spinner1.succeed('MCP endpoints discovered');
|
|
458
517
|
diagnostics.endpointsReachable = true;
|
|
459
|
-
console.log(
|
|
518
|
+
console.log(chalk.green(' ā Service discovery successful'));
|
|
460
519
|
if (options.verbose) {
|
|
461
520
|
const svc = services;
|
|
462
|
-
console.log(
|
|
463
|
-
console.log(
|
|
464
|
-
console.log(
|
|
521
|
+
console.log(chalk.gray(` HTTP: ${svc.mcp_base}`));
|
|
522
|
+
console.log(chalk.gray(` WebSocket: ${svc.mcp_ws_base}`));
|
|
523
|
+
console.log(chalk.gray(` SSE: ${svc.mcp_sse_base}`));
|
|
465
524
|
}
|
|
466
525
|
}
|
|
467
526
|
else {
|
|
468
527
|
spinner1.warn('Using fallback endpoints');
|
|
469
|
-
console.log(
|
|
528
|
+
console.log(chalk.yellow(' ā Service discovery failed, using fallbacks'));
|
|
470
529
|
diagnostics.endpointsReachable = true; // Fallbacks still work
|
|
471
530
|
}
|
|
472
531
|
}
|
|
473
532
|
catch (error) {
|
|
474
533
|
spinner1.fail('Endpoint discovery failed');
|
|
475
|
-
console.log(
|
|
476
|
-
console.log(
|
|
534
|
+
console.log(chalk.red(' ā Cannot discover MCP endpoints'));
|
|
535
|
+
console.log(chalk.gray(` ${error instanceof Error ? error.message : 'Unknown error'}`));
|
|
477
536
|
}
|
|
478
537
|
// Step 3: Test transport protocols
|
|
479
|
-
console.log(
|
|
538
|
+
console.log(chalk.cyan('\n3. Transport Protocol Tests'));
|
|
480
539
|
// Test HTTP/REST endpoint
|
|
481
540
|
if (diagnostics.authenticationValid) {
|
|
482
|
-
const httpSpinner = (
|
|
541
|
+
const httpSpinner = ora('Testing HTTP transport...').start();
|
|
483
542
|
try {
|
|
484
543
|
const startTime = Date.now();
|
|
485
544
|
const axios = (await import('axios')).default;
|
|
@@ -495,22 +554,22 @@ function mcpCommands(program) {
|
|
|
495
554
|
diagnostics.connectionLatency.http = latency;
|
|
496
555
|
diagnostics.transportTests.http = true;
|
|
497
556
|
httpSpinner.succeed(`HTTP transport working (${latency}ms)`);
|
|
498
|
-
console.log(
|
|
557
|
+
console.log(chalk.green(` ā HTTP/REST endpoint reachable`));
|
|
499
558
|
}
|
|
500
559
|
catch (error) {
|
|
501
560
|
httpSpinner.fail('HTTP transport failed');
|
|
502
|
-
console.log(
|
|
561
|
+
console.log(chalk.red(' ā HTTP/REST endpoint failed'));
|
|
503
562
|
if (options.verbose) {
|
|
504
|
-
console.log(
|
|
563
|
+
console.log(chalk.gray(` Error: ${error instanceof Error ? error.message : String(error)}`));
|
|
505
564
|
}
|
|
506
565
|
}
|
|
507
566
|
// Test WebSocket endpoint
|
|
508
|
-
const wsSpinner = (
|
|
567
|
+
const wsSpinner = ora('Testing WebSocket transport...').start();
|
|
509
568
|
try {
|
|
510
569
|
const startTime = Date.now();
|
|
511
570
|
const wsUrl = config.getMCPServerUrl();
|
|
512
571
|
// Create a test WebSocket connection
|
|
513
|
-
const ws = new
|
|
572
|
+
const ws = new WebSocket(wsUrl, [], {
|
|
514
573
|
headers: {
|
|
515
574
|
'Authorization': `Bearer ${token}`,
|
|
516
575
|
'X-API-Key': String(token || vendorKey)
|
|
@@ -535,17 +594,17 @@ function mcpCommands(program) {
|
|
|
535
594
|
});
|
|
536
595
|
});
|
|
537
596
|
wsSpinner.succeed(`WebSocket transport working (${diagnostics.connectionLatency.websocket}ms)`);
|
|
538
|
-
console.log(
|
|
597
|
+
console.log(chalk.green(' ā WebSocket endpoint reachable'));
|
|
539
598
|
}
|
|
540
599
|
catch (error) {
|
|
541
600
|
wsSpinner.fail('WebSocket transport failed');
|
|
542
|
-
console.log(
|
|
601
|
+
console.log(chalk.red(' ā WebSocket endpoint failed'));
|
|
543
602
|
if (options.verbose) {
|
|
544
|
-
console.log(
|
|
603
|
+
console.log(chalk.gray(` Error: ${error instanceof Error ? error.message : String(error)}`));
|
|
545
604
|
}
|
|
546
605
|
}
|
|
547
606
|
// Test SSE endpoint
|
|
548
|
-
const sseSpinner = (
|
|
607
|
+
const sseSpinner = ora('Testing SSE transport...').start();
|
|
549
608
|
try {
|
|
550
609
|
const startTime = Date.now();
|
|
551
610
|
const sseUrl = config.getMCPSSEUrl();
|
|
@@ -562,86 +621,86 @@ function mcpCommands(program) {
|
|
|
562
621
|
diagnostics.connectionLatency.sse = latency;
|
|
563
622
|
diagnostics.transportTests.sse = true;
|
|
564
623
|
sseSpinner.succeed(`SSE transport working (${latency}ms)`);
|
|
565
|
-
console.log(
|
|
624
|
+
console.log(chalk.green(' ā SSE endpoint reachable'));
|
|
566
625
|
}
|
|
567
626
|
catch (error) {
|
|
568
627
|
sseSpinner.fail('SSE transport failed');
|
|
569
|
-
console.log(
|
|
628
|
+
console.log(chalk.red(' ā SSE endpoint failed'));
|
|
570
629
|
if (options.verbose) {
|
|
571
|
-
console.log(
|
|
630
|
+
console.log(chalk.gray(` Error: ${error instanceof Error ? error.message : String(error)}`));
|
|
572
631
|
}
|
|
573
632
|
}
|
|
574
633
|
}
|
|
575
634
|
else {
|
|
576
|
-
console.log(
|
|
635
|
+
console.log(chalk.gray(' - Skipped transport tests (authentication required)'));
|
|
577
636
|
}
|
|
578
637
|
// Step 4: Test current MCP connection
|
|
579
|
-
console.log(
|
|
580
|
-
const client =
|
|
638
|
+
console.log(chalk.cyan('\n4. Current MCP Connection'));
|
|
639
|
+
const client = getMCPClient();
|
|
581
640
|
diagnostics.currentConnection = client.getConnectionStatus();
|
|
582
641
|
if (diagnostics.currentConnection.connected) {
|
|
583
|
-
console.log(
|
|
584
|
-
console.log(
|
|
585
|
-
console.log(
|
|
642
|
+
console.log(chalk.green(' ā MCP client is connected'));
|
|
643
|
+
console.log(chalk.gray(` Mode: ${diagnostics.currentConnection.mode}`));
|
|
644
|
+
console.log(chalk.gray(` Server: ${diagnostics.currentConnection.server}`));
|
|
586
645
|
if (diagnostics.currentConnection.connectionUptime) {
|
|
587
646
|
const uptimeSeconds = Math.floor(diagnostics.currentConnection.connectionUptime / 1000);
|
|
588
|
-
console.log(
|
|
647
|
+
console.log(chalk.gray(` Uptime: ${uptimeSeconds}s`));
|
|
589
648
|
}
|
|
590
649
|
if (diagnostics.currentConnection.lastHealthCheck) {
|
|
591
650
|
const healthCheckAge = Date.now() - diagnostics.currentConnection.lastHealthCheck.getTime();
|
|
592
|
-
console.log(
|
|
651
|
+
console.log(chalk.gray(` Last health check: ${Math.floor(healthCheckAge / 1000)}s ago`));
|
|
593
652
|
}
|
|
594
653
|
}
|
|
595
654
|
else {
|
|
596
|
-
console.log(
|
|
597
|
-
console.log(
|
|
655
|
+
console.log(chalk.red(' ā MCP client is not connected'));
|
|
656
|
+
console.log(chalk.gray(' ā Try: lanonasis mcp connect'));
|
|
598
657
|
}
|
|
599
658
|
// Step 5: Test tool availability
|
|
600
|
-
console.log(
|
|
659
|
+
console.log(chalk.cyan('\n5. Tool Availability'));
|
|
601
660
|
if (diagnostics.currentConnection.connected) {
|
|
602
|
-
const toolSpinner = (
|
|
661
|
+
const toolSpinner = ora('Testing MCP tools...').start();
|
|
603
662
|
try {
|
|
604
663
|
const tools = await client.listTools();
|
|
605
664
|
diagnostics.toolsAvailable = tools.length > 0;
|
|
606
665
|
toolSpinner.succeed(`Found ${tools.length} available tools`);
|
|
607
|
-
console.log(
|
|
666
|
+
console.log(chalk.green(` ā ${tools.length} MCP tools available`));
|
|
608
667
|
if (options.verbose && tools.length > 0) {
|
|
609
|
-
console.log(
|
|
668
|
+
console.log(chalk.gray(' Available tools:'));
|
|
610
669
|
tools.slice(0, 5).forEach(tool => {
|
|
611
|
-
console.log(
|
|
670
|
+
console.log(chalk.gray(` ⢠${tool.name}`));
|
|
612
671
|
});
|
|
613
672
|
if (tools.length > 5) {
|
|
614
|
-
console.log(
|
|
673
|
+
console.log(chalk.gray(` ... and ${tools.length - 5} more`));
|
|
615
674
|
}
|
|
616
675
|
}
|
|
617
676
|
}
|
|
618
677
|
catch (error) {
|
|
619
678
|
toolSpinner.fail('Tool listing failed');
|
|
620
|
-
console.log(
|
|
679
|
+
console.log(chalk.red(' ā Cannot list MCP tools'));
|
|
621
680
|
if (options.verbose) {
|
|
622
|
-
console.log(
|
|
681
|
+
console.log(chalk.gray(` Error: ${error instanceof Error ? error.message : 'Unknown error'}`));
|
|
623
682
|
}
|
|
624
683
|
}
|
|
625
684
|
}
|
|
626
685
|
else {
|
|
627
|
-
console.log(
|
|
686
|
+
console.log(chalk.gray(' - Skipped (not connected to MCP server)'));
|
|
628
687
|
}
|
|
629
688
|
// Step 6: Connection quality measurement
|
|
630
|
-
console.log(
|
|
689
|
+
console.log(chalk.cyan('\n6. Connection Quality'));
|
|
631
690
|
if (Object.keys(diagnostics.connectionLatency).length > 0) {
|
|
632
|
-
console.log(
|
|
691
|
+
console.log(chalk.green(' ā Latency measurements:'));
|
|
633
692
|
Object.entries(diagnostics.connectionLatency).forEach(([transport, latency]) => {
|
|
634
693
|
const quality = latency < 100 ? 'Excellent' : latency < 300 ? 'Good' : latency < 1000 ? 'Fair' : 'Poor';
|
|
635
|
-
const color = latency < 100 ?
|
|
694
|
+
const color = latency < 100 ? chalk.green : latency < 300 ? chalk.yellow : chalk.red;
|
|
636
695
|
console.log(color(` ${transport.toUpperCase()}: ${latency}ms (${quality})`));
|
|
637
696
|
});
|
|
638
697
|
}
|
|
639
698
|
else {
|
|
640
|
-
console.log(
|
|
699
|
+
console.log(chalk.gray(' - No latency measurements available'));
|
|
641
700
|
}
|
|
642
701
|
// Summary and recommendations
|
|
643
|
-
console.log(
|
|
644
|
-
console.log(
|
|
702
|
+
console.log(chalk.blue.bold('\nš MCP Diagnostic Summary'));
|
|
703
|
+
console.log(chalk.cyan('ā'.repeat(50)));
|
|
645
704
|
const issues = [];
|
|
646
705
|
const recommendations = [];
|
|
647
706
|
if (!diagnostics.authenticationValid) {
|
|
@@ -671,30 +730,30 @@ function mcpCommands(program) {
|
|
|
671
730
|
}
|
|
672
731
|
// Show results
|
|
673
732
|
if (issues.length === 0) {
|
|
674
|
-
console.log(
|
|
675
|
-
console.log(
|
|
733
|
+
console.log(chalk.green('ā
All MCP connection checks passed!'));
|
|
734
|
+
console.log(chalk.cyan(' Your MCP connection is working correctly.'));
|
|
676
735
|
if (Object.keys(diagnostics.connectionLatency).length > 0) {
|
|
677
736
|
const avgLatency = Object.values(diagnostics.connectionLatency).reduce((a, b) => a + b, 0) / Object.values(diagnostics.connectionLatency).length;
|
|
678
|
-
console.log(
|
|
737
|
+
console.log(chalk.cyan(` Average latency: ${Math.round(avgLatency)}ms`));
|
|
679
738
|
}
|
|
680
739
|
}
|
|
681
740
|
else {
|
|
682
|
-
console.log(
|
|
741
|
+
console.log(chalk.red(`ā Found ${issues.length} issue(s):`));
|
|
683
742
|
issues.forEach(issue => {
|
|
684
|
-
console.log(
|
|
743
|
+
console.log(chalk.red(` ⢠${issue}`));
|
|
685
744
|
});
|
|
686
|
-
console.log(
|
|
745
|
+
console.log(chalk.yellow('\nš” Recommended actions:'));
|
|
687
746
|
recommendations.forEach(rec => {
|
|
688
|
-
console.log(
|
|
747
|
+
console.log(chalk.cyan(` ⢠${rec}`));
|
|
689
748
|
});
|
|
690
749
|
}
|
|
691
750
|
// Additional troubleshooting info
|
|
692
751
|
if (issues.length > 0) {
|
|
693
|
-
console.log(
|
|
694
|
-
console.log(
|
|
695
|
-
console.log(
|
|
696
|
-
console.log(
|
|
697
|
-
console.log(
|
|
752
|
+
console.log(chalk.gray('\nš§ Additional troubleshooting:'));
|
|
753
|
+
console.log(chalk.gray(' ⢠Try different connection modes: --mode websocket|remote|local'));
|
|
754
|
+
console.log(chalk.gray(' ⢠Check firewall settings for ports 80, 443, and WebSocket'));
|
|
755
|
+
console.log(chalk.gray(' ⢠Verify your network allows outbound HTTPS connections'));
|
|
756
|
+
console.log(chalk.gray(' ⢠Contact support if issues persist'));
|
|
698
757
|
}
|
|
699
758
|
});
|
|
700
759
|
}
|