voyageai-cli 1.23.0 → 1.24.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 +64 -0
- package/package.json +1 -1
- package/src/commands/mcp-server.js +74 -0
- package/src/commands/ping.js +2 -2
- package/src/lib/api.js +6 -8
- package/src/mcp/install.js +201 -0
package/README.md
CHANGED
|
@@ -81,6 +81,7 @@ MongoDB LeafyGreen design system<br/><br/>
|
|
|
81
81
|
- [Environment & Auth](#environment--auth)
|
|
82
82
|
- [Shell Completions](#shell-completions)
|
|
83
83
|
- [All Commands](#all-commands)
|
|
84
|
+
- [MCP Server](#mcp-server)
|
|
84
85
|
- [Screenshots](#screenshots)
|
|
85
86
|
- [Requirements](#requirements)
|
|
86
87
|
- [Author](#author)
|
|
@@ -534,6 +535,12 @@ Covers all 22 commands, subcommands, flags, model names, and explain topics.
|
|
|
534
535
|
| `vai eval` | Evaluate retrieval quality (MRR, nDCG, Recall) |
|
|
535
536
|
| `vai eval compare` | Compare configurations side-by-side |
|
|
536
537
|
| `vai benchmark` | 8 subcommands for model comparison |
|
|
538
|
+
| **MCP Server** | |
|
|
539
|
+
| `vai mcp` | Start the MCP server (expose vai tools to AI agents) |
|
|
540
|
+
| `vai mcp install` | Install vai into AI tool configs (Claude, Cursor, etc.) |
|
|
541
|
+
| `vai mcp uninstall` | Remove vai from AI tool configs |
|
|
542
|
+
| `vai mcp status` | Show installation status across all tools |
|
|
543
|
+
| `vai mcp generate-key` | Generate API key for HTTP server auth |
|
|
537
544
|
| **Tools & Learning** | |
|
|
538
545
|
| `vai models` | List models, benchmarks, architecture |
|
|
539
546
|
| `vai explain` | 25 interactive concept explainers |
|
|
@@ -547,6 +554,63 @@ Covers all 22 commands, subcommands, flags, model names, and explain topics.
|
|
|
547
554
|
|
|
548
555
|
---
|
|
549
556
|
|
|
557
|
+
## MCP Server
|
|
558
|
+
|
|
559
|
+
Expose vai's RAG tools to any MCP-compatible AI agent — Claude Desktop, Claude Code, Cursor, Windsurf, VS Code, and more. **11 tools** for embedding, retrieval, reranking, ingestion, and learning — all accessible without writing code.
|
|
560
|
+
|
|
561
|
+
### One-Command Setup
|
|
562
|
+
|
|
563
|
+
```bash
|
|
564
|
+
# Install into your AI tool of choice
|
|
565
|
+
vai mcp install claude
|
|
566
|
+
vai mcp install cursor
|
|
567
|
+
vai mcp install all # all supported tools at once
|
|
568
|
+
|
|
569
|
+
# Check what's configured
|
|
570
|
+
vai mcp status
|
|
571
|
+
```
|
|
572
|
+
|
|
573
|
+
The install command **merges** into existing configs — it won't touch your other MCP servers.
|
|
574
|
+
|
|
575
|
+
### Supported Tools
|
|
576
|
+
|
|
577
|
+
| Target | AI Tool |
|
|
578
|
+
|--------|---------|
|
|
579
|
+
| `claude` | Claude Desktop |
|
|
580
|
+
| `claude-code` | Claude Code |
|
|
581
|
+
| `cursor` | Cursor |
|
|
582
|
+
| `windsurf` | Windsurf |
|
|
583
|
+
| `vscode` | VS Code |
|
|
584
|
+
|
|
585
|
+
### What Your Agent Gets
|
|
586
|
+
|
|
587
|
+
Once installed, your AI agent can use these tools:
|
|
588
|
+
|
|
589
|
+
| Tool | What It Does |
|
|
590
|
+
|------|-------------|
|
|
591
|
+
| `vai_query` | Full RAG: embed → vector search → rerank |
|
|
592
|
+
| `vai_search` | Raw vector similarity search |
|
|
593
|
+
| `vai_rerank` | Rerank documents against a query |
|
|
594
|
+
| `vai_embed` | Generate embedding vectors |
|
|
595
|
+
| `vai_similarity` | Cosine similarity between texts |
|
|
596
|
+
| `vai_ingest` | Chunk, embed, and store documents |
|
|
597
|
+
| `vai_collections` | List MongoDB collections with vector indexes |
|
|
598
|
+
| `vai_models` | List models with pricing and benchmarks |
|
|
599
|
+
| `vai_topics` | Browse educational topics |
|
|
600
|
+
| `vai_explain` | Get detailed concept explanations |
|
|
601
|
+
| `vai_estimate` | Estimate embedding costs |
|
|
602
|
+
|
|
603
|
+
### Transport Modes
|
|
604
|
+
|
|
605
|
+
```bash
|
|
606
|
+
vai mcp # stdio (default, local)
|
|
607
|
+
vai mcp --transport http --port 3100 # HTTP (remote, multi-client)
|
|
608
|
+
```
|
|
609
|
+
|
|
610
|
+
📖 **Full documentation:** [docs/mcp-server.md](docs/mcp-server.md)
|
|
611
|
+
|
|
612
|
+
---
|
|
613
|
+
|
|
550
614
|
## Screenshots
|
|
551
615
|
|
|
552
616
|
### Desktop App — Dark Theme
|
package/package.json
CHANGED
|
@@ -44,6 +44,80 @@ function registerMcpServer(program) {
|
|
|
44
44
|
const { generateKey } = require('../mcp/server');
|
|
45
45
|
generateKey();
|
|
46
46
|
});
|
|
47
|
+
|
|
48
|
+
// Subcommand: install
|
|
49
|
+
cmd
|
|
50
|
+
.command('install [targets...]')
|
|
51
|
+
.description('Install vai MCP server into AI tool configs (claude, claude-code, cursor, windsurf, vscode, or "all")')
|
|
52
|
+
.option('--force', 'Overwrite existing vai entry', false)
|
|
53
|
+
.option('--transport <mode>', 'Transport mode: stdio or http', 'stdio')
|
|
54
|
+
.option('--port <number>', 'HTTP port (http transport only)', (v) => parseInt(v, 10))
|
|
55
|
+
.option('--api-key <key>', 'Voyage API key to embed in config')
|
|
56
|
+
.action((targets, opts) => {
|
|
57
|
+
const { TARGETS, installTarget } = require('../mcp/install');
|
|
58
|
+
|
|
59
|
+
if (!targets.length) {
|
|
60
|
+
console.log('Usage: vai mcp install <target|all>');
|
|
61
|
+
console.log(`Available targets: ${Object.keys(TARGETS).join(', ')}, all`);
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
const keys = targets.includes('all') ? Object.keys(TARGETS) : targets;
|
|
66
|
+
|
|
67
|
+
for (const key of keys) {
|
|
68
|
+
try {
|
|
69
|
+
const result = installTarget(key, {
|
|
70
|
+
force: opts.force,
|
|
71
|
+
transport: opts.transport,
|
|
72
|
+
port: opts.port,
|
|
73
|
+
apiKey: opts.apiKey,
|
|
74
|
+
});
|
|
75
|
+
console.log(result.installed ? `✅ ${result.message}` : `⚠️ ${result.message}`);
|
|
76
|
+
} catch (err) {
|
|
77
|
+
console.error(`❌ ${key}: ${err.message}`);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
// Subcommand: uninstall
|
|
83
|
+
cmd
|
|
84
|
+
.command('uninstall [targets...]')
|
|
85
|
+
.description('Remove vai MCP server from AI tool configs')
|
|
86
|
+
.action((targets) => {
|
|
87
|
+
const { TARGETS, uninstallTarget } = require('../mcp/install');
|
|
88
|
+
|
|
89
|
+
if (!targets.length) {
|
|
90
|
+
console.log('Usage: vai mcp uninstall <target|all>');
|
|
91
|
+
console.log(`Available targets: ${Object.keys(TARGETS).join(', ')}, all`);
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
const keys = targets.includes('all') ? Object.keys(TARGETS) : targets;
|
|
96
|
+
|
|
97
|
+
for (const key of keys) {
|
|
98
|
+
try {
|
|
99
|
+
const result = uninstallTarget(key);
|
|
100
|
+
console.log(result.removed ? `✅ ${result.message}` : `⚠️ ${result.message}`);
|
|
101
|
+
} catch (err) {
|
|
102
|
+
console.error(`❌ ${key}: ${err.message}`);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
// Subcommand: status
|
|
108
|
+
cmd
|
|
109
|
+
.command('status')
|
|
110
|
+
.description('Show vai MCP installation status across all supported AI tools')
|
|
111
|
+
.action(() => {
|
|
112
|
+
const { statusAll } = require('../mcp/install');
|
|
113
|
+
const results = statusAll();
|
|
114
|
+
|
|
115
|
+
console.log('\nvai MCP Server — Installation Status\n');
|
|
116
|
+
for (const r of results) {
|
|
117
|
+
console.log(` ${r.status.padEnd(18)} ${r.name.padEnd(16)} ${r.configPath}`);
|
|
118
|
+
}
|
|
119
|
+
console.log('');
|
|
120
|
+
});
|
|
47
121
|
}
|
|
48
122
|
|
|
49
123
|
module.exports = { registerMcpServer };
|
package/src/commands/ping.js
CHANGED
package/src/lib/api.js
CHANGED
|
@@ -36,14 +36,12 @@ function requireApiKey() {
|
|
|
36
36
|
const { getConfigValue } = require('./config');
|
|
37
37
|
const key = process.env.VOYAGE_API_KEY || getConfigValue('apiKey');
|
|
38
38
|
if (!key) {
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
console.error(' or Voyage AI platform → Dashboard → API Keys');
|
|
46
|
-
process.exit(1);
|
|
39
|
+
const msg = 'VOYAGE_API_KEY is not set.\n\n' +
|
|
40
|
+
'Option 1: export VOYAGE_API_KEY="your-key-here"\n' +
|
|
41
|
+
'Option 2: vai config set api-key <your-key>\n\n' +
|
|
42
|
+
'Get one from MongoDB Atlas > AI Models > Create model API key\n' +
|
|
43
|
+
' or Voyage AI platform > Dashboard > API Keys';
|
|
44
|
+
throw new Error(msg);
|
|
47
45
|
}
|
|
48
46
|
return key;
|
|
49
47
|
}
|
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const fs = require('fs');
|
|
4
|
+
const path = require('path');
|
|
5
|
+
const os = require('os');
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Known MCP-compatible tools and their config file locations.
|
|
9
|
+
*/
|
|
10
|
+
const TARGETS = {
|
|
11
|
+
claude: {
|
|
12
|
+
name: 'Claude Desktop',
|
|
13
|
+
configPath: () => {
|
|
14
|
+
if (process.platform === 'darwin') return path.join(os.homedir(), 'Library', 'Application Support', 'Claude', 'claude_desktop_config.json');
|
|
15
|
+
if (process.platform === 'win32') return path.join(process.env.APPDATA || '', 'Claude', 'claude_desktop_config.json');
|
|
16
|
+
return path.join(os.homedir(), '.config', 'Claude', 'claude_desktop_config.json');
|
|
17
|
+
},
|
|
18
|
+
},
|
|
19
|
+
'claude-code': {
|
|
20
|
+
name: 'Claude Code',
|
|
21
|
+
configPath: () => path.join(os.homedir(), '.claude', 'settings.json'),
|
|
22
|
+
configKey: 'mcpServers', // same key but different file
|
|
23
|
+
},
|
|
24
|
+
cursor: {
|
|
25
|
+
name: 'Cursor',
|
|
26
|
+
configPath: () => path.join(os.homedir(), '.cursor', 'mcp.json'),
|
|
27
|
+
},
|
|
28
|
+
windsurf: {
|
|
29
|
+
name: 'Windsurf',
|
|
30
|
+
configPath: () => path.join(os.homedir(), '.codeium', 'windsurf', 'mcp_config.json'),
|
|
31
|
+
},
|
|
32
|
+
vscode: {
|
|
33
|
+
name: 'VS Code',
|
|
34
|
+
configPath: () => {
|
|
35
|
+
if (process.platform === 'darwin') return path.join(os.homedir(), 'Library', 'Application Support', 'Code', 'User', 'settings.json');
|
|
36
|
+
if (process.platform === 'win32') return path.join(process.env.APPDATA || '', 'Code', 'User', 'settings.json');
|
|
37
|
+
return path.join(os.homedir(), '.config', 'Code', 'User', 'settings.json');
|
|
38
|
+
},
|
|
39
|
+
configKey: 'mcp.servers',
|
|
40
|
+
},
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Build the vai MCP server entry.
|
|
45
|
+
*/
|
|
46
|
+
function buildVaiEntry(opts = {}) {
|
|
47
|
+
const entry = {
|
|
48
|
+
command: 'vai',
|
|
49
|
+
args: ['mcp-server'],
|
|
50
|
+
};
|
|
51
|
+
if (opts.transport === 'http') {
|
|
52
|
+
entry.args.push('--transport', 'http');
|
|
53
|
+
if (opts.port) entry.args.push('--port', String(opts.port));
|
|
54
|
+
}
|
|
55
|
+
const apiKey = opts.apiKey || process.env.VOYAGE_API_KEY || '';
|
|
56
|
+
if (apiKey) {
|
|
57
|
+
entry.env = { VOYAGE_API_KEY: apiKey };
|
|
58
|
+
}
|
|
59
|
+
return entry;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Read a JSON config file, returning {} if it doesn't exist.
|
|
64
|
+
*/
|
|
65
|
+
function readConfig(filePath) {
|
|
66
|
+
if (!fs.existsSync(filePath)) return null;
|
|
67
|
+
try {
|
|
68
|
+
const raw = fs.readFileSync(filePath, 'utf8');
|
|
69
|
+
return JSON.parse(raw);
|
|
70
|
+
} catch (err) {
|
|
71
|
+
throw new Error(`Failed to parse ${filePath}: ${err.message}`);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Write a JSON config file, creating parent directories as needed.
|
|
77
|
+
*/
|
|
78
|
+
function writeConfig(filePath, config) {
|
|
79
|
+
const dir = path.dirname(filePath);
|
|
80
|
+
if (!fs.existsSync(dir)) {
|
|
81
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
82
|
+
}
|
|
83
|
+
fs.writeFileSync(filePath, JSON.stringify(config, null, 2) + '\n', 'utf8');
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Set a nested key like "mcp.servers" on an object.
|
|
88
|
+
*/
|
|
89
|
+
function getNestedKey(obj, keyPath) {
|
|
90
|
+
const keys = keyPath.split('.');
|
|
91
|
+
let current = obj;
|
|
92
|
+
for (const k of keys) {
|
|
93
|
+
if (current == null || typeof current !== 'object') return undefined;
|
|
94
|
+
current = current[k];
|
|
95
|
+
}
|
|
96
|
+
return current;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
function setNestedKey(obj, keyPath, value) {
|
|
100
|
+
const keys = keyPath.split('.');
|
|
101
|
+
let current = obj;
|
|
102
|
+
for (let i = 0; i < keys.length - 1; i++) {
|
|
103
|
+
if (current[keys[i]] == null || typeof current[keys[i]] !== 'object') {
|
|
104
|
+
current[keys[i]] = {};
|
|
105
|
+
}
|
|
106
|
+
current = current[keys[i]];
|
|
107
|
+
}
|
|
108
|
+
current[keys[keys.length - 1]] = value;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* Install vai MCP entry into a target tool's config.
|
|
113
|
+
* Returns { installed: boolean, message: string }
|
|
114
|
+
*/
|
|
115
|
+
function installTarget(targetKey, opts = {}) {
|
|
116
|
+
const target = TARGETS[targetKey];
|
|
117
|
+
if (!target) {
|
|
118
|
+
return { installed: false, message: `Unknown target: ${targetKey}. Available: ${Object.keys(TARGETS).join(', ')}` };
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
const configPath = target.configPath();
|
|
122
|
+
const mcpKey = target.configKey || 'mcpServers';
|
|
123
|
+
const config = readConfig(configPath) || {};
|
|
124
|
+
|
|
125
|
+
// Get or create the mcpServers object
|
|
126
|
+
let servers = getNestedKey(config, mcpKey);
|
|
127
|
+
if (servers == null || typeof servers !== 'object') {
|
|
128
|
+
servers = {};
|
|
129
|
+
setNestedKey(config, mcpKey, servers);
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
if (servers.vai && !opts.force) {
|
|
133
|
+
return { installed: false, message: `${target.name}: vai already configured in ${configPath} — use --force to overwrite` };
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
const existed = !!servers.vai;
|
|
137
|
+
servers.vai = buildVaiEntry(opts);
|
|
138
|
+
// Ensure the nested key points to our updated servers
|
|
139
|
+
setNestedKey(config, mcpKey, servers);
|
|
140
|
+
|
|
141
|
+
writeConfig(configPath, config);
|
|
142
|
+
return { installed: true, message: `${target.name}: ${existed ? 'updated' : 'installed'} vai in ${configPath}` };
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
/**
|
|
146
|
+
* Uninstall vai MCP entry from a target tool's config.
|
|
147
|
+
*/
|
|
148
|
+
function uninstallTarget(targetKey) {
|
|
149
|
+
const target = TARGETS[targetKey];
|
|
150
|
+
if (!target) {
|
|
151
|
+
return { removed: false, message: `Unknown target: ${targetKey}` };
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
const configPath = target.configPath();
|
|
155
|
+
const config = readConfig(configPath);
|
|
156
|
+
if (!config) {
|
|
157
|
+
return { removed: false, message: `${target.name}: config not found at ${configPath}` };
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
const mcpKey = target.configKey || 'mcpServers';
|
|
161
|
+
const servers = getNestedKey(config, mcpKey);
|
|
162
|
+
if (!servers || !servers.vai) {
|
|
163
|
+
return { removed: false, message: `${target.name}: vai not configured` };
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
delete servers.vai;
|
|
167
|
+
setNestedKey(config, mcpKey, servers);
|
|
168
|
+
writeConfig(configPath, config);
|
|
169
|
+
return { removed: true, message: `${target.name}: removed vai from ${configPath}` };
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
/**
|
|
173
|
+
* Check status of vai MCP across all known tools.
|
|
174
|
+
*/
|
|
175
|
+
function statusAll() {
|
|
176
|
+
const results = [];
|
|
177
|
+
for (const [key, target] of Object.entries(TARGETS)) {
|
|
178
|
+
const configPath = target.configPath();
|
|
179
|
+
const mcpKey = target.configKey || 'mcpServers';
|
|
180
|
+
const config = readConfig(configPath);
|
|
181
|
+
|
|
182
|
+
let status;
|
|
183
|
+
if (!config) {
|
|
184
|
+
status = 'not found';
|
|
185
|
+
} else {
|
|
186
|
+
const servers = getNestedKey(config, mcpKey);
|
|
187
|
+
status = servers && servers.vai ? '✅ installed' : '⬚ not configured';
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
results.push({ target: key, name: target.name, configPath, status });
|
|
191
|
+
}
|
|
192
|
+
return results;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
module.exports = {
|
|
196
|
+
TARGETS,
|
|
197
|
+
installTarget,
|
|
198
|
+
uninstallTarget,
|
|
199
|
+
statusAll,
|
|
200
|
+
buildVaiEntry,
|
|
201
|
+
};
|