@lanonasis/cli 1.5.0 → 1.5.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/README.md +80 -357
- package/dist/commands/api-keys.d.ts +3 -0
- package/dist/commands/api-keys.js +812 -0
- package/dist/commands/auth.js +1 -151
- package/dist/commands/mcp.js +30 -37
- package/dist/commands/memory.js +53 -78
- package/dist/index-simple.js +522 -189
- package/dist/index.js +327 -221
- package/dist/mcp-server.d.ts +2 -0
- package/dist/mcp-server.js +519 -0
- package/dist/utils/api.d.ts +12 -2
- package/dist/utils/api.js +17 -0
- package/dist/utils/config.d.ts +0 -2
- package/dist/utils/config.js +2 -15
- package/dist/utils/formatting.d.ts +2 -0
- package/dist/utils/formatting.js +13 -0
- package/dist/utils/mcp-client.d.ts +49 -6
- package/dist/utils/mcp-client.js +161 -82
- package/package.json +17 -10
- package/dist/utils/completions.d.ts +0 -28
- package/dist/utils/completions.js +0 -276
- package/dist/utils/mcp-client.test.d.ts +0 -1
- package/dist/utils/mcp-client.test.js +0 -125
- package/dist/utils/output.d.ts +0 -23
- package/dist/utils/output.js +0 -97
- package/dist/utils/websocket-mcp-client.d.ts +0 -60
- package/dist/utils/websocket-mcp-client.js +0 -182
- package/dist/utils/websocket-mcp-client.test.d.ts +0 -1
- package/dist/utils/websocket-mcp-client.test.js +0 -126
|
@@ -0,0 +1,519 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
|
|
3
|
+
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
|
4
|
+
import { CallToolRequestSchema, ListToolsRequestSchema } from '@modelcontextprotocol/sdk/types.js';
|
|
5
|
+
import { CLIConfig } from './utils/config.js';
|
|
6
|
+
// MCP Protocol Compliance: Redirect all console output to stderr
|
|
7
|
+
// This prevents stdout pollution which breaks JSON-RPC communication
|
|
8
|
+
const originalConsoleError = console.error;
|
|
9
|
+
// Silent mode for MCP protocol compliance
|
|
10
|
+
const isSilentMode = process.env.LANONASIS_SILENT === 'true' || process.argv.includes('--silent');
|
|
11
|
+
if (isSilentMode) {
|
|
12
|
+
// Completely silence all output except JSON-RPC
|
|
13
|
+
console.log = () => { };
|
|
14
|
+
console.error = () => { };
|
|
15
|
+
console.warn = () => { };
|
|
16
|
+
console.info = () => { };
|
|
17
|
+
console.debug = () => { };
|
|
18
|
+
}
|
|
19
|
+
else {
|
|
20
|
+
// Redirect to stderr for debugging
|
|
21
|
+
console.log = (...args) => originalConsoleError('[MCP-LOG]', ...args);
|
|
22
|
+
console.error = (...args) => originalConsoleError('[MCP-ERROR]', ...args);
|
|
23
|
+
console.warn = (...args) => originalConsoleError('[MCP-WARN]', ...args);
|
|
24
|
+
console.info = (...args) => originalConsoleError('[MCP-INFO]', ...args);
|
|
25
|
+
}
|
|
26
|
+
// Disable colors and verbose output for MCP protocol compliance
|
|
27
|
+
process.env.FORCE_COLOR = '0';
|
|
28
|
+
process.env.DEBUG = '';
|
|
29
|
+
process.env.NODE_ENV = process.env.NODE_ENV || 'production';
|
|
30
|
+
class LanonasisMCPServer {
|
|
31
|
+
server;
|
|
32
|
+
config;
|
|
33
|
+
constructor() {
|
|
34
|
+
this.config = new CLIConfig();
|
|
35
|
+
this.server = new Server({
|
|
36
|
+
name: 'lanonasis-mcp-server',
|
|
37
|
+
version: '1.3.0',
|
|
38
|
+
}, {
|
|
39
|
+
capabilities: {
|
|
40
|
+
tools: {},
|
|
41
|
+
resources: {},
|
|
42
|
+
},
|
|
43
|
+
});
|
|
44
|
+
this.setupHandlers();
|
|
45
|
+
}
|
|
46
|
+
setupHandlers() {
|
|
47
|
+
// List available tools - Comprehensive MCP toolset matching legacy CLI
|
|
48
|
+
this.server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
49
|
+
return {
|
|
50
|
+
tools: [
|
|
51
|
+
// Memory Management Tools
|
|
52
|
+
{
|
|
53
|
+
name: 'create_memory',
|
|
54
|
+
description: 'Create a new memory entry with vector embedding',
|
|
55
|
+
inputSchema: {
|
|
56
|
+
type: 'object',
|
|
57
|
+
properties: {
|
|
58
|
+
title: { type: 'string', description: 'Memory title' },
|
|
59
|
+
content: { type: 'string', description: 'Memory content' },
|
|
60
|
+
memory_type: { type: 'string', description: 'Type of memory', enum: ['context', 'project', 'knowledge', 'reference', 'personal', 'workflow'] },
|
|
61
|
+
tags: { type: 'array', items: { type: 'string' }, description: 'Memory tags' },
|
|
62
|
+
topic_id: { type: 'string', description: 'Topic ID for organization' }
|
|
63
|
+
},
|
|
64
|
+
required: ['title', 'content']
|
|
65
|
+
}
|
|
66
|
+
},
|
|
67
|
+
{
|
|
68
|
+
name: 'search_memories',
|
|
69
|
+
description: 'Search through memories with semantic vector search',
|
|
70
|
+
inputSchema: {
|
|
71
|
+
type: 'object',
|
|
72
|
+
properties: {
|
|
73
|
+
query: { type: 'string', description: 'Search query' },
|
|
74
|
+
memory_type: { type: 'string', description: 'Filter by memory type' },
|
|
75
|
+
limit: { type: 'number', description: 'Maximum results to return', default: 10 },
|
|
76
|
+
threshold: { type: 'number', description: 'Similarity threshold (0.0-1.0)', default: 0.7 },
|
|
77
|
+
tags: { type: 'array', items: { type: 'string' }, description: 'Filter by tags' }
|
|
78
|
+
},
|
|
79
|
+
required: ['query']
|
|
80
|
+
}
|
|
81
|
+
},
|
|
82
|
+
{
|
|
83
|
+
name: 'get_memory',
|
|
84
|
+
description: 'Get a specific memory by ID',
|
|
85
|
+
inputSchema: {
|
|
86
|
+
type: 'object',
|
|
87
|
+
properties: {
|
|
88
|
+
id: { type: 'string', description: 'Memory ID' }
|
|
89
|
+
},
|
|
90
|
+
required: ['id']
|
|
91
|
+
}
|
|
92
|
+
},
|
|
93
|
+
{
|
|
94
|
+
name: 'update_memory',
|
|
95
|
+
description: 'Update an existing memory',
|
|
96
|
+
inputSchema: {
|
|
97
|
+
type: 'object',
|
|
98
|
+
properties: {
|
|
99
|
+
id: { type: 'string', description: 'Memory ID' },
|
|
100
|
+
title: { type: 'string', description: 'Memory title' },
|
|
101
|
+
content: { type: 'string', description: 'Memory content' },
|
|
102
|
+
memory_type: { type: 'string', description: 'Type of memory' },
|
|
103
|
+
tags: { type: 'array', items: { type: 'string' }, description: 'Memory tags' }
|
|
104
|
+
},
|
|
105
|
+
required: ['id']
|
|
106
|
+
}
|
|
107
|
+
},
|
|
108
|
+
{
|
|
109
|
+
name: 'delete_memory',
|
|
110
|
+
description: 'Delete a memory by ID',
|
|
111
|
+
inputSchema: {
|
|
112
|
+
type: 'object',
|
|
113
|
+
properties: {
|
|
114
|
+
id: { type: 'string', description: 'Memory ID' }
|
|
115
|
+
},
|
|
116
|
+
required: ['id']
|
|
117
|
+
}
|
|
118
|
+
},
|
|
119
|
+
{
|
|
120
|
+
name: 'list_memories',
|
|
121
|
+
description: 'List memories with pagination and filters',
|
|
122
|
+
inputSchema: {
|
|
123
|
+
type: 'object',
|
|
124
|
+
properties: {
|
|
125
|
+
limit: { type: 'number', description: 'Number of memories to return', default: 20 },
|
|
126
|
+
offset: { type: 'number', description: 'Offset for pagination', default: 0 },
|
|
127
|
+
memory_type: { type: 'string', description: 'Filter by memory type' },
|
|
128
|
+
tags: { type: 'array', items: { type: 'string' }, description: 'Filter by tags' }
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
},
|
|
132
|
+
// API Key Management Tools
|
|
133
|
+
{
|
|
134
|
+
name: 'create_api_key',
|
|
135
|
+
description: 'Create a new API key',
|
|
136
|
+
inputSchema: {
|
|
137
|
+
type: 'object',
|
|
138
|
+
properties: {
|
|
139
|
+
name: { type: 'string', description: 'API key name' },
|
|
140
|
+
description: { type: 'string', description: 'API key description' },
|
|
141
|
+
project_id: { type: 'string', description: 'Project ID' },
|
|
142
|
+
access_level: { type: 'string', description: 'Access level', enum: ['public', 'authenticated', 'team', 'admin', 'enterprise'] },
|
|
143
|
+
expires_in_days: { type: 'number', description: 'Expiration in days', default: 365 }
|
|
144
|
+
},
|
|
145
|
+
required: ['name']
|
|
146
|
+
}
|
|
147
|
+
},
|
|
148
|
+
{
|
|
149
|
+
name: 'list_api_keys',
|
|
150
|
+
description: 'List API keys',
|
|
151
|
+
inputSchema: {
|
|
152
|
+
type: 'object',
|
|
153
|
+
properties: {
|
|
154
|
+
project_id: { type: 'string', description: 'Filter by project ID' },
|
|
155
|
+
active_only: { type: 'boolean', description: 'Show only active keys', default: true }
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
},
|
|
159
|
+
{
|
|
160
|
+
name: 'rotate_api_key',
|
|
161
|
+
description: 'Rotate an API key',
|
|
162
|
+
inputSchema: {
|
|
163
|
+
type: 'object',
|
|
164
|
+
properties: {
|
|
165
|
+
key_id: { type: 'string', description: 'API key ID to rotate' }
|
|
166
|
+
},
|
|
167
|
+
required: ['key_id']
|
|
168
|
+
}
|
|
169
|
+
},
|
|
170
|
+
{
|
|
171
|
+
name: 'delete_api_key',
|
|
172
|
+
description: 'Delete an API key',
|
|
173
|
+
inputSchema: {
|
|
174
|
+
type: 'object',
|
|
175
|
+
properties: {
|
|
176
|
+
key_id: { type: 'string', description: 'API key ID to delete' }
|
|
177
|
+
},
|
|
178
|
+
required: ['key_id']
|
|
179
|
+
}
|
|
180
|
+
},
|
|
181
|
+
// Project Management Tools
|
|
182
|
+
{
|
|
183
|
+
name: 'create_project',
|
|
184
|
+
description: 'Create a new project',
|
|
185
|
+
inputSchema: {
|
|
186
|
+
type: 'object',
|
|
187
|
+
properties: {
|
|
188
|
+
name: { type: 'string', description: 'Project name' },
|
|
189
|
+
description: { type: 'string', description: 'Project description' },
|
|
190
|
+
organization_id: { type: 'string', description: 'Organization ID' }
|
|
191
|
+
},
|
|
192
|
+
required: ['name']
|
|
193
|
+
}
|
|
194
|
+
},
|
|
195
|
+
{
|
|
196
|
+
name: 'list_projects',
|
|
197
|
+
description: 'List projects',
|
|
198
|
+
inputSchema: {
|
|
199
|
+
type: 'object',
|
|
200
|
+
properties: {
|
|
201
|
+
organization_id: { type: 'string', description: 'Filter by organization ID' }
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
},
|
|
205
|
+
// Organization Management Tools
|
|
206
|
+
{
|
|
207
|
+
name: 'get_organization_info',
|
|
208
|
+
description: 'Get organization information',
|
|
209
|
+
inputSchema: {
|
|
210
|
+
type: 'object',
|
|
211
|
+
properties: {}
|
|
212
|
+
}
|
|
213
|
+
},
|
|
214
|
+
// Authentication Tools
|
|
215
|
+
{
|
|
216
|
+
name: 'get_auth_status',
|
|
217
|
+
description: 'Get authentication status',
|
|
218
|
+
inputSchema: {
|
|
219
|
+
type: 'object',
|
|
220
|
+
properties: {}
|
|
221
|
+
}
|
|
222
|
+
},
|
|
223
|
+
// Configuration Tools
|
|
224
|
+
{
|
|
225
|
+
name: 'get_config',
|
|
226
|
+
description: 'Get configuration settings',
|
|
227
|
+
inputSchema: {
|
|
228
|
+
type: 'object',
|
|
229
|
+
properties: {
|
|
230
|
+
key: { type: 'string', description: 'Specific config key to retrieve' }
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
},
|
|
234
|
+
{
|
|
235
|
+
name: 'set_config',
|
|
236
|
+
description: 'Set configuration setting',
|
|
237
|
+
inputSchema: {
|
|
238
|
+
type: 'object',
|
|
239
|
+
properties: {
|
|
240
|
+
key: { type: 'string', description: 'Configuration key' },
|
|
241
|
+
value: { type: 'string', description: 'Configuration value' }
|
|
242
|
+
},
|
|
243
|
+
required: ['key', 'value']
|
|
244
|
+
}
|
|
245
|
+
},
|
|
246
|
+
// Health and Status Tools
|
|
247
|
+
{
|
|
248
|
+
name: 'get_health_status',
|
|
249
|
+
description: 'Get system health status',
|
|
250
|
+
inputSchema: {
|
|
251
|
+
type: 'object',
|
|
252
|
+
properties: {}
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
]
|
|
256
|
+
};
|
|
257
|
+
});
|
|
258
|
+
// Handle tool calls - Comprehensive implementation
|
|
259
|
+
this.server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
260
|
+
const { name, arguments: args } = request.params;
|
|
261
|
+
try {
|
|
262
|
+
const apiKey = process.env.LANONASIS_API_KEY;
|
|
263
|
+
const apiUrl = process.env.LANONASIS_API_URL || 'https://dashboard.lanonasis.com';
|
|
264
|
+
if (!apiKey) {
|
|
265
|
+
return {
|
|
266
|
+
content: [
|
|
267
|
+
{
|
|
268
|
+
type: 'text',
|
|
269
|
+
text: 'Error: LANONASIS_API_KEY environment variable is required'
|
|
270
|
+
}
|
|
271
|
+
]
|
|
272
|
+
};
|
|
273
|
+
}
|
|
274
|
+
const headers = {
|
|
275
|
+
'Authorization': `Bearer ${apiKey}`,
|
|
276
|
+
'Content-Type': 'application/json',
|
|
277
|
+
'User-Agent': 'lanonasis-mcp-server/1.3.0'
|
|
278
|
+
};
|
|
279
|
+
switch (name) {
|
|
280
|
+
// Memory Management Tools
|
|
281
|
+
case 'create_memory': {
|
|
282
|
+
const response = await fetch(`${apiUrl}/api/v1/memory`, {
|
|
283
|
+
method: 'POST',
|
|
284
|
+
headers,
|
|
285
|
+
body: JSON.stringify(args)
|
|
286
|
+
});
|
|
287
|
+
if (!response.ok) {
|
|
288
|
+
const errorText = await response.text();
|
|
289
|
+
throw new Error(`Memory creation failed: ${response.status} ${response.statusText} - ${errorText}`);
|
|
290
|
+
}
|
|
291
|
+
const result = await response.json();
|
|
292
|
+
return {
|
|
293
|
+
content: [
|
|
294
|
+
{
|
|
295
|
+
type: 'text',
|
|
296
|
+
text: `✅ Memory created successfully:\n${JSON.stringify(result, null, 2)}`
|
|
297
|
+
}
|
|
298
|
+
]
|
|
299
|
+
};
|
|
300
|
+
}
|
|
301
|
+
case 'search_memories': {
|
|
302
|
+
const queryParams = new URLSearchParams();
|
|
303
|
+
if (args.query)
|
|
304
|
+
queryParams.append('query', String(args.query));
|
|
305
|
+
if (args.memory_type)
|
|
306
|
+
queryParams.append('memory_type', String(args.memory_type));
|
|
307
|
+
if (args.limit)
|
|
308
|
+
queryParams.append('limit', args.limit.toString());
|
|
309
|
+
if (args.threshold)
|
|
310
|
+
queryParams.append('threshold', args.threshold.toString());
|
|
311
|
+
if (args.tags && Array.isArray(args.tags)) {
|
|
312
|
+
args.tags.forEach((tag) => queryParams.append('tags', String(tag)));
|
|
313
|
+
}
|
|
314
|
+
const response = await fetch(`${apiUrl}/api/v1/memory/search?${queryParams}`, {
|
|
315
|
+
method: 'GET',
|
|
316
|
+
headers
|
|
317
|
+
});
|
|
318
|
+
if (!response.ok) {
|
|
319
|
+
const errorText = await response.text();
|
|
320
|
+
throw new Error(`Memory search failed: ${response.status} ${response.statusText} - ${errorText}`);
|
|
321
|
+
}
|
|
322
|
+
const result = await response.json();
|
|
323
|
+
return {
|
|
324
|
+
content: [
|
|
325
|
+
{
|
|
326
|
+
type: 'text',
|
|
327
|
+
text: `🔍 Search results (${result.length || 0} found):\n${JSON.stringify(result, null, 2)}`
|
|
328
|
+
}
|
|
329
|
+
]
|
|
330
|
+
};
|
|
331
|
+
}
|
|
332
|
+
case 'get_memory': {
|
|
333
|
+
const response = await fetch(`${apiUrl}/api/v1/memory/${args.id}`, {
|
|
334
|
+
method: 'GET',
|
|
335
|
+
headers
|
|
336
|
+
});
|
|
337
|
+
if (!response.ok) {
|
|
338
|
+
const errorText = await response.text();
|
|
339
|
+
throw new Error(`Memory retrieval failed: ${response.status} ${response.statusText} - ${errorText}`);
|
|
340
|
+
}
|
|
341
|
+
const result = await response.json();
|
|
342
|
+
return {
|
|
343
|
+
content: [
|
|
344
|
+
{
|
|
345
|
+
type: 'text',
|
|
346
|
+
text: `📄 Memory details:\n${JSON.stringify(result, null, 2)}`
|
|
347
|
+
}
|
|
348
|
+
]
|
|
349
|
+
};
|
|
350
|
+
}
|
|
351
|
+
case 'update_memory': {
|
|
352
|
+
const { id, ...updateData } = args;
|
|
353
|
+
const response = await fetch(`${apiUrl}/api/v1/memory/${id}`, {
|
|
354
|
+
method: 'PUT',
|
|
355
|
+
headers,
|
|
356
|
+
body: JSON.stringify(updateData)
|
|
357
|
+
});
|
|
358
|
+
if (!response.ok) {
|
|
359
|
+
const errorText = await response.text();
|
|
360
|
+
throw new Error(`Memory update failed: ${response.status} ${response.statusText} - ${errorText}`);
|
|
361
|
+
}
|
|
362
|
+
const result = await response.json();
|
|
363
|
+
return {
|
|
364
|
+
content: [
|
|
365
|
+
{
|
|
366
|
+
type: 'text',
|
|
367
|
+
text: `✏️ Memory updated successfully:\n${JSON.stringify(result, null, 2)}`
|
|
368
|
+
}
|
|
369
|
+
]
|
|
370
|
+
};
|
|
371
|
+
}
|
|
372
|
+
case 'delete_memory': {
|
|
373
|
+
const response = await fetch(`${apiUrl}/api/v1/memory/${args.id}`, {
|
|
374
|
+
method: 'DELETE',
|
|
375
|
+
headers
|
|
376
|
+
});
|
|
377
|
+
if (!response.ok) {
|
|
378
|
+
const errorText = await response.text();
|
|
379
|
+
throw new Error(`Memory deletion failed: ${response.status} ${response.statusText} - ${errorText}`);
|
|
380
|
+
}
|
|
381
|
+
return {
|
|
382
|
+
content: [
|
|
383
|
+
{
|
|
384
|
+
type: 'text',
|
|
385
|
+
text: `🗑️ Memory deleted successfully (ID: ${args.id})`
|
|
386
|
+
}
|
|
387
|
+
]
|
|
388
|
+
};
|
|
389
|
+
}
|
|
390
|
+
case 'list_memories': {
|
|
391
|
+
const queryParams = new URLSearchParams();
|
|
392
|
+
if (args.limit)
|
|
393
|
+
queryParams.append('limit', args.limit.toString());
|
|
394
|
+
if (args.offset)
|
|
395
|
+
queryParams.append('offset', args.offset.toString());
|
|
396
|
+
if (args.memory_type)
|
|
397
|
+
queryParams.append('memory_type', String(args.memory_type));
|
|
398
|
+
if (args.tags && Array.isArray(args.tags)) {
|
|
399
|
+
args.tags.forEach((tag) => queryParams.append('tags', String(tag)));
|
|
400
|
+
}
|
|
401
|
+
const response = await fetch(`${apiUrl}/api/v1/memory?${queryParams}`, {
|
|
402
|
+
method: 'GET',
|
|
403
|
+
headers
|
|
404
|
+
});
|
|
405
|
+
if (!response.ok) {
|
|
406
|
+
const errorText = await response.text();
|
|
407
|
+
throw new Error(`Memory listing failed: ${response.status} ${response.statusText} - ${errorText}`);
|
|
408
|
+
}
|
|
409
|
+
const result = await response.json();
|
|
410
|
+
return {
|
|
411
|
+
content: [
|
|
412
|
+
{
|
|
413
|
+
type: 'text',
|
|
414
|
+
text: `📋 Memory list (${result.length || 0} items):\n${JSON.stringify(result, null, 2)}`
|
|
415
|
+
}
|
|
416
|
+
]
|
|
417
|
+
};
|
|
418
|
+
}
|
|
419
|
+
// API Key Management Tools
|
|
420
|
+
case 'create_api_key': {
|
|
421
|
+
const response = await fetch(`${apiUrl}/api/v1/api-keys`, {
|
|
422
|
+
method: 'POST',
|
|
423
|
+
headers,
|
|
424
|
+
body: JSON.stringify(args)
|
|
425
|
+
});
|
|
426
|
+
if (!response.ok) {
|
|
427
|
+
const errorText = await response.text();
|
|
428
|
+
throw new Error(`API key creation failed: ${response.status} ${response.statusText} - ${errorText}`);
|
|
429
|
+
}
|
|
430
|
+
const result = await response.json();
|
|
431
|
+
return {
|
|
432
|
+
content: [
|
|
433
|
+
{
|
|
434
|
+
type: 'text',
|
|
435
|
+
text: `🔑 API key created successfully:\n${JSON.stringify(result, null, 2)}`
|
|
436
|
+
}
|
|
437
|
+
]
|
|
438
|
+
};
|
|
439
|
+
}
|
|
440
|
+
case 'list_api_keys': {
|
|
441
|
+
const queryParams = new URLSearchParams();
|
|
442
|
+
if (args.project_id)
|
|
443
|
+
queryParams.append('project_id', String(args.project_id));
|
|
444
|
+
if (args.active_only !== undefined)
|
|
445
|
+
queryParams.append('active_only', args.active_only.toString());
|
|
446
|
+
const response = await fetch(`${apiUrl}/api/v1/api-keys?${queryParams}`, {
|
|
447
|
+
method: 'GET',
|
|
448
|
+
headers
|
|
449
|
+
});
|
|
450
|
+
if (!response.ok) {
|
|
451
|
+
const errorText = await response.text();
|
|
452
|
+
throw new Error(`API key listing failed: ${response.status} ${response.statusText} - ${errorText}`);
|
|
453
|
+
}
|
|
454
|
+
const result = await response.json();
|
|
455
|
+
return {
|
|
456
|
+
content: [
|
|
457
|
+
{
|
|
458
|
+
type: 'text',
|
|
459
|
+
text: `🔑 API keys (${result.length || 0} found):\n${JSON.stringify(result, null, 2)}`
|
|
460
|
+
}
|
|
461
|
+
]
|
|
462
|
+
};
|
|
463
|
+
}
|
|
464
|
+
case 'get_health_status': {
|
|
465
|
+
const response = await fetch(`${apiUrl}/api/v1/health`, {
|
|
466
|
+
method: 'GET',
|
|
467
|
+
headers
|
|
468
|
+
});
|
|
469
|
+
if (!response.ok) {
|
|
470
|
+
const errorText = await response.text();
|
|
471
|
+
throw new Error(`Health check failed: ${response.status} ${response.statusText} - ${errorText}`);
|
|
472
|
+
}
|
|
473
|
+
const result = await response.json();
|
|
474
|
+
return {
|
|
475
|
+
content: [
|
|
476
|
+
{
|
|
477
|
+
type: 'text',
|
|
478
|
+
text: `💚 System health status:\n${JSON.stringify(result, null, 2)}`
|
|
479
|
+
}
|
|
480
|
+
]
|
|
481
|
+
};
|
|
482
|
+
}
|
|
483
|
+
default:
|
|
484
|
+
return {
|
|
485
|
+
content: [
|
|
486
|
+
{
|
|
487
|
+
type: 'text',
|
|
488
|
+
text: `❌ Unknown tool: ${name}. Available tools: create_memory, search_memories, get_memory, update_memory, delete_memory, list_memories, create_api_key, list_api_keys, get_health_status`
|
|
489
|
+
}
|
|
490
|
+
]
|
|
491
|
+
};
|
|
492
|
+
}
|
|
493
|
+
}
|
|
494
|
+
catch (error) {
|
|
495
|
+
const errorMessage = error instanceof Error ? error.message : 'Unknown error occurred';
|
|
496
|
+
return {
|
|
497
|
+
content: [
|
|
498
|
+
{
|
|
499
|
+
type: 'text',
|
|
500
|
+
text: `❌ Error: ${errorMessage}`
|
|
501
|
+
}
|
|
502
|
+
]
|
|
503
|
+
};
|
|
504
|
+
}
|
|
505
|
+
});
|
|
506
|
+
}
|
|
507
|
+
async run() {
|
|
508
|
+
const transport = new StdioServerTransport();
|
|
509
|
+
await this.server.connect(transport);
|
|
510
|
+
// Log to stderr that server is ready
|
|
511
|
+
console.error('[MCP-INFO] Lanonasis MCP Server started and ready');
|
|
512
|
+
}
|
|
513
|
+
}
|
|
514
|
+
// Start the server
|
|
515
|
+
const server = new LanonasisMCPServer();
|
|
516
|
+
server.run().catch((error) => {
|
|
517
|
+
console.error('[MCP-ERROR] Failed to start server:', error);
|
|
518
|
+
process.exit(1);
|
|
519
|
+
});
|
package/dist/utils/api.d.ts
CHANGED
|
@@ -57,7 +57,7 @@ export interface GetMemoriesParams {
|
|
|
57
57
|
limit?: number;
|
|
58
58
|
offset?: number;
|
|
59
59
|
memory_type?: MemoryType;
|
|
60
|
-
tags?: string[];
|
|
60
|
+
tags?: string[] | string;
|
|
61
61
|
topic_id?: string;
|
|
62
62
|
sort_by?: 'created_at' | 'updated_at' | 'last_accessed' | 'access_count';
|
|
63
63
|
sort_order?: 'asc' | 'desc';
|
|
@@ -125,13 +125,19 @@ export interface HealthStatus {
|
|
|
125
125
|
}>;
|
|
126
126
|
}
|
|
127
127
|
export interface PaginatedResponse<T> {
|
|
128
|
-
data
|
|
128
|
+
data?: T[];
|
|
129
|
+
memories?: T[];
|
|
130
|
+
results?: T[];
|
|
129
131
|
pagination: {
|
|
130
132
|
total: number;
|
|
131
133
|
limit: number;
|
|
132
134
|
offset: number;
|
|
133
135
|
has_more: boolean;
|
|
136
|
+
page?: number;
|
|
137
|
+
pages?: number;
|
|
134
138
|
};
|
|
139
|
+
total_results?: number;
|
|
140
|
+
search_time_ms?: number;
|
|
135
141
|
}
|
|
136
142
|
export interface ApiErrorResponse {
|
|
137
143
|
error: string;
|
|
@@ -159,6 +165,10 @@ export declare class APIClient {
|
|
|
159
165
|
updateTopic(id: string, data: UpdateTopicRequest): Promise<MemoryTopic>;
|
|
160
166
|
deleteTopic(id: string): Promise<void>;
|
|
161
167
|
getHealth(): Promise<HealthStatus>;
|
|
168
|
+
get<T = any>(url: string, config?: AxiosRequestConfig): Promise<T>;
|
|
169
|
+
post<T = any>(url: string, data?: any, config?: AxiosRequestConfig): Promise<T>;
|
|
170
|
+
put<T = any>(url: string, data?: any, config?: AxiosRequestConfig): Promise<T>;
|
|
171
|
+
delete<T = any>(url: string, config?: AxiosRequestConfig): Promise<T>;
|
|
162
172
|
request<T = Record<string, unknown>>(config: AxiosRequestConfig): Promise<T>;
|
|
163
173
|
}
|
|
164
174
|
export declare const apiClient: APIClient;
|
package/dist/utils/api.js
CHANGED
|
@@ -132,6 +132,23 @@ export class APIClient {
|
|
|
132
132
|
const response = await this.client.get('/api/v1/health');
|
|
133
133
|
return response.data;
|
|
134
134
|
}
|
|
135
|
+
// Generic HTTP methods
|
|
136
|
+
async get(url, config) {
|
|
137
|
+
const response = await this.client.get(url, config);
|
|
138
|
+
return response.data;
|
|
139
|
+
}
|
|
140
|
+
async post(url, data, config) {
|
|
141
|
+
const response = await this.client.post(url, data, config);
|
|
142
|
+
return response.data;
|
|
143
|
+
}
|
|
144
|
+
async put(url, data, config) {
|
|
145
|
+
const response = await this.client.put(url, data, config);
|
|
146
|
+
return response.data;
|
|
147
|
+
}
|
|
148
|
+
async delete(url, config) {
|
|
149
|
+
const response = await this.client.delete(url, config);
|
|
150
|
+
return response.data;
|
|
151
|
+
}
|
|
135
152
|
// Generic request method
|
|
136
153
|
async request(config) {
|
|
137
154
|
const response = await this.client.request(config);
|
package/dist/utils/config.d.ts
CHANGED
|
@@ -16,8 +16,6 @@ export declare class CLIConfig {
|
|
|
16
16
|
setApiUrl(url: string): Promise<void>;
|
|
17
17
|
setToken(token: string): Promise<void>;
|
|
18
18
|
getToken(): string | undefined;
|
|
19
|
-
setApiKey(apiKey: string): Promise<void>;
|
|
20
|
-
getApiKey(): string | undefined;
|
|
21
19
|
getCurrentUser(): Promise<UserProfile | undefined>;
|
|
22
20
|
isAuthenticated(): Promise<boolean>;
|
|
23
21
|
logout(): Promise<void>;
|
package/dist/utils/config.js
CHANGED
|
@@ -39,7 +39,7 @@ export class CLIConfig {
|
|
|
39
39
|
getApiUrl() {
|
|
40
40
|
return process.env.MEMORY_API_URL ||
|
|
41
41
|
this.config.apiUrl ||
|
|
42
|
-
'
|
|
42
|
+
'https://api.lanonasis.com';
|
|
43
43
|
}
|
|
44
44
|
async setApiUrl(url) {
|
|
45
45
|
this.config.apiUrl = url;
|
|
@@ -67,22 +67,10 @@ export class CLIConfig {
|
|
|
67
67
|
getToken() {
|
|
68
68
|
return this.config.token;
|
|
69
69
|
}
|
|
70
|
-
async setApiKey(apiKey) {
|
|
71
|
-
this.config.apiKey = apiKey;
|
|
72
|
-
await this.save();
|
|
73
|
-
}
|
|
74
|
-
getApiKey() {
|
|
75
|
-
return this.config.apiKey || process.env.LANONASIS_API_KEY;
|
|
76
|
-
}
|
|
77
70
|
async getCurrentUser() {
|
|
78
71
|
return this.config.user;
|
|
79
72
|
}
|
|
80
73
|
async isAuthenticated() {
|
|
81
|
-
// Check for API key first
|
|
82
|
-
const apiKey = this.getApiKey();
|
|
83
|
-
if (apiKey)
|
|
84
|
-
return true;
|
|
85
|
-
// Then check for valid JWT token
|
|
86
74
|
const token = this.getToken();
|
|
87
75
|
if (!token)
|
|
88
76
|
return false;
|
|
@@ -97,7 +85,6 @@ export class CLIConfig {
|
|
|
97
85
|
}
|
|
98
86
|
async logout() {
|
|
99
87
|
this.config.token = undefined;
|
|
100
|
-
this.config.apiKey = undefined;
|
|
101
88
|
this.config.user = undefined;
|
|
102
89
|
await this.save();
|
|
103
90
|
}
|
|
@@ -133,7 +120,7 @@ export class CLIConfig {
|
|
|
133
120
|
return this.config.mcpServerPath || path.join(__dirname, '../../../../onasis-gateway/mcp-server/server.js');
|
|
134
121
|
}
|
|
135
122
|
getMCPServerUrl() {
|
|
136
|
-
return this.config.mcpServerUrl || 'https://
|
|
123
|
+
return this.config.mcpServerUrl || 'https://dashboard.lanonasis.com';
|
|
137
124
|
}
|
|
138
125
|
shouldUseRemoteMCP() {
|
|
139
126
|
const preference = this.config.mcpPreference || 'auto';
|
|
@@ -2,3 +2,5 @@ export declare function formatOutput(data: unknown, format?: string): void;
|
|
|
2
2
|
export declare function formatBytes(bytes: number): string;
|
|
3
3
|
export declare function truncateText(text: string, maxLength: number): string;
|
|
4
4
|
export declare function formatDuration(ms: number): string;
|
|
5
|
+
export declare function formatDate(date: string | Date): string;
|
|
6
|
+
export declare function formatTableData(data: unknown[]): string[][];
|
package/dist/utils/formatting.js
CHANGED
|
@@ -32,3 +32,16 @@ export function formatDuration(ms) {
|
|
|
32
32
|
return `${(ms / 1000).toFixed(1)}s`;
|
|
33
33
|
return `${(ms / 60000).toFixed(1)}m`;
|
|
34
34
|
}
|
|
35
|
+
export function formatDate(date) {
|
|
36
|
+
const d = new Date(date);
|
|
37
|
+
return d.toLocaleString();
|
|
38
|
+
}
|
|
39
|
+
export function formatTableData(data) {
|
|
40
|
+
return data.map(item => {
|
|
41
|
+
if (Array.isArray(item))
|
|
42
|
+
return item.map(String);
|
|
43
|
+
if (typeof item === 'object' && item !== null)
|
|
44
|
+
return Object.values(item).map(String);
|
|
45
|
+
return [String(item)];
|
|
46
|
+
});
|
|
47
|
+
}
|