@lanonasis/cli 3.9.7 → 3.9.9
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/CHANGELOG.md +18 -0
- package/dist/commands/api-keys.js +7 -7
- package/dist/commands/auth.js +2 -2
- package/dist/commands/completion.js +10 -0
- package/dist/commands/guide.js +3 -3
- package/dist/commands/mcp.js +78 -11
- package/dist/commands/memory.js +544 -11
- package/dist/core/dashboard.js +4 -4
- package/dist/index.js +8 -1
- package/dist/mcp/schemas/tool-schemas.js +1 -1
- package/dist/mcp/server/lanonasis-server.js +2 -2
- package/dist/mcp-server-entry.js +0 -0
- package/dist/utils/api.d.ts +22 -1
- package/dist/utils/api.js +198 -12
- package/dist/utils/config.d.ts +10 -5
- package/dist/utils/config.js +66 -32
- package/dist/utils/mcp-client.d.ts +2 -0
- package/dist/utils/mcp-client.js +74 -46
- package/package.json +3 -2
package/dist/utils/mcp-client.js
CHANGED
|
@@ -356,31 +356,69 @@ export class MCPClient {
|
|
|
356
356
|
const jitter = cappedDelay * 0.25 * (Math.random() - 0.5);
|
|
357
357
|
return Math.round(cappedDelay + jitter);
|
|
358
358
|
}
|
|
359
|
+
async resolveAuthCredential() {
|
|
360
|
+
const authMethod = String(this.config.get('authMethod') || '').toLowerCase();
|
|
361
|
+
const token = this.config.get('token');
|
|
362
|
+
const vendorKey = await this.config.getVendorKeyAsync();
|
|
363
|
+
if (authMethod === 'vendor_key' && typeof vendorKey === 'string' && vendorKey.trim().length > 0) {
|
|
364
|
+
return { value: vendorKey.trim(), source: 'vendor_key' };
|
|
365
|
+
}
|
|
366
|
+
if ((authMethod === 'oauth' || authMethod === 'oauth2' || authMethod === 'jwt') &&
|
|
367
|
+
typeof token === 'string' &&
|
|
368
|
+
token.trim().length > 0) {
|
|
369
|
+
return { value: token.trim(), source: 'token' };
|
|
370
|
+
}
|
|
371
|
+
if (typeof token === 'string' && token.trim().length > 0) {
|
|
372
|
+
return { value: token.trim(), source: 'token' };
|
|
373
|
+
}
|
|
374
|
+
if (typeof vendorKey === 'string' && vendorKey.trim().length > 0) {
|
|
375
|
+
return { value: vendorKey.trim(), source: 'vendor_key' };
|
|
376
|
+
}
|
|
377
|
+
const envKey = process.env.LANONASIS_API_KEY;
|
|
378
|
+
if (typeof envKey === 'string' && envKey.trim().length > 0) {
|
|
379
|
+
return { value: envKey.trim(), source: 'env' };
|
|
380
|
+
}
|
|
381
|
+
return null;
|
|
382
|
+
}
|
|
383
|
+
buildAuthHeaders(auth) {
|
|
384
|
+
const headers = {};
|
|
385
|
+
const value = auth.value.trim();
|
|
386
|
+
if (!value) {
|
|
387
|
+
return headers;
|
|
388
|
+
}
|
|
389
|
+
if (auth.source === 'vendor_key' || value.startsWith('lano_') || value.startsWith('lms_')) {
|
|
390
|
+
headers['X-API-Key'] = value;
|
|
391
|
+
headers['X-Auth-Method'] = 'vendor_key';
|
|
392
|
+
headers['X-Project-Scope'] = 'lanonasis-maas';
|
|
393
|
+
return headers;
|
|
394
|
+
}
|
|
395
|
+
if (value.toLowerCase().startsWith('bearer ')) {
|
|
396
|
+
headers['Authorization'] = value;
|
|
397
|
+
headers['X-Auth-Method'] = 'jwt';
|
|
398
|
+
headers['X-Project-Scope'] = 'lanonasis-maas';
|
|
399
|
+
return headers;
|
|
400
|
+
}
|
|
401
|
+
headers['Authorization'] = `Bearer ${value}`;
|
|
402
|
+
headers['X-Auth-Method'] = 'jwt';
|
|
403
|
+
headers['X-Project-Scope'] = 'lanonasis-maas';
|
|
404
|
+
return headers;
|
|
405
|
+
}
|
|
359
406
|
/**
|
|
360
407
|
* Validate authentication credentials before attempting MCP connection
|
|
361
408
|
*/
|
|
362
409
|
async validateAuthBeforeConnect() {
|
|
363
|
-
const
|
|
364
|
-
|
|
365
|
-
// Check if we have any authentication credentials
|
|
366
|
-
if (!token && !vendorKey) {
|
|
410
|
+
const auth = await this.resolveAuthCredential();
|
|
411
|
+
if (!auth) {
|
|
367
412
|
throw new Error('AUTHENTICATION_REQUIRED: No authentication credentials found. Run "lanonasis auth login" first.');
|
|
368
413
|
}
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
throw new Error(`AUTHENTICATION_INVALID: ${error instanceof Error ? error.message : 'Token validation failed'}`);
|
|
376
|
-
}
|
|
377
|
-
}
|
|
378
|
-
// If we have a vendor key, ensure it is valid (non-empty)
|
|
379
|
-
if (vendorKey && !token) {
|
|
380
|
-
const validationResult = this.config.validateVendorKeyFormat(vendorKey);
|
|
381
|
-
if (validationResult !== true) {
|
|
382
|
-
throw new Error(`AUTHENTICATION_INVALID: ${typeof validationResult === 'string' ? validationResult : 'Vendor key is invalid'}`);
|
|
414
|
+
await this.config.refreshTokenIfNeeded();
|
|
415
|
+
const verification = await this.config.verifyCurrentCredentialsWithServer();
|
|
416
|
+
if (!verification.valid) {
|
|
417
|
+
const reason = verification.reason || 'Credential verification failed';
|
|
418
|
+
if (verification.method === 'none') {
|
|
419
|
+
throw new Error(`AUTHENTICATION_REQUIRED: ${reason}`);
|
|
383
420
|
}
|
|
421
|
+
throw new Error(`AUTHENTICATION_INVALID: ${reason}`);
|
|
384
422
|
}
|
|
385
423
|
}
|
|
386
424
|
/**
|
|
@@ -460,12 +498,10 @@ export class MCPClient {
|
|
|
460
498
|
async initializeSSE(serverUrl) {
|
|
461
499
|
// Use the proper SSE endpoint from config
|
|
462
500
|
const sseUrl = this.config.getMCPSSEUrl() ?? `${serverUrl}/events`;
|
|
463
|
-
const
|
|
464
|
-
|
|
465
|
-
const authKey = token || vendorKey || process.env.LANONASIS_API_KEY;
|
|
466
|
-
if (authKey) {
|
|
501
|
+
const auth = await this.resolveAuthCredential();
|
|
502
|
+
if (auth) {
|
|
467
503
|
// EventSource doesn't support headers directly, append token to URL
|
|
468
|
-
this.sseConnection = new EventSource(`${sseUrl}?token=${encodeURIComponent(
|
|
504
|
+
this.sseConnection = new EventSource(`${sseUrl}?token=${encodeURIComponent(auth.value)}`);
|
|
469
505
|
this.sseConnection.onmessage = (event) => {
|
|
470
506
|
try {
|
|
471
507
|
const data = JSON.parse(event.data);
|
|
@@ -479,7 +515,11 @@ export class MCPClient {
|
|
|
479
515
|
}
|
|
480
516
|
};
|
|
481
517
|
this.sseConnection.onerror = () => {
|
|
482
|
-
|
|
518
|
+
if (process.env.CLI_VERBOSE === 'true') {
|
|
519
|
+
console.error(chalk.yellow('⚠️ SSE connection error (stream disabled for this session)'));
|
|
520
|
+
}
|
|
521
|
+
this.sseConnection?.close();
|
|
522
|
+
this.sseConnection = null;
|
|
483
523
|
};
|
|
484
524
|
}
|
|
485
525
|
}
|
|
@@ -487,12 +527,11 @@ export class MCPClient {
|
|
|
487
527
|
* Initialize WebSocket connection for enterprise MCP server
|
|
488
528
|
*/
|
|
489
529
|
async initializeWebSocket(wsUrl) {
|
|
490
|
-
const
|
|
491
|
-
|
|
492
|
-
const authKey = token || vendorKey || process.env.LANONASIS_API_KEY;
|
|
493
|
-
if (!authKey) {
|
|
530
|
+
const auth = await this.resolveAuthCredential();
|
|
531
|
+
if (!auth) {
|
|
494
532
|
throw new Error('API key required for WebSocket mode. Set LANONASIS_API_KEY or login first.');
|
|
495
533
|
}
|
|
534
|
+
const wsHeaders = this.buildAuthHeaders(auth);
|
|
496
535
|
return new Promise((resolve, reject) => {
|
|
497
536
|
try {
|
|
498
537
|
// Close existing connection if any
|
|
@@ -502,10 +541,7 @@ export class MCPClient {
|
|
|
502
541
|
}
|
|
503
542
|
// Create new WebSocket connection with authentication
|
|
504
543
|
this.wsConnection = new WebSocket(wsUrl, [], {
|
|
505
|
-
headers:
|
|
506
|
-
'Authorization': `Bearer ${authKey}`,
|
|
507
|
-
'X-API-Key': authKey
|
|
508
|
-
}
|
|
544
|
+
headers: wsHeaders
|
|
509
545
|
});
|
|
510
546
|
this.wsConnection.on('open', () => {
|
|
511
547
|
console.log(chalk.green('✅ Connected to MCP WebSocket server'));
|
|
@@ -653,19 +689,14 @@ export class MCPClient {
|
|
|
653
689
|
*/
|
|
654
690
|
async checkRemoteHealth(serverUrl) {
|
|
655
691
|
const apiUrl = serverUrl ?? this.config.getMCPRestUrl() ?? 'https://mcp.lanonasis.com/api/v1';
|
|
656
|
-
const
|
|
657
|
-
|
|
658
|
-
const authKey = token || vendorKey || process.env.LANONASIS_API_KEY;
|
|
659
|
-
if (!authKey) {
|
|
692
|
+
const auth = await this.resolveAuthCredential();
|
|
693
|
+
if (!auth) {
|
|
660
694
|
throw new Error('No authentication token available');
|
|
661
695
|
}
|
|
662
696
|
try {
|
|
663
697
|
const axios = (await import('axios')).default;
|
|
664
698
|
await axios.get(`${apiUrl}/health`, {
|
|
665
|
-
headers:
|
|
666
|
-
'Authorization': `Bearer ${authKey}`,
|
|
667
|
-
'X-API-Key': authKey
|
|
668
|
-
},
|
|
699
|
+
headers: this.buildAuthHeaders(auth),
|
|
669
700
|
timeout: 5000
|
|
670
701
|
});
|
|
671
702
|
}
|
|
@@ -786,10 +817,8 @@ export class MCPClient {
|
|
|
786
817
|
*/
|
|
787
818
|
async callRemoteTool(toolName, args) {
|
|
788
819
|
const apiUrl = this.config.getMCPRestUrl() ?? 'https://mcp.lanonasis.com/api/v1';
|
|
789
|
-
const
|
|
790
|
-
|
|
791
|
-
const authKey = token || vendorKey || process.env.LANONASIS_API_KEY;
|
|
792
|
-
if (!authKey) {
|
|
820
|
+
const auth = await this.resolveAuthCredential();
|
|
821
|
+
if (!auth) {
|
|
793
822
|
throw new Error('Authentication required. Run "lanonasis auth login" first.');
|
|
794
823
|
}
|
|
795
824
|
// Map MCP tool names to REST API endpoints
|
|
@@ -845,8 +874,7 @@ export class MCPClient {
|
|
|
845
874
|
method: mapping.method,
|
|
846
875
|
url: `${apiUrl}${endpoint}`,
|
|
847
876
|
headers: {
|
|
848
|
-
|
|
849
|
-
'X-API-Key': authKey,
|
|
877
|
+
...this.buildAuthHeaders(auth),
|
|
850
878
|
'Content-Type': 'application/json'
|
|
851
879
|
},
|
|
852
880
|
data: mapping.transform ? mapping.transform(args) : undefined,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lanonasis/cli",
|
|
3
|
-
"version": "3.9.
|
|
3
|
+
"version": "3.9.9",
|
|
4
4
|
"description": "Professional CLI for LanOnasis Memory as a Service (MaaS) with MCP support, seamless inline editing, and enterprise-grade security",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"lanonasis",
|
|
@@ -52,6 +52,7 @@
|
|
|
52
52
|
"CHANGELOG.md"
|
|
53
53
|
],
|
|
54
54
|
"dependencies": {
|
|
55
|
+
"@lanonasis/mem-intel-sdk": "2.0.3",
|
|
55
56
|
"@lanonasis/oauth-client": "2.0.0",
|
|
56
57
|
"@lanonasis/security-sdk": "1.0.5",
|
|
57
58
|
"@modelcontextprotocol/sdk": "^1.26.0",
|
|
@@ -85,7 +86,7 @@
|
|
|
85
86
|
"typescript": "^5.9.3"
|
|
86
87
|
},
|
|
87
88
|
"scripts": {
|
|
88
|
-
"build": "rimraf dist && tsc -p tsconfig.json",
|
|
89
|
+
"build": "rimraf dist && tsc -p tsconfig.json && chmod +x dist/index.js dist/mcp-server-entry.js 2>/dev/null || true",
|
|
89
90
|
"prepublishOnly": "npm run build",
|
|
90
91
|
"postinstall": "node scripts/postinstall.js",
|
|
91
92
|
"test": "[ -f node_modules/jest/bin/jest.js ] || bun install --no-save; node --experimental-vm-modules node_modules/jest/bin/jest.js",
|