@lanonasis/cli 3.7.8 → 3.8.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/commands/auth.js +4 -6
- package/dist/commands/config.js +4 -3
- package/dist/commands/mcp.js +60 -5
- package/dist/commands/memory.js +2 -2
- package/dist/mcp/access-control.js +2 -2
- package/dist/mcp/schemas/tool-schemas.d.ts +12 -12
- package/dist/mcp/server/lanonasis-server.d.ts +9 -0
- package/dist/mcp/server/lanonasis-server.js +55 -3
- package/dist/mcp-server-entry.d.ts +20 -0
- package/dist/mcp-server-entry.js +54 -0
- package/dist/mcp-server.js +2 -1
- package/dist/utils/api.js +11 -11
- package/dist/utils/config.d.ts +1 -0
- package/dist/utils/config.js +84 -21
- package/dist/utils/crypto-utils.js +1 -1
- package/package.json +6 -5
package/dist/commands/auth.js
CHANGED
|
@@ -370,7 +370,7 @@ export async function diagnoseCommand() {
|
|
|
370
370
|
// Step 2: Check stored credentials
|
|
371
371
|
console.log(chalk.cyan('\n2. Stored Credentials'));
|
|
372
372
|
const token = config.getToken();
|
|
373
|
-
const vendorKey = config.
|
|
373
|
+
const vendorKey = await config.getVendorKeyAsync();
|
|
374
374
|
const authMethod = config.get('authMethod');
|
|
375
375
|
if (vendorKey) {
|
|
376
376
|
diagnostics.hasCredentials = true;
|
|
@@ -707,7 +707,7 @@ async function handleOAuthFlow(config) {
|
|
|
707
707
|
await config.setToken(tokens.access_token);
|
|
708
708
|
await config.set('refresh_token', tokens.refresh_token);
|
|
709
709
|
await config.set('token_expires_at', Date.now() + (tokens.expires_in * 1000));
|
|
710
|
-
await config.set('authMethod', '
|
|
710
|
+
await config.set('authMethod', 'oauth');
|
|
711
711
|
// The OAuth access token from auth-gateway works as the API token for all services
|
|
712
712
|
// Store it as the vendor key equivalent for MCP and API access
|
|
713
713
|
spinner.text = 'Configuring unified access...';
|
|
@@ -825,10 +825,8 @@ async function handleCredentialsFlow(options, config) {
|
|
|
825
825
|
if (response.user.role) {
|
|
826
826
|
console.log(`Role: ${response.user.role}`);
|
|
827
827
|
}
|
|
828
|
-
console.log(chalk.gray('✓ API access configured'));
|
|
829
|
-
console.log();
|
|
830
|
-
console.log(chalk.dim('Note: MCP WebSocket commands require a vendor key.'));
|
|
831
|
-
console.log(chalk.dim('Run'), chalk.white('onasis auth vendor-key <key>'), chalk.dim('to configure MCP access.'));
|
|
828
|
+
console.log(chalk.gray('✓ API and MCP access configured'));
|
|
829
|
+
console.log(chalk.dim('Your JWT token works with all services: API, MCP, CLI.'));
|
|
832
830
|
}
|
|
833
831
|
catch (error) {
|
|
834
832
|
spinner.fail('Login failed');
|
package/dist/commands/config.js
CHANGED
|
@@ -382,7 +382,7 @@ export function configCommands(program) {
|
|
|
382
382
|
// Step 2: Validate authentication configuration
|
|
383
383
|
console.log(chalk.cyan('\n2. Authentication Configuration'));
|
|
384
384
|
const token = config.getToken();
|
|
385
|
-
const vendorKey = config.
|
|
385
|
+
const vendorKey = await config.getVendorKeyAsync();
|
|
386
386
|
const authMethod = config.get('authMethod');
|
|
387
387
|
if (!token && !vendorKey) {
|
|
388
388
|
console.log(chalk.yellow(' ⚠ No authentication credentials configured'));
|
|
@@ -391,8 +391,9 @@ export function configCommands(program) {
|
|
|
391
391
|
else {
|
|
392
392
|
console.log(chalk.green(' ✓ Authentication credentials found'));
|
|
393
393
|
// Validate auth method consistency
|
|
394
|
-
|
|
395
|
-
|
|
394
|
+
// Note: OAuth users can have vendorKey stored (for MCP access) while authMethod is 'oauth'
|
|
395
|
+
if (vendorKey && authMethod !== 'vendor_key' && authMethod !== 'oauth') {
|
|
396
|
+
console.log(chalk.yellow(' ⚠ Auth method mismatch (has vendor key but method is not vendor_key or oauth)'));
|
|
396
397
|
validation.issues.push('Auth method mismatch');
|
|
397
398
|
if (options.repair) {
|
|
398
399
|
config.set('authMethod', 'vendor_key');
|
package/dist/commands/mcp.js
CHANGED
|
@@ -169,6 +169,7 @@ export function mcpCommands(program) {
|
|
|
169
169
|
const client = getMCPClient();
|
|
170
170
|
await client.disconnect();
|
|
171
171
|
console.log(chalk.green('✓ Disconnected from MCP server'));
|
|
172
|
+
process.exit(0);
|
|
172
173
|
});
|
|
173
174
|
// Status command
|
|
174
175
|
mcp.command('status')
|
|
@@ -183,6 +184,7 @@ export function mcpCommands(program) {
|
|
|
183
184
|
await config.init();
|
|
184
185
|
let healthLabel = chalk.gray('Unknown');
|
|
185
186
|
let healthDetails;
|
|
187
|
+
let isServiceReachable = false;
|
|
186
188
|
try {
|
|
187
189
|
const axios = (await import('axios')).default;
|
|
188
190
|
// Derive MCP health URL from discovered REST base (e.g. https://mcp.lanonasis.com/api/v1 -> https://mcp.lanonasis.com/health)
|
|
@@ -190,7 +192,7 @@ export function mcpCommands(program) {
|
|
|
190
192
|
const rootBase = restUrl.replace(/\/api\/v1$/, '');
|
|
191
193
|
const healthUrl = `${rootBase}/health`;
|
|
192
194
|
const token = config.getToken();
|
|
193
|
-
const vendorKey = config.
|
|
195
|
+
const vendorKey = await config.getVendorKeyAsync();
|
|
194
196
|
const headers = {};
|
|
195
197
|
if (vendorKey) {
|
|
196
198
|
headers['X-API-Key'] = vendorKey;
|
|
@@ -207,14 +209,17 @@ export function mcpCommands(program) {
|
|
|
207
209
|
const overallStatus = String(response.data?.status ?? '').toLowerCase();
|
|
208
210
|
const ok = response.status === 200 && (!overallStatus || overallStatus === 'healthy');
|
|
209
211
|
if (ok) {
|
|
210
|
-
healthLabel = chalk.green('
|
|
212
|
+
healthLabel = chalk.green('Healthy');
|
|
213
|
+
isServiceReachable = true;
|
|
211
214
|
}
|
|
212
215
|
else {
|
|
213
216
|
healthLabel = chalk.yellow('Degraded');
|
|
217
|
+
isServiceReachable = true; // Service is reachable but degraded
|
|
214
218
|
}
|
|
215
219
|
}
|
|
216
220
|
catch (error) {
|
|
217
221
|
healthLabel = chalk.red('Unreachable');
|
|
222
|
+
isServiceReachable = false;
|
|
218
223
|
if (error instanceof Error) {
|
|
219
224
|
healthDetails = error.message;
|
|
220
225
|
}
|
|
@@ -224,7 +229,14 @@ export function mcpCommands(program) {
|
|
|
224
229
|
}
|
|
225
230
|
console.log(chalk.cyan('\n📊 MCP Connection Status'));
|
|
226
231
|
console.log(chalk.cyan('========================'));
|
|
227
|
-
|
|
232
|
+
// Show status based on service reachability, not in-memory connection state
|
|
233
|
+
// The CLI isn't a persistent daemon - "connected" means the service is available
|
|
234
|
+
if (isServiceReachable) {
|
|
235
|
+
console.log(`Status: ${chalk.green('Ready')} (service reachable)`);
|
|
236
|
+
}
|
|
237
|
+
else {
|
|
238
|
+
console.log(`Status: ${chalk.red('Unavailable')} (service unreachable)`);
|
|
239
|
+
}
|
|
228
240
|
// Display mode with proper labels
|
|
229
241
|
let modeDisplay;
|
|
230
242
|
switch (status.mode) {
|
|
@@ -246,7 +258,8 @@ export function mcpCommands(program) {
|
|
|
246
258
|
if (healthDetails && process.env.CLI_VERBOSE === 'true') {
|
|
247
259
|
console.log(chalk.gray(`Health details: ${healthDetails}`));
|
|
248
260
|
}
|
|
249
|
-
|
|
261
|
+
// Show features when service is reachable
|
|
262
|
+
if (isServiceReachable) {
|
|
250
263
|
if (status.mode === 'remote') {
|
|
251
264
|
console.log(`\n${chalk.cyan('Features:')}`);
|
|
252
265
|
console.log('• Real-time updates via SSE');
|
|
@@ -259,7 +272,12 @@ export function mcpCommands(program) {
|
|
|
259
272
|
console.log('• Authenticated WebSocket connection');
|
|
260
273
|
console.log('• Production-ready MCP server');
|
|
261
274
|
}
|
|
275
|
+
console.log(chalk.green('\n✓ MCP tools are available. Run "lanonasis mcp tools" to see them.'));
|
|
276
|
+
}
|
|
277
|
+
else {
|
|
278
|
+
console.log(chalk.yellow('\n⚠ MCP service is not reachable. Run "lanonasis mcp diagnose" for troubleshooting.'));
|
|
262
279
|
}
|
|
280
|
+
process.exit(0);
|
|
263
281
|
});
|
|
264
282
|
// List tools command
|
|
265
283
|
mcp.command('tools')
|
|
@@ -456,6 +474,42 @@ export function mcpCommands(program) {
|
|
|
456
474
|
console.log(' --prefer-local : Use local stdio mode (development only)');
|
|
457
475
|
console.log(' --auto : Auto-detect based on configuration (default)');
|
|
458
476
|
}
|
|
477
|
+
process.exit(0);
|
|
478
|
+
});
|
|
479
|
+
// Start MCP server for external clients
|
|
480
|
+
mcp.command('start')
|
|
481
|
+
.description('Start MCP server for external clients (Claude Desktop, Cursor, etc.)')
|
|
482
|
+
.option('--transport <type>', 'Transport: stdio (default), ws, http, sse', 'stdio')
|
|
483
|
+
.option('--port <number>', 'Port for ws/http/sse', '3009')
|
|
484
|
+
.option('--host <address>', 'Host address', '127.0.0.1')
|
|
485
|
+
.action(async (options) => {
|
|
486
|
+
const apiKey = process.env.LANONASIS_API_KEY;
|
|
487
|
+
if (!apiKey) {
|
|
488
|
+
console.error('Error: LANONASIS_API_KEY environment variable required');
|
|
489
|
+
process.exit(1);
|
|
490
|
+
}
|
|
491
|
+
try {
|
|
492
|
+
const { LanonasisMCPServer } = await import('../mcp/server/lanonasis-server.js');
|
|
493
|
+
const server = new LanonasisMCPServer({
|
|
494
|
+
apiKey,
|
|
495
|
+
transport: options.transport,
|
|
496
|
+
port: parseInt(options.port, 10),
|
|
497
|
+
host: options.host
|
|
498
|
+
});
|
|
499
|
+
if (options.transport === 'stdio') {
|
|
500
|
+
// Log to stderr since stdout is for MCP protocol
|
|
501
|
+
console.error(`Starting MCP server in stdio mode...`);
|
|
502
|
+
await server.startStdio();
|
|
503
|
+
}
|
|
504
|
+
else {
|
|
505
|
+
console.error(`Starting MCP server on ${options.host}:${options.port} (${options.transport})...`);
|
|
506
|
+
await server.start();
|
|
507
|
+
}
|
|
508
|
+
}
|
|
509
|
+
catch (error) {
|
|
510
|
+
console.error(`Failed to start MCP server: ${error instanceof Error ? error.message : 'Unknown error'}`);
|
|
511
|
+
process.exit(1);
|
|
512
|
+
}
|
|
459
513
|
});
|
|
460
514
|
// Diagnose MCP connection issues
|
|
461
515
|
mcp.command('diagnose')
|
|
@@ -483,7 +537,7 @@ export function mcpCommands(program) {
|
|
|
483
537
|
// Step 1: Check authentication status
|
|
484
538
|
console.log(chalk.cyan('1. Authentication Status'));
|
|
485
539
|
const token = config.getToken();
|
|
486
|
-
const vendorKey = config.
|
|
540
|
+
const vendorKey = await config.getVendorKeyAsync();
|
|
487
541
|
if (!token && !vendorKey) {
|
|
488
542
|
console.log(chalk.red(' ✖ No authentication credentials found'));
|
|
489
543
|
console.log(chalk.gray(' → Run: lanonasis auth login'));
|
|
@@ -755,5 +809,6 @@ export function mcpCommands(program) {
|
|
|
755
809
|
console.log(chalk.gray(' • Verify your network allows outbound HTTPS connections'));
|
|
756
810
|
console.log(chalk.gray(' • Contact support if issues persist'));
|
|
757
811
|
}
|
|
812
|
+
process.exit(0);
|
|
758
813
|
});
|
|
759
814
|
}
|
package/dist/commands/memory.js
CHANGED
|
@@ -31,9 +31,9 @@ export function memoryCommands(program) {
|
|
|
31
31
|
validate: (input) => input.length > 0 || 'Title is required'
|
|
32
32
|
},
|
|
33
33
|
{
|
|
34
|
-
type: '
|
|
34
|
+
type: 'input',
|
|
35
35
|
name: 'content',
|
|
36
|
-
message: 'Memory content:',
|
|
36
|
+
message: 'Memory content (or use -c flag for multi-line):',
|
|
37
37
|
default: content,
|
|
38
38
|
validate: (input) => input.length > 0 || 'Content is required'
|
|
39
39
|
},
|
|
@@ -192,7 +192,7 @@ export class MemoryAccessControl {
|
|
|
192
192
|
const apiUrl = this.config.get('apiUrl') || 'https://api.lanonasis.com';
|
|
193
193
|
const token = this.config.get('token');
|
|
194
194
|
const axios = (await import('axios')).default;
|
|
195
|
-
const response = await axios.get(`${apiUrl}/api/v1/
|
|
195
|
+
const response = await axios.get(`${apiUrl}/api/v1/memories/${memoryId}`, {
|
|
196
196
|
headers: {
|
|
197
197
|
'Authorization': `Bearer ${token}`,
|
|
198
198
|
'Content-Type': 'application/json'
|
|
@@ -210,7 +210,7 @@ export class MemoryAccessControl {
|
|
|
210
210
|
const apiUrl = this.config.get('apiUrl') || 'https://api.lanonasis.com';
|
|
211
211
|
const token = this.config.get('token');
|
|
212
212
|
const axios = (await import('axios')).default;
|
|
213
|
-
const response = await axios.get(`${apiUrl}/api/v1/
|
|
213
|
+
const response = await axios.get(`${apiUrl}/api/v1/memories?user_id=${userId}`, {
|
|
214
214
|
headers: {
|
|
215
215
|
'Authorization': `Bearer ${token}`,
|
|
216
216
|
'Content-Type': 'application/json'
|
|
@@ -15,15 +15,15 @@ export declare const MemoryCreateSchema: z.ZodObject<{
|
|
|
15
15
|
content?: string;
|
|
16
16
|
tags?: string[];
|
|
17
17
|
topic_id?: string;
|
|
18
|
-
memory_type?: "context" | "reference" | "note";
|
|
19
18
|
metadata?: Record<string, any>;
|
|
19
|
+
memory_type?: "context" | "reference" | "note";
|
|
20
20
|
}, {
|
|
21
21
|
title?: string;
|
|
22
22
|
content?: string;
|
|
23
23
|
tags?: string[];
|
|
24
24
|
topic_id?: string;
|
|
25
|
-
memory_type?: "context" | "reference" | "note";
|
|
26
25
|
metadata?: Record<string, any>;
|
|
26
|
+
memory_type?: "context" | "reference" | "note";
|
|
27
27
|
}>;
|
|
28
28
|
export declare const MemorySearchSchema: z.ZodObject<{
|
|
29
29
|
query: z.ZodString;
|
|
@@ -59,15 +59,15 @@ export declare const MemoryUpdateSchema: z.ZodObject<{
|
|
|
59
59
|
content?: string;
|
|
60
60
|
tags?: string[];
|
|
61
61
|
memory_id?: string;
|
|
62
|
-
memory_type?: "context" | "reference" | "note";
|
|
63
62
|
metadata?: Record<string, any>;
|
|
63
|
+
memory_type?: "context" | "reference" | "note";
|
|
64
64
|
}, {
|
|
65
65
|
title?: string;
|
|
66
66
|
content?: string;
|
|
67
67
|
tags?: string[];
|
|
68
68
|
memory_id?: string;
|
|
69
|
-
memory_type?: "context" | "reference" | "note";
|
|
70
69
|
metadata?: Record<string, any>;
|
|
70
|
+
memory_type?: "context" | "reference" | "note";
|
|
71
71
|
}>;
|
|
72
72
|
export declare const MemoryDeleteSchema: z.ZodObject<{
|
|
73
73
|
memory_id: z.ZodString;
|
|
@@ -217,13 +217,13 @@ export declare const BulkOperationSchema: z.ZodObject<{
|
|
|
217
217
|
transaction: z.ZodDefault<z.ZodBoolean>;
|
|
218
218
|
}, "strip", z.ZodTypeAny, {
|
|
219
219
|
operation?: "create" | "delete" | "update";
|
|
220
|
-
entity_type?: "topic" | "memory" | "apikey";
|
|
221
220
|
items?: Record<string, any>[];
|
|
221
|
+
entity_type?: "topic" | "memory" | "apikey";
|
|
222
222
|
transaction?: boolean;
|
|
223
223
|
}, {
|
|
224
224
|
operation?: "create" | "delete" | "update";
|
|
225
|
-
entity_type?: "topic" | "memory" | "apikey";
|
|
226
225
|
items?: Record<string, any>[];
|
|
226
|
+
entity_type?: "topic" | "memory" | "apikey";
|
|
227
227
|
transaction?: boolean;
|
|
228
228
|
}>;
|
|
229
229
|
export declare const ImportExportSchema: z.ZodObject<{
|
|
@@ -387,15 +387,15 @@ export declare const MCPSchemas: {
|
|
|
387
387
|
content?: string;
|
|
388
388
|
tags?: string[];
|
|
389
389
|
topic_id?: string;
|
|
390
|
-
memory_type?: "context" | "reference" | "note";
|
|
391
390
|
metadata?: Record<string, any>;
|
|
391
|
+
memory_type?: "context" | "reference" | "note";
|
|
392
392
|
}, {
|
|
393
393
|
title?: string;
|
|
394
394
|
content?: string;
|
|
395
395
|
tags?: string[];
|
|
396
396
|
topic_id?: string;
|
|
397
|
-
memory_type?: "context" | "reference" | "note";
|
|
398
397
|
metadata?: Record<string, any>;
|
|
398
|
+
memory_type?: "context" | "reference" | "note";
|
|
399
399
|
}>;
|
|
400
400
|
search: z.ZodObject<{
|
|
401
401
|
query: z.ZodString;
|
|
@@ -431,15 +431,15 @@ export declare const MCPSchemas: {
|
|
|
431
431
|
content?: string;
|
|
432
432
|
tags?: string[];
|
|
433
433
|
memory_id?: string;
|
|
434
|
-
memory_type?: "context" | "reference" | "note";
|
|
435
434
|
metadata?: Record<string, any>;
|
|
435
|
+
memory_type?: "context" | "reference" | "note";
|
|
436
436
|
}, {
|
|
437
437
|
title?: string;
|
|
438
438
|
content?: string;
|
|
439
439
|
tags?: string[];
|
|
440
440
|
memory_id?: string;
|
|
441
|
-
memory_type?: "context" | "reference" | "note";
|
|
442
441
|
metadata?: Record<string, any>;
|
|
442
|
+
memory_type?: "context" | "reference" | "note";
|
|
443
443
|
}>;
|
|
444
444
|
delete: z.ZodObject<{
|
|
445
445
|
memory_id: z.ZodString;
|
|
@@ -597,13 +597,13 @@ export declare const MCPSchemas: {
|
|
|
597
597
|
transaction: z.ZodDefault<z.ZodBoolean>;
|
|
598
598
|
}, "strip", z.ZodTypeAny, {
|
|
599
599
|
operation?: "create" | "delete" | "update";
|
|
600
|
-
entity_type?: "topic" | "memory" | "apikey";
|
|
601
600
|
items?: Record<string, any>[];
|
|
601
|
+
entity_type?: "topic" | "memory" | "apikey";
|
|
602
602
|
transaction?: boolean;
|
|
603
603
|
}, {
|
|
604
604
|
operation?: "create" | "delete" | "update";
|
|
605
|
-
entity_type?: "topic" | "memory" | "apikey";
|
|
606
605
|
items?: Record<string, any>[];
|
|
606
|
+
entity_type?: "topic" | "memory" | "apikey";
|
|
607
607
|
transaction?: boolean;
|
|
608
608
|
}>;
|
|
609
609
|
importExport: z.ZodObject<{
|
|
@@ -9,6 +9,10 @@ export interface LanonasisServerOptions {
|
|
|
9
9
|
verbose?: boolean;
|
|
10
10
|
apiUrl?: string;
|
|
11
11
|
token?: string;
|
|
12
|
+
apiKey?: string;
|
|
13
|
+
transport?: 'stdio' | 'ws' | 'http' | 'sse';
|
|
14
|
+
port?: number;
|
|
15
|
+
host?: string;
|
|
12
16
|
preferredTransport?: 'stdio' | 'websocket' | 'http';
|
|
13
17
|
enableTransportFallback?: boolean;
|
|
14
18
|
}
|
|
@@ -209,6 +213,11 @@ export declare class LanonasisMCPServer {
|
|
|
209
213
|
* Start the server
|
|
210
214
|
*/
|
|
211
215
|
start(): Promise<void>;
|
|
216
|
+
/**
|
|
217
|
+
* Start the server in stdio mode for external MCP clients (Claude Desktop, Cursor, etc.)
|
|
218
|
+
* This is the primary entry point for `lanonasis mcp start`
|
|
219
|
+
*/
|
|
220
|
+
startStdio(): Promise<void>;
|
|
212
221
|
/**
|
|
213
222
|
* Stop the server
|
|
214
223
|
*/
|
|
@@ -407,7 +407,15 @@ export class LanonasisMCPServer {
|
|
|
407
407
|
text: `Authentication Error: ${error instanceof Error ? error.message : 'Authentication failed'}`
|
|
408
408
|
}
|
|
409
409
|
],
|
|
410
|
-
isError: true
|
|
410
|
+
isError: true,
|
|
411
|
+
task: {
|
|
412
|
+
taskId: `${clientId}-${Date.now()}`,
|
|
413
|
+
status: 'failed',
|
|
414
|
+
ttl: null,
|
|
415
|
+
createdAt: new Date().toISOString(),
|
|
416
|
+
lastUpdatedAt: new Date().toISOString(),
|
|
417
|
+
statusMessage: 'Authentication failed'
|
|
418
|
+
}
|
|
411
419
|
};
|
|
412
420
|
}
|
|
413
421
|
this.updateConnectionActivity(clientId);
|
|
@@ -419,7 +427,14 @@ export class LanonasisMCPServer {
|
|
|
419
427
|
type: 'text',
|
|
420
428
|
text: JSON.stringify(result, null, 2)
|
|
421
429
|
}
|
|
422
|
-
]
|
|
430
|
+
],
|
|
431
|
+
task: {
|
|
432
|
+
taskId: `${clientId}-${Date.now()}`,
|
|
433
|
+
status: 'completed',
|
|
434
|
+
ttl: null,
|
|
435
|
+
createdAt: new Date().toISOString(),
|
|
436
|
+
lastUpdatedAt: new Date().toISOString()
|
|
437
|
+
}
|
|
423
438
|
};
|
|
424
439
|
}
|
|
425
440
|
catch (error) {
|
|
@@ -430,7 +445,15 @@ export class LanonasisMCPServer {
|
|
|
430
445
|
text: `Error: ${error instanceof Error ? error.message : 'Unknown error'}`
|
|
431
446
|
}
|
|
432
447
|
],
|
|
433
|
-
isError: true
|
|
448
|
+
isError: true,
|
|
449
|
+
task: {
|
|
450
|
+
taskId: `${clientId}-${Date.now()}`,
|
|
451
|
+
status: 'failed',
|
|
452
|
+
ttl: null,
|
|
453
|
+
createdAt: new Date().toISOString(),
|
|
454
|
+
lastUpdatedAt: new Date().toISOString(),
|
|
455
|
+
statusMessage: error instanceof Error ? error.message : 'Unknown error'
|
|
456
|
+
}
|
|
434
457
|
};
|
|
435
458
|
}
|
|
436
459
|
});
|
|
@@ -1473,6 +1496,35 @@ Please choose an option (1-4):`
|
|
|
1473
1496
|
throw error;
|
|
1474
1497
|
}
|
|
1475
1498
|
}
|
|
1499
|
+
/**
|
|
1500
|
+
* Start the server in stdio mode for external MCP clients (Claude Desktop, Cursor, etc.)
|
|
1501
|
+
* This is the primary entry point for `lanonasis mcp start`
|
|
1502
|
+
*/
|
|
1503
|
+
async startStdio() {
|
|
1504
|
+
await this.initialize();
|
|
1505
|
+
try {
|
|
1506
|
+
// Use API key from options if provided (from LANONASIS_API_KEY env var)
|
|
1507
|
+
if (this.options.apiKey) {
|
|
1508
|
+
// Set the API key for authentication
|
|
1509
|
+
await this.config.setVendorKey(this.options.apiKey);
|
|
1510
|
+
}
|
|
1511
|
+
// Create stdio transport
|
|
1512
|
+
this.transport = new StdioServerTransport();
|
|
1513
|
+
await this.server.connect(this.transport);
|
|
1514
|
+
// Log to stderr since stdout is for MCP protocol
|
|
1515
|
+
console.error(chalk.cyan('🚀 Lanonasis MCP Server started (stdio mode)'));
|
|
1516
|
+
console.error(chalk.gray(`Backend: ${this.config.getApiUrl()}`));
|
|
1517
|
+
console.error(chalk.gray(`Tools: 18+ available`));
|
|
1518
|
+
console.error(chalk.gray('Ready for MCP client connections...'));
|
|
1519
|
+
// Keep the process alive
|
|
1520
|
+
process.stdin.resume();
|
|
1521
|
+
}
|
|
1522
|
+
catch (error) {
|
|
1523
|
+
console.error(chalk.red('❌ Failed to start MCP Server:'));
|
|
1524
|
+
console.error(chalk.red(error instanceof Error ? error.message : 'Unknown error'));
|
|
1525
|
+
throw error;
|
|
1526
|
+
}
|
|
1527
|
+
}
|
|
1476
1528
|
/**
|
|
1477
1529
|
* Stop the server
|
|
1478
1530
|
*/
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Lanonasis MCP Server Entry Point
|
|
4
|
+
*
|
|
5
|
+
* Direct entry point for external MCP clients (Claude Desktop, Cursor, Windsurf, etc.)
|
|
6
|
+
* This allows simple configuration like:
|
|
7
|
+
*
|
|
8
|
+
* claude mcp add lanonasis -- lanonasis-mcp
|
|
9
|
+
*
|
|
10
|
+
* Or in claude_desktop_config.json:
|
|
11
|
+
* {
|
|
12
|
+
* "mcpServers": {
|
|
13
|
+
* "lanonasis": {
|
|
14
|
+
* "command": "lanonasis-mcp",
|
|
15
|
+
* "env": { "LANONASIS_API_KEY": "lano_xxx" }
|
|
16
|
+
* }
|
|
17
|
+
* }
|
|
18
|
+
* }
|
|
19
|
+
*/
|
|
20
|
+
export {};
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Lanonasis MCP Server Entry Point
|
|
4
|
+
*
|
|
5
|
+
* Direct entry point for external MCP clients (Claude Desktop, Cursor, Windsurf, etc.)
|
|
6
|
+
* This allows simple configuration like:
|
|
7
|
+
*
|
|
8
|
+
* claude mcp add lanonasis -- lanonasis-mcp
|
|
9
|
+
*
|
|
10
|
+
* Or in claude_desktop_config.json:
|
|
11
|
+
* {
|
|
12
|
+
* "mcpServers": {
|
|
13
|
+
* "lanonasis": {
|
|
14
|
+
* "command": "lanonasis-mcp",
|
|
15
|
+
* "env": { "LANONASIS_API_KEY": "lano_xxx" }
|
|
16
|
+
* }
|
|
17
|
+
* }
|
|
18
|
+
* }
|
|
19
|
+
*/
|
|
20
|
+
import { LanonasisMCPServer } from './mcp/server/lanonasis-server.js';
|
|
21
|
+
async function main() {
|
|
22
|
+
// Get API key from environment
|
|
23
|
+
const apiKey = process.env.LANONASIS_API_KEY;
|
|
24
|
+
if (!apiKey) {
|
|
25
|
+
console.error('Error: LANONASIS_API_KEY environment variable is required');
|
|
26
|
+
console.error('');
|
|
27
|
+
console.error('Usage:');
|
|
28
|
+
console.error(' LANONASIS_API_KEY=lano_xxx lanonasis-mcp');
|
|
29
|
+
console.error('');
|
|
30
|
+
console.error('Or configure in Claude Desktop/Cursor:');
|
|
31
|
+
console.error(' {');
|
|
32
|
+
console.error(' "mcpServers": {');
|
|
33
|
+
console.error(' "lanonasis": {');
|
|
34
|
+
console.error(' "command": "lanonasis-mcp",');
|
|
35
|
+
console.error(' "env": { "LANONASIS_API_KEY": "your_api_key" }');
|
|
36
|
+
console.error(' }');
|
|
37
|
+
console.error(' }');
|
|
38
|
+
console.error(' }');
|
|
39
|
+
process.exit(1);
|
|
40
|
+
}
|
|
41
|
+
try {
|
|
42
|
+
const server = new LanonasisMCPServer({
|
|
43
|
+
apiKey,
|
|
44
|
+
verbose: process.env.LOG_LEVEL === 'debug'
|
|
45
|
+
});
|
|
46
|
+
// Start in stdio mode (standard for MCP clients)
|
|
47
|
+
await server.startStdio();
|
|
48
|
+
}
|
|
49
|
+
catch (error) {
|
|
50
|
+
console.error(`Failed to start MCP server: ${error instanceof Error ? error.message : 'Unknown error'}`);
|
|
51
|
+
process.exit(1);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
main();
|
package/dist/mcp-server.js
CHANGED
|
@@ -77,12 +77,13 @@ export class CLIMCPServer {
|
|
|
77
77
|
console.error(`Auth: ${this.config.hasVendorKey() ? 'Vendor Key' : 'JWT Token'}`);
|
|
78
78
|
}
|
|
79
79
|
const resolvedPort = typeof port === 'number' && !Number.isNaN(port) ? port : 3001;
|
|
80
|
+
const vendorKey = await this.config.getVendorKeyAsync();
|
|
80
81
|
// Set environment variables from CLI config
|
|
81
82
|
const env = {
|
|
82
83
|
...process.env,
|
|
83
84
|
PORT: resolvedPort.toString(),
|
|
84
85
|
MEMORY_API_URL: this.config.getApiUrl(),
|
|
85
|
-
LANONASIS_VENDOR_KEY:
|
|
86
|
+
LANONASIS_VENDOR_KEY: vendorKey,
|
|
86
87
|
LANONASIS_TOKEN: this.config.getToken(),
|
|
87
88
|
MCP_VERBOSE: verbose ? 'true' : 'false',
|
|
88
89
|
CLI_ALIGNED: 'true'
|
package/dist/utils/api.js
CHANGED
|
@@ -27,7 +27,7 @@ export class APIClient {
|
|
|
27
27
|
}
|
|
28
28
|
// Enhanced Authentication Support
|
|
29
29
|
const token = this.config.getToken();
|
|
30
|
-
const vendorKey = this.config.
|
|
30
|
+
const vendorKey = await this.config.getVendorKeyAsync();
|
|
31
31
|
if (vendorKey) {
|
|
32
32
|
// Vendor key authentication (validated server-side)
|
|
33
33
|
// Send raw key - server handles hashing for comparison
|
|
@@ -99,40 +99,40 @@ export class APIClient {
|
|
|
99
99
|
});
|
|
100
100
|
return response.data;
|
|
101
101
|
}
|
|
102
|
-
// Memory operations - aligned with
|
|
103
|
-
// All memory endpoints use /api/v1/
|
|
102
|
+
// Memory operations - aligned with REST API canonical endpoints
|
|
103
|
+
// All memory endpoints use /api/v1/memories path (plural, per REST conventions)
|
|
104
104
|
async createMemory(data) {
|
|
105
|
-
const response = await this.client.post('/api/v1/
|
|
105
|
+
const response = await this.client.post('/api/v1/memories', data);
|
|
106
106
|
return response.data;
|
|
107
107
|
}
|
|
108
108
|
async getMemories(params = {}) {
|
|
109
|
-
const response = await this.client.get('/api/v1/
|
|
109
|
+
const response = await this.client.get('/api/v1/memories', { params });
|
|
110
110
|
return response.data;
|
|
111
111
|
}
|
|
112
112
|
async getMemory(id) {
|
|
113
|
-
const response = await this.client.get(`/api/v1/
|
|
113
|
+
const response = await this.client.get(`/api/v1/memories/${id}`);
|
|
114
114
|
return response.data;
|
|
115
115
|
}
|
|
116
116
|
async updateMemory(id, data) {
|
|
117
|
-
const response = await this.client.put(`/api/v1/
|
|
117
|
+
const response = await this.client.put(`/api/v1/memories/${id}`, data);
|
|
118
118
|
return response.data;
|
|
119
119
|
}
|
|
120
120
|
async deleteMemory(id) {
|
|
121
|
-
await this.client.delete(`/api/v1/
|
|
121
|
+
await this.client.delete(`/api/v1/memories/${id}`);
|
|
122
122
|
}
|
|
123
123
|
async searchMemories(query, options = {}) {
|
|
124
|
-
const response = await this.client.post('/api/v1/
|
|
124
|
+
const response = await this.client.post('/api/v1/memories/search', {
|
|
125
125
|
query,
|
|
126
126
|
...options
|
|
127
127
|
});
|
|
128
128
|
return response.data;
|
|
129
129
|
}
|
|
130
130
|
async getMemoryStats() {
|
|
131
|
-
const response = await this.client.get('/api/v1/
|
|
131
|
+
const response = await this.client.get('/api/v1/memories/stats');
|
|
132
132
|
return response.data;
|
|
133
133
|
}
|
|
134
134
|
async bulkDeleteMemories(memoryIds) {
|
|
135
|
-
const response = await this.client.post('/api/v1/
|
|
135
|
+
const response = await this.client.post('/api/v1/memories/bulk/delete', {
|
|
136
136
|
memory_ids: memoryIds
|
|
137
137
|
});
|
|
138
138
|
return response.data;
|
package/dist/utils/config.d.ts
CHANGED
package/dist/utils/config.js
CHANGED
|
@@ -14,6 +14,7 @@ export class CLIConfig {
|
|
|
14
14
|
authCheckCache = null;
|
|
15
15
|
AUTH_CACHE_TTL = 5 * 60 * 1000; // 5 minutes
|
|
16
16
|
apiKeyStorage;
|
|
17
|
+
vendorKeyCache;
|
|
17
18
|
constructor() {
|
|
18
19
|
this.configDir = path.join(os.homedir(), '.maas');
|
|
19
20
|
this.configPath = path.join(this.configDir, 'config.json');
|
|
@@ -28,6 +29,7 @@ export class CLIConfig {
|
|
|
28
29
|
this.configDir = configDir;
|
|
29
30
|
this.configPath = path.join(configDir, 'config.json');
|
|
30
31
|
this.lockFile = path.join(configDir, 'config.lock');
|
|
32
|
+
this.vendorKeyCache = undefined;
|
|
31
33
|
}
|
|
32
34
|
/**
|
|
33
35
|
* Exposes the current config path for tests and diagnostics.
|
|
@@ -45,6 +47,8 @@ export class CLIConfig {
|
|
|
45
47
|
}
|
|
46
48
|
}
|
|
47
49
|
async load() {
|
|
50
|
+
// Reset in-memory cache; disk state may have changed
|
|
51
|
+
this.vendorKeyCache = undefined;
|
|
48
52
|
try {
|
|
49
53
|
const data = await fs.readFile(this.configPath, 'utf-8');
|
|
50
54
|
this.config = JSON.parse(data);
|
|
@@ -170,7 +174,7 @@ export class CLIConfig {
|
|
|
170
174
|
getApiUrl() {
|
|
171
175
|
const baseUrl = process.env.MEMORY_API_URL ||
|
|
172
176
|
this.config.apiUrl ||
|
|
173
|
-
'https://
|
|
177
|
+
'https://api.lanonasis.com'; // Primary REST API endpoint
|
|
174
178
|
// Ensure we don't double-append /api/v1 - strip it if present since APIClient adds it
|
|
175
179
|
return baseUrl.replace(/\/api\/v1\/?$/, '');
|
|
176
180
|
}
|
|
@@ -192,8 +196,8 @@ export class CLIConfig {
|
|
|
192
196
|
if (!this.config.discoveredServices) {
|
|
193
197
|
this.config.discoveredServices = {
|
|
194
198
|
auth_base: 'https://auth.lanonasis.com',
|
|
195
|
-
memory_base: 'https://
|
|
196
|
-
mcp_base: 'https://mcp.lanonasis.com/api/v1', //
|
|
199
|
+
memory_base: 'https://api.lanonasis.com', // Primary REST API (Supabase Edge Functions)
|
|
200
|
+
mcp_base: 'https://mcp.lanonasis.com/api/v1', // MCP protocol REST path
|
|
197
201
|
mcp_ws_base: 'wss://mcp.lanonasis.com/ws',
|
|
198
202
|
mcp_sse_base: 'https://mcp.lanonasis.com/api/v1/events',
|
|
199
203
|
project_scope: 'lanonasis-maas'
|
|
@@ -245,10 +249,10 @@ export class CLIConfig {
|
|
|
245
249
|
if (authBase.includes('localhost') || authBase.includes('127.0.0.1')) {
|
|
246
250
|
authBase = 'https://auth.lanonasis.com';
|
|
247
251
|
}
|
|
248
|
-
// Memory base should be the
|
|
252
|
+
// Memory base should be the REST API URL without /api/v1 suffix
|
|
249
253
|
// The API client will append the path as needed
|
|
250
|
-
const rawMemoryBase = discovered.endpoints?.http || 'https://
|
|
251
|
-
const memoryBase = rawMemoryBase.replace(/\/api\/v1\/?$/, '') || 'https://
|
|
254
|
+
const rawMemoryBase = discovered.endpoints?.http || 'https://api.lanonasis.com/api/v1';
|
|
255
|
+
const memoryBase = rawMemoryBase.replace(/\/api\/v1\/?$/, '') || 'https://api.lanonasis.com';
|
|
252
256
|
this.config.discoveredServices = {
|
|
253
257
|
auth_base: authBase || 'https://auth.lanonasis.com',
|
|
254
258
|
memory_base: memoryBase,
|
|
@@ -371,8 +375,8 @@ export class CLIConfig {
|
|
|
371
375
|
const nodeEnv = (process.env.NODE_ENV ?? '').toLowerCase();
|
|
372
376
|
const isDevEnvironment = nodeEnv === 'development' || nodeEnv === 'test';
|
|
373
377
|
const defaultAuthBase = isDevEnvironment ? 'http://localhost:4000' : 'https://auth.lanonasis.com';
|
|
374
|
-
const defaultMemoryBase = isDevEnvironment ? 'http://localhost:4000' : 'https://
|
|
375
|
-
const defaultMcpBase = isDevEnvironment ? 'http://localhost:4100/api/v1' : 'https://mcp.lanonasis.com/api/v1'; //
|
|
378
|
+
const defaultMemoryBase = isDevEnvironment ? 'http://localhost:4000' : 'https://api.lanonasis.com'; // Primary REST API (Supabase Edge Functions)
|
|
379
|
+
const defaultMcpBase = isDevEnvironment ? 'http://localhost:4100/api/v1' : 'https://mcp.lanonasis.com/api/v1'; // MCP protocol REST path
|
|
376
380
|
const defaultMcpWsBase = isDevEnvironment ? 'ws://localhost:4100/ws' : 'wss://mcp.lanonasis.com/ws';
|
|
377
381
|
const defaultMcpSseBase = isDevEnvironment ? 'http://localhost:4100/api/v1/events' : 'https://mcp.lanonasis.com/api/v1/events';
|
|
378
382
|
const endpoints = {
|
|
@@ -438,8 +442,8 @@ export class CLIConfig {
|
|
|
438
442
|
}
|
|
439
443
|
const currentServices = this.config.discoveredServices ?? {
|
|
440
444
|
auth_base: 'https://auth.lanonasis.com',
|
|
441
|
-
memory_base: 'https://
|
|
442
|
-
mcp_base: 'https://mcp.lanonasis.com/api/v1', //
|
|
445
|
+
memory_base: 'https://api.lanonasis.com', // Primary REST API (Supabase Edge Functions)
|
|
446
|
+
mcp_base: 'https://mcp.lanonasis.com/api/v1', // MCP protocol REST path
|
|
443
447
|
mcp_ws_base: 'wss://mcp.lanonasis.com/ws',
|
|
444
448
|
mcp_sse_base: 'https://mcp.lanonasis.com/api/v1/events',
|
|
445
449
|
project_scope: 'lanonasis-maas'
|
|
@@ -488,12 +492,18 @@ export class CLIConfig {
|
|
|
488
492
|
environment: process.env.NODE_ENV || 'production',
|
|
489
493
|
createdAt: new Date().toISOString()
|
|
490
494
|
});
|
|
495
|
+
// Cache the vendor key for this process so synchronous callers can reuse it
|
|
496
|
+
this.vendorKeyCache = trimmedKey;
|
|
491
497
|
if (process.env.CLI_VERBOSE === 'true') {
|
|
492
498
|
console.log('🔐 Vendor key stored securely via @lanonasis/oauth-client');
|
|
493
499
|
}
|
|
494
500
|
// Store a reference marker in config (not the actual key)
|
|
495
501
|
this.config.vendorKey = 'stored_in_api_key_storage';
|
|
496
|
-
|
|
502
|
+
// Only set authMethod to 'vendor_key' if not already set to OAuth
|
|
503
|
+
// This prevents overwriting OAuth auth method when storing the token for MCP access
|
|
504
|
+
if (!this.config.authMethod || !['oauth', 'oauth2', 'jwt'].includes(this.config.authMethod)) {
|
|
505
|
+
this.config.authMethod = 'vendor_key';
|
|
506
|
+
}
|
|
497
507
|
this.config.lastValidated = new Date().toISOString();
|
|
498
508
|
await this.resetFailureCount(); // Reset failure count on successful auth
|
|
499
509
|
await this.save();
|
|
@@ -566,10 +576,16 @@ export class CLIConfig {
|
|
|
566
576
|
}
|
|
567
577
|
}
|
|
568
578
|
getVendorKey() {
|
|
579
|
+
if (this.vendorKeyCache) {
|
|
580
|
+
return this.vendorKeyCache;
|
|
581
|
+
}
|
|
569
582
|
try {
|
|
570
583
|
// Retrieve from secure storage using ApiKeyStorage (synchronous wrapper)
|
|
571
584
|
const stored = this.getVendorKeySync();
|
|
572
|
-
|
|
585
|
+
if (stored) {
|
|
586
|
+
this.vendorKeyCache = stored;
|
|
587
|
+
}
|
|
588
|
+
return this.vendorKeyCache;
|
|
573
589
|
}
|
|
574
590
|
catch (error) {
|
|
575
591
|
if (process.env.CLI_VERBOSE === 'true') {
|
|
@@ -600,7 +616,8 @@ export class CLIConfig {
|
|
|
600
616
|
await this.apiKeyStorage.initialize();
|
|
601
617
|
const stored = await this.apiKeyStorage.retrieve();
|
|
602
618
|
if (stored) {
|
|
603
|
-
|
|
619
|
+
this.vendorKeyCache = stored.apiKey;
|
|
620
|
+
return this.vendorKeyCache;
|
|
604
621
|
}
|
|
605
622
|
}
|
|
606
623
|
catch (error) {
|
|
@@ -613,13 +630,14 @@ export class CLIConfig {
|
|
|
613
630
|
if (process.env.CLI_VERBOSE === 'true') {
|
|
614
631
|
console.log('ℹ️ Found legacy plaintext vendor key, will migrate on next auth');
|
|
615
632
|
}
|
|
616
|
-
|
|
633
|
+
this.vendorKeyCache = this.config.vendorKey;
|
|
634
|
+
return this.vendorKeyCache;
|
|
617
635
|
}
|
|
618
636
|
return undefined;
|
|
619
637
|
}
|
|
620
638
|
hasVendorKey() {
|
|
621
639
|
// Check for marker or legacy storage
|
|
622
|
-
return !!this.config.vendorKey;
|
|
640
|
+
return !!(this.vendorKeyCache || this.config.vendorKey);
|
|
623
641
|
}
|
|
624
642
|
async setApiUrl(url) {
|
|
625
643
|
this.config.apiUrl = url;
|
|
@@ -678,11 +696,41 @@ export class CLIConfig {
|
|
|
678
696
|
this.authCheckCache = { isValid: true, timestamp: Date.now() };
|
|
679
697
|
return true;
|
|
680
698
|
}
|
|
681
|
-
//
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
699
|
+
// Vendor key not recently validated - verify with server
|
|
700
|
+
try {
|
|
701
|
+
await this.discoverServices();
|
|
702
|
+
const authBase = this.config.discoveredServices?.auth_base || 'https://auth.lanonasis.com';
|
|
703
|
+
// Ping auth health with vendor key to verify it's still valid
|
|
704
|
+
await this.pingAuthHealth(axios, authBase, {
|
|
705
|
+
'X-API-Key': vendorKey,
|
|
706
|
+
'X-Auth-Method': 'vendor_key',
|
|
707
|
+
'X-Project-Scope': 'lanonasis-maas'
|
|
708
|
+
}, { timeout: 5000, proxy: false });
|
|
709
|
+
// Update last validated timestamp on success
|
|
710
|
+
this.config.lastValidated = new Date().toISOString();
|
|
711
|
+
await this.save().catch(() => { }); // Don't fail auth check if save fails
|
|
712
|
+
this.authCheckCache = { isValid: true, timestamp: Date.now() };
|
|
713
|
+
return true;
|
|
714
|
+
}
|
|
715
|
+
catch (error) {
|
|
716
|
+
// Server validation failed - check for grace period (7 days offline)
|
|
717
|
+
const gracePeriod = 7 * 24 * 60 * 60 * 1000;
|
|
718
|
+
const withinGracePeriod = lastValidated &&
|
|
719
|
+
(Date.now() - new Date(lastValidated).getTime()) < gracePeriod;
|
|
720
|
+
if (withinGracePeriod) {
|
|
721
|
+
if (process.env.CLI_VERBOSE === 'true') {
|
|
722
|
+
console.warn('⚠️ Unable to validate vendor key with server, using cached validation');
|
|
723
|
+
}
|
|
724
|
+
this.authCheckCache = { isValid: true, timestamp: Date.now() };
|
|
725
|
+
return true;
|
|
726
|
+
}
|
|
727
|
+
// Grace period expired - require server validation
|
|
728
|
+
if (process.env.CLI_VERBOSE === 'true') {
|
|
729
|
+
console.warn('⚠️ Vendor key validation failed and grace period expired');
|
|
730
|
+
}
|
|
731
|
+
this.authCheckCache = { isValid: false, timestamp: Date.now() };
|
|
732
|
+
return false;
|
|
733
|
+
}
|
|
686
734
|
}
|
|
687
735
|
// Handle token-based authentication
|
|
688
736
|
const token = this.getToken();
|
|
@@ -848,10 +896,25 @@ export class CLIConfig {
|
|
|
848
896
|
async logout() {
|
|
849
897
|
this.config.token = undefined;
|
|
850
898
|
this.config.user = undefined;
|
|
899
|
+
this.vendorKeyCache = undefined;
|
|
900
|
+
this.config.vendorKey = undefined;
|
|
901
|
+
this.config.authMethod = undefined;
|
|
902
|
+
try {
|
|
903
|
+
await this.apiKeyStorage.initialize();
|
|
904
|
+
// ApiKeyStorage may implement clear() to remove encrypted secrets
|
|
905
|
+
const storage = this.apiKeyStorage;
|
|
906
|
+
if (typeof storage.clear === 'function') {
|
|
907
|
+
await storage.clear();
|
|
908
|
+
}
|
|
909
|
+
}
|
|
910
|
+
catch {
|
|
911
|
+
// Ignore storage cleanup errors during logout
|
|
912
|
+
}
|
|
851
913
|
await this.save();
|
|
852
914
|
}
|
|
853
915
|
async clear() {
|
|
854
916
|
this.config = {};
|
|
917
|
+
this.vendorKeyCache = undefined;
|
|
855
918
|
await this.save();
|
|
856
919
|
}
|
|
857
920
|
async exists() {
|
|
@@ -866,7 +929,7 @@ export class CLIConfig {
|
|
|
866
929
|
// Enhanced credential validation methods
|
|
867
930
|
async validateStoredCredentials() {
|
|
868
931
|
try {
|
|
869
|
-
const vendorKey = this.
|
|
932
|
+
const vendorKey = await this.getVendorKeyAsync();
|
|
870
933
|
const token = this.getToken();
|
|
871
934
|
if (!vendorKey && !token) {
|
|
872
935
|
return false;
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
*/
|
|
9
9
|
import crypto from 'crypto';
|
|
10
10
|
import { homedir, platform, hostname } from 'os';
|
|
11
|
-
import { hashApiKey, isSha256Hash } from '
|
|
11
|
+
import { hashApiKey, isSha256Hash } from '@lanonasis/security-sdk/hash-utils';
|
|
12
12
|
// Encryption algorithm configuration
|
|
13
13
|
const ALGORITHM = 'aes-256-gcm';
|
|
14
14
|
const KEY_LENGTH = 32; // 256 bits
|
package/package.json
CHANGED
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lanonasis/cli",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.8.1",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
7
7
|
"bin": {
|
|
8
8
|
"onasis": "dist/index.js",
|
|
9
|
-
"lanonasis": "dist/index.js"
|
|
9
|
+
"lanonasis": "dist/index.js",
|
|
10
|
+
"lanonasis-mcp": "dist/mcp-server-entry.js"
|
|
10
11
|
},
|
|
11
12
|
"exports": {
|
|
12
13
|
".": {
|
|
@@ -23,8 +24,8 @@
|
|
|
23
24
|
],
|
|
24
25
|
"dependencies": {
|
|
25
26
|
"@lanonasis/oauth-client": "1.2.5",
|
|
26
|
-
"@lanonasis/security-sdk": "
|
|
27
|
-
"@modelcontextprotocol/sdk": "^1.
|
|
27
|
+
"@lanonasis/security-sdk": "1.0.5",
|
|
28
|
+
"@modelcontextprotocol/sdk": "^1.25.2",
|
|
28
29
|
"axios": "^1.7.7",
|
|
29
30
|
"chalk": "^5.3.0",
|
|
30
31
|
"cli-progress": "^3.12.0",
|
|
@@ -61,4 +62,4 @@
|
|
|
61
62
|
"test:watch": "npm test -- --watch",
|
|
62
63
|
"test:coverage": "npm test -- --coverage"
|
|
63
64
|
}
|
|
64
|
-
}
|
|
65
|
+
}
|