@lanonasis/cli 1.0.1 ā 1.1.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 +77 -5
- 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 +20 -13
- package/dist/commands/topics.js +10 -5
- package/dist/index-simple.js +1 -1
- package/dist/index.js +27 -3
- 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/README.md
CHANGED
|
@@ -1,8 +1,14 @@
|
|
|
1
1
|
# Lanonasis CLI - Enterprise Infrastructure Management
|
|
2
2
|
|
|
3
|
-
š **Professional CLI for Lanonasis Platform Services**
|
|
3
|
+
š **Professional CLI for Lanonasis Platform Services with MCP Integration**
|
|
4
4
|
|
|
5
|
-
The Lanonasis CLI provides a powerful command-line interface for interacting with the entire Lanonasis ecosystem, including Memory as a Service (MaaS), infrastructure management, and multi-service orchestration. Manage your memories, search through knowledge bases, organize your thoughts, and control your infrastructure - all from the terminal.
|
|
5
|
+
The Lanonasis CLI provides a powerful command-line interface for interacting with the entire Lanonasis ecosystem, including Memory as a Service (MaaS), infrastructure management, and multi-service orchestration. Now with **Model Context Protocol (MCP)** integration for unified AI-agent communication. Manage your memories, search through knowledge bases, organize your thoughts, and control your infrastructure - all from the terminal.
|
|
6
|
+
|
|
7
|
+
## š New in v1.1.0
|
|
8
|
+
- **MCP Integration**: Full Model Context Protocol support for AI agents
|
|
9
|
+
- **Hybrid Mode**: Seamless switching between local MCP and remote API
|
|
10
|
+
- **Real-time Updates**: SSE streaming for live memory synchronization
|
|
11
|
+
- **Unified Interface**: Same commands work with local or cloud backends
|
|
6
12
|
|
|
7
13
|
## ā” Quick Start
|
|
8
14
|
|
|
@@ -135,6 +141,40 @@ memory search "my query" # Direct memory command
|
|
|
135
141
|
maas list --type knowledge # MaaS command
|
|
136
142
|
```
|
|
137
143
|
|
|
144
|
+
## š¤ MCP Integration (Model Context Protocol)
|
|
145
|
+
|
|
146
|
+
The CLI now includes full MCP support for AI agent integration:
|
|
147
|
+
|
|
148
|
+
```bash
|
|
149
|
+
# Connect to MCP server
|
|
150
|
+
lanonasis mcp connect # Auto-detect mode
|
|
151
|
+
lanonasis mcp connect --remote # Use cloud API
|
|
152
|
+
lanonasis mcp connect --local # Use local server
|
|
153
|
+
|
|
154
|
+
# Check MCP status
|
|
155
|
+
lanonasis mcp status
|
|
156
|
+
|
|
157
|
+
# List available tools
|
|
158
|
+
lanonasis mcp tools
|
|
159
|
+
|
|
160
|
+
# Memory operations via MCP
|
|
161
|
+
lanonasis mcp memory create -t "Title" -c "Content"
|
|
162
|
+
lanonasis mcp memory search "query"
|
|
163
|
+
|
|
164
|
+
# Stream real-time updates
|
|
165
|
+
lanonasis memory-mcp stream
|
|
166
|
+
|
|
167
|
+
# Configure MCP preferences
|
|
168
|
+
lanonasis mcp config --prefer-remote
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
### MCP Features:
|
|
172
|
+
- **Unified Interface**: Same commands for local/remote backends
|
|
173
|
+
- **Auto-Connect**: Automatically connects based on auth status
|
|
174
|
+
- **Tool Discovery**: Dynamic listing of available MCP tools
|
|
175
|
+
- **Real-time SSE**: Live updates when using remote mode
|
|
176
|
+
- **Hybrid Mode**: Seamless fallback between MCP and REST API
|
|
177
|
+
|
|
138
178
|
## š MaaS Service Integration
|
|
139
179
|
|
|
140
180
|
This CLI is designed to work with Memory as a Service platforms that provide:
|
|
@@ -181,11 +221,43 @@ node dist/index-simple.js help
|
|
|
181
221
|
- **Configuration** - Flexible service setup
|
|
182
222
|
- **Help System** - Comprehensive documentation
|
|
183
223
|
|
|
224
|
+
## š¦ SDK & Related Packages
|
|
225
|
+
|
|
226
|
+
### Memory Client SDK
|
|
227
|
+
Install the TypeScript/JavaScript SDK for application integration:
|
|
228
|
+
|
|
229
|
+
```bash
|
|
230
|
+
# Install SDK for your applications
|
|
231
|
+
npm install @lanonasis/memory-client
|
|
232
|
+
|
|
233
|
+
# Use in your code
|
|
234
|
+
import { createMemoryClient } from '@lanonasis/memory-client';
|
|
235
|
+
|
|
236
|
+
const client = createMemoryClient({
|
|
237
|
+
baseURL: 'https://api.lanonasis.com',
|
|
238
|
+
apiKey: 'your-api-key-here'
|
|
239
|
+
});
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
### Complete Installation for Developers
|
|
243
|
+
```bash
|
|
244
|
+
# Install CLI globally for command-line usage
|
|
245
|
+
npm install -g @lanonasis/cli
|
|
246
|
+
|
|
247
|
+
# Install SDK locally for application development
|
|
248
|
+
npm install @lanonasis/memory-client
|
|
249
|
+
|
|
250
|
+
# Now you have both CLI and SDK available!
|
|
251
|
+
lanonasis --help # CLI commands
|
|
252
|
+
# SDK available for import in your code
|
|
253
|
+
```
|
|
254
|
+
|
|
184
255
|
## š Related Projects
|
|
185
256
|
|
|
186
|
-
- **Memory Service Backend** - Full MaaS API server
|
|
187
|
-
- **Memory SDK** - JavaScript/TypeScript SDK
|
|
188
|
-
- **Memory Visualizer** - Interactive memory exploration
|
|
257
|
+
- **Memory Service Backend** - Full MaaS API server ([GitHub](https://github.com/thefixer3x/vibe-memory))
|
|
258
|
+
- **Memory Client SDK** - JavaScript/TypeScript SDK (`@lanonasis/memory-client`)
|
|
259
|
+
- **Memory Visualizer** - Interactive memory exploration (included in backend)
|
|
260
|
+
- **VSCode Extension** - IDE integration (coming soon)
|
|
189
261
|
|
|
190
262
|
## š License
|
|
191
263
|
|
package/dist/commands/auth.d.ts
CHANGED
package/dist/commands/auth.js
CHANGED
|
@@ -49,7 +49,9 @@ export async function loginCommand(options) {
|
|
|
49
49
|
}
|
|
50
50
|
catch (error) {
|
|
51
51
|
spinner.fail('Login failed');
|
|
52
|
-
|
|
52
|
+
const errorMessage = error instanceof Error ? error.message : 'Unknown error';
|
|
53
|
+
const errorResponse = error && typeof error === 'object' && 'response' in error ? error.response : null;
|
|
54
|
+
if (errorResponse && typeof errorResponse === 'object' && 'status' in errorResponse && errorResponse.status === 401) {
|
|
53
55
|
console.error(chalk.red('ā Invalid email or password'));
|
|
54
56
|
// Ask if they want to register
|
|
55
57
|
const answer = await inquirer.prompt([
|
|
@@ -65,7 +67,7 @@ export async function loginCommand(options) {
|
|
|
65
67
|
}
|
|
66
68
|
}
|
|
67
69
|
else {
|
|
68
|
-
console.error(chalk.red('ā Login failed:'),
|
|
70
|
+
console.error(chalk.red('ā Login failed:'), errorMessage);
|
|
69
71
|
}
|
|
70
72
|
process.exit(1);
|
|
71
73
|
}
|
|
@@ -98,7 +100,7 @@ async function registerFlow(defaultEmail) {
|
|
|
98
100
|
message: 'Confirm password:',
|
|
99
101
|
mask: '*',
|
|
100
102
|
validate: (input, answers) => {
|
|
101
|
-
return input === answers
|
|
103
|
+
return input === answers?.password || 'Passwords do not match';
|
|
102
104
|
}
|
|
103
105
|
},
|
|
104
106
|
{
|
|
@@ -124,7 +126,8 @@ async function registerFlow(defaultEmail) {
|
|
|
124
126
|
}
|
|
125
127
|
catch (error) {
|
|
126
128
|
spinner.fail('Registration failed');
|
|
127
|
-
|
|
129
|
+
const errorMessage = error instanceof Error ? error.message : 'Unknown error';
|
|
130
|
+
console.error(chalk.red('ā Registration failed:'), errorMessage);
|
|
128
131
|
process.exit(1);
|
|
129
132
|
}
|
|
130
133
|
}
|
package/dist/commands/config.js
CHANGED
|
@@ -3,6 +3,65 @@ import inquirer from 'inquirer';
|
|
|
3
3
|
import { CLIConfig } from '../utils/config.js';
|
|
4
4
|
import { apiClient } from '../utils/api.js';
|
|
5
5
|
export function configCommands(program) {
|
|
6
|
+
// Generic config set command
|
|
7
|
+
program
|
|
8
|
+
.command('set <key> <value>')
|
|
9
|
+
.description('Set configuration value')
|
|
10
|
+
.action(async (key, value) => {
|
|
11
|
+
const config = new CLIConfig();
|
|
12
|
+
await config.init();
|
|
13
|
+
// Handle special cases
|
|
14
|
+
switch (key) {
|
|
15
|
+
case 'api-url':
|
|
16
|
+
await config.setApiUrl(value);
|
|
17
|
+
console.log(chalk.green('ā API URL updated:'), value);
|
|
18
|
+
break;
|
|
19
|
+
case 'ai-integration':
|
|
20
|
+
if (value === 'claude-mcp') {
|
|
21
|
+
config.set('mcpEnabled', true);
|
|
22
|
+
config.set('aiIntegration', 'claude-mcp');
|
|
23
|
+
console.log(chalk.green('ā AI integration set to Claude MCP'));
|
|
24
|
+
console.log(chalk.cyan(' MCP will be automatically initialized for memory operations'));
|
|
25
|
+
console.log(chalk.cyan(' Run "lanonasis mcp-server init" to test the connection'));
|
|
26
|
+
}
|
|
27
|
+
else {
|
|
28
|
+
console.log(chalk.yellow('ā ļø Unknown AI integration:'), value);
|
|
29
|
+
console.log(chalk.gray(' Currently supported: claude-mcp'));
|
|
30
|
+
}
|
|
31
|
+
break;
|
|
32
|
+
case 'mcp-use-remote':
|
|
33
|
+
config.set('mcpUseRemote', value === 'true');
|
|
34
|
+
console.log(chalk.green('ā MCP remote mode:'), value === 'true' ? 'enabled' : 'disabled');
|
|
35
|
+
break;
|
|
36
|
+
case 'mcp-server-path':
|
|
37
|
+
config.set('mcpServerPath', value);
|
|
38
|
+
console.log(chalk.green('ā MCP server path updated:'), value);
|
|
39
|
+
break;
|
|
40
|
+
case 'mcp-server-url':
|
|
41
|
+
config.set('mcpServerUrl', value);
|
|
42
|
+
console.log(chalk.green('ā MCP server URL updated:'), value);
|
|
43
|
+
break;
|
|
44
|
+
default:
|
|
45
|
+
// Generic config set
|
|
46
|
+
config.set(key, value);
|
|
47
|
+
console.log(chalk.green(`ā ${key} set to:`), value);
|
|
48
|
+
}
|
|
49
|
+
});
|
|
50
|
+
// Generic config get command
|
|
51
|
+
program
|
|
52
|
+
.command('get <key>')
|
|
53
|
+
.description('Get configuration value')
|
|
54
|
+
.action(async (key) => {
|
|
55
|
+
const config = new CLIConfig();
|
|
56
|
+
await config.init();
|
|
57
|
+
const value = config.get(key);
|
|
58
|
+
if (value !== undefined) {
|
|
59
|
+
console.log(chalk.green(`${key}:`), value);
|
|
60
|
+
}
|
|
61
|
+
else {
|
|
62
|
+
console.log(chalk.yellow(`ā ļø ${key} is not set`));
|
|
63
|
+
}
|
|
64
|
+
});
|
|
6
65
|
// Show current configuration
|
|
7
66
|
program
|
|
8
67
|
.command('show')
|
|
@@ -26,6 +85,29 @@ export function configCommands(program) {
|
|
|
26
85
|
}
|
|
27
86
|
}
|
|
28
87
|
});
|
|
88
|
+
// List all configuration options
|
|
89
|
+
program
|
|
90
|
+
.command('list')
|
|
91
|
+
.description('List all configuration options')
|
|
92
|
+
.action(async () => {
|
|
93
|
+
const config = new CLIConfig();
|
|
94
|
+
await config.init();
|
|
95
|
+
console.log(chalk.blue.bold('š Configuration Options'));
|
|
96
|
+
console.log();
|
|
97
|
+
const configOptions = [
|
|
98
|
+
{ key: 'api-url', description: 'API endpoint URL', current: config.getApiUrl() },
|
|
99
|
+
{ key: 'ai-integration', description: 'AI integration mode', current: config.get('aiIntegration') || 'none' },
|
|
100
|
+
{ key: 'mcp-use-remote', description: 'Use remote MCP server', current: config.get('mcpUseRemote') || false },
|
|
101
|
+
{ key: 'mcp-server-path', description: 'Local MCP server path', current: config.get('mcpServerPath') || 'default' },
|
|
102
|
+
{ key: 'mcp-server-url', description: 'Remote MCP server URL', current: config.get('mcpServerUrl') || 'https://api.lanonasis.com' },
|
|
103
|
+
{ key: 'mcpEnabled', description: 'MCP integration enabled', current: config.get('mcpEnabled') || false }
|
|
104
|
+
];
|
|
105
|
+
configOptions.forEach(opt => {
|
|
106
|
+
console.log(chalk.green(opt.key.padEnd(20)), chalk.gray(opt.description.padEnd(30)), chalk.yellow(String(opt.current)));
|
|
107
|
+
});
|
|
108
|
+
console.log();
|
|
109
|
+
console.log(chalk.gray('Use "lanonasis config set <key> <value>" to update any option'));
|
|
110
|
+
});
|
|
29
111
|
// Set API URL
|
|
30
112
|
program
|
|
31
113
|
.command('set-url')
|
|
@@ -72,24 +154,26 @@ export function configCommands(program) {
|
|
|
72
154
|
console.log(chalk.green('ā Connection successful'));
|
|
73
155
|
console.log(`Status: ${health.status}`);
|
|
74
156
|
console.log(`Version: ${health.version}`);
|
|
75
|
-
console.log(`Uptime: ${Math.round(health.uptime)}s`);
|
|
76
157
|
if (health.dependencies) {
|
|
77
158
|
console.log();
|
|
78
159
|
console.log(chalk.yellow('Dependencies:'));
|
|
79
160
|
Object.entries(health.dependencies).forEach(([name, info]) => {
|
|
80
161
|
const status = info.status === 'healthy' ? chalk.green('ā') : chalk.red('ā');
|
|
81
|
-
|
|
162
|
+
const responseTime = info.response_time || info.latency_ms || 0;
|
|
163
|
+
console.log(` ${status} ${name}: ${info.status} (${responseTime}ms)`);
|
|
82
164
|
});
|
|
83
165
|
}
|
|
84
166
|
}
|
|
85
167
|
catch (error) {
|
|
86
168
|
console.log(chalk.red('ā Connection failed'));
|
|
87
|
-
|
|
169
|
+
const errorCode = error && typeof error === 'object' && 'code' in error ? error.code : null;
|
|
170
|
+
const errorMessage = error instanceof Error ? error.message : 'Unknown error';
|
|
171
|
+
if (errorCode === 'ECONNREFUSED') {
|
|
88
172
|
console.error(chalk.red('Cannot connect to API server'));
|
|
89
173
|
console.log(chalk.yellow('Make sure the API server is running'));
|
|
90
174
|
}
|
|
91
175
|
else {
|
|
92
|
-
console.error(chalk.red('Error:'),
|
|
176
|
+
console.error(chalk.red('Error:'), errorMessage);
|
|
93
177
|
}
|
|
94
178
|
process.exit(1);
|
|
95
179
|
}
|
package/dist/commands/init.d.ts
CHANGED
|
@@ -0,0 +1,318 @@
|
|
|
1
|
+
import chalk from 'chalk';
|
|
2
|
+
import ora from 'ora';
|
|
3
|
+
import { table } from 'table';
|
|
4
|
+
import { getMCPClient } from '../utils/mcp-client.js';
|
|
5
|
+
import { CLIConfig } from '../utils/config.js';
|
|
6
|
+
export function mcpCommands(program) {
|
|
7
|
+
const mcp = program
|
|
8
|
+
.command('mcp')
|
|
9
|
+
.description('MCP (Model Context Protocol) server operations');
|
|
10
|
+
// Also register mcp-server command directly on program for convenience
|
|
11
|
+
const mcpServer = program
|
|
12
|
+
.command('mcp-server')
|
|
13
|
+
.description('MCP server initialization and management');
|
|
14
|
+
mcpServer.command('init')
|
|
15
|
+
.description('Initialize MCP server configuration')
|
|
16
|
+
.action(async () => {
|
|
17
|
+
console.log(chalk.cyan('š Initializing MCP Server Configuration'));
|
|
18
|
+
console.log('');
|
|
19
|
+
const config = new CLIConfig();
|
|
20
|
+
const isAuthenticated = !!config.get('token');
|
|
21
|
+
if (isAuthenticated) {
|
|
22
|
+
console.log(chalk.green('ā Authenticated - Using remote MCP mode'));
|
|
23
|
+
console.log(' Your memory operations will use api.lanonasis.com');
|
|
24
|
+
console.log(' with real-time SSE updates enabled');
|
|
25
|
+
}
|
|
26
|
+
else {
|
|
27
|
+
console.log(chalk.yellow('ā ļø Not authenticated - Using local MCP mode'));
|
|
28
|
+
console.log(' Run "lanonasis auth login" to enable remote mode');
|
|
29
|
+
}
|
|
30
|
+
console.log('');
|
|
31
|
+
console.log(chalk.cyan('Available MCP Commands:'));
|
|
32
|
+
console.log(' lanonasis mcp connect # Auto-connect to best mode');
|
|
33
|
+
console.log(' lanonasis mcp connect -r # Force remote mode');
|
|
34
|
+
console.log(' lanonasis mcp connect -l # Force local mode');
|
|
35
|
+
console.log(' lanonasis mcp status # Check connection status');
|
|
36
|
+
console.log(' lanonasis mcp tools # List available tools');
|
|
37
|
+
console.log('');
|
|
38
|
+
console.log(chalk.cyan('Memory operations are MCP-powered by default!'));
|
|
39
|
+
// Auto-connect to MCP
|
|
40
|
+
const spinner = ora('Auto-connecting to MCP...').start();
|
|
41
|
+
try {
|
|
42
|
+
const client = getMCPClient();
|
|
43
|
+
const connected = await client.connect({ useRemote: isAuthenticated });
|
|
44
|
+
if (connected) {
|
|
45
|
+
spinner.succeed(chalk.green(`Connected to ${isAuthenticated ? 'remote' : 'local'} MCP server`));
|
|
46
|
+
}
|
|
47
|
+
else {
|
|
48
|
+
spinner.fail('Failed to auto-connect to MCP');
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
catch (error) {
|
|
52
|
+
spinner.fail('MCP auto-connect failed');
|
|
53
|
+
}
|
|
54
|
+
});
|
|
55
|
+
// Connect command
|
|
56
|
+
mcp.command('connect')
|
|
57
|
+
.description('Connect to MCP server (local or remote)')
|
|
58
|
+
.option('-l, --local', 'Connect to local MCP server')
|
|
59
|
+
.option('-r, --remote', 'Connect to remote MCP server (api.lanonasis.com)')
|
|
60
|
+
.option('-s, --server <path>', 'Local MCP server path')
|
|
61
|
+
.option('-u, --url <url>', 'Remote MCP server URL')
|
|
62
|
+
.action(async (options) => {
|
|
63
|
+
const spinner = ora('Connecting to MCP server...').start();
|
|
64
|
+
const config = new CLIConfig();
|
|
65
|
+
try {
|
|
66
|
+
// Determine connection mode
|
|
67
|
+
let useRemote = options.remote;
|
|
68
|
+
if (!options.local && !options.remote) {
|
|
69
|
+
// Default to remote if authenticated, otherwise local
|
|
70
|
+
useRemote = !!config.get('token');
|
|
71
|
+
}
|
|
72
|
+
// Save preference
|
|
73
|
+
config.set('mcpUseRemote', useRemote);
|
|
74
|
+
if (options.server) {
|
|
75
|
+
config.set('mcpServerPath', options.server);
|
|
76
|
+
}
|
|
77
|
+
if (options.url) {
|
|
78
|
+
config.set('mcpServerUrl', options.url);
|
|
79
|
+
}
|
|
80
|
+
const client = getMCPClient();
|
|
81
|
+
const connected = await client.connect({
|
|
82
|
+
useRemote,
|
|
83
|
+
serverPath: options.server,
|
|
84
|
+
serverUrl: options.url
|
|
85
|
+
});
|
|
86
|
+
if (connected) {
|
|
87
|
+
spinner.succeed(chalk.green(`Connected to ${useRemote ? 'remote' : 'local'} MCP server`));
|
|
88
|
+
if (useRemote) {
|
|
89
|
+
console.log(chalk.cyan('ā¹ļø Using remote MCP via api.lanonasis.com'));
|
|
90
|
+
console.log(chalk.cyan('š” SSE endpoint active for real-time updates'));
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
else {
|
|
94
|
+
spinner.fail('Failed to connect to MCP server');
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
catch (error) {
|
|
98
|
+
spinner.fail(`Connection failed: ${error instanceof Error ? error.message : 'Unknown error'}`);
|
|
99
|
+
process.exit(1);
|
|
100
|
+
}
|
|
101
|
+
});
|
|
102
|
+
// Disconnect command
|
|
103
|
+
mcp.command('disconnect')
|
|
104
|
+
.description('Disconnect from MCP server')
|
|
105
|
+
.action(async () => {
|
|
106
|
+
const client = getMCPClient();
|
|
107
|
+
await client.disconnect();
|
|
108
|
+
console.log(chalk.green('ā Disconnected from MCP server'));
|
|
109
|
+
});
|
|
110
|
+
// Status command
|
|
111
|
+
mcp.command('status')
|
|
112
|
+
.description('Show MCP connection status')
|
|
113
|
+
.action(async () => {
|
|
114
|
+
const client = getMCPClient();
|
|
115
|
+
const status = client.getConnectionStatus();
|
|
116
|
+
console.log(chalk.cyan('\nš MCP Connection Status'));
|
|
117
|
+
console.log(chalk.cyan('========================'));
|
|
118
|
+
console.log(`Status: ${status.connected ? chalk.green('Connected') : chalk.red('Disconnected')}`);
|
|
119
|
+
console.log(`Mode: ${status.mode === 'remote' ? chalk.blue('Remote (API)') : chalk.yellow('Local')}`);
|
|
120
|
+
console.log(`Server: ${status.server}`);
|
|
121
|
+
if (status.connected && status.mode === 'remote') {
|
|
122
|
+
console.log(`\n${chalk.cyan('Features:')}`);
|
|
123
|
+
console.log('⢠Real-time updates via SSE');
|
|
124
|
+
console.log('⢠Authenticated API access');
|
|
125
|
+
console.log('⢠MCP-compatible tool interface');
|
|
126
|
+
}
|
|
127
|
+
});
|
|
128
|
+
// List tools command
|
|
129
|
+
mcp.command('tools')
|
|
130
|
+
.description('List available MCP tools')
|
|
131
|
+
.action(async () => {
|
|
132
|
+
const spinner = ora('Fetching available tools...').start();
|
|
133
|
+
try {
|
|
134
|
+
const client = getMCPClient();
|
|
135
|
+
if (!client.isConnectedToServer()) {
|
|
136
|
+
spinner.info('Not connected. Attempting auto-connect...');
|
|
137
|
+
const config = new CLIConfig();
|
|
138
|
+
const useRemote = !!config.get('token');
|
|
139
|
+
await client.connect({ useRemote });
|
|
140
|
+
}
|
|
141
|
+
const tools = await client.listTools();
|
|
142
|
+
spinner.succeed('Tools fetched successfully');
|
|
143
|
+
console.log(chalk.cyan('\nš§ Available MCP Tools'));
|
|
144
|
+
console.log(chalk.cyan('====================='));
|
|
145
|
+
const tableData = [
|
|
146
|
+
[chalk.bold('Tool Name'), chalk.bold('Description')]
|
|
147
|
+
];
|
|
148
|
+
tools.forEach(tool => {
|
|
149
|
+
tableData.push([
|
|
150
|
+
chalk.green(tool.name),
|
|
151
|
+
tool.description
|
|
152
|
+
]);
|
|
153
|
+
});
|
|
154
|
+
console.log(table(tableData, {
|
|
155
|
+
border: {
|
|
156
|
+
topBody: 'ā',
|
|
157
|
+
topJoin: 'ā¬',
|
|
158
|
+
topLeft: 'ā',
|
|
159
|
+
topRight: 'ā',
|
|
160
|
+
bottomBody: 'ā',
|
|
161
|
+
bottomJoin: 'ā“',
|
|
162
|
+
bottomLeft: 'ā',
|
|
163
|
+
bottomRight: 'ā',
|
|
164
|
+
bodyLeft: 'ā',
|
|
165
|
+
bodyRight: 'ā',
|
|
166
|
+
bodyJoin: 'ā',
|
|
167
|
+
joinBody: 'ā',
|
|
168
|
+
joinLeft: 'ā',
|
|
169
|
+
joinRight: 'ā¤',
|
|
170
|
+
joinJoin: 'ā¼'
|
|
171
|
+
}
|
|
172
|
+
}));
|
|
173
|
+
}
|
|
174
|
+
catch (error) {
|
|
175
|
+
spinner.fail(`Failed to fetch tools: ${error instanceof Error ? error.message : 'Unknown error'}`);
|
|
176
|
+
process.exit(1);
|
|
177
|
+
}
|
|
178
|
+
});
|
|
179
|
+
// Call tool command
|
|
180
|
+
mcp.command('call')
|
|
181
|
+
.description('Call an MCP tool directly')
|
|
182
|
+
.argument('<tool>', 'Tool name to call')
|
|
183
|
+
.option('-a, --args <json>', 'Tool arguments as JSON')
|
|
184
|
+
.action(async (toolName, options) => {
|
|
185
|
+
const spinner = ora(`Calling tool: ${toolName}...`).start();
|
|
186
|
+
try {
|
|
187
|
+
const client = getMCPClient();
|
|
188
|
+
if (!client.isConnectedToServer()) {
|
|
189
|
+
spinner.info('Not connected. Attempting auto-connect...');
|
|
190
|
+
const config = new CLIConfig();
|
|
191
|
+
const useRemote = !!config.get('token');
|
|
192
|
+
await client.connect({ useRemote });
|
|
193
|
+
}
|
|
194
|
+
let args = {};
|
|
195
|
+
if (options.args) {
|
|
196
|
+
try {
|
|
197
|
+
args = JSON.parse(options.args);
|
|
198
|
+
}
|
|
199
|
+
catch (error) {
|
|
200
|
+
spinner.fail('Invalid JSON arguments');
|
|
201
|
+
process.exit(1);
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
const result = await client.callTool(toolName, args);
|
|
205
|
+
spinner.succeed(`Tool ${toolName} executed successfully`);
|
|
206
|
+
console.log(chalk.cyan('\nš¤ Tool Result:'));
|
|
207
|
+
console.log(JSON.stringify(result, null, 2));
|
|
208
|
+
}
|
|
209
|
+
catch (error) {
|
|
210
|
+
spinner.fail(`Tool execution failed: ${error instanceof Error ? error.message : 'Unknown error'}`);
|
|
211
|
+
process.exit(1);
|
|
212
|
+
}
|
|
213
|
+
});
|
|
214
|
+
// Memory-specific MCP commands
|
|
215
|
+
const memory = mcp.command('memory')
|
|
216
|
+
.description('Memory operations via MCP');
|
|
217
|
+
memory.command('create')
|
|
218
|
+
.description('Create memory via MCP')
|
|
219
|
+
.requiredOption('-t, --title <title>', 'Memory title')
|
|
220
|
+
.requiredOption('-c, --content <content>', 'Memory content')
|
|
221
|
+
.option('-T, --type <type>', 'Memory type', 'context')
|
|
222
|
+
.option('--tags <tags>', 'Comma-separated tags')
|
|
223
|
+
.action(async (options) => {
|
|
224
|
+
const spinner = ora('Creating memory via MCP...').start();
|
|
225
|
+
try {
|
|
226
|
+
const client = getMCPClient();
|
|
227
|
+
if (!client.isConnectedToServer()) {
|
|
228
|
+
spinner.info('Not connected. Attempting auto-connect...');
|
|
229
|
+
const config = new CLIConfig();
|
|
230
|
+
const useRemote = !!config.get('token');
|
|
231
|
+
await client.connect({ useRemote });
|
|
232
|
+
}
|
|
233
|
+
const result = await client.callTool('memory_create_memory', {
|
|
234
|
+
title: options.title,
|
|
235
|
+
content: options.content,
|
|
236
|
+
memory_type: options.type,
|
|
237
|
+
tags: options.tags ? options.tags.split(',').map((t) => t.trim()) : []
|
|
238
|
+
});
|
|
239
|
+
spinner.succeed('Memory created successfully');
|
|
240
|
+
console.log(chalk.green('\nā Memory created'));
|
|
241
|
+
console.log(`ID: ${chalk.cyan(result.id)}`);
|
|
242
|
+
console.log(`Title: ${result.title}`);
|
|
243
|
+
console.log(`Type: ${result.memory_type}`);
|
|
244
|
+
}
|
|
245
|
+
catch (error) {
|
|
246
|
+
spinner.fail(`Failed to create memory: ${error instanceof Error ? error.message : 'Unknown error'}`);
|
|
247
|
+
process.exit(1);
|
|
248
|
+
}
|
|
249
|
+
});
|
|
250
|
+
memory.command('search')
|
|
251
|
+
.description('Search memories via MCP')
|
|
252
|
+
.argument('<query>', 'Search query')
|
|
253
|
+
.option('-l, --limit <number>', 'Maximum results', '10')
|
|
254
|
+
.option('-t, --threshold <number>', 'Similarity threshold (0-1)', '0.7')
|
|
255
|
+
.action(async (query, options) => {
|
|
256
|
+
const spinner = ora('Searching memories via MCP...').start();
|
|
257
|
+
try {
|
|
258
|
+
const client = getMCPClient();
|
|
259
|
+
if (!client.isConnectedToServer()) {
|
|
260
|
+
spinner.info('Not connected. Attempting auto-connect...');
|
|
261
|
+
const config = new CLIConfig();
|
|
262
|
+
const useRemote = !!config.get('token');
|
|
263
|
+
await client.connect({ useRemote });
|
|
264
|
+
}
|
|
265
|
+
const results = await client.callTool('memory_search_memories', {
|
|
266
|
+
query,
|
|
267
|
+
limit: parseInt(options.limit),
|
|
268
|
+
threshold: parseFloat(options.threshold)
|
|
269
|
+
});
|
|
270
|
+
spinner.succeed(`Found ${results.length} memories`);
|
|
271
|
+
if (results.length === 0) {
|
|
272
|
+
console.log(chalk.yellow('\nNo memories found matching your query'));
|
|
273
|
+
return;
|
|
274
|
+
}
|
|
275
|
+
console.log(chalk.cyan('\nš Search Results:'));
|
|
276
|
+
results.forEach((memory, index) => {
|
|
277
|
+
console.log(`\n${chalk.bold(`${index + 1}. ${memory.title}`)}`);
|
|
278
|
+
console.log(` ID: ${chalk.gray(memory.id)}`);
|
|
279
|
+
console.log(` Type: ${chalk.blue(memory.memory_type)}`);
|
|
280
|
+
console.log(` Score: ${chalk.green((memory.relevance_score * 100).toFixed(1) + '%')}`);
|
|
281
|
+
console.log(` Content: ${memory.content.substring(0, 100)}...`);
|
|
282
|
+
});
|
|
283
|
+
}
|
|
284
|
+
catch (error) {
|
|
285
|
+
spinner.fail(`Search failed: ${error instanceof Error ? error.message : 'Unknown error'}`);
|
|
286
|
+
process.exit(1);
|
|
287
|
+
}
|
|
288
|
+
});
|
|
289
|
+
// Configure MCP preferences
|
|
290
|
+
mcp.command('config')
|
|
291
|
+
.description('Configure MCP preferences')
|
|
292
|
+
.option('--prefer-remote', 'Prefer remote MCP server when available')
|
|
293
|
+
.option('--prefer-local', 'Prefer local MCP server')
|
|
294
|
+
.option('--auto', 'Auto-detect best connection mode')
|
|
295
|
+
.action(async (options) => {
|
|
296
|
+
const config = new CLIConfig();
|
|
297
|
+
if (options.preferRemote) {
|
|
298
|
+
config.set('mcpPreference', 'remote');
|
|
299
|
+
console.log(chalk.green('ā Set MCP preference to remote'));
|
|
300
|
+
}
|
|
301
|
+
else if (options.preferLocal) {
|
|
302
|
+
config.set('mcpPreference', 'local');
|
|
303
|
+
console.log(chalk.green('ā Set MCP preference to local'));
|
|
304
|
+
}
|
|
305
|
+
else if (options.auto) {
|
|
306
|
+
config.set('mcpPreference', 'auto');
|
|
307
|
+
console.log(chalk.green('ā Set MCP preference to auto-detect'));
|
|
308
|
+
}
|
|
309
|
+
else {
|
|
310
|
+
const current = config.get('mcpPreference') || 'auto';
|
|
311
|
+
console.log(`Current MCP preference: ${chalk.cyan(current)}`);
|
|
312
|
+
console.log('\nOptions:');
|
|
313
|
+
console.log(' --prefer-remote : Use remote MCP server (api.lanonasis.com)');
|
|
314
|
+
console.log(' --prefer-local : Use local MCP server');
|
|
315
|
+
console.log(' --auto : Auto-detect based on authentication');
|
|
316
|
+
}
|
|
317
|
+
});
|
|
318
|
+
}
|