@danainnovations/cortex-mcp 1.0.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/dist/cli.js ADDED
@@ -0,0 +1,740 @@
1
+ #!/usr/bin/env node
2
+
3
+ // bin/cli.ts
4
+ import { Command } from "commander";
5
+
6
+ // src/cli/setup.ts
7
+ import * as readline from "readline";
8
+
9
+ // src/constants.ts
10
+ var DEFAULT_SERVER_URL = "https://cortex-bice.vercel.app";
11
+ var PROTOCOL_VERSION = "2024-11-05";
12
+ var AVAILABLE_MCPS = [
13
+ {
14
+ name: "github",
15
+ displayName: "GitHub",
16
+ description: "Repos, PRs, issues, branches, code review (30 tools)",
17
+ serverName: "cortex-github"
18
+ },
19
+ {
20
+ name: "vercel",
21
+ displayName: "Vercel",
22
+ description: "Deployments, projects, env vars (15 tools)",
23
+ serverName: "cortex-vercel"
24
+ },
25
+ {
26
+ name: "supabase",
27
+ displayName: "Supabase",
28
+ description: "Database, migrations, edge functions (20+ tools)",
29
+ serverName: "cortex-supabase"
30
+ },
31
+ {
32
+ name: "sonance_brand",
33
+ displayName: "Sonance Brand",
34
+ description: "Brand design system, product data",
35
+ serverName: "cortex-sonance-brand"
36
+ }
37
+ ];
38
+ var MCP_NAMES = AVAILABLE_MCPS.map((m) => m.name);
39
+ var DEFAULT_MCPS = [...MCP_NAMES];
40
+ var CONFIG_DIR_NAME = ".cortex-mcp";
41
+ var CONFIG_FILE_NAME = "config.json";
42
+
43
+ // src/config/storage.ts
44
+ import { existsSync, mkdirSync, readFileSync, writeFileSync } from "fs";
45
+ import { join as join2 } from "path";
46
+
47
+ // src/utils/platform.ts
48
+ import { homedir, platform } from "os";
49
+ import { join } from "path";
50
+ function getHomeDir() {
51
+ return homedir();
52
+ }
53
+ function getPlatform() {
54
+ const p = platform();
55
+ if (p === "darwin") return "macos";
56
+ if (p === "win32") return "windows";
57
+ return "linux";
58
+ }
59
+ function getClaudeDesktopConfigPath() {
60
+ const home = getHomeDir();
61
+ const p = getPlatform();
62
+ switch (p) {
63
+ case "macos":
64
+ return join(
65
+ home,
66
+ "Library",
67
+ "Application Support",
68
+ "Claude",
69
+ "claude_desktop_config.json"
70
+ );
71
+ case "windows":
72
+ return join(
73
+ process.env.APPDATA || join(home, "AppData", "Roaming"),
74
+ "Claude",
75
+ "claude_desktop_config.json"
76
+ );
77
+ case "linux":
78
+ return join(home, ".config", "Claude", "claude_desktop_config.json");
79
+ }
80
+ }
81
+ function getCursorConfigPath() {
82
+ const home = getHomeDir();
83
+ return join(home, ".cursor", "mcp.json");
84
+ }
85
+
86
+ // src/config/storage.ts
87
+ function getConfigDir() {
88
+ return join2(getHomeDir(), CONFIG_DIR_NAME);
89
+ }
90
+ function getConfigPath() {
91
+ return join2(getConfigDir(), CONFIG_FILE_NAME);
92
+ }
93
+ function readConfig() {
94
+ const path = getConfigPath();
95
+ if (!existsSync(path)) return null;
96
+ try {
97
+ const raw = readFileSync(path, "utf-8");
98
+ return JSON.parse(raw);
99
+ } catch {
100
+ return null;
101
+ }
102
+ }
103
+ function writeConfig(config) {
104
+ const dir = getConfigDir();
105
+ if (!existsSync(dir)) {
106
+ mkdirSync(dir, { recursive: true, mode: 448 });
107
+ }
108
+ const path = getConfigPath();
109
+ writeFileSync(path, JSON.stringify(config, null, 2) + "\n", {
110
+ mode: 384
111
+ });
112
+ }
113
+ function createConfig(apiKey, mcps) {
114
+ return {
115
+ version: 1,
116
+ server: DEFAULT_SERVER_URL,
117
+ apiKey,
118
+ mcps,
119
+ configuredClients: []
120
+ };
121
+ }
122
+
123
+ // src/config/clients.ts
124
+ import { existsSync as existsSync2, readFileSync as readFileSync2, writeFileSync as writeFileSync2 } from "fs";
125
+ import { dirname } from "path";
126
+ import { mkdirSync as mkdirSync2 } from "fs";
127
+ import { execSync } from "child_process";
128
+ function detectClients() {
129
+ const clients = [];
130
+ const desktopPath = getClaudeDesktopConfigPath();
131
+ const desktopDir = dirname(desktopPath);
132
+ clients.push({
133
+ type: "claude-desktop",
134
+ name: "Claude Desktop",
135
+ configPath: desktopPath,
136
+ detected: existsSync2(desktopDir)
137
+ });
138
+ let claudeCodeDetected = false;
139
+ try {
140
+ execSync("which claude", { stdio: "pipe" });
141
+ claudeCodeDetected = true;
142
+ } catch {
143
+ }
144
+ clients.push({
145
+ type: "claude-code",
146
+ name: "Claude Code",
147
+ configPath: null,
148
+ detected: claudeCodeDetected
149
+ });
150
+ const cursorPath = getCursorConfigPath();
151
+ const cursorDir = dirname(cursorPath);
152
+ clients.push({
153
+ type: "stdio",
154
+ name: "Cursor",
155
+ configPath: cursorPath,
156
+ detected: existsSync2(cursorDir)
157
+ });
158
+ return clients;
159
+ }
160
+ function buildHttpEntries(serverUrl, apiKey, mcps) {
161
+ const entries = {};
162
+ for (const mcp of AVAILABLE_MCPS) {
163
+ if (!mcps.includes(mcp.name)) continue;
164
+ entries[mcp.serverName] = {
165
+ url: `${serverUrl}/mcp/${mcp.name}`,
166
+ headers: { "x-api-key": apiKey }
167
+ };
168
+ }
169
+ return entries;
170
+ }
171
+ function configureClaudeDesktop(serverUrl, apiKey, mcps) {
172
+ const configPath = getClaudeDesktopConfigPath();
173
+ const dir = dirname(configPath);
174
+ if (!existsSync2(dir)) {
175
+ mkdirSync2(dir, { recursive: true });
176
+ }
177
+ let config = {};
178
+ if (existsSync2(configPath)) {
179
+ try {
180
+ config = JSON.parse(readFileSync2(configPath, "utf-8"));
181
+ } catch {
182
+ }
183
+ }
184
+ if (!config.mcpServers || typeof config.mcpServers !== "object") {
185
+ config.mcpServers = {};
186
+ }
187
+ const servers = config.mcpServers;
188
+ for (const key of Object.keys(servers)) {
189
+ if (key.startsWith("cortex-")) {
190
+ delete servers[key];
191
+ }
192
+ }
193
+ const entries = buildHttpEntries(serverUrl, apiKey, mcps);
194
+ Object.assign(servers, entries);
195
+ writeFileSync2(configPath, JSON.stringify(config, null, 2) + "\n");
196
+ }
197
+ function configureClaudeCode(serverUrl, apiKey, mcps) {
198
+ for (const mcp of AVAILABLE_MCPS) {
199
+ if (!mcps.includes(mcp.name)) continue;
200
+ const url = `${serverUrl}/mcp/${mcp.name}`;
201
+ try {
202
+ execSync(`claude mcp remove ${mcp.serverName}`, { stdio: "pipe" });
203
+ } catch {
204
+ }
205
+ execSync(
206
+ `claude mcp add ${mcp.serverName} --transport http --url "${url}" --header "x-api-key: ${apiKey}"`,
207
+ { stdio: "pipe" }
208
+ );
209
+ }
210
+ }
211
+ function generateStdioSnippet(apiKey) {
212
+ const config = {
213
+ mcpServers: {
214
+ cortex: {
215
+ command: "npx",
216
+ args: ["-y", "@danainnovations/cortex-mcp", "serve"],
217
+ env: { CORTEX_API_KEY: apiKey }
218
+ }
219
+ }
220
+ };
221
+ return JSON.stringify(config, null, 2);
222
+ }
223
+ function resetClaudeDesktop() {
224
+ const configPath = getClaudeDesktopConfigPath();
225
+ if (!existsSync2(configPath)) return false;
226
+ try {
227
+ const config = JSON.parse(readFileSync2(configPath, "utf-8"));
228
+ if (!config.mcpServers) return false;
229
+ const servers = config.mcpServers;
230
+ let removed = false;
231
+ for (const key of Object.keys(servers)) {
232
+ if (key.startsWith("cortex-") || key === "cortex") {
233
+ delete servers[key];
234
+ removed = true;
235
+ }
236
+ }
237
+ if (removed) {
238
+ writeFileSync2(configPath, JSON.stringify(config, null, 2) + "\n");
239
+ }
240
+ return removed;
241
+ } catch {
242
+ return false;
243
+ }
244
+ }
245
+ function resetClaudeCode() {
246
+ let removed = false;
247
+ for (const mcp of AVAILABLE_MCPS) {
248
+ try {
249
+ execSync(`claude mcp remove ${mcp.serverName}`, { stdio: "pipe" });
250
+ removed = true;
251
+ } catch {
252
+ }
253
+ }
254
+ return removed;
255
+ }
256
+ function configureClient(clientType, serverUrl, apiKey, mcps) {
257
+ switch (clientType) {
258
+ case "claude-desktop":
259
+ configureClaudeDesktop(serverUrl, apiKey, mcps);
260
+ return "Claude Desktop configured";
261
+ case "claude-code":
262
+ configureClaudeCode(serverUrl, apiKey, mcps);
263
+ return "Claude Code configured";
264
+ case "stdio":
265
+ return "Add this to your client config:\n\n" + generateStdioSnippet(apiKey);
266
+ }
267
+ }
268
+
269
+ // src/utils/validation.ts
270
+ function isValidApiKey(key) {
271
+ return /^ctx_[a-zA-Z0-9]+_[a-zA-Z0-9]+$/.test(key.trim());
272
+ }
273
+ async function validateApiKeyRemote(serverUrl, apiKey) {
274
+ try {
275
+ const response = await fetch(`${serverUrl}/mcp/github`, {
276
+ method: "POST",
277
+ headers: {
278
+ "Content-Type": "application/json",
279
+ "x-api-key": apiKey,
280
+ "mcp-protocol-version": "2024-11-05"
281
+ },
282
+ body: JSON.stringify({
283
+ jsonrpc: "2.0",
284
+ method: "initialize",
285
+ params: {
286
+ protocolVersion: "2024-11-05",
287
+ capabilities: {},
288
+ clientInfo: { name: "cortex-mcp-setup", version: "1.0.0" }
289
+ },
290
+ id: "validate"
291
+ })
292
+ });
293
+ if (response.status === 401 || response.status === 403) {
294
+ return { valid: false, error: "Invalid or expired API key" };
295
+ }
296
+ if (!response.ok) {
297
+ return { valid: false, error: `Server returned ${response.status}` };
298
+ }
299
+ return { valid: true };
300
+ } catch {
301
+ return { valid: false, error: "Could not reach the Cortex server" };
302
+ }
303
+ }
304
+
305
+ // src/cli/setup.ts
306
+ var rl = readline.createInterface({
307
+ input: process.stdin,
308
+ output: process.stderr
309
+ });
310
+ function ask(question) {
311
+ return new Promise((resolve) => {
312
+ rl.question(question, (answer) => resolve(answer.trim()));
313
+ });
314
+ }
315
+ function log(msg) {
316
+ process.stderr.write(msg + "\n");
317
+ }
318
+ async function runSetup() {
319
+ log("");
320
+ log(" Cortex MCP Setup");
321
+ log(" Connect your AI tools to GitHub, Vercel, Supabase & Sonance Brand");
322
+ log("");
323
+ log(" Step 1: API Key");
324
+ log(" Get one at https://aidentity.app/settings/keys");
325
+ log("");
326
+ let apiKey = "";
327
+ while (true) {
328
+ apiKey = await ask(" Enter your Cortex API key: ");
329
+ if (!isValidApiKey(apiKey)) {
330
+ log(
331
+ " That doesn't look like a Cortex API key. It should start with 'ctx_'."
332
+ );
333
+ continue;
334
+ }
335
+ log(" Validating...");
336
+ const { valid, error } = await validateApiKeyRemote(
337
+ DEFAULT_SERVER_URL,
338
+ apiKey
339
+ );
340
+ if (!valid) {
341
+ log(` Key validation failed: ${error}`);
342
+ log(" Please try again.\n");
343
+ continue;
344
+ }
345
+ log(" Key validated successfully.\n");
346
+ break;
347
+ }
348
+ log(" Step 2: Select MCPs");
349
+ log(" Available MCPs (all enabled by default):\n");
350
+ for (const mcp of AVAILABLE_MCPS) {
351
+ log(` - ${mcp.displayName.padEnd(15)} ${mcp.description}`);
352
+ }
353
+ log("");
354
+ const mcpInput = await ask(
355
+ ` MCPs to enable (comma-separated, or press Enter for all): `
356
+ );
357
+ let selectedMcps;
358
+ if (!mcpInput) {
359
+ selectedMcps = [...DEFAULT_MCPS];
360
+ log(" All MCPs enabled.\n");
361
+ } else {
362
+ selectedMcps = mcpInput.split(",").map((s) => s.trim().toLowerCase()).filter(
363
+ (s) => AVAILABLE_MCPS.some(
364
+ (m) => m.name === s || m.displayName.toLowerCase() === s
365
+ )
366
+ );
367
+ selectedMcps = selectedMcps.map((s) => {
368
+ const found = AVAILABLE_MCPS.find(
369
+ (m) => m.displayName.toLowerCase() === s
370
+ );
371
+ return found ? found.name : s;
372
+ });
373
+ if (selectedMcps.length === 0) {
374
+ selectedMcps = [...DEFAULT_MCPS];
375
+ log(" No valid MCPs recognized. Enabling all.\n");
376
+ } else {
377
+ log(` Enabled: ${selectedMcps.join(", ")}
378
+ `);
379
+ }
380
+ }
381
+ log(" Step 3: Configure AI Clients\n");
382
+ const clients = detectClients();
383
+ const configuredClients = [];
384
+ for (const client of clients) {
385
+ if (!client.detected) {
386
+ log(` ${client.name}: not detected, skipping`);
387
+ continue;
388
+ }
389
+ const answer = await ask(` Configure ${client.name}? (Y/n): `);
390
+ if (answer.toLowerCase() === "n") {
391
+ log(` Skipping ${client.name}`);
392
+ continue;
393
+ }
394
+ try {
395
+ if (client.type === "claude-desktop") {
396
+ configureClaudeDesktop(DEFAULT_SERVER_URL, apiKey, selectedMcps);
397
+ log(` ${client.name}: configured`);
398
+ configuredClients.push(client.type);
399
+ } else if (client.type === "claude-code") {
400
+ configureClaudeCode(DEFAULT_SERVER_URL, apiKey, selectedMcps);
401
+ log(` ${client.name}: configured`);
402
+ configuredClients.push(client.type);
403
+ }
404
+ } catch (err) {
405
+ const msg = err instanceof Error ? err.message : String(err);
406
+ log(` ${client.name}: failed \u2014 ${msg}`);
407
+ }
408
+ }
409
+ log("");
410
+ const stdioAnswer = await ask(
411
+ " Do you also need a config snippet for OpenClaw or other stdio clients? (y/N): "
412
+ );
413
+ if (stdioAnswer.toLowerCase() === "y") {
414
+ log("\n Add this to your client's MCP config:\n");
415
+ log(generateStdioSnippet(apiKey));
416
+ log("");
417
+ configuredClients.push("stdio");
418
+ }
419
+ const config = createConfig(apiKey, selectedMcps);
420
+ config.configuredClients = configuredClients;
421
+ writeConfig(config);
422
+ log("");
423
+ log(" Setup complete! Restart your AI clients to see the new tools.");
424
+ log(` Config saved to ~/.cortex-mcp/config.json`);
425
+ log("");
426
+ rl.close();
427
+ }
428
+
429
+ // src/cli/configure.ts
430
+ var VALID_CLIENTS = {
431
+ "claude-desktop": "claude-desktop",
432
+ "claude-code": "claude-code",
433
+ stdio: "stdio"
434
+ };
435
+ async function runConfigure(options) {
436
+ const { key, client } = options;
437
+ if (!isValidApiKey(key)) {
438
+ console.error(
439
+ "Invalid API key format. Must start with 'ctx_'. Get one at https://aidentity.app/settings/keys"
440
+ );
441
+ process.exit(1);
442
+ }
443
+ const clientType = VALID_CLIENTS[client];
444
+ if (!clientType) {
445
+ console.error(
446
+ `Unknown client: ${client}. Valid options: ${Object.keys(VALID_CLIENTS).join(", ")}`
447
+ );
448
+ process.exit(1);
449
+ }
450
+ let selectedMcps;
451
+ if (options.mcps) {
452
+ selectedMcps = options.mcps.split(",").map((s) => s.trim()).filter((s) => MCP_NAMES.includes(s));
453
+ if (selectedMcps.length === 0) {
454
+ console.error(
455
+ `No valid MCPs. Available: ${MCP_NAMES.join(", ")}`
456
+ );
457
+ process.exit(1);
458
+ }
459
+ } else {
460
+ selectedMcps = [...DEFAULT_MCPS];
461
+ }
462
+ try {
463
+ const result = configureClient(
464
+ clientType,
465
+ DEFAULT_SERVER_URL,
466
+ key,
467
+ selectedMcps
468
+ );
469
+ console.log(result);
470
+ } catch (err) {
471
+ const msg = err instanceof Error ? err.message : String(err);
472
+ console.error(`Failed to configure ${client}: ${msg}`);
473
+ process.exit(1);
474
+ }
475
+ const config = createConfig(key, selectedMcps);
476
+ config.configuredClients = [clientType];
477
+ writeConfig(config);
478
+ console.log(`Config saved to ~/.cortex-mcp/config.json`);
479
+ }
480
+
481
+ // src/proxy/stdio-server.ts
482
+ import { Server } from "@modelcontextprotocol/sdk/server/index.js";
483
+ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
484
+ import {
485
+ CallToolRequestSchema,
486
+ ListToolsRequestSchema
487
+ } from "@modelcontextprotocol/sdk/types.js";
488
+
489
+ // src/proxy/http-client.ts
490
+ var CortexHttpClient = class {
491
+ constructor(serverUrl, apiKey, endpoint = "cortex") {
492
+ this.serverUrl = serverUrl;
493
+ this.apiKey = apiKey;
494
+ this.endpoint = endpoint;
495
+ }
496
+ sessionId = null;
497
+ requestId = 0;
498
+ /** Send an initialize request to establish a session */
499
+ async initialize() {
500
+ const response = await this.sendRequest("initialize", {
501
+ protocolVersion: PROTOCOL_VERSION,
502
+ capabilities: {},
503
+ clientInfo: { name: "cortex-mcp-proxy", version: "1.0.0" }
504
+ });
505
+ await this.sendNotification("notifications/initialized", {});
506
+ return response;
507
+ }
508
+ /** List available tools */
509
+ async listTools() {
510
+ return this.sendRequest("tools/list", {});
511
+ }
512
+ /** Call a tool */
513
+ async callTool(name, args) {
514
+ return this.sendRequest("tools/call", { name, arguments: args });
515
+ }
516
+ /** Send a JSON-RPC request and return the response */
517
+ async sendRequest(method, params) {
518
+ const id = String(++this.requestId);
519
+ const body = { jsonrpc: "2.0", method, params, id };
520
+ const headers = {
521
+ "Content-Type": "application/json",
522
+ "x-api-key": this.apiKey,
523
+ "mcp-protocol-version": PROTOCOL_VERSION
524
+ };
525
+ if (this.sessionId) {
526
+ headers["mcp-session-id"] = this.sessionId;
527
+ }
528
+ const url = `${this.serverUrl}/mcp/${this.endpoint}`;
529
+ const response = await fetch(url, {
530
+ method: "POST",
531
+ headers,
532
+ body: JSON.stringify(body)
533
+ });
534
+ const newSessionId = response.headers.get("mcp-session-id");
535
+ if (newSessionId) {
536
+ this.sessionId = newSessionId;
537
+ }
538
+ if (!response.ok) {
539
+ const text = await response.text();
540
+ return {
541
+ jsonrpc: "2.0",
542
+ error: {
543
+ code: -32e3,
544
+ message: this.humanReadableError(response.status, text)
545
+ },
546
+ id
547
+ };
548
+ }
549
+ return await response.json();
550
+ }
551
+ /** Send a JSON-RPC notification (no response expected) */
552
+ async sendNotification(method, params) {
553
+ const body = { jsonrpc: "2.0", method, params };
554
+ const headers = {
555
+ "Content-Type": "application/json",
556
+ "x-api-key": this.apiKey,
557
+ "mcp-protocol-version": PROTOCOL_VERSION
558
+ };
559
+ if (this.sessionId) {
560
+ headers["mcp-session-id"] = this.sessionId;
561
+ }
562
+ const url = `${this.serverUrl}/mcp/${this.endpoint}`;
563
+ try {
564
+ await fetch(url, {
565
+ method: "POST",
566
+ headers,
567
+ body: JSON.stringify(body)
568
+ });
569
+ } catch {
570
+ }
571
+ }
572
+ /** Convert HTTP status codes to user-friendly messages */
573
+ humanReadableError(status, body) {
574
+ switch (status) {
575
+ case 401:
576
+ return "Invalid API key. Check your key at https://aidentity.app/settings/keys";
577
+ case 403:
578
+ return "API key lacks MCP permissions. Create a new key with MCP access.";
579
+ case 404:
580
+ return "MCP endpoint not found. The server may be misconfigured.";
581
+ case 503:
582
+ return "MCP protocol is disabled on the server.";
583
+ default:
584
+ return `Server error (${status}): ${body.slice(0, 200)}`;
585
+ }
586
+ }
587
+ };
588
+
589
+ // src/proxy/stdio-server.ts
590
+ async function startStdioServer(options) {
591
+ const { serverUrl, apiKey, endpoint = "cortex" } = options;
592
+ const cortex = new CortexHttpClient(serverUrl, apiKey, endpoint);
593
+ const server = new Server(
594
+ { name: "cortex-mcp", version: "1.0.0" },
595
+ { capabilities: { tools: { listChanged: false } } }
596
+ );
597
+ server.setRequestHandler(ListToolsRequestSchema, async () => {
598
+ const response = await cortex.listTools();
599
+ if (response.error) {
600
+ throw new Error(response.error.message);
601
+ }
602
+ const result = response.result;
603
+ return { tools: result.tools || [] };
604
+ });
605
+ server.setRequestHandler(CallToolRequestSchema, async (request) => {
606
+ const { name, arguments: args } = request.params;
607
+ const response = await cortex.callTool(name, args ?? {});
608
+ if (response.error) {
609
+ return {
610
+ content: [{ type: "text", text: response.error.message }],
611
+ isError: true
612
+ };
613
+ }
614
+ const result = response.result;
615
+ return result;
616
+ });
617
+ await cortex.initialize();
618
+ const transport = new StdioServerTransport();
619
+ await server.connect(transport);
620
+ }
621
+
622
+ // src/cli/serve.ts
623
+ async function runServe() {
624
+ let apiKey = process.env.CORTEX_API_KEY;
625
+ let serverUrl = DEFAULT_SERVER_URL;
626
+ if (!apiKey) {
627
+ const config = readConfig();
628
+ if (config) {
629
+ apiKey = config.apiKey;
630
+ serverUrl = config.server || DEFAULT_SERVER_URL;
631
+ }
632
+ }
633
+ if (!apiKey) {
634
+ process.stderr.write(
635
+ "No API key found. Set CORTEX_API_KEY env var or run: npx @danainnovations/cortex-mcp setup\n"
636
+ );
637
+ process.exit(1);
638
+ }
639
+ await startStdioServer({ serverUrl, apiKey });
640
+ }
641
+
642
+ // src/cli/status.ts
643
+ function runStatus() {
644
+ const config = readConfig();
645
+ if (!config) {
646
+ console.log("No configuration found. Run: npx @danainnovations/cortex-mcp setup");
647
+ return;
648
+ }
649
+ const maskedKey = config.apiKey.slice(0, 8) + "****" + config.apiKey.slice(-4);
650
+ console.log("");
651
+ console.log(" Cortex MCP Status");
652
+ console.log(" -----------------");
653
+ console.log(` Config: ${getConfigPath()}`);
654
+ console.log(` Server: ${config.server}`);
655
+ console.log(` API Key: ${maskedKey}`);
656
+ console.log("");
657
+ console.log(" Enabled MCPs:");
658
+ for (const mcpName of config.mcps) {
659
+ const mcp = AVAILABLE_MCPS.find((m) => m.name === mcpName);
660
+ const display = mcp ? mcp.displayName : mcpName;
661
+ console.log(` ${display.padEnd(15)} ${config.server}/mcp/${mcpName}`);
662
+ }
663
+ console.log("");
664
+ console.log(" Configured Clients:");
665
+ if (config.configuredClients.length === 0) {
666
+ console.log(" (none)");
667
+ } else {
668
+ for (const client of config.configuredClients) {
669
+ console.log(` ${client}`);
670
+ }
671
+ }
672
+ console.log("");
673
+ }
674
+
675
+ // src/cli/reset.ts
676
+ import { existsSync as existsSync3, unlinkSync, rmdirSync } from "fs";
677
+ function runReset() {
678
+ console.log("");
679
+ console.log(" Resetting Cortex MCP configuration...");
680
+ const desktopReset = resetClaudeDesktop();
681
+ console.log(
682
+ ` Claude Desktop: ${desktopReset ? "entries removed" : "no entries found"}`
683
+ );
684
+ const codeReset = resetClaudeCode();
685
+ console.log(
686
+ ` Claude Code: ${codeReset ? "entries removed" : "no entries found"}`
687
+ );
688
+ const configPath = getConfigPath();
689
+ if (existsSync3(configPath)) {
690
+ unlinkSync(configPath);
691
+ console.log(` Config file: removed`);
692
+ }
693
+ const configDir = getConfigDir();
694
+ try {
695
+ rmdirSync(configDir);
696
+ } catch {
697
+ }
698
+ console.log("");
699
+ console.log(" Done. Restart your AI clients to apply changes.");
700
+ console.log("");
701
+ }
702
+
703
+ // bin/cli.ts
704
+ var program = new Command();
705
+ program.name("cortex-mcp").description(
706
+ "Connect your AI tools to GitHub, Vercel, Supabase & Sonance Brand via Cortex"
707
+ ).version("1.0.0");
708
+ program.command("setup").description("Interactive setup wizard \u2014 configure API key, MCPs, and clients").action(async () => {
709
+ try {
710
+ await runSetup();
711
+ } catch (err) {
712
+ if (err.code === "ERR_USE_AFTER_CLOSE") {
713
+ process.exit(0);
714
+ }
715
+ console.error("Setup failed:", err);
716
+ process.exit(1);
717
+ }
718
+ });
719
+ program.command("configure").description("Non-interactive configuration for a specific client").requiredOption("--key <key>", "Cortex API key (ctx_...)").requiredOption(
720
+ "--client <client>",
721
+ "Client to configure (claude-desktop, claude-code, stdio)"
722
+ ).option(
723
+ "--mcps <mcps>",
724
+ "Comma-separated MCP names (default: all)"
725
+ ).action(async (options) => {
726
+ await runConfigure(options);
727
+ });
728
+ program.command("serve").description(
729
+ "Start stdio MCP proxy server (for OpenClaw and other stdio clients)"
730
+ ).action(async () => {
731
+ await runServe();
732
+ });
733
+ program.command("status").description("Show current Cortex MCP configuration").action(() => {
734
+ runStatus();
735
+ });
736
+ program.command("reset").description("Remove all Cortex MCP entries from AI clients").action(() => {
737
+ runReset();
738
+ });
739
+ program.parse();
740
+ //# sourceMappingURL=cli.js.map