omnikey-cli 1.0.38 → 1.0.40
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 +59 -0
- package/backend-dist/agent/agentPrompts.js +51 -6
- package/backend-dist/agent/agentServer.js +26 -4
- package/backend-dist/agent/imageTool.js +2 -1
- package/backend-dist/agent/mcpPromptCache.js +35 -0
- package/backend-dist/agent/mcpRuntime.js +245 -0
- package/backend-dist/agent/utils.js +2 -2
- package/backend-dist/ai-client.js +7 -7
- package/backend-dist/featureRoutes.js +2 -2
- package/backend-dist/index.js +6 -3
- package/backend-dist/mcpServerRoutes.js +222 -0
- package/backend-dist/models/mcpServer.js +102 -0
- package/dist/index.js +47 -7
- package/dist/mcpServer.js +334 -0
- package/dist/onboard.js +2 -2
- package/package.json +4 -3
- package/src/index.ts +53 -7
- package/src/mcpServer.ts +390 -0
- package/src/onboard.ts +2 -2
|
@@ -0,0 +1,334 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.mcpAdd = mcpAdd;
|
|
7
|
+
exports.mcpList = mcpList;
|
|
8
|
+
exports.mcpRemove = mcpRemove;
|
|
9
|
+
exports.mcpToggle = mcpToggle;
|
|
10
|
+
exports.mcpUpdate = mcpUpdate;
|
|
11
|
+
const axios_1 = __importDefault(require("axios"));
|
|
12
|
+
const inquirer_1 = __importDefault(require("inquirer"));
|
|
13
|
+
const utils_1 = require("./utils");
|
|
14
|
+
async function getJwt() {
|
|
15
|
+
const config = (0, utils_1.readConfig)();
|
|
16
|
+
const port = (0, utils_1.getPort)();
|
|
17
|
+
const licenseKey = config.OMNIKEY_LICENSE_KEY || '';
|
|
18
|
+
const baseUrl = `http://localhost:${port}`;
|
|
19
|
+
const res = await axios_1.default.post(`${baseUrl}/api/subscription/activate`, { licenseKey }, { timeout: 10000 });
|
|
20
|
+
return res.data.token;
|
|
21
|
+
}
|
|
22
|
+
function getBaseUrl() {
|
|
23
|
+
return `http://localhost:${(0, utils_1.getPort)()}`;
|
|
24
|
+
}
|
|
25
|
+
async function authHeaders() {
|
|
26
|
+
let token;
|
|
27
|
+
try {
|
|
28
|
+
token = await getJwt();
|
|
29
|
+
}
|
|
30
|
+
catch (err) {
|
|
31
|
+
throw new Error(`Authentication failed — make sure the OmniKey backend is running and your license key is configured.\nCause: ${err?.message ?? String(err)}`);
|
|
32
|
+
}
|
|
33
|
+
return { Authorization: `Bearer ${token}` };
|
|
34
|
+
}
|
|
35
|
+
function parseLines(input) {
|
|
36
|
+
return input
|
|
37
|
+
.split('\n')
|
|
38
|
+
.map((l) => l.trim())
|
|
39
|
+
.filter((l) => l.length > 0);
|
|
40
|
+
}
|
|
41
|
+
function parseKeyValueLines(input) {
|
|
42
|
+
const out = {};
|
|
43
|
+
for (const line of parseLines(input)) {
|
|
44
|
+
const idx = line.indexOf('=');
|
|
45
|
+
if (idx <= 0)
|
|
46
|
+
continue;
|
|
47
|
+
const key = line.slice(0, idx).trim();
|
|
48
|
+
const value = line.slice(idx + 1).trim();
|
|
49
|
+
if (key)
|
|
50
|
+
out[key] = value;
|
|
51
|
+
}
|
|
52
|
+
return out;
|
|
53
|
+
}
|
|
54
|
+
async function promptTransportFields(transport, defaults) {
|
|
55
|
+
if (transport === 'stdio') {
|
|
56
|
+
const ans = await inquirer_1.default.prompt([
|
|
57
|
+
{
|
|
58
|
+
type: 'input',
|
|
59
|
+
name: 'command',
|
|
60
|
+
message: 'Command (executable path or name):',
|
|
61
|
+
default: defaults?.command ?? '',
|
|
62
|
+
validate: (v) => v.trim().length > 0 || 'Command is required for stdio transport',
|
|
63
|
+
},
|
|
64
|
+
{
|
|
65
|
+
type: 'editor',
|
|
66
|
+
name: 'args',
|
|
67
|
+
message: 'Args (one per line):',
|
|
68
|
+
default: (defaults?.args ?? []).join('\n'),
|
|
69
|
+
},
|
|
70
|
+
{
|
|
71
|
+
type: 'editor',
|
|
72
|
+
name: 'env',
|
|
73
|
+
message: 'Environment variables (one KEY=VALUE per line):',
|
|
74
|
+
default: formatKVForEditor(defaults?.env),
|
|
75
|
+
},
|
|
76
|
+
]);
|
|
77
|
+
return {
|
|
78
|
+
command: ans.command.trim(),
|
|
79
|
+
args: parseLines(ans.args),
|
|
80
|
+
env: parseKeyValueLines(ans.env),
|
|
81
|
+
url: null,
|
|
82
|
+
headers: {},
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
const ans = await inquirer_1.default.prompt([
|
|
86
|
+
{
|
|
87
|
+
type: 'input',
|
|
88
|
+
name: 'url',
|
|
89
|
+
message: `URL for ${transport} transport:`,
|
|
90
|
+
default: defaults?.url ?? '',
|
|
91
|
+
validate: (v) => v.trim().length > 0 || 'URL is required',
|
|
92
|
+
},
|
|
93
|
+
{
|
|
94
|
+
type: 'editor',
|
|
95
|
+
name: 'headers',
|
|
96
|
+
message: 'Headers (one KEY=VALUE per line):',
|
|
97
|
+
default: formatKVForEditor(defaults?.headers),
|
|
98
|
+
},
|
|
99
|
+
]);
|
|
100
|
+
return {
|
|
101
|
+
url: ans.url.trim(),
|
|
102
|
+
headers: parseKeyValueLines(ans.headers),
|
|
103
|
+
command: null,
|
|
104
|
+
args: [],
|
|
105
|
+
env: {},
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
function formatKVForEditor(dict) {
|
|
109
|
+
if (!dict)
|
|
110
|
+
return '';
|
|
111
|
+
return Object.entries(dict)
|
|
112
|
+
.map(([k, v]) => `${k}=${v}`)
|
|
113
|
+
.join('\n');
|
|
114
|
+
}
|
|
115
|
+
async function mcpAdd() {
|
|
116
|
+
const baseAnswers = await inquirer_1.default.prompt([
|
|
117
|
+
{
|
|
118
|
+
type: 'input',
|
|
119
|
+
name: 'name',
|
|
120
|
+
message: 'Name (unique, e.g. "github"):',
|
|
121
|
+
validate: (v) => v.trim().length > 0 || 'Name is required',
|
|
122
|
+
},
|
|
123
|
+
{
|
|
124
|
+
type: 'input',
|
|
125
|
+
name: 'description',
|
|
126
|
+
message: 'Description (optional):',
|
|
127
|
+
},
|
|
128
|
+
{
|
|
129
|
+
type: 'list',
|
|
130
|
+
name: 'transport',
|
|
131
|
+
message: 'Transport:',
|
|
132
|
+
choices: [
|
|
133
|
+
{ name: 'stdio (local process)', value: 'stdio' },
|
|
134
|
+
{ name: 'http', value: 'http' },
|
|
135
|
+
{ name: 'sse', value: 'sse' },
|
|
136
|
+
],
|
|
137
|
+
default: 'stdio',
|
|
138
|
+
},
|
|
139
|
+
{
|
|
140
|
+
type: 'confirm',
|
|
141
|
+
name: 'isEnabled',
|
|
142
|
+
message: 'Enabled?',
|
|
143
|
+
default: true,
|
|
144
|
+
},
|
|
145
|
+
]);
|
|
146
|
+
const transportFields = await promptTransportFields(baseAnswers.transport);
|
|
147
|
+
try {
|
|
148
|
+
const headers = await authHeaders();
|
|
149
|
+
const res = await axios_1.default.post(`${getBaseUrl()}/api/mcp-servers`, {
|
|
150
|
+
name: baseAnswers.name.trim(),
|
|
151
|
+
description: baseAnswers.description.trim() || null,
|
|
152
|
+
transport: baseAnswers.transport,
|
|
153
|
+
isEnabled: baseAnswers.isEnabled,
|
|
154
|
+
...transportFields,
|
|
155
|
+
}, { headers, timeout: 15000 });
|
|
156
|
+
console.log('\nMCP server created:');
|
|
157
|
+
printServer(res.data);
|
|
158
|
+
}
|
|
159
|
+
catch (err) {
|
|
160
|
+
const msg = err.response?.data?.error ?? err.message;
|
|
161
|
+
console.error(`Error creating MCP server: ${msg}`);
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
async function mcpList() {
|
|
165
|
+
try {
|
|
166
|
+
const headers = await authHeaders();
|
|
167
|
+
const res = await axios_1.default.get(`${getBaseUrl()}/api/mcp-servers`, {
|
|
168
|
+
headers,
|
|
169
|
+
timeout: 10000,
|
|
170
|
+
});
|
|
171
|
+
const { servers } = res.data;
|
|
172
|
+
if (servers.length === 0) {
|
|
173
|
+
console.log('No MCP servers installed.');
|
|
174
|
+
return;
|
|
175
|
+
}
|
|
176
|
+
console.log('\nMCP Servers:');
|
|
177
|
+
console.log('─'.repeat(90));
|
|
178
|
+
console.log(padRight('ID', 28) +
|
|
179
|
+
padRight('Name', 22) +
|
|
180
|
+
padRight('Transport', 12) +
|
|
181
|
+
padRight('Enabled', 10) +
|
|
182
|
+
'Endpoint');
|
|
183
|
+
console.log('─'.repeat(90));
|
|
184
|
+
for (const s of servers) {
|
|
185
|
+
const endpoint = s.transport === 'stdio' ? (s.command ?? '—') : (s.url ?? '—');
|
|
186
|
+
console.log(padRight(s.id.slice(0, 26), 28) +
|
|
187
|
+
padRight(s.name.slice(0, 20), 22) +
|
|
188
|
+
padRight(s.transport, 12) +
|
|
189
|
+
padRight(s.isEnabled ? 'yes' : 'no', 10) +
|
|
190
|
+
endpoint.slice(0, 40));
|
|
191
|
+
}
|
|
192
|
+
console.log('─'.repeat(90));
|
|
193
|
+
}
|
|
194
|
+
catch (err) {
|
|
195
|
+
const msg = err.response?.data?.error ?? err.message;
|
|
196
|
+
console.error(`Error fetching MCP servers: ${msg}`);
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
async function pickServer(action) {
|
|
200
|
+
const headers = await authHeaders();
|
|
201
|
+
const res = await axios_1.default.get(`${getBaseUrl()}/api/mcp-servers`, {
|
|
202
|
+
headers,
|
|
203
|
+
timeout: 10000,
|
|
204
|
+
});
|
|
205
|
+
const { servers } = res.data;
|
|
206
|
+
if (servers.length === 0) {
|
|
207
|
+
console.log(`No MCP servers to ${action}.`);
|
|
208
|
+
return null;
|
|
209
|
+
}
|
|
210
|
+
const { id } = await inquirer_1.default.prompt([
|
|
211
|
+
{
|
|
212
|
+
type: 'list',
|
|
213
|
+
name: 'id',
|
|
214
|
+
message: `Select an MCP server to ${action}:`,
|
|
215
|
+
choices: servers.map((s) => ({
|
|
216
|
+
name: `${s.name} [${s.transport}] ${s.isEnabled ? '✓' : '✗'}`,
|
|
217
|
+
value: s.id,
|
|
218
|
+
})),
|
|
219
|
+
},
|
|
220
|
+
]);
|
|
221
|
+
return servers.find((s) => s.id === id) ?? null;
|
|
222
|
+
}
|
|
223
|
+
async function mcpRemove() {
|
|
224
|
+
try {
|
|
225
|
+
const server = await pickServer('remove');
|
|
226
|
+
if (!server)
|
|
227
|
+
return;
|
|
228
|
+
const { confirm } = await inquirer_1.default.prompt([
|
|
229
|
+
{
|
|
230
|
+
type: 'confirm',
|
|
231
|
+
name: 'confirm',
|
|
232
|
+
message: `Delete MCP server "${server.name}"?`,
|
|
233
|
+
default: false,
|
|
234
|
+
},
|
|
235
|
+
]);
|
|
236
|
+
if (!confirm) {
|
|
237
|
+
console.log('Aborted.');
|
|
238
|
+
return;
|
|
239
|
+
}
|
|
240
|
+
const headers = await authHeaders();
|
|
241
|
+
await axios_1.default.delete(`${getBaseUrl()}/api/mcp-servers/${server.id}`, {
|
|
242
|
+
headers,
|
|
243
|
+
timeout: 10000,
|
|
244
|
+
});
|
|
245
|
+
console.log('MCP server removed.');
|
|
246
|
+
}
|
|
247
|
+
catch (err) {
|
|
248
|
+
const msg = err.response?.data?.error ?? err.message;
|
|
249
|
+
console.error(`Error removing MCP server: ${msg}`);
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
async function mcpToggle(id) {
|
|
253
|
+
try {
|
|
254
|
+
const headers = await authHeaders();
|
|
255
|
+
const current = await axios_1.default.get(`${getBaseUrl()}/api/mcp-servers/${id}`, {
|
|
256
|
+
headers,
|
|
257
|
+
timeout: 10000,
|
|
258
|
+
});
|
|
259
|
+
const newState = !current.data.isEnabled;
|
|
260
|
+
const res = await axios_1.default.patch(`${getBaseUrl()}/api/mcp-servers/${id}`, { isEnabled: newState }, { headers, timeout: 10000 });
|
|
261
|
+
console.log(`MCP server ${res.data.name} is now ${res.data.isEnabled ? 'enabled' : 'disabled'}.`);
|
|
262
|
+
}
|
|
263
|
+
catch (err) {
|
|
264
|
+
const msg = err.response?.data?.error ?? err.message;
|
|
265
|
+
console.error(`Error toggling MCP server: ${msg}`);
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
async function mcpUpdate(id) {
|
|
269
|
+
try {
|
|
270
|
+
const headers = await authHeaders();
|
|
271
|
+
const current = (await axios_1.default.get(`${getBaseUrl()}/api/mcp-servers/${id}`, {
|
|
272
|
+
headers,
|
|
273
|
+
timeout: 10000,
|
|
274
|
+
})).data;
|
|
275
|
+
const baseAnswers = await inquirer_1.default.prompt([
|
|
276
|
+
{
|
|
277
|
+
type: 'input',
|
|
278
|
+
name: 'name',
|
|
279
|
+
message: 'Name:',
|
|
280
|
+
default: current.name,
|
|
281
|
+
},
|
|
282
|
+
{
|
|
283
|
+
type: 'input',
|
|
284
|
+
name: 'description',
|
|
285
|
+
message: 'Description:',
|
|
286
|
+
default: current.description ?? '',
|
|
287
|
+
},
|
|
288
|
+
{
|
|
289
|
+
type: 'list',
|
|
290
|
+
name: 'transport',
|
|
291
|
+
message: 'Transport:',
|
|
292
|
+
choices: ['stdio', 'http', 'sse'],
|
|
293
|
+
default: current.transport,
|
|
294
|
+
},
|
|
295
|
+
{
|
|
296
|
+
type: 'confirm',
|
|
297
|
+
name: 'isEnabled',
|
|
298
|
+
message: 'Enabled?',
|
|
299
|
+
default: current.isEnabled,
|
|
300
|
+
},
|
|
301
|
+
]);
|
|
302
|
+
const transportFields = await promptTransportFields(baseAnswers.transport, current);
|
|
303
|
+
const res = await axios_1.default.patch(`${getBaseUrl()}/api/mcp-servers/${id}`, {
|
|
304
|
+
name: baseAnswers.name.trim(),
|
|
305
|
+
description: baseAnswers.description.trim() || null,
|
|
306
|
+
transport: baseAnswers.transport,
|
|
307
|
+
isEnabled: baseAnswers.isEnabled,
|
|
308
|
+
...transportFields,
|
|
309
|
+
}, { headers, timeout: 15000 });
|
|
310
|
+
console.log('\nMCP server updated:');
|
|
311
|
+
printServer(res.data);
|
|
312
|
+
}
|
|
313
|
+
catch (err) {
|
|
314
|
+
const msg = err.response?.data?.error ?? err.message;
|
|
315
|
+
console.error(`Error updating MCP server: ${msg}`);
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
function printServer(s) {
|
|
319
|
+
console.log(` ID: ${s.id}`);
|
|
320
|
+
console.log(` Name: ${s.name}`);
|
|
321
|
+
console.log(` Transport: ${s.transport}`);
|
|
322
|
+
console.log(` Enabled: ${s.isEnabled}`);
|
|
323
|
+
if (s.transport === 'stdio') {
|
|
324
|
+
console.log(` Command: ${s.command ?? '—'}`);
|
|
325
|
+
if (s.args.length > 0)
|
|
326
|
+
console.log(` Args: ${s.args.join(' ')}`);
|
|
327
|
+
}
|
|
328
|
+
else {
|
|
329
|
+
console.log(` URL: ${s.url ?? '—'}`);
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
function padRight(str, width) {
|
|
333
|
+
return str.length >= width ? str.slice(0, width) : str + ' '.repeat(width - str.length);
|
|
334
|
+
}
|
package/dist/onboard.js
CHANGED
|
@@ -9,8 +9,8 @@ const fs_1 = __importDefault(require("fs"));
|
|
|
9
9
|
const path_1 = __importDefault(require("path"));
|
|
10
10
|
const utils_1 = require("./utils");
|
|
11
11
|
const AI_PROVIDERS = [
|
|
12
|
-
{ name: 'OpenAI (gpt-4o-mini / gpt-5.
|
|
13
|
-
{ name: 'Anthropic — Claude (claude-haiku / claude-
|
|
12
|
+
{ name: 'OpenAI (gpt-4o-mini / gpt-5.5)', value: 'openai' },
|
|
13
|
+
{ name: 'Anthropic — Claude (claude-haiku / claude-opus)', value: 'anthropic' },
|
|
14
14
|
{ name: 'Google Gemini (gemini-2.5-flash / gemini-2.5-pro)', value: 'gemini' },
|
|
15
15
|
];
|
|
16
16
|
const SEARCH_PROVIDERS = [
|
package/package.json
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
"access": "public",
|
|
5
5
|
"registry": "https://registry.npmjs.org/"
|
|
6
6
|
},
|
|
7
|
-
"version": "1.0.
|
|
7
|
+
"version": "1.0.40",
|
|
8
8
|
"description": "CLI for onboarding users to Omnikey AI and configuring OPENAI_API_KEY. Use Yarn for install/build.",
|
|
9
9
|
"engines": {
|
|
10
10
|
"node": ">=14.0.0",
|
|
@@ -27,9 +27,10 @@
|
|
|
27
27
|
"author": "Gurinder Rawala",
|
|
28
28
|
"license": "MIT",
|
|
29
29
|
"dependencies": {
|
|
30
|
-
"@anthropic-ai/sdk": "^0.
|
|
30
|
+
"@anthropic-ai/sdk": "^0.96.0",
|
|
31
31
|
"@google-cloud/storage": "^7.19.0",
|
|
32
32
|
"@google/genai": "^1.46.0",
|
|
33
|
+
"@modelcontextprotocol/sdk": "^1.29.0",
|
|
33
34
|
"axios": "^1.13.5",
|
|
34
35
|
"commander": "^11.0.0",
|
|
35
36
|
"cors": "^2.8.5",
|
|
@@ -38,7 +39,7 @@
|
|
|
38
39
|
"express": "^4.21.2",
|
|
39
40
|
"inquirer": "^9.0.0",
|
|
40
41
|
"jsonwebtoken": "^9.0.3",
|
|
41
|
-
"openai": "^6.
|
|
42
|
+
"openai": "^6.37.0",
|
|
42
43
|
"pg": "^8.18.0",
|
|
43
44
|
"pg-hstore": "^2.3.4",
|
|
44
45
|
"playwright-core": "^1.50.0",
|
package/src/index.ts
CHANGED
|
@@ -11,6 +11,7 @@ import { showConfig } from './showConfig';
|
|
|
11
11
|
import { setConfig } from './setConfig';
|
|
12
12
|
import { grantBrowserAccess, reopenBrowserDebugProfile } from './grantBrowserAccess';
|
|
13
13
|
import { scheduleAdd, scheduleList, scheduleRemove, scheduleRunNow } from './scheduleJob';
|
|
14
|
+
import { mcpAdd, mcpList, mcpRemove, mcpToggle, mcpUpdate } from './mcpServer';
|
|
14
15
|
|
|
15
16
|
const program = new Command();
|
|
16
17
|
|
|
@@ -110,28 +111,73 @@ program
|
|
|
110
111
|
await reopenBrowserDebugProfile();
|
|
111
112
|
});
|
|
112
113
|
|
|
113
|
-
const scheduleCmd = program
|
|
114
|
-
.command('schedule')
|
|
115
|
-
.description('Manage scheduled prompt jobs');
|
|
114
|
+
const scheduleCmd = program.command('schedule').description('Manage scheduled prompt jobs');
|
|
116
115
|
|
|
117
116
|
scheduleCmd
|
|
118
117
|
.command('add')
|
|
119
118
|
.description('Add a new scheduled job')
|
|
120
|
-
.action(async () => {
|
|
119
|
+
.action(async () => {
|
|
120
|
+
await scheduleAdd();
|
|
121
|
+
});
|
|
121
122
|
|
|
122
123
|
scheduleCmd
|
|
123
124
|
.command('list')
|
|
124
125
|
.description('List all scheduled jobs')
|
|
125
|
-
.action(async () => {
|
|
126
|
+
.action(async () => {
|
|
127
|
+
await scheduleList();
|
|
128
|
+
});
|
|
126
129
|
|
|
127
130
|
scheduleCmd
|
|
128
131
|
.command('remove')
|
|
129
132
|
.description('Remove a scheduled job')
|
|
130
|
-
.action(async () => {
|
|
133
|
+
.action(async () => {
|
|
134
|
+
await scheduleRemove();
|
|
135
|
+
});
|
|
131
136
|
|
|
132
137
|
scheduleCmd
|
|
133
138
|
.command('run-now <id>')
|
|
134
139
|
.description('Immediately run a scheduled job by ID')
|
|
135
|
-
.action(async (id: string) => {
|
|
140
|
+
.action(async (id: string) => {
|
|
141
|
+
await scheduleRunNow(id);
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
const mcpCmd = program
|
|
145
|
+
.command('mcp')
|
|
146
|
+
.description('Manage MCP (Model Context Protocol) servers available to the agent');
|
|
147
|
+
|
|
148
|
+
mcpCmd
|
|
149
|
+
.command('add')
|
|
150
|
+
.description('Install a new MCP server')
|
|
151
|
+
.action(async () => {
|
|
152
|
+
await mcpAdd();
|
|
153
|
+
});
|
|
154
|
+
|
|
155
|
+
mcpCmd
|
|
156
|
+
.command('list')
|
|
157
|
+
.description('List installed MCP servers')
|
|
158
|
+
.action(async () => {
|
|
159
|
+
await mcpList();
|
|
160
|
+
});
|
|
161
|
+
|
|
162
|
+
mcpCmd
|
|
163
|
+
.command('remove')
|
|
164
|
+
.description('Remove an installed MCP server')
|
|
165
|
+
.action(async () => {
|
|
166
|
+
await mcpRemove();
|
|
167
|
+
});
|
|
168
|
+
|
|
169
|
+
mcpCmd
|
|
170
|
+
.command('toggle <id>')
|
|
171
|
+
.description('Toggle an MCP server enabled/disabled by ID')
|
|
172
|
+
.action(async (id: string) => {
|
|
173
|
+
await mcpToggle(id);
|
|
174
|
+
});
|
|
175
|
+
|
|
176
|
+
mcpCmd
|
|
177
|
+
.command('update <id>')
|
|
178
|
+
.description('Update an existing MCP server by ID')
|
|
179
|
+
.action(async (id: string) => {
|
|
180
|
+
await mcpUpdate(id);
|
|
181
|
+
});
|
|
136
182
|
|
|
137
183
|
program.parseAsync(process.argv);
|