@lanonasis/cli 3.7.4 → 3.7.6
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 +43 -59
- package/dist/utils/api.js +16 -15
- package/dist/utils/config.js +16 -11
- package/dist/utils/mcp-client.js +19 -11
- package/package.json +2 -2
package/dist/commands/auth.js
CHANGED
|
@@ -91,7 +91,7 @@ async function handleAuthenticationFailure(error, config, authMethod = 'jwt') {
|
|
|
91
91
|
await config.clearInvalidCredentials();
|
|
92
92
|
break;
|
|
93
93
|
default:
|
|
94
|
-
console.log(chalk.red(`Unexpected error: ${error.message || 'Unknown error'}`));
|
|
94
|
+
console.log(chalk.red(`Unexpected error: ${sanitizeErrorMessage(error.message || 'Unknown error')}`));
|
|
95
95
|
console.log(chalk.gray('• Please try again'));
|
|
96
96
|
console.log(chalk.gray('• If the problem persists, contact support'));
|
|
97
97
|
}
|
|
@@ -183,12 +183,38 @@ function generatePKCE() {
|
|
|
183
183
|
.digest('base64url');
|
|
184
184
|
return { verifier, challenge };
|
|
185
185
|
}
|
|
186
|
+
/**
|
|
187
|
+
* Sanitize error messages to prevent command injection
|
|
188
|
+
*/
|
|
189
|
+
function sanitizeErrorMessage(message) {
|
|
190
|
+
if (typeof message !== 'string')
|
|
191
|
+
return 'Unknown error';
|
|
192
|
+
// Remove potential command injection characters
|
|
193
|
+
return message
|
|
194
|
+
.replace(/[;&|`$()]/g, '') // Remove shell metacharacters
|
|
195
|
+
.replace(/<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi, '') // Remove script tags
|
|
196
|
+
.replace(/javascript:/gi, '') // Remove javascript: URLs
|
|
197
|
+
.trim();
|
|
198
|
+
}
|
|
186
199
|
/**
|
|
187
200
|
* Start local HTTP server to catch OAuth2 callback
|
|
188
201
|
*/
|
|
189
202
|
function createCallbackServer(port = 8888) {
|
|
190
203
|
return new Promise((resolve, reject) => {
|
|
204
|
+
// Sanitize HTML to prevent XSS
|
|
205
|
+
function sanitizeHtml(str) {
|
|
206
|
+
return str
|
|
207
|
+
.replace(/&/g, '&')
|
|
208
|
+
.replace(/</g, '<')
|
|
209
|
+
.replace(/>/g, '>')
|
|
210
|
+
.replace(/"/g, '"')
|
|
211
|
+
.replace(/'/g, ''');
|
|
212
|
+
}
|
|
191
213
|
const server = http.createServer((req, res) => {
|
|
214
|
+
// Set security headers
|
|
215
|
+
res.setHeader('X-Content-Type-Options', 'nosniff');
|
|
216
|
+
res.setHeader('X-Frame-Options', 'DENY');
|
|
217
|
+
res.setHeader('Referrer-Policy', 'strict-origin-when-cross-origin');
|
|
192
218
|
const parsedUrl = url.parse(req.url, true);
|
|
193
219
|
if (parsedUrl.pathname === '/callback') {
|
|
194
220
|
const { code, state, error, error_description } = parsedUrl.query;
|
|
@@ -200,7 +226,7 @@ function createCallbackServer(port = 8888) {
|
|
|
200
226
|
<head><title>Authentication Failed</title></head>
|
|
201
227
|
<body style="font-family: sans-serif; text-align: center; padding: 50px;">
|
|
202
228
|
<h1>❌ Authentication Failed</h1>
|
|
203
|
-
<p>${error_description || error}</p>
|
|
229
|
+
<p>${sanitizeHtml(String(error_description || error))}</p>
|
|
204
230
|
<p style="color: gray;">You can close this window.</p>
|
|
205
231
|
</body>
|
|
206
232
|
</html>
|
|
@@ -280,7 +306,9 @@ async function exchangeCodeForTokens(code, verifier, authBase, redirectUri) {
|
|
|
280
306
|
}
|
|
281
307
|
/**
|
|
282
308
|
* Refresh OAuth2 access token using refresh token
|
|
309
|
+
* @internal Used for token refresh flows
|
|
283
310
|
*/
|
|
311
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
284
312
|
async function refreshOAuth2Token(config) {
|
|
285
313
|
const refreshToken = config.get('refresh_token');
|
|
286
314
|
if (!refreshToken) {
|
|
@@ -300,45 +328,11 @@ async function refreshOAuth2Token(config) {
|
|
|
300
328
|
await config.set('token_expires_at', Date.now() + (response.expires_in * 1000));
|
|
301
329
|
return true;
|
|
302
330
|
}
|
|
303
|
-
catch
|
|
331
|
+
catch {
|
|
304
332
|
console.error(chalk.yellow('⚠️ Token refresh failed, please re-authenticate'));
|
|
305
333
|
return false;
|
|
306
334
|
}
|
|
307
335
|
}
|
|
308
|
-
/**
|
|
309
|
-
* Exchange Supabase JWT token for auth-gateway API key
|
|
310
|
-
* This enables CLI to work with MCP WebSocket and all services seamlessly
|
|
311
|
-
*/
|
|
312
|
-
async function exchangeSupabaseTokenForApiKey(supabaseToken, config) {
|
|
313
|
-
try {
|
|
314
|
-
const discoveredServices = config.get('discoveredServices');
|
|
315
|
-
const authBase = discoveredServices?.auth_base || 'https://auth.lanonasis.com';
|
|
316
|
-
if (process.env.CLI_VERBOSE === 'true') {
|
|
317
|
-
console.log(chalk.dim(` Exchanging token at: ${authBase}/v1/auth/token/exchange`));
|
|
318
|
-
}
|
|
319
|
-
const response = await axios.post(`${authBase}/v1/auth/token/exchange`, {
|
|
320
|
-
project_scope: 'lanonasis-maas',
|
|
321
|
-
platform: 'cli'
|
|
322
|
-
}, {
|
|
323
|
-
headers: {
|
|
324
|
-
'Authorization': `Bearer ${supabaseToken}`,
|
|
325
|
-
'Content-Type': 'application/json',
|
|
326
|
-
'X-Project-Scope': 'lanonasis-maas'
|
|
327
|
-
}
|
|
328
|
-
});
|
|
329
|
-
return {
|
|
330
|
-
access_token: response.data.access_token,
|
|
331
|
-
user: response.data.user
|
|
332
|
-
};
|
|
333
|
-
}
|
|
334
|
-
catch (error) {
|
|
335
|
-
console.error(chalk.yellow('⚠️ Token exchange failed:', error.message));
|
|
336
|
-
if (process.env.CLI_VERBOSE === 'true' && error.response) {
|
|
337
|
-
console.error(chalk.dim(' Response:', JSON.stringify(error.response.data, null, 2)));
|
|
338
|
-
}
|
|
339
|
-
return null;
|
|
340
|
-
}
|
|
341
|
-
}
|
|
342
336
|
export async function diagnoseCommand() {
|
|
343
337
|
const config = new CLIConfig();
|
|
344
338
|
await config.init();
|
|
@@ -708,33 +702,23 @@ async function handleOAuthFlow(config) {
|
|
|
708
702
|
}
|
|
709
703
|
const tokens = await exchangeCodeForTokens(code, pkce.verifier, authBase, redirectUri);
|
|
710
704
|
spinner.succeed('Access tokens received');
|
|
711
|
-
// Store OAuth tokens
|
|
705
|
+
// Store OAuth tokens - these are already valid auth-gateway tokens from /oauth/token
|
|
706
|
+
// No need for additional exchange since /oauth/token returns auth-gateway's own tokens
|
|
712
707
|
await config.setToken(tokens.access_token);
|
|
713
708
|
await config.set('refresh_token', tokens.refresh_token);
|
|
714
709
|
await config.set('token_expires_at', Date.now() + (tokens.expires_in * 1000));
|
|
715
|
-
|
|
710
|
+
await config.set('authMethod', 'oauth2');
|
|
711
|
+
// The OAuth access token from auth-gateway works as the API token for all services
|
|
712
|
+
// Store it as the vendor key equivalent for MCP and API access
|
|
716
713
|
spinner.text = 'Configuring unified access...';
|
|
717
714
|
spinner.start();
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
console.log(chalk.green('✓ OAuth2 authentication successful'));
|
|
726
|
-
console.log(colors.info('You can now use all Lanonasis services'));
|
|
727
|
-
console.log(chalk.gray('✓ MCP, API, and CLI access configured'));
|
|
728
|
-
}
|
|
729
|
-
else {
|
|
730
|
-
// Fallback
|
|
731
|
-
await config.set('authMethod', 'oauth2');
|
|
732
|
-
spinner.warn('Token exchange failed, OAuth token stored');
|
|
733
|
-
console.log();
|
|
734
|
-
console.log(chalk.green('✓ OAuth2 authentication successful'));
|
|
735
|
-
console.log(colors.info('You can now use Lanonasis services'));
|
|
736
|
-
console.log(chalk.yellow('⚠️ Some services may require re-authentication'));
|
|
737
|
-
}
|
|
715
|
+
// Use the OAuth access token directly - it's already an auth-gateway token
|
|
716
|
+
await config.setVendorKey(tokens.access_token);
|
|
717
|
+
spinner.succeed('Unified authentication configured');
|
|
718
|
+
console.log();
|
|
719
|
+
console.log(chalk.green('✓ OAuth2 authentication successful'));
|
|
720
|
+
console.log(colors.info('You can now use all Lanonasis services'));
|
|
721
|
+
console.log(chalk.gray('✓ MCP, API, and CLI access configured'));
|
|
738
722
|
process.exit(0);
|
|
739
723
|
}
|
|
740
724
|
catch (error) {
|
package/dist/utils/api.js
CHANGED
|
@@ -2,7 +2,6 @@ import axios from 'axios';
|
|
|
2
2
|
import chalk from 'chalk';
|
|
3
3
|
import { randomUUID } from 'crypto';
|
|
4
4
|
import { CLIConfig } from './config.js';
|
|
5
|
-
import { ensureApiKeyHash } from './hash-utils.js';
|
|
6
5
|
export class APIClient {
|
|
7
6
|
client;
|
|
8
7
|
config;
|
|
@@ -31,7 +30,8 @@ export class APIClient {
|
|
|
31
30
|
const vendorKey = this.config.getVendorKey();
|
|
32
31
|
if (vendorKey) {
|
|
33
32
|
// Vendor key authentication (validated server-side)
|
|
34
|
-
|
|
33
|
+
// Send raw key - server handles hashing for comparison
|
|
34
|
+
config.headers['X-API-Key'] = vendorKey;
|
|
35
35
|
config.headers['X-Auth-Method'] = 'vendor_key';
|
|
36
36
|
}
|
|
37
37
|
else if (token) {
|
|
@@ -100,61 +100,62 @@ export class APIClient {
|
|
|
100
100
|
return response.data;
|
|
101
101
|
}
|
|
102
102
|
// Memory operations - aligned with existing schema
|
|
103
|
+
// All memory endpoints use /api/v1/memory path
|
|
103
104
|
async createMemory(data) {
|
|
104
|
-
const response = await this.client.post('/memory', data);
|
|
105
|
+
const response = await this.client.post('/api/v1/memory', data);
|
|
105
106
|
return response.data;
|
|
106
107
|
}
|
|
107
108
|
async getMemories(params = {}) {
|
|
108
|
-
const response = await this.client.get('/memory', { params });
|
|
109
|
+
const response = await this.client.get('/api/v1/memory', { params });
|
|
109
110
|
return response.data;
|
|
110
111
|
}
|
|
111
112
|
async getMemory(id) {
|
|
112
|
-
const response = await this.client.get(`/memory/${id}`);
|
|
113
|
+
const response = await this.client.get(`/api/v1/memory/${id}`);
|
|
113
114
|
return response.data;
|
|
114
115
|
}
|
|
115
116
|
async updateMemory(id, data) {
|
|
116
|
-
const response = await this.client.put(`/memory/${id}`, data);
|
|
117
|
+
const response = await this.client.put(`/api/v1/memory/${id}`, data);
|
|
117
118
|
return response.data;
|
|
118
119
|
}
|
|
119
120
|
async deleteMemory(id) {
|
|
120
|
-
await this.client.delete(`/memory/${id}`);
|
|
121
|
+
await this.client.delete(`/api/v1/memory/${id}`);
|
|
121
122
|
}
|
|
122
123
|
async searchMemories(query, options = {}) {
|
|
123
|
-
const response = await this.client.post('/memory/search', {
|
|
124
|
+
const response = await this.client.post('/api/v1/memory/search', {
|
|
124
125
|
query,
|
|
125
126
|
...options
|
|
126
127
|
});
|
|
127
128
|
return response.data;
|
|
128
129
|
}
|
|
129
130
|
async getMemoryStats() {
|
|
130
|
-
const response = await this.client.get('/memory/stats');
|
|
131
|
+
const response = await this.client.get('/api/v1/memory/stats');
|
|
131
132
|
return response.data;
|
|
132
133
|
}
|
|
133
134
|
async bulkDeleteMemories(memoryIds) {
|
|
134
|
-
const response = await this.client.post('/memory/bulk/delete', {
|
|
135
|
+
const response = await this.client.post('/api/v1/memory/bulk/delete', {
|
|
135
136
|
memory_ids: memoryIds
|
|
136
137
|
});
|
|
137
138
|
return response.data;
|
|
138
139
|
}
|
|
139
140
|
// Topic operations - working with existing memory_topics table
|
|
140
141
|
async createTopic(data) {
|
|
141
|
-
const response = await this.client.post('/topics', data);
|
|
142
|
+
const response = await this.client.post('/api/v1/topics', data);
|
|
142
143
|
return response.data;
|
|
143
144
|
}
|
|
144
145
|
async getTopics() {
|
|
145
|
-
const response = await this.client.get('/topics');
|
|
146
|
+
const response = await this.client.get('/api/v1/topics');
|
|
146
147
|
return response.data;
|
|
147
148
|
}
|
|
148
149
|
async getTopic(id) {
|
|
149
|
-
const response = await this.client.get(`/topics/${id}`);
|
|
150
|
+
const response = await this.client.get(`/api/v1/topics/${id}`);
|
|
150
151
|
return response.data;
|
|
151
152
|
}
|
|
152
153
|
async updateTopic(id, data) {
|
|
153
|
-
const response = await this.client.put(`/topics/${id}`, data);
|
|
154
|
+
const response = await this.client.put(`/api/v1/topics/${id}`, data);
|
|
154
155
|
return response.data;
|
|
155
156
|
}
|
|
156
157
|
async deleteTopic(id) {
|
|
157
|
-
await this.client.delete(`/topics/${id}`);
|
|
158
|
+
await this.client.delete(`/api/v1/topics/${id}`);
|
|
158
159
|
}
|
|
159
160
|
// Health check
|
|
160
161
|
async getHealth() {
|
package/dist/utils/config.js
CHANGED
|
@@ -168,9 +168,11 @@ export class CLIConfig {
|
|
|
168
168
|
}
|
|
169
169
|
}
|
|
170
170
|
getApiUrl() {
|
|
171
|
-
|
|
171
|
+
const baseUrl = process.env.MEMORY_API_URL ||
|
|
172
172
|
this.config.apiUrl ||
|
|
173
|
-
'https://
|
|
173
|
+
'https://mcp.lanonasis.com';
|
|
174
|
+
// Ensure we don't double-append /api/v1 - strip it if present since APIClient adds it
|
|
175
|
+
return baseUrl.replace(/\/api\/v1\/?$/, '');
|
|
174
176
|
}
|
|
175
177
|
// Get API URLs with fallbacks - try multiple endpoints
|
|
176
178
|
getApiUrlsWithFallbacks() {
|
|
@@ -190,8 +192,8 @@ export class CLIConfig {
|
|
|
190
192
|
if (!this.config.discoveredServices) {
|
|
191
193
|
this.config.discoveredServices = {
|
|
192
194
|
auth_base: 'https://auth.lanonasis.com',
|
|
193
|
-
memory_base: 'https://mcp.lanonasis.com/api/v1
|
|
194
|
-
mcp_base: 'https://mcp.lanonasis.com/api/v1',
|
|
195
|
+
memory_base: 'https://mcp.lanonasis.com', // Base URL without /api/v1
|
|
196
|
+
mcp_base: 'https://mcp.lanonasis.com/api/v1', // Full MCP REST path
|
|
195
197
|
mcp_ws_base: 'wss://mcp.lanonasis.com/ws',
|
|
196
198
|
mcp_sse_base: 'https://mcp.lanonasis.com/api/v1/events',
|
|
197
199
|
project_scope: 'lanonasis-maas'
|
|
@@ -243,13 +245,16 @@ export class CLIConfig {
|
|
|
243
245
|
if (authBase.includes('localhost') || authBase.includes('127.0.0.1')) {
|
|
244
246
|
authBase = 'https://auth.lanonasis.com';
|
|
245
247
|
}
|
|
246
|
-
|
|
248
|
+
// Memory base should be the MCP base URL without /api/v1 suffix
|
|
249
|
+
// The API client will append the path as needed
|
|
250
|
+
const rawMemoryBase = discovered.endpoints?.http || 'https://mcp.lanonasis.com/api/v1';
|
|
251
|
+
const memoryBase = rawMemoryBase.replace(/\/api\/v1\/?$/, '') || 'https://mcp.lanonasis.com';
|
|
247
252
|
this.config.discoveredServices = {
|
|
248
253
|
auth_base: authBase || 'https://auth.lanonasis.com',
|
|
249
254
|
memory_base: memoryBase,
|
|
250
|
-
mcp_base: memoryBase
|
|
255
|
+
mcp_base: `${memoryBase}/api/v1`, // Full path for MCP REST calls
|
|
251
256
|
mcp_ws_base: discovered.endpoints?.websocket || 'wss://mcp.lanonasis.com/ws',
|
|
252
|
-
mcp_sse_base: discovered.endpoints?.sse ||
|
|
257
|
+
mcp_sse_base: discovered.endpoints?.sse || `${memoryBase}/api/v1/events`,
|
|
253
258
|
project_scope: 'lanonasis-maas'
|
|
254
259
|
};
|
|
255
260
|
this.config.apiUrl = memoryBase;
|
|
@@ -366,8 +371,8 @@ export class CLIConfig {
|
|
|
366
371
|
const nodeEnv = (process.env.NODE_ENV ?? '').toLowerCase();
|
|
367
372
|
const isDevEnvironment = nodeEnv === 'development' || nodeEnv === 'test';
|
|
368
373
|
const defaultAuthBase = isDevEnvironment ? 'http://localhost:4000' : 'https://auth.lanonasis.com';
|
|
369
|
-
const defaultMemoryBase = isDevEnvironment ? 'http://localhost:4000
|
|
370
|
-
const defaultMcpBase = isDevEnvironment ? 'http://localhost:4100/api/v1' : 'https://mcp.lanonasis.com/api/v1';
|
|
374
|
+
const defaultMemoryBase = isDevEnvironment ? 'http://localhost:4000' : 'https://mcp.lanonasis.com'; // Base URL without /api/v1
|
|
375
|
+
const defaultMcpBase = isDevEnvironment ? 'http://localhost:4100/api/v1' : 'https://mcp.lanonasis.com/api/v1'; // Full MCP REST path
|
|
371
376
|
const defaultMcpWsBase = isDevEnvironment ? 'ws://localhost:4100/ws' : 'wss://mcp.lanonasis.com/ws';
|
|
372
377
|
const defaultMcpSseBase = isDevEnvironment ? 'http://localhost:4100/api/v1/events' : 'https://mcp.lanonasis.com/api/v1/events';
|
|
373
378
|
const endpoints = {
|
|
@@ -433,8 +438,8 @@ export class CLIConfig {
|
|
|
433
438
|
}
|
|
434
439
|
const currentServices = this.config.discoveredServices ?? {
|
|
435
440
|
auth_base: 'https://auth.lanonasis.com',
|
|
436
|
-
memory_base: 'https://mcp.lanonasis.com/api/v1
|
|
437
|
-
mcp_base: 'https://mcp.lanonasis.com/api/v1',
|
|
441
|
+
memory_base: 'https://mcp.lanonasis.com', // Base URL without /api/v1
|
|
442
|
+
mcp_base: 'https://mcp.lanonasis.com/api/v1', // Full MCP REST path
|
|
438
443
|
mcp_ws_base: 'wss://mcp.lanonasis.com/ws',
|
|
439
444
|
mcp_sse_base: 'https://mcp.lanonasis.com/api/v1/events',
|
|
440
445
|
project_scope: 'lanonasis-maas'
|
package/dist/utils/mcp-client.js
CHANGED
|
@@ -456,9 +456,11 @@ export class MCPClient {
|
|
|
456
456
|
// Use the proper SSE endpoint from config
|
|
457
457
|
const sseUrl = this.config.getMCPSSEUrl() ?? `${serverUrl}/events`;
|
|
458
458
|
const token = this.config.get('token');
|
|
459
|
-
|
|
459
|
+
const vendorKey = this.config.get('vendorKey');
|
|
460
|
+
const authKey = token || vendorKey || process.env.LANONASIS_API_KEY;
|
|
461
|
+
if (authKey) {
|
|
460
462
|
// EventSource doesn't support headers directly, append token to URL
|
|
461
|
-
this.sseConnection = new EventSource(`${sseUrl}?token=${encodeURIComponent(
|
|
463
|
+
this.sseConnection = new EventSource(`${sseUrl}?token=${encodeURIComponent(authKey)}`);
|
|
462
464
|
this.sseConnection.onmessage = (event) => {
|
|
463
465
|
try {
|
|
464
466
|
const data = JSON.parse(event.data);
|
|
@@ -478,7 +480,9 @@ export class MCPClient {
|
|
|
478
480
|
*/
|
|
479
481
|
async initializeWebSocket(wsUrl) {
|
|
480
482
|
const token = this.config.get('token');
|
|
481
|
-
|
|
483
|
+
const vendorKey = this.config.get('vendorKey');
|
|
484
|
+
const authKey = token || vendorKey || process.env.LANONASIS_API_KEY;
|
|
485
|
+
if (!authKey) {
|
|
482
486
|
throw new Error('API key required for WebSocket mode. Set LANONASIS_API_KEY or login first.');
|
|
483
487
|
}
|
|
484
488
|
return new Promise((resolve, reject) => {
|
|
@@ -491,8 +495,8 @@ export class MCPClient {
|
|
|
491
495
|
// Create new WebSocket connection with authentication
|
|
492
496
|
this.wsConnection = new WebSocket(wsUrl, [], {
|
|
493
497
|
headers: {
|
|
494
|
-
'Authorization': `Bearer ${
|
|
495
|
-
'X-API-Key':
|
|
498
|
+
'Authorization': `Bearer ${authKey}`,
|
|
499
|
+
'X-API-Key': authKey
|
|
496
500
|
}
|
|
497
501
|
});
|
|
498
502
|
this.wsConnection.on('open', () => {
|
|
@@ -624,15 +628,17 @@ export class MCPClient {
|
|
|
624
628
|
async checkRemoteHealth() {
|
|
625
629
|
const apiUrl = this.config.getMCPRestUrl() ?? 'https://mcp.lanonasis.com/api/v1';
|
|
626
630
|
const token = this.config.get('token');
|
|
627
|
-
|
|
631
|
+
const vendorKey = this.config.get('vendorKey');
|
|
632
|
+
const authKey = token || vendorKey || process.env.LANONASIS_API_KEY;
|
|
633
|
+
if (!authKey) {
|
|
628
634
|
throw new Error('No authentication token available');
|
|
629
635
|
}
|
|
630
636
|
try {
|
|
631
637
|
const axios = (await import('axios')).default;
|
|
632
638
|
await axios.get(`${apiUrl}/health`, {
|
|
633
639
|
headers: {
|
|
634
|
-
'Authorization': `Bearer ${
|
|
635
|
-
'
|
|
640
|
+
'Authorization': `Bearer ${authKey}`,
|
|
641
|
+
'X-API-Key': authKey
|
|
636
642
|
},
|
|
637
643
|
timeout: 5000
|
|
638
644
|
});
|
|
@@ -749,7 +755,9 @@ export class MCPClient {
|
|
|
749
755
|
async callRemoteTool(toolName, args) {
|
|
750
756
|
const apiUrl = this.config.getMCPRestUrl() ?? 'https://mcp.lanonasis.com/api/v1';
|
|
751
757
|
const token = this.config.get('token');
|
|
752
|
-
|
|
758
|
+
const vendorKey = this.config.get('vendorKey');
|
|
759
|
+
const authKey = token || vendorKey || process.env.LANONASIS_API_KEY;
|
|
760
|
+
if (!authKey) {
|
|
753
761
|
throw new Error('Authentication required. Run "lanonasis auth login" first.');
|
|
754
762
|
}
|
|
755
763
|
// Map MCP tool names to REST API endpoints
|
|
@@ -805,8 +813,8 @@ export class MCPClient {
|
|
|
805
813
|
method: mapping.method,
|
|
806
814
|
url: `${apiUrl}${endpoint}`,
|
|
807
815
|
headers: {
|
|
808
|
-
'Authorization': `Bearer ${
|
|
809
|
-
'
|
|
816
|
+
'Authorization': `Bearer ${authKey}`,
|
|
817
|
+
'X-API-Key': authKey,
|
|
810
818
|
'Content-Type': 'application/json'
|
|
811
819
|
},
|
|
812
820
|
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.7.
|
|
3
|
+
"version": "3.7.6",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -46,7 +46,7 @@
|
|
|
46
46
|
"@jest/globals": "^29.7.0",
|
|
47
47
|
"@types/cli-progress": "^3.11.6",
|
|
48
48
|
"@types/inquirer": "^9.0.7",
|
|
49
|
-
"@types/node": "^22.
|
|
49
|
+
"@types/node": "^22.19.3",
|
|
50
50
|
"@types/ws": "^8.5.12",
|
|
51
51
|
"jest": "^29.7.0",
|
|
52
52
|
"rimraf": "^5.0.7",
|