@lanonasis/cli 1.0.1 → 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +166 -6
- package/dist/commands/auth.d.ts +6 -1
- package/dist/commands/auth.js +7 -4
- package/dist/commands/config.js +88 -4
- package/dist/commands/init.d.ts +5 -1
- package/dist/commands/mcp.d.ts +2 -0
- package/dist/commands/mcp.js +318 -0
- package/dist/commands/memory.js +37 -27
- package/dist/commands/topics.js +12 -7
- package/dist/index-simple.js +1 -1
- package/dist/index.js +28 -5
- package/dist/utils/api.d.ts +155 -15
- package/dist/utils/config.d.ts +6 -0
- package/dist/utils/config.js +46 -12
- package/dist/utils/formatting.d.ts +1 -1
- package/dist/utils/mcp-client.d.ts +53 -0
- package/dist/utils/mcp-client.js +249 -0
- package/package.json +17 -4
package/dist/utils/api.d.ts
CHANGED
|
@@ -1,24 +1,164 @@
|
|
|
1
1
|
import { AxiosRequestConfig } from 'axios';
|
|
2
|
+
export interface AuthResponse {
|
|
3
|
+
user: {
|
|
4
|
+
id: string;
|
|
5
|
+
email: string;
|
|
6
|
+
organization_id: string;
|
|
7
|
+
role: 'admin' | 'user' | 'viewer';
|
|
8
|
+
plan: 'free' | 'pro' | 'enterprise';
|
|
9
|
+
created_at: string;
|
|
10
|
+
updated_at: string;
|
|
11
|
+
};
|
|
12
|
+
token: string;
|
|
13
|
+
expires_at: string;
|
|
14
|
+
}
|
|
15
|
+
export interface RegisterRequest {
|
|
16
|
+
email: string;
|
|
17
|
+
password: string;
|
|
18
|
+
organization_name?: string;
|
|
19
|
+
}
|
|
20
|
+
export interface LoginRequest {
|
|
21
|
+
email: string;
|
|
22
|
+
password: string;
|
|
23
|
+
}
|
|
24
|
+
export type MemoryType = 'context' | 'project' | 'knowledge' | 'reference' | 'personal' | 'workflow';
|
|
25
|
+
export interface MemoryEntry {
|
|
26
|
+
id: string;
|
|
27
|
+
title: string;
|
|
28
|
+
content: string;
|
|
29
|
+
memory_type: MemoryType;
|
|
30
|
+
tags: string[];
|
|
31
|
+
topic_id?: string | null;
|
|
32
|
+
user_id: string;
|
|
33
|
+
organization_id: string;
|
|
34
|
+
metadata?: Record<string, unknown>;
|
|
35
|
+
created_at: string;
|
|
36
|
+
updated_at: string;
|
|
37
|
+
last_accessed?: string;
|
|
38
|
+
access_count: number;
|
|
39
|
+
}
|
|
40
|
+
export interface CreateMemoryRequest {
|
|
41
|
+
title: string;
|
|
42
|
+
content: string;
|
|
43
|
+
memory_type?: MemoryType;
|
|
44
|
+
tags?: string[];
|
|
45
|
+
topic_id?: string;
|
|
46
|
+
metadata?: Record<string, unknown>;
|
|
47
|
+
}
|
|
48
|
+
export interface UpdateMemoryRequest {
|
|
49
|
+
title?: string;
|
|
50
|
+
content?: string;
|
|
51
|
+
memory_type?: MemoryType;
|
|
52
|
+
tags?: string[];
|
|
53
|
+
topic_id?: string | null;
|
|
54
|
+
metadata?: Record<string, unknown>;
|
|
55
|
+
}
|
|
56
|
+
export interface GetMemoriesParams {
|
|
57
|
+
limit?: number;
|
|
58
|
+
offset?: number;
|
|
59
|
+
memory_type?: MemoryType;
|
|
60
|
+
tags?: string[];
|
|
61
|
+
topic_id?: string;
|
|
62
|
+
sort_by?: 'created_at' | 'updated_at' | 'last_accessed' | 'access_count';
|
|
63
|
+
sort_order?: 'asc' | 'desc';
|
|
64
|
+
}
|
|
65
|
+
export interface SearchMemoryRequest {
|
|
66
|
+
query: string;
|
|
67
|
+
memory_types?: MemoryType[];
|
|
68
|
+
tags?: string[];
|
|
69
|
+
topic_id?: string;
|
|
70
|
+
limit?: number;
|
|
71
|
+
threshold?: number;
|
|
72
|
+
}
|
|
73
|
+
export interface MemorySearchResult extends MemoryEntry {
|
|
74
|
+
relevance_score: number;
|
|
75
|
+
}
|
|
76
|
+
export interface MemoryStats {
|
|
77
|
+
total_memories: number;
|
|
78
|
+
memories_by_type: Record<MemoryType, number>;
|
|
79
|
+
total_size_bytes: number;
|
|
80
|
+
avg_access_count: number;
|
|
81
|
+
most_accessed_memory?: MemoryEntry;
|
|
82
|
+
recent_memories: MemoryEntry[];
|
|
83
|
+
}
|
|
84
|
+
export interface BulkDeleteRequest {
|
|
85
|
+
memory_ids: string[];
|
|
86
|
+
}
|
|
87
|
+
export interface BulkDeleteResponse {
|
|
88
|
+
deleted_count: number;
|
|
89
|
+
failed_deletes?: string[];
|
|
90
|
+
}
|
|
91
|
+
export interface MemoryTopic {
|
|
92
|
+
id: string;
|
|
93
|
+
name: string;
|
|
94
|
+
description?: string;
|
|
95
|
+
color?: string;
|
|
96
|
+
icon?: string;
|
|
97
|
+
user_id: string;
|
|
98
|
+
parent_topic_id?: string;
|
|
99
|
+
is_system: boolean;
|
|
100
|
+
metadata?: Record<string, unknown>;
|
|
101
|
+
created_at: string;
|
|
102
|
+
updated_at: string;
|
|
103
|
+
}
|
|
104
|
+
export interface CreateTopicRequest {
|
|
105
|
+
name: string;
|
|
106
|
+
description?: string;
|
|
107
|
+
color?: string;
|
|
108
|
+
icon?: string;
|
|
109
|
+
parent_topic_id?: string;
|
|
110
|
+
}
|
|
111
|
+
export interface UpdateTopicRequest {
|
|
112
|
+
name?: string;
|
|
113
|
+
description?: string;
|
|
114
|
+
color?: string;
|
|
115
|
+
icon?: string;
|
|
116
|
+
parent_topic_id?: string;
|
|
117
|
+
}
|
|
118
|
+
export interface HealthStatus {
|
|
119
|
+
status: 'healthy' | 'unhealthy';
|
|
120
|
+
version: string;
|
|
121
|
+
timestamp: string;
|
|
122
|
+
dependencies: Record<string, {
|
|
123
|
+
status: string;
|
|
124
|
+
latency_ms?: number;
|
|
125
|
+
}>;
|
|
126
|
+
}
|
|
127
|
+
export interface PaginatedResponse<T> {
|
|
128
|
+
data: T[];
|
|
129
|
+
pagination: {
|
|
130
|
+
total: number;
|
|
131
|
+
limit: number;
|
|
132
|
+
offset: number;
|
|
133
|
+
has_more: boolean;
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
export interface ApiErrorResponse {
|
|
137
|
+
error: string;
|
|
138
|
+
message: string;
|
|
139
|
+
status_code: number;
|
|
140
|
+
details?: Record<string, unknown>;
|
|
141
|
+
}
|
|
2
142
|
export declare class APIClient {
|
|
3
143
|
private client;
|
|
4
144
|
private config;
|
|
5
145
|
constructor();
|
|
6
|
-
login(email: string, password: string): Promise<
|
|
7
|
-
register(email: string, password: string, organizationName?: string): Promise<
|
|
8
|
-
createMemory(data:
|
|
9
|
-
getMemories(params?:
|
|
10
|
-
getMemory(id: string): Promise<
|
|
11
|
-
updateMemory(id: string, data:
|
|
146
|
+
login(email: string, password: string): Promise<AuthResponse>;
|
|
147
|
+
register(email: string, password: string, organizationName?: string): Promise<AuthResponse>;
|
|
148
|
+
createMemory(data: CreateMemoryRequest): Promise<MemoryEntry>;
|
|
149
|
+
getMemories(params?: GetMemoriesParams): Promise<PaginatedResponse<MemoryEntry>>;
|
|
150
|
+
getMemory(id: string): Promise<MemoryEntry>;
|
|
151
|
+
updateMemory(id: string, data: UpdateMemoryRequest): Promise<MemoryEntry>;
|
|
12
152
|
deleteMemory(id: string): Promise<void>;
|
|
13
|
-
searchMemories(query: string, options?:
|
|
14
|
-
getMemoryStats(): Promise<
|
|
15
|
-
bulkDeleteMemories(memoryIds: string[]): Promise<
|
|
16
|
-
createTopic(data:
|
|
17
|
-
getTopics(): Promise<
|
|
18
|
-
getTopic(id: string): Promise<
|
|
19
|
-
updateTopic(id: string, data:
|
|
153
|
+
searchMemories(query: string, options?: Omit<SearchMemoryRequest, 'query'>): Promise<PaginatedResponse<MemorySearchResult>>;
|
|
154
|
+
getMemoryStats(): Promise<MemoryStats>;
|
|
155
|
+
bulkDeleteMemories(memoryIds: string[]): Promise<BulkDeleteResponse>;
|
|
156
|
+
createTopic(data: CreateTopicRequest): Promise<MemoryTopic>;
|
|
157
|
+
getTopics(): Promise<MemoryTopic[]>;
|
|
158
|
+
getTopic(id: string): Promise<MemoryTopic>;
|
|
159
|
+
updateTopic(id: string, data: UpdateTopicRequest): Promise<MemoryTopic>;
|
|
20
160
|
deleteTopic(id: string): Promise<void>;
|
|
21
|
-
getHealth(): Promise<
|
|
22
|
-
request<T =
|
|
161
|
+
getHealth(): Promise<HealthStatus>;
|
|
162
|
+
request<T = Record<string, unknown>>(config: AxiosRequestConfig): Promise<T>;
|
|
23
163
|
}
|
|
24
164
|
export declare const apiClient: APIClient;
|
package/dist/utils/config.d.ts
CHANGED
|
@@ -22,5 +22,11 @@ export declare class CLIConfig {
|
|
|
22
22
|
clear(): Promise<void>;
|
|
23
23
|
getConfigPath(): string;
|
|
24
24
|
exists(): Promise<boolean>;
|
|
25
|
+
get(key: string): any;
|
|
26
|
+
set(key: string, value: any): void;
|
|
27
|
+
setAndSave(key: string, value: any): Promise<void>;
|
|
28
|
+
getMCPServerPath(): string;
|
|
29
|
+
getMCPServerUrl(): string;
|
|
30
|
+
shouldUseRemoteMCP(): boolean;
|
|
25
31
|
}
|
|
26
32
|
export {};
|
package/dist/utils/config.js
CHANGED
|
@@ -1,7 +1,10 @@
|
|
|
1
|
-
import fs from 'fs/promises';
|
|
2
|
-
import path from 'path';
|
|
3
|
-
import os from 'os';
|
|
1
|
+
import * as fs from 'fs/promises';
|
|
2
|
+
import * as path from 'path';
|
|
3
|
+
import * as os from 'os';
|
|
4
4
|
import { jwtDecode } from 'jwt-decode';
|
|
5
|
+
import { fileURLToPath } from 'url';
|
|
6
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
7
|
+
const __dirname = path.dirname(__filename);
|
|
5
8
|
export class CLIConfig {
|
|
6
9
|
configDir;
|
|
7
10
|
configPath;
|
|
@@ -15,7 +18,7 @@ export class CLIConfig {
|
|
|
15
18
|
await fs.mkdir(this.configDir, { recursive: true });
|
|
16
19
|
await this.load();
|
|
17
20
|
}
|
|
18
|
-
catch
|
|
21
|
+
catch {
|
|
19
22
|
// Config doesn't exist yet, that's ok
|
|
20
23
|
}
|
|
21
24
|
}
|
|
@@ -24,7 +27,7 @@ export class CLIConfig {
|
|
|
24
27
|
const data = await fs.readFile(this.configPath, 'utf-8');
|
|
25
28
|
this.config = JSON.parse(data);
|
|
26
29
|
}
|
|
27
|
-
catch
|
|
30
|
+
catch {
|
|
28
31
|
this.config = {};
|
|
29
32
|
}
|
|
30
33
|
}
|
|
@@ -50,13 +53,13 @@ export class CLIConfig {
|
|
|
50
53
|
// We'll need to fetch full user details from the API
|
|
51
54
|
// For now, store what we can decode
|
|
52
55
|
this.config.user = {
|
|
53
|
-
email: decoded.email || '',
|
|
54
|
-
organization_id: decoded.organizationId || '',
|
|
55
|
-
role: decoded.role || '',
|
|
56
|
-
plan: decoded.plan || ''
|
|
56
|
+
email: String(decoded.email || ''),
|
|
57
|
+
organization_id: String(decoded.organizationId || ''),
|
|
58
|
+
role: String(decoded.role || ''),
|
|
59
|
+
plan: String(decoded.plan || '')
|
|
57
60
|
};
|
|
58
61
|
}
|
|
59
|
-
catch
|
|
62
|
+
catch {
|
|
60
63
|
// Invalid token, don't store user info
|
|
61
64
|
}
|
|
62
65
|
await this.save();
|
|
@@ -74,9 +77,9 @@ export class CLIConfig {
|
|
|
74
77
|
try {
|
|
75
78
|
const decoded = jwtDecode(token);
|
|
76
79
|
const now = Date.now() / 1000;
|
|
77
|
-
return decoded.exp > now;
|
|
80
|
+
return typeof decoded.exp === 'number' && decoded.exp > now;
|
|
78
81
|
}
|
|
79
|
-
catch
|
|
82
|
+
catch {
|
|
80
83
|
return false;
|
|
81
84
|
}
|
|
82
85
|
}
|
|
@@ -101,4 +104,35 @@ export class CLIConfig {
|
|
|
101
104
|
return false;
|
|
102
105
|
}
|
|
103
106
|
}
|
|
107
|
+
// Generic get/set methods for MCP and other dynamic config
|
|
108
|
+
get(key) {
|
|
109
|
+
return this.config[key];
|
|
110
|
+
}
|
|
111
|
+
set(key, value) {
|
|
112
|
+
this.config[key] = value;
|
|
113
|
+
}
|
|
114
|
+
async setAndSave(key, value) {
|
|
115
|
+
this.set(key, value);
|
|
116
|
+
await this.save();
|
|
117
|
+
}
|
|
118
|
+
// MCP-specific helpers
|
|
119
|
+
getMCPServerPath() {
|
|
120
|
+
return this.config.mcpServerPath || path.join(__dirname, '../../../../onasis-gateway/mcp-server/server.js');
|
|
121
|
+
}
|
|
122
|
+
getMCPServerUrl() {
|
|
123
|
+
return this.config.mcpServerUrl || 'https://api.lanonasis.com';
|
|
124
|
+
}
|
|
125
|
+
shouldUseRemoteMCP() {
|
|
126
|
+
const preference = this.config.mcpPreference || 'auto';
|
|
127
|
+
switch (preference) {
|
|
128
|
+
case 'remote':
|
|
129
|
+
return true;
|
|
130
|
+
case 'local':
|
|
131
|
+
return false;
|
|
132
|
+
case 'auto':
|
|
133
|
+
default:
|
|
134
|
+
// Use remote if authenticated, otherwise local
|
|
135
|
+
return !!this.config.token;
|
|
136
|
+
}
|
|
137
|
+
}
|
|
104
138
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export declare function formatOutput(data:
|
|
1
|
+
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;
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
interface MCPConnectionOptions {
|
|
2
|
+
serverPath?: string;
|
|
3
|
+
serverUrl?: string;
|
|
4
|
+
useRemote?: boolean;
|
|
5
|
+
}
|
|
6
|
+
export declare class MCPClient {
|
|
7
|
+
private client;
|
|
8
|
+
private config;
|
|
9
|
+
private isConnected;
|
|
10
|
+
private sseConnection;
|
|
11
|
+
constructor();
|
|
12
|
+
/**
|
|
13
|
+
* Connect to MCP server (local or remote)
|
|
14
|
+
*/
|
|
15
|
+
connect(options?: MCPConnectionOptions): Promise<boolean>;
|
|
16
|
+
/**
|
|
17
|
+
* Initialize SSE connection for real-time updates
|
|
18
|
+
*/
|
|
19
|
+
private initializeSSE;
|
|
20
|
+
/**
|
|
21
|
+
* Disconnect from MCP server
|
|
22
|
+
*/
|
|
23
|
+
disconnect(): Promise<void>;
|
|
24
|
+
/**
|
|
25
|
+
* Call an MCP tool
|
|
26
|
+
*/
|
|
27
|
+
callTool(toolName: string, args: any): Promise<any>;
|
|
28
|
+
/**
|
|
29
|
+
* Call remote tool via REST API with MCP interface
|
|
30
|
+
*/
|
|
31
|
+
private callRemoteTool;
|
|
32
|
+
/**
|
|
33
|
+
* List available tools
|
|
34
|
+
*/
|
|
35
|
+
listTools(): Promise<Array<{
|
|
36
|
+
name: string;
|
|
37
|
+
description: string;
|
|
38
|
+
}>>;
|
|
39
|
+
/**
|
|
40
|
+
* Check if connected to MCP server
|
|
41
|
+
*/
|
|
42
|
+
isConnectedToServer(): boolean;
|
|
43
|
+
/**
|
|
44
|
+
* Get connection status details
|
|
45
|
+
*/
|
|
46
|
+
getConnectionStatus(): {
|
|
47
|
+
connected: boolean;
|
|
48
|
+
mode: string;
|
|
49
|
+
server?: string;
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
export declare function getMCPClient(): MCPClient;
|
|
53
|
+
export {};
|
|
@@ -0,0 +1,249 @@
|
|
|
1
|
+
import { Client } from '@modelcontextprotocol/sdk/client/index.js';
|
|
2
|
+
import { StdioClientTransport } from '@modelcontextprotocol/sdk/client/stdio.js';
|
|
3
|
+
import chalk from 'chalk';
|
|
4
|
+
import { CLIConfig } from './config.js';
|
|
5
|
+
import * as path from 'path';
|
|
6
|
+
import { EventSource } from 'eventsource';
|
|
7
|
+
import { fileURLToPath } from 'url';
|
|
8
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
9
|
+
const __dirname = path.dirname(__filename);
|
|
10
|
+
export class MCPClient {
|
|
11
|
+
client = null;
|
|
12
|
+
config;
|
|
13
|
+
isConnected = false;
|
|
14
|
+
sseConnection = null;
|
|
15
|
+
constructor() {
|
|
16
|
+
this.config = new CLIConfig();
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Connect to MCP server (local or remote)
|
|
20
|
+
*/
|
|
21
|
+
async connect(options = {}) {
|
|
22
|
+
try {
|
|
23
|
+
const useRemote = options.useRemote ?? this.config.get('mcpUseRemote') ?? false;
|
|
24
|
+
if (useRemote) {
|
|
25
|
+
// For remote MCP, we'll use the REST API with MCP-style interface
|
|
26
|
+
const serverUrl = options.serverUrl ?? this.config.get('mcpServerUrl') ?? 'https://api.lanonasis.com';
|
|
27
|
+
console.log(chalk.cyan(`Connecting to remote MCP server at ${serverUrl}...`));
|
|
28
|
+
// Initialize SSE connection for real-time updates
|
|
29
|
+
await this.initializeSSE(serverUrl);
|
|
30
|
+
this.isConnected = true;
|
|
31
|
+
return true;
|
|
32
|
+
}
|
|
33
|
+
else {
|
|
34
|
+
// Local MCP server connection
|
|
35
|
+
const serverPath = options.serverPath ?? this.config.get('mcpServerPath') ?? path.join(__dirname, '../../../../onasis-gateway/mcp-server/server.js');
|
|
36
|
+
console.log(chalk.cyan(`Connecting to local MCP server at ${serverPath}...`));
|
|
37
|
+
const transport = new StdioClientTransport({
|
|
38
|
+
command: 'node',
|
|
39
|
+
args: [serverPath]
|
|
40
|
+
});
|
|
41
|
+
this.client = new Client({
|
|
42
|
+
name: '@lanonasis/cli',
|
|
43
|
+
version: '1.0.0'
|
|
44
|
+
}, {
|
|
45
|
+
capabilities: {}
|
|
46
|
+
});
|
|
47
|
+
await this.client.connect(transport);
|
|
48
|
+
this.isConnected = true;
|
|
49
|
+
console.log(chalk.green('✓ Connected to MCP server'));
|
|
50
|
+
return true;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
catch (error) {
|
|
54
|
+
console.error(chalk.red('Failed to connect to MCP server:'), error);
|
|
55
|
+
this.isConnected = false;
|
|
56
|
+
return false;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Initialize SSE connection for real-time updates
|
|
61
|
+
*/
|
|
62
|
+
async initializeSSE(serverUrl) {
|
|
63
|
+
const sseUrl = `${serverUrl}/sse`;
|
|
64
|
+
const token = this.config.get('token');
|
|
65
|
+
if (token) {
|
|
66
|
+
// EventSource doesn't support headers directly, append token to URL
|
|
67
|
+
this.sseConnection = new EventSource(`${sseUrl}?token=${encodeURIComponent(token)}`);
|
|
68
|
+
this.sseConnection.onmessage = (event) => {
|
|
69
|
+
try {
|
|
70
|
+
const data = JSON.parse(event.data);
|
|
71
|
+
console.log(chalk.blue('📡 Real-time update:'), data.type);
|
|
72
|
+
}
|
|
73
|
+
catch (error) {
|
|
74
|
+
// Ignore parse errors
|
|
75
|
+
}
|
|
76
|
+
};
|
|
77
|
+
this.sseConnection.onerror = (error) => {
|
|
78
|
+
console.error(chalk.yellow('⚠️ SSE connection error (will retry)'));
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Disconnect from MCP server
|
|
84
|
+
*/
|
|
85
|
+
async disconnect() {
|
|
86
|
+
if (this.client) {
|
|
87
|
+
await this.client.close();
|
|
88
|
+
this.client = null;
|
|
89
|
+
}
|
|
90
|
+
if (this.sseConnection) {
|
|
91
|
+
this.sseConnection.close();
|
|
92
|
+
this.sseConnection = null;
|
|
93
|
+
}
|
|
94
|
+
this.isConnected = false;
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Call an MCP tool
|
|
98
|
+
*/
|
|
99
|
+
async callTool(toolName, args) {
|
|
100
|
+
if (!this.isConnected) {
|
|
101
|
+
throw new Error('Not connected to MCP server. Run "lanonasis mcp connect" first.');
|
|
102
|
+
}
|
|
103
|
+
const useRemote = this.config.get('mcpUseRemote') ?? false;
|
|
104
|
+
if (useRemote) {
|
|
105
|
+
// Remote MCP calls are translated to REST API calls
|
|
106
|
+
return await this.callRemoteTool(toolName, args);
|
|
107
|
+
}
|
|
108
|
+
else {
|
|
109
|
+
// Local MCP server call
|
|
110
|
+
if (!this.client) {
|
|
111
|
+
throw new Error('MCP client not initialized');
|
|
112
|
+
}
|
|
113
|
+
try {
|
|
114
|
+
const result = await this.client.callTool({
|
|
115
|
+
name: toolName,
|
|
116
|
+
arguments: args
|
|
117
|
+
});
|
|
118
|
+
return result;
|
|
119
|
+
}
|
|
120
|
+
catch (error) {
|
|
121
|
+
throw new Error(`MCP tool call failed: ${error instanceof Error ? error.message : 'Unknown error'}`);
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* Call remote tool via REST API with MCP interface
|
|
127
|
+
*/
|
|
128
|
+
async callRemoteTool(toolName, args) {
|
|
129
|
+
const apiUrl = this.config.get('apiUrl') ?? 'https://api.lanonasis.com';
|
|
130
|
+
const token = this.config.get('token');
|
|
131
|
+
if (!token) {
|
|
132
|
+
throw new Error('Authentication required. Run "lanonasis auth login" first.');
|
|
133
|
+
}
|
|
134
|
+
// Map MCP tool names to REST API endpoints
|
|
135
|
+
const toolMappings = {
|
|
136
|
+
'memory_create_memory': {
|
|
137
|
+
method: 'POST',
|
|
138
|
+
endpoint: '/api/v1/memory',
|
|
139
|
+
transform: (args) => args
|
|
140
|
+
},
|
|
141
|
+
'memory_search_memories': {
|
|
142
|
+
method: 'POST',
|
|
143
|
+
endpoint: '/api/v1/memory/search',
|
|
144
|
+
transform: (args) => args
|
|
145
|
+
},
|
|
146
|
+
'memory_get_memory': {
|
|
147
|
+
method: 'GET',
|
|
148
|
+
endpoint: `/api/v1/memory/${args.memory_id}`,
|
|
149
|
+
transform: () => undefined
|
|
150
|
+
},
|
|
151
|
+
'memory_update_memory': {
|
|
152
|
+
method: 'PUT',
|
|
153
|
+
endpoint: `/api/v1/memory/${args.memory_id}`,
|
|
154
|
+
transform: (args) => {
|
|
155
|
+
const { memory_id, ...data } = args;
|
|
156
|
+
return data;
|
|
157
|
+
}
|
|
158
|
+
},
|
|
159
|
+
'memory_delete_memory': {
|
|
160
|
+
method: 'DELETE',
|
|
161
|
+
endpoint: `/api/v1/memory/${args.memory_id}`,
|
|
162
|
+
transform: () => undefined
|
|
163
|
+
},
|
|
164
|
+
'memory_list_memories': {
|
|
165
|
+
method: 'GET',
|
|
166
|
+
endpoint: '/api/v1/memory',
|
|
167
|
+
transform: (args) => args
|
|
168
|
+
}
|
|
169
|
+
};
|
|
170
|
+
const mapping = toolMappings[toolName];
|
|
171
|
+
if (!mapping) {
|
|
172
|
+
throw new Error(`Unknown tool: ${toolName}`);
|
|
173
|
+
}
|
|
174
|
+
try {
|
|
175
|
+
const axios = (await import('axios')).default;
|
|
176
|
+
const response = await axios({
|
|
177
|
+
method: mapping.method,
|
|
178
|
+
url: `${apiUrl}${mapping.endpoint}`,
|
|
179
|
+
headers: {
|
|
180
|
+
'Authorization': `Bearer ${token}`,
|
|
181
|
+
'Content-Type': 'application/json'
|
|
182
|
+
},
|
|
183
|
+
data: mapping.transform ? mapping.transform(args) : undefined,
|
|
184
|
+
params: mapping.method === 'GET' ? args : undefined
|
|
185
|
+
});
|
|
186
|
+
return response.data;
|
|
187
|
+
}
|
|
188
|
+
catch (error) {
|
|
189
|
+
throw new Error(`Remote tool call failed: ${error.response?.data?.error || error.message}`);
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
/**
|
|
193
|
+
* List available tools
|
|
194
|
+
*/
|
|
195
|
+
async listTools() {
|
|
196
|
+
if (!this.isConnected) {
|
|
197
|
+
throw new Error('Not connected to MCP server');
|
|
198
|
+
}
|
|
199
|
+
const useRemote = this.config.get('mcpUseRemote') ?? false;
|
|
200
|
+
if (useRemote) {
|
|
201
|
+
// Return hardcoded list for remote mode
|
|
202
|
+
return [
|
|
203
|
+
{ name: 'memory_create_memory', description: 'Create a new memory entry' },
|
|
204
|
+
{ name: 'memory_search_memories', description: 'Search memories using semantic search' },
|
|
205
|
+
{ name: 'memory_get_memory', description: 'Get a specific memory by ID' },
|
|
206
|
+
{ name: 'memory_update_memory', description: 'Update an existing memory' },
|
|
207
|
+
{ name: 'memory_delete_memory', description: 'Delete a memory' },
|
|
208
|
+
{ name: 'memory_list_memories', description: 'List all memories with pagination' }
|
|
209
|
+
];
|
|
210
|
+
}
|
|
211
|
+
else {
|
|
212
|
+
if (!this.client) {
|
|
213
|
+
throw new Error('MCP client not initialized');
|
|
214
|
+
}
|
|
215
|
+
const tools = await this.client.listTools();
|
|
216
|
+
return tools.tools.map(tool => ({
|
|
217
|
+
name: tool.name,
|
|
218
|
+
description: tool.description || 'No description available'
|
|
219
|
+
}));
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
/**
|
|
223
|
+
* Check if connected to MCP server
|
|
224
|
+
*/
|
|
225
|
+
isConnectedToServer() {
|
|
226
|
+
return this.isConnected;
|
|
227
|
+
}
|
|
228
|
+
/**
|
|
229
|
+
* Get connection status details
|
|
230
|
+
*/
|
|
231
|
+
getConnectionStatus() {
|
|
232
|
+
const useRemote = this.config.get('mcpUseRemote') ?? false;
|
|
233
|
+
return {
|
|
234
|
+
connected: this.isConnected,
|
|
235
|
+
mode: useRemote ? 'remote' : 'local',
|
|
236
|
+
server: useRemote
|
|
237
|
+
? (this.config.get('mcpServerUrl') ?? 'https://api.lanonasis.com')
|
|
238
|
+
: (this.config.get('mcpServerPath') ?? 'local MCP server')
|
|
239
|
+
};
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
// Singleton instance
|
|
243
|
+
let mcpClientInstance = null;
|
|
244
|
+
export function getMCPClient() {
|
|
245
|
+
if (!mcpClientInstance) {
|
|
246
|
+
mcpClientInstance = new MCPClient();
|
|
247
|
+
}
|
|
248
|
+
return mcpClientInstance;
|
|
249
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lanonasis/cli",
|
|
3
|
-
"version": "1.0
|
|
3
|
+
"version": "1.2.0",
|
|
4
4
|
"description": "Lanonasis Enterprise CLI - Memory as a Service and Infrastructure Management",
|
|
5
5
|
"main": "dist/index-simple.js",
|
|
6
6
|
"bin": {
|
|
@@ -34,11 +34,24 @@
|
|
|
34
34
|
"README.md"
|
|
35
35
|
],
|
|
36
36
|
"dependencies": {
|
|
37
|
-
"
|
|
37
|
+
"@modelcontextprotocol/sdk": "^1.17.0",
|
|
38
|
+
"@types/eventsource": "^1.1.15",
|
|
39
|
+
"axios": "^1.11.0",
|
|
40
|
+
"chalk": "^5.4.1",
|
|
41
|
+
"commander": "^12.1.0",
|
|
42
|
+
"date-fns": "^4.1.0",
|
|
43
|
+
"dotenv": "^17.2.1",
|
|
44
|
+
"eventsource": "^4.0.0",
|
|
45
|
+
"inquirer": "^12.9.0",
|
|
46
|
+
"jwt-decode": "^4.0.0",
|
|
47
|
+
"open": "^10.2.0",
|
|
48
|
+
"ora": "^8.2.0",
|
|
49
|
+
"table": "^6.9.0",
|
|
50
|
+
"word-wrap": "^1.2.5"
|
|
38
51
|
},
|
|
39
52
|
"devDependencies": {
|
|
40
|
-
"@types/node": "^22.10.2",
|
|
41
53
|
"@types/inquirer": "^9.0.7",
|
|
54
|
+
"@types/node": "^22.10.2",
|
|
42
55
|
"@typescript-eslint/eslint-plugin": "^8.18.1",
|
|
43
56
|
"@typescript-eslint/parser": "^8.18.1",
|
|
44
57
|
"eslint": "^9.17.0",
|
|
@@ -48,4 +61,4 @@
|
|
|
48
61
|
"engines": {
|
|
49
62
|
"node": ">=18.0.0"
|
|
50
63
|
}
|
|
51
|
-
}
|
|
64
|
+
}
|