@danainnovations/cortex-mcp 1.0.58 → 1.0.59

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.
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ openBrowser
4
+ } from "./chunk-DIHPZXVU.js";
5
+ export {
6
+ openBrowser
7
+ };
8
+ //# sourceMappingURL=browser-6BYJNEZN.js.map
@@ -41,6 +41,10 @@ function getCursorConfigPath() {
41
41
  const home = getHomeDir();
42
42
  return join(home, ".cursor", "mcp.json");
43
43
  }
44
+ function getCodexConfigPath() {
45
+ const home = getHomeDir();
46
+ return join(home, ".codex", "config.toml");
47
+ }
44
48
 
45
49
  // src/utils/browser.ts
46
50
  function openBrowser(url) {
@@ -55,6 +59,7 @@ export {
55
59
  getHomeDir,
56
60
  getClaudeDesktopConfigPath,
57
61
  getCursorConfigPath,
62
+ getCodexConfigPath,
58
63
  openBrowser
59
64
  };
60
- //# sourceMappingURL=chunk-JWMGLAAN.js.map
65
+ //# sourceMappingURL=chunk-DIHPZXVU.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/utils/browser.ts","../src/utils/platform.ts"],"sourcesContent":["import { exec } from \"node:child_process\";\nimport { getPlatform } from \"./platform.js\";\n\nexport function openBrowser(url: string): Promise<void> {\n return new Promise((resolve) => {\n const platform = getPlatform();\n const cmd =\n platform === \"macos\" ? \"open\" :\n platform === \"windows\" ? \"start\" :\n \"xdg-open\";\n exec(`${cmd} \"${url}\"`, () => resolve());\n });\n}\n","import { homedir, platform } from \"node:os\";\nimport { join } from \"node:path\";\n\n/** Get the user's home directory */\nexport function getHomeDir(): string {\n return homedir();\n}\n\n/** Get the current platform */\nexport function getPlatform(): \"macos\" | \"windows\" | \"linux\" {\n const p = platform();\n if (p === \"darwin\") return \"macos\";\n if (p === \"win32\") return \"windows\";\n return \"linux\";\n}\n\n/**\n * Get the Claude Desktop config file path for the current platform.\n */\nexport function getClaudeDesktopConfigPath(): string {\n const home = getHomeDir();\n const p = getPlatform();\n\n switch (p) {\n case \"macos\":\n return join(\n home,\n \"Library\",\n \"Application Support\",\n \"Claude\",\n \"claude_desktop_config.json\"\n );\n case \"windows\":\n return join(\n process.env.APPDATA || join(home, \"AppData\", \"Roaming\"),\n \"Claude\",\n \"claude_desktop_config.json\"\n );\n case \"linux\":\n return join(home, \".config\", \"Claude\", \"claude_desktop_config.json\");\n }\n}\n\n/**\n * Get the Cursor MCP config file path for the current platform.\n */\nexport function getCursorConfigPath(): string {\n const home = getHomeDir();\n return join(home, \".cursor\", \"mcp.json\");\n}\n"],"mappings":";;;AAAA,SAAS,YAAY;;;ACArB,SAAS,SAAS,gBAAgB;AAClC,SAAS,YAAY;AAGd,SAAS,aAAqB;AACnC,SAAO,QAAQ;AACjB;AAGO,SAAS,cAA6C;AAC3D,QAAM,IAAI,SAAS;AACnB,MAAI,MAAM,SAAU,QAAO;AAC3B,MAAI,MAAM,QAAS,QAAO;AAC1B,SAAO;AACT;AAKO,SAAS,6BAAqC;AACnD,QAAM,OAAO,WAAW;AACxB,QAAM,IAAI,YAAY;AAEtB,UAAQ,GAAG;AAAA,IACT,KAAK;AACH,aAAO;AAAA,QACL;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,MACF;AAAA,IACF,KAAK;AACH,aAAO;AAAA,QACL,QAAQ,IAAI,WAAW,KAAK,MAAM,WAAW,SAAS;AAAA,QACtD;AAAA,QACA;AAAA,MACF;AAAA,IACF,KAAK;AACH,aAAO,KAAK,MAAM,WAAW,UAAU,4BAA4B;AAAA,EACvE;AACF;AAKO,SAAS,sBAA8B;AAC5C,QAAM,OAAO,WAAW;AACxB,SAAO,KAAK,MAAM,WAAW,UAAU;AACzC;;;AD9CO,SAAS,YAAY,KAA4B;AACtD,SAAO,IAAI,QAAQ,CAAC,YAAY;AAC9B,UAAMA,YAAW,YAAY;AAC7B,UAAM,MACJA,cAAa,UAAU,SACvBA,cAAa,YAAY,UACzB;AACF,SAAK,GAAG,GAAG,KAAK,GAAG,KAAK,MAAM,QAAQ,CAAC;AAAA,EACzC,CAAC;AACH;","names":["platform"]}
1
+ {"version":3,"sources":["../src/utils/browser.ts","../src/utils/platform.ts"],"sourcesContent":["import { exec } from \"node:child_process\";\nimport { getPlatform } from \"./platform.js\";\n\nexport function openBrowser(url: string): Promise<void> {\n return new Promise((resolve) => {\n const platform = getPlatform();\n const cmd =\n platform === \"macos\" ? \"open\" :\n platform === \"windows\" ? \"start\" :\n \"xdg-open\";\n exec(`${cmd} \"${url}\"`, () => resolve());\n });\n}\n","import { homedir, platform } from \"node:os\";\nimport { join } from \"node:path\";\n\n/** Get the user's home directory */\nexport function getHomeDir(): string {\n return homedir();\n}\n\n/** Get the current platform */\nexport function getPlatform(): \"macos\" | \"windows\" | \"linux\" {\n const p = platform();\n if (p === \"darwin\") return \"macos\";\n if (p === \"win32\") return \"windows\";\n return \"linux\";\n}\n\n/**\n * Get the Claude Desktop config file path for the current platform.\n */\nexport function getClaudeDesktopConfigPath(): string {\n const home = getHomeDir();\n const p = getPlatform();\n\n switch (p) {\n case \"macos\":\n return join(\n home,\n \"Library\",\n \"Application Support\",\n \"Claude\",\n \"claude_desktop_config.json\"\n );\n case \"windows\":\n return join(\n process.env.APPDATA || join(home, \"AppData\", \"Roaming\"),\n \"Claude\",\n \"claude_desktop_config.json\"\n );\n case \"linux\":\n return join(home, \".config\", \"Claude\", \"claude_desktop_config.json\");\n }\n}\n\n/**\n * Get the Cursor MCP config file path for the current platform.\n */\nexport function getCursorConfigPath(): string {\n const home = getHomeDir();\n return join(home, \".cursor\", \"mcp.json\");\n}\n\n/**\n * Get the OpenAI Codex config file path.\n */\nexport function getCodexConfigPath(): string {\n const home = getHomeDir();\n return join(home, \".codex\", \"config.toml\");\n}\n"],"mappings":";;;AAAA,SAAS,YAAY;;;ACArB,SAAS,SAAS,gBAAgB;AAClC,SAAS,YAAY;AAGd,SAAS,aAAqB;AACnC,SAAO,QAAQ;AACjB;AAGO,SAAS,cAA6C;AAC3D,QAAM,IAAI,SAAS;AACnB,MAAI,MAAM,SAAU,QAAO;AAC3B,MAAI,MAAM,QAAS,QAAO;AAC1B,SAAO;AACT;AAKO,SAAS,6BAAqC;AACnD,QAAM,OAAO,WAAW;AACxB,QAAM,IAAI,YAAY;AAEtB,UAAQ,GAAG;AAAA,IACT,KAAK;AACH,aAAO;AAAA,QACL;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,MACF;AAAA,IACF,KAAK;AACH,aAAO;AAAA,QACL,QAAQ,IAAI,WAAW,KAAK,MAAM,WAAW,SAAS;AAAA,QACtD;AAAA,QACA;AAAA,MACF;AAAA,IACF,KAAK;AACH,aAAO,KAAK,MAAM,WAAW,UAAU,4BAA4B;AAAA,EACvE;AACF;AAKO,SAAS,sBAA8B;AAC5C,QAAM,OAAO,WAAW;AACxB,SAAO,KAAK,MAAM,WAAW,UAAU;AACzC;AAKO,SAAS,qBAA6B;AAC3C,QAAM,OAAO,WAAW;AACxB,SAAO,KAAK,MAAM,UAAU,aAAa;AAC3C;;;ADtDO,SAAS,YAAY,KAA4B;AACtD,SAAO,IAAI,QAAQ,CAAC,YAAY;AAC9B,UAAMA,YAAW,YAAY;AAC7B,UAAM,MACJA,cAAa,UAAU,SACvBA,cAAa,YAAY,UACzB;AACF,SAAK,GAAG,GAAG,KAAK,GAAG,KAAK,MAAM,QAAQ,CAAC;AAAA,EACzC,CAAC;AACH;","names":["platform"]}
package/dist/cli.js CHANGED
@@ -12,10 +12,11 @@ import {
12
12
  } from "./chunk-WDD2YERC.js";
13
13
  import {
14
14
  getClaudeDesktopConfigPath,
15
+ getCodexConfigPath,
15
16
  getCursorConfigPath,
16
17
  getHomeDir,
17
18
  openBrowser
18
- } from "./chunk-JWMGLAAN.js";
19
+ } from "./chunk-DIHPZXVU.js";
19
20
 
20
21
  // bin/cli.ts
21
22
  import { Command } from "commander";
@@ -97,6 +98,14 @@ function detectClients() {
97
98
  configPath: cursorPath,
98
99
  detected: existsSync2(cursorDir)
99
100
  });
101
+ const codexPath = getCodexConfigPath();
102
+ const codexDir = dirname(codexPath);
103
+ clients.push({
104
+ type: "codex",
105
+ name: "Codex",
106
+ configPath: codexPath,
107
+ detected: existsSync2(codexDir)
108
+ });
100
109
  return clients;
101
110
  }
102
111
  function buildHttpEntries(serverUrl, apiKey, mcps) {
@@ -244,6 +253,63 @@ function resetClaudeCode() {
244
253
  }
245
254
  return removed;
246
255
  }
256
+ function removeCortexTomlSections(content) {
257
+ const lines = content.split("\n");
258
+ const result = [];
259
+ let skipping = false;
260
+ for (const line of lines) {
261
+ const trimmed = line.trim();
262
+ if (trimmed.startsWith("[")) {
263
+ skipping = /^\[mcp_servers\.cortex[_-]/.test(trimmed) || trimmed === "[mcp_servers.cortex]";
264
+ }
265
+ if (!skipping) {
266
+ result.push(line);
267
+ }
268
+ }
269
+ return result.join("\n");
270
+ }
271
+ function configureCodex(serverUrl, apiKey, mcps) {
272
+ const configPath = getCodexConfigPath();
273
+ const dir = dirname(configPath);
274
+ if (!existsSync2(dir)) {
275
+ mkdirSync2(dir, { recursive: true });
276
+ }
277
+ let content = "";
278
+ if (existsSync2(configPath)) {
279
+ try {
280
+ content = readFileSync2(configPath, "utf-8");
281
+ } catch {
282
+ }
283
+ }
284
+ content = removeCortexTomlSections(content);
285
+ const sections = [];
286
+ for (const mcp of AVAILABLE_MCPS) {
287
+ if (!mcps.includes(mcp.name)) continue;
288
+ sections.push(`[mcp_servers.${mcp.serverName}]`);
289
+ sections.push(`url = "${serverUrl}/mcp/${mcp.name}"`);
290
+ sections.push(`[mcp_servers.${mcp.serverName}.http_headers]`);
291
+ sections.push(`"x-api-key" = "${apiKey}"`);
292
+ sections.push("");
293
+ }
294
+ const trimmed = content.trimEnd();
295
+ const newContent = trimmed ? trimmed + "\n\n" + sections.join("\n") + "\n" : sections.join("\n") + "\n";
296
+ writeFileSync2(configPath, newContent);
297
+ }
298
+ function resetCodex() {
299
+ const configPath = getCodexConfigPath();
300
+ if (!existsSync2(configPath)) return false;
301
+ try {
302
+ const content = readFileSync2(configPath, "utf-8");
303
+ const cleaned = removeCortexTomlSections(content);
304
+ if (cleaned.length < content.length) {
305
+ writeFileSync2(configPath, cleaned);
306
+ return true;
307
+ }
308
+ return false;
309
+ } catch {
310
+ return false;
311
+ }
312
+ }
247
313
  function configureClient(clientType, serverUrl, apiKey, mcps) {
248
314
  switch (clientType) {
249
315
  case "claude-desktop":
@@ -255,6 +321,9 @@ function configureClient(clientType, serverUrl, apiKey, mcps) {
255
321
  case "cursor":
256
322
  configureCursor(serverUrl, apiKey, mcps);
257
323
  return "Cursor configured";
324
+ case "codex":
325
+ configureCodex(serverUrl, apiKey, mcps);
326
+ return "Codex configured";
258
327
  case "stdio":
259
328
  return "Add this to your client config:\n\n" + generateStdioSnippet(apiKey);
260
329
  }
@@ -814,6 +883,10 @@ async function runSetup(emailHint) {
814
883
  configureCursor(DEFAULT_SERVER_URL, apiKey, selectedMcps);
815
884
  log3(` ${client.name}: configured`);
816
885
  configuredClients.push(client.type);
886
+ } else if (client.type === "codex") {
887
+ configureCodex(DEFAULT_SERVER_URL, apiKey, selectedMcps);
888
+ log3(` ${client.name}: configured`);
889
+ configuredClients.push(client.type);
817
890
  }
818
891
  } catch (err) {
819
892
  const msg = err instanceof Error ? err.message : String(err);
@@ -921,6 +994,8 @@ async function runSetup(emailHint) {
921
994
  configureClaudeCode(DEFAULT_SERVER_URL, newKey, selectedMcps);
922
995
  } else if (clientType === "cursor") {
923
996
  configureCursor(DEFAULT_SERVER_URL, newKey, selectedMcps);
997
+ } else if (clientType === "codex") {
998
+ configureCodex(DEFAULT_SERVER_URL, newKey, selectedMcps);
924
999
  }
925
1000
  log3(` ${clientType}: updated`);
926
1001
  } catch {
@@ -945,6 +1020,7 @@ var VALID_CLIENTS = {
945
1020
  "claude-desktop": "claude-desktop",
946
1021
  "claude-code": "claude-code",
947
1022
  cursor: "cursor",
1023
+ codex: "codex",
948
1024
  stdio: "stdio"
949
1025
  };
950
1026
  async function runConfigure(options) {
@@ -1408,6 +1484,10 @@ function runReset() {
1408
1484
  console.log(
1409
1485
  ` Cursor: ${cursorReset ? "entries removed" : "no entries found"}`
1410
1486
  );
1487
+ const codexReset = resetCodex();
1488
+ console.log(
1489
+ ` Codex: ${codexReset ? "entries removed" : "no entries found"}`
1490
+ );
1411
1491
  const configPath = getConfigPath();
1412
1492
  if (existsSync4(configPath)) {
1413
1493
  unlinkSync2(configPath);
@@ -1594,7 +1674,7 @@ async function runDisconnect(provider) {
1594
1674
  // bin/cli.ts
1595
1675
  var program = new Command();
1596
1676
  program.name("cortex-mcp").description(
1597
- "Connect your AI tools to Asana, GitHub, Microsoft 365, Monday.com, Salesforce, Vercel & Supabase via Cortex"
1677
+ "Connect your AI tools to Asana, GitHub, Microsoft 365, Monday.com, Salesforce, Vercel & Supabase via Cortex \u2014 supports Claude, Cursor, Codex & more"
1598
1678
  ).version("1.0.0");
1599
1679
  program.command("setup").description("Interactive setup wizard \u2014 configure MCPs and AI clients").option(
1600
1680
  "--email <email>",
@@ -1612,7 +1692,7 @@ program.command("setup").description("Interactive setup wizard \u2014 configure
1612
1692
  });
1613
1693
  program.command("configure").description("Non-interactive configuration for a specific client").option("--key <key>", "Cortex API key (uses built-in default if not provided)").requiredOption(
1614
1694
  "--client <client>",
1615
- "Client to configure (claude-desktop, claude-code, cursor, stdio)"
1695
+ "Client to configure (claude-desktop, claude-code, cursor, codex, stdio)"
1616
1696
  ).option(
1617
1697
  "--mcps <mcps>",
1618
1698
  "Comma-separated MCP names (default: all)"
@@ -1679,7 +1759,7 @@ program.command("disconnect <provider>").description("Remove your personal OAuth
1679
1759
  });
1680
1760
  program.command("connect-mobile").description("Connect Cortex to Claude on mobile \u2014 opens setup page in browser").action(async () => {
1681
1761
  const { DEFAULT_SERVER_URL: DEFAULT_SERVER_URL2 } = await import("./constants-YJ6WYI46.js");
1682
- const { openBrowser: openBrowser2 } = await import("./browser-LPEABS5F.js");
1762
+ const { openBrowser: openBrowser2 } = await import("./browser-6BYJNEZN.js");
1683
1763
  const url = `${DEFAULT_SERVER_URL2}/connect`;
1684
1764
  console.log("\nOpening Cortex connect page...");
1685
1765
  console.log(` ${url}
package/dist/cli.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../bin/cli.ts","../src/cli/setup.ts","../src/config/storage.ts","../src/config/clients.ts","../src/auth/credentials.ts","../src/cli/login.ts","../src/cli/connect.ts","../src/cli/configure.ts","../src/proxy/stdio-server.ts","../src/proxy/http-client.ts","../src/cli/serve.ts","../src/cli/status.ts","../src/cli/reset.ts","../src/cli/logout.ts","../src/cli/whoami.ts","../src/cli/connections.ts","../src/cli/disconnect.ts"],"sourcesContent":["import { Command } from \"commander\";\nimport { runSetup } from \"../src/cli/setup.js\";\nimport { runConfigure } from \"../src/cli/configure.js\";\nimport { runServe } from \"../src/cli/serve.js\";\nimport { runStatus } from \"../src/cli/status.js\";\nimport { runReset } from \"../src/cli/reset.js\";\nimport { runLogin } from \"../src/cli/login.js\";\nimport { runLogout } from \"../src/cli/logout.js\";\nimport { runWhoami } from \"../src/cli/whoami.js\";\nimport { runConnect } from \"../src/cli/connect.js\";\nimport { runConnections } from \"../src/cli/connections.js\";\nimport { runDisconnect } from \"../src/cli/disconnect.js\";\n\nconst program = new Command();\n\nprogram\n .name(\"cortex-mcp\")\n .description(\n \"Connect your AI tools to Asana, GitHub, Microsoft 365, Monday.com, Salesforce, Vercel & Supabase via Cortex\"\n )\n .version(\"1.0.0\");\n\nprogram\n .command(\"setup\")\n .description(\"Interactive setup wizard — configure MCPs and AI clients\")\n .option(\n \"--email <email>\",\n \"Company email (use if your Okta email differs from your directory email)\"\n )\n .action(async (options: { email?: string }) => {\n try {\n await runSetup(options.email);\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code === \"ERR_USE_AFTER_CLOSE\") {\n // readline closed — user pressed Ctrl+C\n process.exit(0);\n }\n console.error(\"Setup failed:\", err);\n process.exit(1);\n }\n });\n\nprogram\n .command(\"configure\")\n .description(\"Non-interactive configuration for a specific client\")\n .option(\"--key <key>\", \"Cortex API key (uses built-in default if not provided)\")\n .requiredOption(\n \"--client <client>\",\n \"Client to configure (claude-desktop, claude-code, cursor, stdio)\"\n )\n .option(\n \"--mcps <mcps>\",\n \"Comma-separated MCP names (default: all)\",\n )\n .action(async (options) => {\n await runConfigure(options);\n });\n\nprogram\n .command(\"serve\")\n .description(\n \"Start stdio MCP proxy server (for OpenClaw and other stdio clients)\"\n )\n .action(async () => {\n await runServe();\n });\n\nprogram\n .command(\"status\")\n .description(\"Show current Cortex MCP configuration\")\n .action(() => {\n runStatus();\n });\n\nprogram\n .command(\"reset\")\n .description(\"Remove all Cortex MCP entries from AI clients\")\n .action(() => {\n runReset();\n });\n\nprogram\n .command(\"login\")\n .description(\"Sign in with your company Okta SSO account\")\n .option(\n \"--email <email>\",\n \"Company email (use if your Okta email differs from your directory email)\"\n )\n .action(async (options: { email?: string }) => {\n try {\n await runLogin(options.email);\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code === \"ERR_USE_AFTER_CLOSE\") {\n process.exit(0);\n }\n console.error(\"Login failed:\", err);\n process.exit(1);\n }\n });\n\nprogram\n .command(\"logout\")\n .description(\"Sign out and remove stored credentials\")\n .action(() => {\n runLogout();\n });\n\nprogram\n .command(\"whoami\")\n .description(\"Show current authenticated user\")\n .action(() => {\n runWhoami();\n });\n\nprogram\n .command(\"connect <provider>\")\n .description(\"Connect your personal account to an MCP service (e.g., asana)\")\n .action(async (provider: string) => {\n try {\n await runConnect(provider);\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code === \"ERR_USE_AFTER_CLOSE\") {\n process.exit(0);\n }\n console.error(\"Connect failed:\", err);\n process.exit(1);\n }\n });\n\nprogram\n .command(\"connections\")\n .description(\"List your OAuth connections to MCP services\")\n .action(async () => {\n try {\n await runConnections();\n } catch (err) {\n console.error(\"Failed:\", err);\n process.exit(1);\n }\n });\n\nprogram\n .command(\"disconnect <provider>\")\n .description(\"Remove your personal OAuth connection to an MCP service\")\n .action(async (provider: string) => {\n try {\n await runDisconnect(provider);\n } catch (err) {\n console.error(\"Disconnect failed:\", err);\n process.exit(1);\n }\n });\n\nprogram\n .command(\"connect-mobile\")\n .description(\"Connect Cortex to Claude on mobile — opens setup page in browser\")\n .action(async () => {\n const { DEFAULT_SERVER_URL } = await import(\"../src/constants.js\");\n const { openBrowser } = await import(\"../src/utils/browser.js\");\n const url = `${DEFAULT_SERVER_URL}/connect`;\n console.log(\"\\nOpening Cortex connect page...\");\n console.log(` ${url}\\n`);\n console.log(\"Follow the steps to connect Cortex to your Claude account.\");\n console.log(\"Once connected, tools will be available on web, desktop, and mobile.\\n\");\n await openBrowser(url);\n });\n\nprogram.parse();\n","import * as readline from \"node:readline\";\nimport {\n AVAILABLE_MCPS,\n DEFAULT_MCPS,\n DEFAULT_SERVER_URL,\n} from \"../constants.js\";\nimport { createConfig, writeConfig } from \"../config/storage.js\";\nimport {\n configureClaudeCode,\n configureClaudeDesktop,\n configureCursor,\n detectClients,\n generateStdioSnippet,\n} from \"../config/clients.js\";\nimport type { ClientType } from \"../config/types.js\";\nimport {\n deleteCredentials,\n getEffectiveApiKey,\n readCredentials,\n writeCredentials,\n} from \"../auth/credentials.js\";\nimport {\n loginWithSSO,\n showConnectionsAndAutoConnect,\n type LoginResult,\n} from \"./login.js\";\n\nconst rl = readline.createInterface({\n input: process.stdin,\n output: process.stderr,\n});\n\nfunction ask(question: string): Promise<string> {\n return new Promise((resolve) => {\n rl.question(question, (answer) => resolve(answer.trim()));\n });\n}\n\nfunction log(msg: string): void {\n process.stderr.write(msg + \"\\n\");\n}\n\ntype ApiKeyValidationResult = \"valid\" | \"invalid\" | \"unreachable\";\n\nasync function validateApiKey(\n apiKey: string,\n serverUrl: string,\n): Promise<ApiKeyValidationResult> {\n try {\n const resp = await fetch(`${serverUrl}/api/v1/oauth/connections`, {\n headers: { \"x-api-key\": apiKey },\n });\n\n if (resp.ok) {\n return \"valid\";\n }\n\n if (resp.status === 401 || resp.status === 403) {\n return \"invalid\";\n }\n\n return \"unreachable\";\n } catch {\n return \"unreachable\";\n }\n}\n\n/**\n * Interactive setup wizard. Guides the user through:\n * 1. Selecting MCPs\n * 2. Detecting and configuring AI clients\n * 3. Signing in via Okta SSO\n * 4. Connecting personal accounts (Asana)\n */\nexport async function runSetup(emailHint?: string): Promise<void> {\n let apiKey = getEffectiveApiKey();\n let creds = readCredentials();\n\n log(\"\");\n log(\" Cortex MCP Setup\");\n log(\" Connect your AI tools to Asana, GitHub, Monday.com, Salesforce, M365, Vercel & Supabase\");\n log(\"\");\n\n // ─────────────────────────────────────────\n // Step 1: Select MCPs\n // ─────────────────────────────────────────\n log(\" Step 1: Select MCPs\");\n log(\" Available MCPs (all enabled by default):\\n\");\n\n for (const mcp of AVAILABLE_MCPS) {\n log(` - ${mcp.displayName.padEnd(15)} ${mcp.description}`);\n }\n log(\"\");\n\n const mcpInput = await ask(\n ` MCPs to enable (comma-separated, or press Enter for all): `\n );\n\n let selectedMcps: string[];\n if (!mcpInput) {\n selectedMcps = [...DEFAULT_MCPS];\n log(\" All MCPs enabled.\\n\");\n } else {\n selectedMcps = mcpInput\n .split(\",\")\n .map((s) => s.trim().toLowerCase())\n .filter((s) =>\n AVAILABLE_MCPS.some(\n (m) => m.name === s || m.displayName.toLowerCase() === s\n )\n );\n\n // Map display names to internal names\n selectedMcps = selectedMcps.map((s) => {\n const found = AVAILABLE_MCPS.find(\n (m) => m.displayName.toLowerCase() === s\n );\n return found ? found.name : s;\n });\n\n if (selectedMcps.length === 0) {\n selectedMcps = [...DEFAULT_MCPS];\n log(\" No valid MCPs recognized. Enabling all.\\n\");\n } else {\n log(` Enabled: ${selectedMcps.join(\", \")}\\n`);\n }\n }\n\n // ─────────────────────────────────────────\n // Step 2: Detect and configure clients\n // ─────────────────────────────────────────\n log(\" Step 2: Configure AI Clients\\n\");\n\n const clients = detectClients();\n const configuredClients: ClientType[] = [];\n\n for (const client of clients) {\n if (!client.detected) {\n log(` ${client.name}: not detected, skipping`);\n continue;\n }\n\n const answer = await ask(` Configure ${client.name}? (Y/n): `);\n if (answer.toLowerCase() === \"n\") {\n log(` Skipping ${client.name}`);\n continue;\n }\n\n try {\n if (client.type === \"claude-desktop\") {\n configureClaudeDesktop(DEFAULT_SERVER_URL, apiKey, selectedMcps);\n log(` ${client.name}: configured`);\n configuredClients.push(client.type);\n } else if (client.type === \"claude-code\") {\n configureClaudeCode(DEFAULT_SERVER_URL, apiKey, selectedMcps);\n log(` ${client.name}: configured`);\n configuredClients.push(client.type);\n } else if (client.type === \"cursor\") {\n configureCursor(DEFAULT_SERVER_URL, apiKey, selectedMcps);\n log(` ${client.name}: configured`);\n configuredClients.push(client.type);\n }\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n log(` ${client.name}: failed \\u2014 ${msg}`);\n }\n }\n\n // Ask about stdio\n log(\"\");\n const stdioAnswer = await ask(\n \" Do you also need a config snippet for OpenClaw or other stdio clients? (y/N): \"\n );\n if (stdioAnswer.toLowerCase() === \"y\") {\n log(\"\\n Add this to your client's MCP config:\\n\");\n log(generateStdioSnippet(apiKey));\n log(\"\");\n configuredClients.push(\"stdio\");\n }\n\n // Save config (will update again after login with personal key)\n const config = createConfig(apiKey, selectedMcps);\n config.configuredClients = configuredClients;\n writeConfig(config);\n\n // ─────────────────────────────────────────\n // Step 3: Sign In\n // ─────────────────────────────────────────\n log(\"\");\n log(\" Step 3: Sign In\\n\");\n\n let shouldLogin = !creds;\n if (creds) {\n log(` Already signed in as ${creds.name || creds.email}`);\n\n const validation = await validateApiKey(creds.apiKey, DEFAULT_SERVER_URL);\n if (validation === \"invalid\") {\n log(\" Saved session is no longer valid. Re-authenticating...\");\n deleteCredentials();\n creds = null;\n shouldLogin = true;\n } else {\n apiKey = creds.apiKey;\n\n if (validation === \"unreachable\") {\n log(\" Warning: Could not validate saved session. Continuing with existing credentials.\");\n }\n }\n }\n\n if (shouldLogin) {\n log(\" Sign in with your company Okta SSO account.\");\n log(\"\");\n\n // Close readline before SSO (it uses stdin; browser flow doesn't need it)\n rl.close();\n\n let result: LoginResult = await loginWithSSO(DEFAULT_SERVER_URL, emailHint);\n\n // Handle email hint retry if AD verification failed\n if (result.status === \"needs_hint\") {\n let hintEmail: string;\n\n if (emailHint) {\n // --email was already provided; use it directly for retry\n hintEmail = emailHint;\n } else {\n log(\"\");\n log(\n ` Your SSO email (${result.ssoEmail}) was not found in the employee directory.`\n );\n log(\n \" This can happen if your Okta account uses a different email\"\n + \" than your company directory.\"\n );\n log(\"\");\n\n const hintRl = readline.createInterface({\n input: process.stdin,\n output: process.stderr,\n });\n\n hintEmail = await new Promise<string>((resolve) => {\n hintRl.question(\" Enter your company email address: \", (a) =>\n resolve(a.trim())\n );\n });\n hintRl.close();\n\n if (!hintEmail || !hintEmail.includes(\"@\")) {\n log(\" Invalid email. Run 'cortex-mcp login --email you@company.com' to try again.\");\n process.exit(1);\n }\n }\n\n log(\"\");\n log(\" Retrying with your company email. You'll need to complete SSO again.\");\n log(\"\");\n\n result = await loginWithSSO(DEFAULT_SERVER_URL, hintEmail);\n\n if (result.status === \"needs_hint\") {\n log(\"\");\n log(\" The provided email was also not found in the employee directory.\");\n log(\" Please verify your email and contact IT if the issue persists.\");\n process.exit(1);\n }\n }\n\n if (result.status !== \"success\") {\n log(\" Login failed. Run 'cortex-mcp login' to try again.\");\n process.exit(1);\n }\n\n const { apiKey: newKey, email, name } = result;\n apiKey = newKey;\n\n // Save credentials\n writeCredentials({\n apiKey: newKey,\n email,\n name,\n authenticatedAt: new Date().toISOString(),\n });\n\n log(` Authenticated as ${name || email}${name ? ` (${email})` : \"\"}`);\n log(\" Personal API key saved.\");\n\n // Update client configs with new personal key\n if (configuredClients.length > 0) {\n log(\"\");\n log(\" Updating clients with personal key:\");\n for (const clientType of configuredClients) {\n try {\n if (clientType === \"claude-desktop\") {\n configureClaudeDesktop(DEFAULT_SERVER_URL, newKey, selectedMcps);\n } else if (clientType === \"claude-code\") {\n configureClaudeCode(DEFAULT_SERVER_URL, newKey, selectedMcps);\n } else if (clientType === \"cursor\") {\n configureCursor(DEFAULT_SERVER_URL, newKey, selectedMcps);\n }\n log(` ${clientType}: updated`);\n } catch {\n log(` ${clientType}: failed to update`);\n }\n }\n }\n\n // Update saved config with personal key\n config.apiKey = newKey;\n writeConfig(config);\n\n creds = readCredentials();\n }\n\n // ─────────────────────────────────────────\n // Step 4: Connect Accounts\n // ─────────────────────────────────────────\n log(\"\");\n log(\" Step 4: Connect Accounts (optional)\\n\");\n\n await showConnectionsAndAutoConnect(apiKey, DEFAULT_SERVER_URL);\n\n log(\" Setup complete! Restart your AI clients to see the new tools.\");\n log(` Config saved to ~/.cortex-mcp/config.json`);\n log(\"\");\n}\n","import { existsSync, mkdirSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport { CONFIG_DIR_NAME, CONFIG_FILE_NAME, DEFAULT_SERVER_URL } from \"../constants.js\";\nimport { getHomeDir } from \"../utils/platform.js\";\nimport type { CortexMcpConfig } from \"./types.js\";\n\n/** Get the config directory path */\nexport function getConfigDir(): string {\n return join(getHomeDir(), CONFIG_DIR_NAME);\n}\n\n/** Get the config file path */\nexport function getConfigPath(): string {\n return join(getConfigDir(), CONFIG_FILE_NAME);\n}\n\n/** Read the current config, or return null if none exists */\nexport function readConfig(): CortexMcpConfig | null {\n const path = getConfigPath();\n if (!existsSync(path)) return null;\n\n try {\n const raw = readFileSync(path, \"utf-8\");\n return JSON.parse(raw) as CortexMcpConfig;\n } catch {\n return null;\n }\n}\n\n/** Write config to disk (creates directory with 700 permissions, file with 600) */\nexport function writeConfig(config: CortexMcpConfig): void {\n const dir = getConfigDir();\n if (!existsSync(dir)) {\n mkdirSync(dir, { recursive: true, mode: 0o700 });\n }\n\n const path = getConfigPath();\n writeFileSync(path, JSON.stringify(config, null, 2) + \"\\n\", {\n mode: 0o600,\n });\n}\n\n/** Create a default config with the given API key and MCPs */\nexport function createConfig(\n apiKey: string,\n mcps: string[]\n): CortexMcpConfig {\n return {\n version: 1,\n server: DEFAULT_SERVER_URL,\n apiKey,\n mcps,\n configuredClients: [],\n };\n}\n","import { existsSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { dirname } from \"node:path\";\nimport { mkdirSync } from \"node:fs\";\nimport { execSync } from \"node:child_process\";\nimport { AVAILABLE_MCPS } from \"../constants.js\";\nimport {\n getClaudeDesktopConfigPath,\n getCursorConfigPath,\n} from \"../utils/platform.js\";\nimport type { ClientType, DetectedClient, HttpMcpEntry } from \"./types.js\";\n\n/**\n * Detect which AI clients are installed on this machine.\n */\nexport function detectClients(): DetectedClient[] {\n const clients: DetectedClient[] = [];\n\n // Claude Desktop\n const desktopPath = getClaudeDesktopConfigPath();\n const desktopDir = dirname(desktopPath);\n clients.push({\n type: \"claude-desktop\",\n name: \"Claude Desktop\",\n configPath: desktopPath,\n detected: existsSync(desktopDir),\n });\n\n // Claude Code\n let claudeCodeDetected = false;\n try {\n execSync(\"which claude\", { stdio: \"pipe\" });\n claudeCodeDetected = true;\n } catch {\n // claude CLI not in PATH\n }\n clients.push({\n type: \"claude-code\",\n name: \"Claude Code\",\n configPath: null,\n detected: claudeCodeDetected,\n });\n\n // Cursor\n const cursorPath = getCursorConfigPath();\n const cursorDir = dirname(cursorPath);\n clients.push({\n type: \"cursor\",\n name: \"Cursor\",\n configPath: cursorPath,\n detected: existsSync(cursorDir),\n });\n\n return clients;\n}\n\n/**\n * Build per-MCP HTTP entries for a given server URL and API key.\n */\nexport function buildHttpEntries(\n serverUrl: string,\n apiKey: string,\n mcps: string[]\n): Record<string, HttpMcpEntry> {\n const entries: Record<string, HttpMcpEntry> = {};\n\n for (const mcp of AVAILABLE_MCPS) {\n if (!mcps.includes(mcp.name)) continue;\n entries[mcp.serverName] = {\n url: `${serverUrl}/mcp/${mcp.name}`,\n headers: { \"x-api-key\": apiKey },\n };\n }\n\n return entries;\n}\n\n/**\n * Configure Claude Desktop by merging a stdio proxy entry into its config file.\n * Uses command/args/env format (Claude Desktop does not support HTTP url/headers).\n * Preserves existing non-Cortex entries.\n */\nexport function configureClaudeDesktop(\n _serverUrl: string,\n apiKey: string,\n _mcps: string[]\n): void {\n const configPath = getClaudeDesktopConfigPath();\n const dir = dirname(configPath);\n\n // Ensure directory exists\n if (!existsSync(dir)) {\n mkdirSync(dir, { recursive: true });\n }\n\n // Read existing config or start fresh\n let config: Record<string, unknown> = {};\n if (existsSync(configPath)) {\n try {\n config = JSON.parse(readFileSync(configPath, \"utf-8\"));\n } catch {\n // Corrupted file — start fresh\n }\n }\n\n // Ensure mcpServers key exists\n if (!config.mcpServers || typeof config.mcpServers !== \"object\") {\n config.mcpServers = {};\n }\n\n const servers = config.mcpServers as Record<string, unknown>;\n\n // Remove existing cortex-* and cortex entries\n for (const key of Object.keys(servers)) {\n if (key.startsWith(\"cortex-\") || key === \"cortex\") {\n delete servers[key];\n }\n }\n\n // Add stdio proxy entry (Claude Desktop only supports command/args)\n // API key is read from ~/.cortex-mcp/credentials.json at runtime by the serve command,\n // so we don't bake it into the env (avoids stale key issues on re-login).\n servers[\"cortex\"] = {\n command: \"npx\",\n args: [\"-y\", \"@danainnovations/cortex-mcp@latest\", \"serve\"],\n };\n\n writeFileSync(configPath, JSON.stringify(config, null, 2) + \"\\n\");\n}\n\n/**\n * Configure Claude Code by running `claude mcp add` commands.\n */\nexport function configureClaudeCode(\n serverUrl: string,\n apiKey: string,\n mcps: string[]\n): void {\n for (const mcp of AVAILABLE_MCPS) {\n if (!mcps.includes(mcp.name)) continue;\n\n const url = `${serverUrl}/mcp/${mcp.name}`;\n\n // Remove existing entry first (ignore errors if it doesn't exist)\n try {\n execSync(`claude mcp remove ${mcp.serverName}`, { stdio: \"pipe\" });\n } catch {\n // Entry didn't exist — fine\n }\n\n execSync(\n `claude mcp add --transport http ${mcp.serverName} ${url} -H \"x-api-key: ${apiKey}\"`,\n { stdio: \"pipe\" }\n );\n }\n}\n\n/**\n * Configure Cursor by writing HTTP MCP entries to its config file.\n * Cursor supports HTTP transport natively.\n */\nexport function configureCursor(\n serverUrl: string,\n apiKey: string,\n mcps: string[]\n): void {\n const configPath = getCursorConfigPath();\n const dir = dirname(configPath);\n\n if (!existsSync(dir)) {\n mkdirSync(dir, { recursive: true });\n }\n\n let config: Record<string, unknown> = {};\n if (existsSync(configPath)) {\n try {\n config = JSON.parse(readFileSync(configPath, \"utf-8\"));\n } catch {\n // Corrupted file — start fresh\n }\n }\n\n if (!config.mcpServers || typeof config.mcpServers !== \"object\") {\n config.mcpServers = {};\n }\n\n const servers = config.mcpServers as Record<string, unknown>;\n\n // Remove existing cortex-* entries\n for (const key of Object.keys(servers)) {\n if (key.startsWith(\"cortex-\")) {\n delete servers[key];\n }\n }\n\n // Add new HTTP entries\n const entries = buildHttpEntries(serverUrl, apiKey, mcps);\n Object.assign(servers, entries);\n\n writeFileSync(configPath, JSON.stringify(config, null, 2) + \"\\n\");\n}\n\n/**\n * Generate a stdio config snippet for clients that need it (OpenClaw, etc.)\n */\nexport function generateStdioSnippet(_apiKey: string): string {\n const config = {\n mcpServers: {\n cortex: {\n command: \"npx\",\n args: [\"-y\", \"@danainnovations/cortex-mcp@latest\", \"serve\"],\n },\n },\n };\n return JSON.stringify(config, null, 2);\n}\n\n/**\n * Remove all cortex-* MCP entries from Claude Desktop config.\n */\nexport function resetClaudeDesktop(): boolean {\n const configPath = getClaudeDesktopConfigPath();\n if (!existsSync(configPath)) return false;\n\n try {\n const config = JSON.parse(readFileSync(configPath, \"utf-8\"));\n if (!config.mcpServers) return false;\n\n const servers = config.mcpServers as Record<string, unknown>;\n let removed = false;\n for (const key of Object.keys(servers)) {\n if (key.startsWith(\"cortex-\") || key === \"cortex\") {\n delete servers[key];\n removed = true;\n }\n }\n\n if (removed) {\n writeFileSync(configPath, JSON.stringify(config, null, 2) + \"\\n\");\n }\n return removed;\n } catch {\n return false;\n }\n}\n\n/**\n * Remove cortex MCP entries from Cursor config.\n */\nexport function resetCursor(): boolean {\n const configPath = getCursorConfigPath();\n if (!existsSync(configPath)) return false;\n\n try {\n const config = JSON.parse(readFileSync(configPath, \"utf-8\"));\n if (!config.mcpServers) return false;\n\n const servers = config.mcpServers as Record<string, unknown>;\n let removed = false;\n for (const key of Object.keys(servers)) {\n if (key.startsWith(\"cortex-\") || key === \"cortex\") {\n delete servers[key];\n removed = true;\n }\n }\n\n if (removed) {\n writeFileSync(configPath, JSON.stringify(config, null, 2) + \"\\n\");\n }\n return removed;\n } catch {\n return false;\n }\n}\n\n/**\n * Remove cortex MCP entries from Claude Code.\n */\nexport function resetClaudeCode(): boolean {\n let removed = false;\n for (const mcp of AVAILABLE_MCPS) {\n try {\n execSync(`claude mcp remove ${mcp.serverName}`, { stdio: \"pipe\" });\n removed = true;\n } catch {\n // Entry didn't exist\n }\n }\n return removed;\n}\n\n/**\n * Configure a specific client type.\n */\nexport function configureClient(\n clientType: ClientType,\n serverUrl: string,\n apiKey: string,\n mcps: string[]\n): string {\n switch (clientType) {\n case \"claude-desktop\":\n configureClaudeDesktop(serverUrl, apiKey, mcps);\n return \"Claude Desktop configured\";\n case \"claude-code\":\n configureClaudeCode(serverUrl, apiKey, mcps);\n return \"Claude Code configured\";\n case \"cursor\":\n configureCursor(serverUrl, apiKey, mcps);\n return \"Cursor configured\";\n case \"stdio\":\n return (\n \"Add this to your client config:\\n\\n\" +\n generateStdioSnippet(apiKey)\n );\n }\n}\n","import { existsSync, mkdirSync, readFileSync, unlinkSync, writeFileSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport { CONFIG_DIR_NAME, CREDENTIALS_FILE_NAME, DEFAULT_API_KEY } from \"../constants.js\";\nimport { readConfig } from \"../config/storage.js\";\nimport { getHomeDir } from \"../utils/platform.js\";\n\n/** Stored credentials from a successful login */\nexport interface CortexCredentials {\n apiKey: string;\n email: string;\n name?: string;\n authenticatedAt: string; // ISO 8601\n}\n\n/** Get the credentials file path (~/.cortex-mcp/credentials.json) */\nexport function getCredentialsPath(): string {\n return join(getHomeDir(), CONFIG_DIR_NAME, CREDENTIALS_FILE_NAME);\n}\n\n/** Read stored credentials, or return null if not logged in */\nexport function readCredentials(): CortexCredentials | null {\n const path = getCredentialsPath();\n if (!existsSync(path)) return null;\n\n try {\n const raw = readFileSync(path, \"utf-8\");\n return JSON.parse(raw) as CortexCredentials;\n } catch {\n return null;\n }\n}\n\n/** Write credentials to disk (creates directory with 700, file with 600 permissions) */\nexport function writeCredentials(creds: CortexCredentials): void {\n const dir = join(getHomeDir(), CONFIG_DIR_NAME);\n if (!existsSync(dir)) {\n mkdirSync(dir, { recursive: true, mode: 0o700 });\n }\n\n const path = getCredentialsPath();\n writeFileSync(path, JSON.stringify(creds, null, 2) + \"\\n\", {\n mode: 0o600,\n });\n}\n\n/** Delete stored credentials */\nexport function deleteCredentials(): void {\n const path = getCredentialsPath();\n if (existsSync(path)) {\n unlinkSync(path);\n }\n}\n\n/**\n * Get the effective API key to use.\n * Priority: CORTEX_API_KEY env var > stored credentials > config file > default shared key\n */\nexport function getEffectiveApiKey(): string {\n // 1. Environment variable (highest priority)\n const envKey = process.env.CORTEX_API_KEY;\n if (envKey) return envKey;\n\n // 2. Personal credentials from login\n const creds = readCredentials();\n if (creds?.apiKey) return creds.apiKey;\n\n // 3. Config file (set during setup)\n const config = readConfig();\n if (config?.apiKey) return config.apiKey;\n\n // 4. Shared default key (fallback)\n return DEFAULT_API_KEY;\n}\n","import * as readline from \"node:readline\";\nimport { AVAILABLE_MCPS, DEFAULT_SERVER_URL } from \"../constants.js\";\nimport { readConfig, writeConfig } from \"../config/storage.js\";\nimport { configureClient } from \"../config/clients.js\";\nimport { readCredentials, writeCredentials } from \"../auth/credentials.js\";\nimport { openBrowser } from \"../utils/browser.js\";\nimport { connectProvider } from \"./connect.js\";\n\nfunction log(msg: string): void {\n process.stderr.write(msg + \"\\n\");\n}\n\nfunction sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n\nexport type LoginResult =\n | { status: \"success\"; apiKey: string; email: string; name?: string }\n | { status: \"needs_hint\"; ssoEmail: string }\n | { status: \"failed\" };\n\n/**\n * Core SSO login flow: initiate -> browser -> poll.\n * Reusable by both the `login` command and the setup wizard.\n *\n * Optionally accepts an emailHint for users whose Okta email\n * differs from their company directory email.\n */\nexport async function loginWithSSO(\n serverUrl: string,\n emailHint?: string,\n): Promise<LoginResult> {\n // Initiate auth flow\n let sessionId: string;\n let authUrl: string;\n let expiresIn: number;\n\n try {\n const body: Record<string, string> = {};\n if (emailHint) {\n body.email_hint = emailHint;\n }\n\n const resp = await fetch(`${serverUrl}/api/v1/auth/employee/initiate`, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify(body),\n });\n\n if (!resp.ok) {\n log(` Error: Failed to start authentication (HTTP ${resp.status})`);\n return { status: \"failed\" };\n }\n\n const data = (await resp.json()) as {\n session_id: string;\n auth_url: string;\n expires_in: number;\n };\n sessionId = data.session_id;\n authUrl = data.auth_url;\n expiresIn = data.expires_in;\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n log(` Error: Could not reach Cortex server at ${serverUrl}`);\n log(` ${msg}`);\n return { status: \"failed\" };\n }\n\n // Open browser\n log(\" Opening browser for Okta SSO login...\");\n await openBrowser(authUrl);\n log(\" If the browser didn't open, visit:\");\n log(` ${authUrl}`);\n log(\"\");\n\n // Poll for completion\n const deadline = Date.now() + expiresIn * 1000;\n process.stderr.write(\" Waiting for authentication\");\n\n while (Date.now() < deadline) {\n await sleep(3000);\n\n try {\n const resp = await fetch(\n `${serverUrl}/api/v1/auth/employee/poll/${sessionId}`\n );\n const result = (await resp.json()) as {\n status: string;\n api_key?: string;\n employee_name?: string;\n employee_email?: string;\n sso_email?: string;\n user_info?: { email?: string; name?: string };\n error_message?: string;\n };\n\n if (result.status === \"completed\") {\n process.stderr.write(\"\\n\\n\");\n\n const email =\n result.employee_email || result.user_info?.email || \"unknown\";\n const name = result.employee_name || result.user_info?.name || \"\";\n const apiKey = result.api_key || \"\";\n\n return { status: \"success\", apiKey, email, name: name || undefined };\n }\n\n if (result.status === \"expired\") {\n process.stderr.write(\"\\n\");\n log(\" Authentication session expired. Please try again.\");\n return { status: \"failed\" };\n }\n\n if (result.status === \"error\") {\n process.stderr.write(\"\\n\");\n\n // If AD verification failed and no hint was provided, signal for retry\n if (\n result.error_message === \"not_verified_employee\" &&\n !emailHint\n ) {\n return {\n status: \"needs_hint\",\n ssoEmail: result.sso_email || \"unknown\",\n };\n }\n\n log(\n ` Authentication failed: ${result.error_message || \"unknown error\"}`\n );\n return { status: \"failed\" };\n }\n\n // Still pending\n process.stderr.write(\".\");\n } catch {\n process.stderr.write(\"!\");\n }\n }\n\n process.stderr.write(\"\\n\");\n log(\" Timeout waiting for authentication. Please try again.\");\n return { status: \"failed\" };\n}\n\n/**\n * Show MCP connection status and auto-connect personal MCPs (e.g., Asana).\n */\nexport async function showConnectionsAndAutoConnect(\n apiKey: string,\n serverUrl: string,\n): Promise<void> {\n // Fetch existing connections\n let existingConnections: Array<{\n mcp_name: string;\n account_email: string | null;\n is_company_default: boolean;\n }> = [];\n\n try {\n const resp = await fetch(`${serverUrl}/api/v1/oauth/connections`, {\n headers: { \"x-api-key\": apiKey },\n });\n if (resp.ok) {\n const data = (await resp.json()) as {\n connections: typeof existingConnections;\n };\n existingConnections = data.connections || [];\n } else {\n log(\n ` Warning: Could not fetch current MCP connections (HTTP ${resp.status}).`\n );\n if (resp.status === 401 || resp.status === 403) {\n log(\" Warning: Authentication may be expired. Run 'cortex-mcp login' to refresh.\");\n }\n }\n } catch {\n log(\" Warning: Could not fetch current MCP connections due to a network error.\");\n }\n\n // Show MCP connections table\n log(\"\");\n log(\" MCP Connections\");\n log(\" \" + \"\\u2500\".repeat(45));\n\n const personalMcps: Array<{ name: string; displayName: string }> = [];\n\n for (const mcp of AVAILABLE_MCPS) {\n const conn = existingConnections.find((c) => c.mcp_name === mcp.name);\n\n if (mcp.authMode === \"company\") {\n log(` ${mcp.displayName.padEnd(15)} company default`);\n } else {\n // Personal auth required\n if (conn && !conn.is_company_default && conn.account_email) {\n log(` ${mcp.displayName.padEnd(15)} ${conn.account_email}`);\n } else {\n log(\n ` ${mcp.displayName.padEnd(15)} not connected (personal account required)`\n );\n personalMcps.push({ name: mcp.name, displayName: mcp.displayName });\n }\n }\n }\n\n log(\"\");\n\n // Auto-connect unconnected personal MCPs\n if (personalMcps.length === 0) {\n log(\" All accounts connected!\");\n log(\"\");\n return;\n }\n\n log(\" The following MCPs require a personal account to access your data.\");\n log(\" Skip any you don't have an account for — you can always connect later.\\n\");\n\n const rl = readline.createInterface({\n input: process.stdin,\n output: process.stderr,\n });\n\n const ask = (question: string): Promise<string> =>\n new Promise((resolve) => {\n rl.question(question, (answer) => resolve(answer.trim().toLowerCase()));\n });\n\n for (const mcp of personalMcps) {\n const answer = await ask(\n ` Connect ${mcp.displayName}? (Y/n/s to skip all): `\n );\n\n if (answer === \"s\") {\n log(\" Skipping remaining account connections.\");\n log(\" You can connect anytime with: cortex-mcp connect <provider>\\n\");\n break;\n }\n\n if (answer === \"n\") {\n log(` Skipped. Connect later with: cortex-mcp connect ${mcp.name}`);\n log(\"\");\n continue;\n }\n\n // Y or Enter — proceed with OAuth\n log(\"\");\n const success = await connectProvider(\n mcp.name,\n mcp.displayName,\n apiKey,\n serverUrl,\n \"installUrl\" in mcp ? (mcp.installUrl as string) : undefined,\n );\n\n if (!success) {\n log(\n ` You can connect later with: cortex-mcp connect ${mcp.name}`\n );\n }\n log(\"\");\n }\n\n rl.close();\n}\n\n/**\n * Prompt the user for their company email when Okta email doesn't match AD.\n */\nasync function promptForEmailHint(ssoEmail: string): Promise<string | null> {\n log(\"\");\n log(` Your SSO email (${ssoEmail}) was not found in the employee directory.`);\n log(\n \" This can happen if your Okta account uses a different email than your company directory.\"\n );\n log(\"\");\n\n const rl = readline.createInterface({\n input: process.stdin,\n output: process.stderr,\n });\n\n const answer = await new Promise<string>((resolve) => {\n rl.question(\" Enter your company email address: \", (a) =>\n resolve(a.trim())\n );\n });\n rl.close();\n\n if (!answer || !answer.includes(\"@\")) {\n log(\" Invalid email. Run 'cortex-mcp login --email you@company.com' to try again.\");\n return null;\n }\n\n return answer;\n}\n\n/**\n * Log in via Okta SSO to get a personal API key.\n * Opens the browser, polls for completion, stores credentials,\n * auto-reconfigures any previously set up AI clients,\n * and prompts to connect personal MCP accounts (e.g., Asana).\n *\n * @param emailHint Optional company email (via --email flag) when Okta email differs from AD\n */\nexport async function runLogin(emailHint?: string): Promise<void> {\n // 1. Check if already logged in\n const existing = readCredentials();\n if (existing) {\n log(\"\");\n log(` Already logged in as ${existing.name || existing.email}`);\n log(\" Run 'cortex-mcp logout' first to switch accounts.\");\n log(\"\");\n return;\n }\n\n const config = readConfig();\n const serverUrl = config?.server || DEFAULT_SERVER_URL;\n\n log(\"\");\n log(\" Cortex MCP Login\");\n log(\" Sign in with your company Okta SSO account\");\n log(\"\");\n\n // 2. Run SSO flow\n let result = await loginWithSSO(serverUrl, emailHint);\n\n // 3. Handle email hint retry if AD verification failed\n if (result.status === \"needs_hint\") {\n let hintEmail: string | null;\n\n if (emailHint) {\n // --email was already provided but SSO email still didn't match\n // (this shouldn't happen since hint is passed on first try, but handle it)\n hintEmail = emailHint;\n } else {\n hintEmail = await promptForEmailHint(result.ssoEmail);\n }\n\n if (!hintEmail) {\n process.exit(1);\n }\n\n log(\"\");\n log(\" Retrying with your company email. You'll need to complete SSO again.\");\n log(\"\");\n\n result = await loginWithSSO(serverUrl, hintEmail);\n\n if (result.status === \"needs_hint\") {\n log(\"\");\n log(\" The provided email was also not found in the employee directory.\");\n log(\" Please verify your email and contact IT if the issue persists.\");\n process.exit(1);\n }\n }\n\n if (result.status !== \"success\") {\n process.exit(1);\n }\n\n const { apiKey, email, name } = result;\n\n // 3. Save credentials\n writeCredentials({\n apiKey,\n email,\n name,\n authenticatedAt: new Date().toISOString(),\n });\n\n log(` Authenticated as ${name || email}${name ? ` (${email})` : \"\"}`);\n log(\" Personal API key saved.\");\n\n // 4. Auto-reconfigure existing clients and update saved config\n const existingConfig = readConfig();\n if (existingConfig) {\n // Always update the stored API key\n existingConfig.apiKey = apiKey;\n\n // Re-configure clients if any were previously set up\n if (existingConfig.configuredClients?.length > 0) {\n log(\"\");\n log(\" Updating configured clients:\");\n\n for (const clientType of existingConfig.configuredClients) {\n try {\n configureClient(\n clientType,\n existingConfig.server || DEFAULT_SERVER_URL,\n apiKey,\n existingConfig.mcps\n );\n log(` ${clientType}: updated`);\n } catch {\n log(` ${clientType}: failed to update`);\n }\n }\n }\n\n writeConfig(existingConfig);\n }\n\n // 5. Show MCP connection status and auto-connect personal MCPs\n await showConnectionsAndAutoConnect(apiKey, serverUrl);\n\n log(\" Done! Restart your AI clients to apply.\");\n log(\"\");\n}\n","import { AVAILABLE_MCPS, DEFAULT_SERVER_URL } from \"../constants.js\";\nimport { readConfig } from \"../config/storage.js\";\nimport { readCredentials } from \"../auth/credentials.js\";\nimport { openBrowser } from \"../utils/browser.js\";\n\nfunction log(msg: string): void {\n process.stderr.write(msg + \"\\n\");\n}\n\nfunction sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n\nfunction waitForEnter(): Promise<void> {\n return new Promise((resolve) => {\n process.stdin.setRawMode?.(false);\n process.stdin.resume();\n process.stdin.once(\"data\", () => {\n process.stdin.pause();\n resolve();\n });\n });\n}\n\n/**\n * Core OAuth connect flow: initiate -> browser -> poll.\n * Reusable by both the `connect` command and the post-login auto-connect.\n *\n * Returns true on success, false on failure/timeout.\n */\nexport async function connectProvider(\n providerName: string,\n displayName: string,\n apiKey: string,\n serverUrl: string,\n installUrl?: string,\n): Promise<boolean> {\n // 1. Initiate OAuth flow\n let sessionId: string;\n let authUrl: string;\n let expiresIn: number;\n\n try {\n const resp = await fetch(\n `${serverUrl}/api/v1/oauth/connect/${providerName}/initiate`,\n {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n \"x-api-key\": apiKey,\n },\n }\n );\n\n if (!resp.ok) {\n if (resp.status === 401) {\n log(\" Error: Your session has expired. Run 'cortex-mcp login' to re-authenticate.\");\n return false;\n }\n\n const err = (await resp.json().catch(() => ({}))) as { detail?: string };\n log(` Error: ${err.detail || `HTTP ${resp.status}`}`);\n return false;\n }\n\n const data = (await resp.json()) as {\n session_id: string;\n authorization_url: string;\n expires_in: number;\n };\n sessionId = data.session_id;\n authUrl = data.authorization_url;\n expiresIn = data.expires_in;\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n log(` Error: Could not reach Cortex server at ${serverUrl}`);\n log(` ${msg}`);\n return false;\n }\n\n // 2. App installation (Monday.com requires install before authorize)\n if (installUrl) {\n log(` First, install the ${displayName} app on your account...`);\n await openBrowser(installUrl);\n log(\" If the browser didn't open, visit:\");\n log(` ${installUrl}`);\n log(\"\");\n log(\" Press Enter once the app is installed...\");\n await waitForEnter();\n log(\"\");\n }\n\n // 3. Open browser\n log(` Opening browser for ${displayName} authorization...`);\n await openBrowser(authUrl);\n log(\" If the browser didn't open, visit:\");\n log(` ${authUrl}`);\n log(\"\");\n\n // 4. Poll for completion\n const deadline = Date.now() + expiresIn * 1000;\n process.stderr.write(\" Waiting for authorization\");\n\n while (Date.now() < deadline) {\n await sleep(3000);\n\n try {\n const resp = await fetch(\n `${serverUrl}/api/v1/oauth/connect/poll/${sessionId}`,\n {\n headers: {\n \"x-api-key\": apiKey,\n },\n }\n );\n const result = (await resp.json()) as {\n status: string;\n account_email?: string;\n account_name?: string;\n error_message?: string;\n };\n\n if (result.status === \"completed\") {\n process.stderr.write(\"\\n\\n\");\n const who = result.account_email || \"unknown\";\n log(` Connected as ${who}`);\n log(` ${displayName} tools will now use your personal account.`);\n log(\"\");\n return true;\n }\n\n if (result.status === \"expired\") {\n process.stderr.write(\"\\n\");\n log(\" Authorization session expired. Please try again.\");\n return false;\n }\n\n if (result.status === \"error\") {\n process.stderr.write(\"\\n\");\n log(\n ` Connection failed: ${result.error_message || \"unknown error\"}`\n );\n return false;\n }\n\n // Still pending\n process.stderr.write(\".\");\n } catch {\n process.stderr.write(\"!\");\n }\n }\n\n process.stderr.write(\"\\n\");\n log(\" Timeout waiting for authorization. Please try again.\");\n return false;\n}\n\n/**\n * Connect a personal OAuth account (e.g., Asana) via browser-based flow.\n * CLI command handler — validates credentials and delegates to connectProvider().\n */\nexport async function runConnect(provider: string): Promise<void> {\n // 1. Verify user is logged in\n const creds = readCredentials();\n if (!creds) {\n log(\"\");\n log(\" You must be logged in first.\");\n log(\" Run: cortex-mcp login\");\n log(\"\");\n process.exit(1);\n }\n\n // 2. Validate provider\n const mcp = AVAILABLE_MCPS.find(\n (m) => m.name === provider || m.displayName.toLowerCase() === provider.toLowerCase()\n );\n if (!mcp) {\n log(\"\");\n log(` Unknown provider: ${provider}`);\n log(` Available: ${AVAILABLE_MCPS.map((m) => m.name).join(\", \")}`);\n log(\"\");\n process.exit(1);\n }\n\n const config = readConfig();\n const serverUrl = config?.server || DEFAULT_SERVER_URL;\n\n log(\"\");\n log(` Cortex MCP — Connect ${mcp.displayName}`);\n log(` Link your personal ${mcp.displayName} account`);\n log(\"\");\n\n const success = await connectProvider(\n mcp.name,\n mcp.displayName,\n creds.apiKey,\n serverUrl,\n \"installUrl\" in mcp ? (mcp.installUrl as string) : undefined,\n );\n\n if (!success) {\n process.exit(1);\n }\n}\n","import { DEFAULT_MCPS, DEFAULT_SERVER_URL, MCP_NAMES } from \"../constants.js\";\nimport { getEffectiveApiKey } from \"../auth/credentials.js\";\nimport { createConfig, writeConfig } from \"../config/storage.js\";\nimport { configureClient } from \"../config/clients.js\";\nimport type { ClientType } from \"../config/types.js\";\n\ninterface ConfigureOptions {\n key?: string;\n mcps?: string;\n client: string;\n}\n\nconst VALID_CLIENTS: Record<string, ClientType> = {\n \"claude-desktop\": \"claude-desktop\",\n \"claude-code\": \"claude-code\",\n cursor: \"cursor\",\n stdio: \"stdio\",\n};\n\n/**\n * Non-interactive configure command.\n * Writes config to a specific client.\n */\nexport async function runConfigure(options: ConfigureOptions): Promise<void> {\n const key = options.key || getEffectiveApiKey();\n const { client } = options;\n\n // Validate client\n const clientType = VALID_CLIENTS[client];\n if (!clientType) {\n console.error(\n `Unknown client: ${client}. Valid options: ${Object.keys(VALID_CLIENTS).join(\", \")}`\n );\n process.exit(1);\n }\n\n // Parse MCPs\n let selectedMcps: string[];\n if (options.mcps) {\n selectedMcps = options.mcps\n .split(\",\")\n .map((s) => s.trim())\n .filter((s) => MCP_NAMES.includes(s));\n\n if (selectedMcps.length === 0) {\n console.error(\n `No valid MCPs. Available: ${MCP_NAMES.join(\", \")}`\n );\n process.exit(1);\n }\n } else {\n selectedMcps = [...DEFAULT_MCPS];\n }\n\n // Configure\n try {\n const result = configureClient(\n clientType,\n DEFAULT_SERVER_URL,\n key,\n selectedMcps\n );\n console.log(result);\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n console.error(`Failed to configure ${client}: ${msg}`);\n process.exit(1);\n }\n\n // Save config\n const config = createConfig(key, selectedMcps);\n config.configuredClients = [clientType];\n writeConfig(config);\n\n console.log(`Config saved to ~/.cortex-mcp/config.json`);\n}\n","import { readFileSync, statSync } from \"node:fs\";\nimport { Server } from \"@modelcontextprotocol/sdk/server/index.js\";\nimport { StdioServerTransport } from \"@modelcontextprotocol/sdk/server/stdio.js\";\nimport {\n CallToolRequestSchema,\n ListToolsRequestSchema,\n} from \"@modelcontextprotocol/sdk/types.js\";\nimport { CortexHttpClient } from \"./http-client.js\";\n\ninterface StdioServerOptions {\n serverUrl: string;\n apiKey: string;\n /** Use \"cortex\" for composite endpoint, or a specific MCP name */\n endpoint?: string;\n}\n\n/** Tools that support local file_path → upload interception */\nconst UPLOAD_TOOLS = new Set([\"upload_file\", \"upload_file_to_sharepoint\"]);\n\n/** Max file size for inline base64 upload via JSON-RPC (3MB).\n * 3MB raw → 4MB base64 → safely within Vercel's ~4.5MB body limit. */\nconst INLINE_UPLOAD_MAX = 3 * 1024 * 1024;\n\n/**\n * Override upload tool schemas so the LLM only sees `file_path` (not `content`).\n * This forces the LLM to pass a local file path, which the proxy handles locally\n * — no base64 encoding by the LLM, no truncation, no corruption.\n */\nfunction overrideUploadToolSchema(\n tool: Record<string, unknown>\n): Record<string, unknown> {\n const name = tool.name as string;\n const baseName = name.includes(\"__\") ? name.split(\"__\").pop()! : name;\n\n if (baseName === \"upload_file\") {\n return {\n ...tool,\n description:\n \"Upload a local file to the user's OneDrive. \" +\n \"Provide the absolute local file path — the file is read \" +\n \"and uploaded automatically. Works with any file size.\",\n inputSchema: {\n type: \"object\",\n required: [\"file_path\", \"path\"],\n properties: {\n file_path: {\n type: \"string\",\n description:\n \"Absolute path to the local file to upload \" +\n \"(e.g. '/Users/name/Documents/report.xlsx')\",\n },\n path: {\n type: \"string\",\n description:\n \"Destination path in OneDrive \" +\n \"(e.g. 'Documents/report.xlsx')\",\n },\n content_type: {\n type: \"string\",\n description: \"MIME type. Defaults to 'application/octet-stream'\",\n },\n },\n },\n };\n }\n\n if (baseName === \"upload_file_to_sharepoint\") {\n return {\n ...tool,\n description:\n \"Upload a local file to a SharePoint document library. \" +\n \"Provide the absolute local file path — the file is read \" +\n \"and uploaded automatically.\",\n inputSchema: {\n type: \"object\",\n required: [\"file_path\", \"site_id\", \"path\"],\n properties: {\n file_path: {\n type: \"string\",\n description: \"Absolute path to the local file to upload\",\n },\n site_id: {\n type: \"string\",\n description: \"SharePoint site ID\",\n },\n path: {\n type: \"string\",\n description:\n \"Destination path in the site drive \" +\n \"(e.g. 'Shared Documents/report.pdf')\",\n },\n content_type: {\n type: \"string\",\n description: \"MIME type. Defaults to 'application/octet-stream'\",\n },\n },\n },\n };\n }\n\n return tool;\n}\n\n/**\n * Handle a file upload tool call locally by reading the file from disk.\n *\n * - Small files (≤3MB): base64-encode and forward as `content` param\n * - Large files (>3MB): get an upload session URL from backend, then\n * relay 2.5MB chunks through the backend's `upload_file_chunk` tool\n * (the backend has unrestricted internet; the proxy may be sandboxed)\n */\nasync function handleLocalFileUpload(\n cortex: CortexHttpClient,\n toolName: string,\n args: Record<string, unknown>\n): Promise<{ content: Array<{ type: string; text: string }>; isError: boolean }> {\n const filePath = args.file_path as string;\n\n // Validate file exists\n let fileSize: number;\n try {\n fileSize = statSync(filePath as string).size;\n } catch {\n return {\n content: [{ type: \"text\", text: JSON.stringify({\n success: false,\n error: `File not found: ${filePath}`,\n }) }],\n isError: true,\n };\n }\n\n if (fileSize <= INLINE_UPLOAD_MAX) {\n // Small file: read, base64-encode, and forward via normal JSON-RPC\n const fileBuffer = readFileSync(filePath);\n const base64Content = fileBuffer.toString(\"base64\");\n\n const forwardArgs: Record<string, unknown> = { ...args, content: base64Content };\n delete forwardArgs.file_path;\n\n console.error(\n `[cortex-mcp] ${toolName}: reading local file (${(fileSize / 1024).toFixed(1)}KB), forwarding as base64`\n );\n\n const response = await cortex.callTool(toolName, forwardArgs);\n\n if (response.error) {\n return {\n content: [{ type: \"text\", text: response.error.message }],\n isError: true,\n };\n }\n\n return response.result as {\n content: Array<{ type: string; text: string }>;\n isError: boolean;\n };\n }\n\n // Large file: use upload session to upload directly to Microsoft Graph\n console.error(\n `[cortex-mcp] ${toolName}: large file (${(fileSize / 1024 / 1024).toFixed(1)}MB), using upload session`\n );\n\n // Step 1: Get pre-authenticated upload URL from backend\n // Preserve composite prefix (e.g. \"m365__\") so the backend routes correctly\n const prefix = toolName.includes(\"__\") ? toolName.split(\"__\")[0] + \"__\" : \"\";\n const sessionResponse = await cortex.callTool(`${prefix}create_upload_session`, {\n path: args.path,\n });\n\n if (sessionResponse.error) {\n return {\n content: [{ type: \"text\", text: sessionResponse.error.message }],\n isError: true,\n };\n }\n\n const sessionResult = sessionResponse.result as {\n content: Array<{ type: string; text: string }>;\n };\n\n let sessionData: { uploadUrl?: string };\n try {\n sessionData = JSON.parse(sessionResult.content[0].text);\n } catch {\n return {\n content: [{ type: \"text\", text: JSON.stringify({\n success: false,\n error: \"Failed to parse upload session response from backend\",\n }) }],\n isError: true,\n };\n }\n\n const uploadUrl = sessionData.uploadUrl;\n if (!uploadUrl) {\n return {\n content: [{ type: \"text\", text: JSON.stringify({\n success: false,\n error: \"Backend did not return an uploadUrl\",\n }) }],\n isError: true,\n };\n }\n\n // Step 2: Upload file in chunks through the Cortex backend.\n // We relay via the backend (which has unrestricted internet) instead of\n // uploading directly to Graph — the proxy may be in a sandboxed VM that\n // blocks outbound connections to SharePoint/Microsoft Graph.\n const fileBuffer = readFileSync(filePath);\n const chunkSize = 2.5 * 1024 * 1024; // 2.5MB → ~3.33MB base64 → within Vercel 4.5MB limit\n const total = fileBuffer.length;\n let driveItem: Record<string, unknown> = {};\n\n for (let start = 0; start < total; start += chunkSize) {\n const end = Math.min(start + chunkSize, total);\n const chunk = fileBuffer.subarray(start, end);\n const chunkBase64 = Buffer.from(chunk).toString(\"base64\");\n\n console.error(\n `[cortex-mcp] Uploading chunk ${start}-${end - 1}/${total} via backend relay`\n );\n\n const chunkResponse = await cortex.callTool(`${prefix}upload_file_chunk`, {\n upload_url: uploadUrl,\n chunk: chunkBase64,\n range_start: start,\n range_end: end - 1,\n total_size: total,\n });\n\n if (chunkResponse.error) {\n return {\n content: [{ type: \"text\", text: chunkResponse.error.message }],\n isError: true,\n };\n }\n\n const chunkResult = chunkResponse.result as {\n content: Array<{ type: string; text: string }>;\n };\n\n let chunkData: Record<string, unknown>;\n try {\n chunkData = JSON.parse(chunkResult.content[0].text) as Record<string, unknown>;\n } catch {\n return {\n content: [{ type: \"text\", text: JSON.stringify({\n success: false,\n error: \"Failed to parse chunk upload response from backend\",\n }) }],\n isError: true,\n };\n }\n\n if (!chunkData.success) {\n return {\n content: [{ type: \"text\", text: JSON.stringify(chunkData) }],\n isError: true,\n };\n }\n\n // Final chunk (200/201) contains the DriveItem\n if (chunkData.status === 200 || chunkData.status === 201) {\n driveItem = (chunkData.data as Record<string, unknown>) ?? {};\n }\n }\n\n return {\n content: [{ type: \"text\", text: JSON.stringify({\n success: true,\n file: driveItem,\n message: `Uploaded '${args.path}' (${(fileSize / 1024 / 1024).toFixed(1)}MB) via upload session`,\n }) }],\n isError: false,\n };\n}\n\n/**\n * Start a stdio MCP server that proxies all requests to the hosted Cortex server.\n * This is used by clients that only support stdio transport (e.g., OpenClaw).\n */\nexport async function startStdioServer(\n options: StdioServerOptions\n): Promise<void> {\n const { serverUrl, apiKey, endpoint = \"cortex\" } = options;\n\n const cortex = new CortexHttpClient(serverUrl, apiKey, endpoint);\n\n const server = new Server(\n { name: \"cortex-mcp\", version: \"1.0.0\" },\n { capabilities: { tools: { listChanged: false } } }\n );\n\n // Lazy initialization — runs on first request, not at startup\n let initialized = false;\n\n async function ensureInitialized(): Promise<void> {\n if (initialized) return;\n try {\n console.error(\"[cortex-mcp] Initializing backend session...\");\n await cortex.initialize();\n console.error(\"[cortex-mcp] Backend session established.\");\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n console.error(`[cortex-mcp] Backend initialization failed: ${msg}`);\n // Continue anyway — tools/list and tools/call may still work without a session\n }\n initialized = true;\n }\n\n // Forward tools/list to Cortex\n server.setRequestHandler(ListToolsRequestSchema, async () => {\n await ensureInitialized();\n const response = await cortex.listTools();\n\n if (response.error) {\n throw new Error(response.error.message);\n }\n\n const result = response.result as { tools: Record<string, unknown>[] };\n const tools = (result.tools || []).map(overrideUploadToolSchema);\n return { tools };\n });\n\n // Forward tools/call to Cortex (with local file upload interception)\n server.setRequestHandler(CallToolRequestSchema, async (request) => {\n await ensureInitialized();\n const { name, arguments: args } = request.params;\n const typedArgs = (args ?? {}) as Record<string, unknown>;\n\n // Intercept upload tools with file_path — handle locally\n // Composite endpoint prefixes tool names with \"{mcp}__\", so match on suffix\n const baseName = name.includes(\"__\") ? name.split(\"__\").pop()! : name;\n if (UPLOAD_TOOLS.has(baseName) && typedArgs.file_path) {\n return handleLocalFileUpload(cortex, name, typedArgs);\n }\n\n const response = await cortex.callTool(name, typedArgs);\n\n if (response.error) {\n return {\n content: [{ type: \"text\" as const, text: response.error.message }],\n isError: true,\n };\n }\n\n const result = response.result as {\n content: Array<{ type: string; text: string }>;\n isError: boolean;\n };\n\n return result;\n });\n\n // Connect to stdio transport immediately — do NOT block on backend init\n console.error(\"[cortex-mcp] Starting stdio server...\");\n const transport = new StdioServerTransport();\n await server.connect(transport);\n console.error(\"[cortex-mcp] Stdio server connected.\");\n}\n","import { PROTOCOL_VERSION } from \"../constants.js\";\n\n/** JSON-RPC 2.0 request */\ninterface JsonRpcRequest {\n jsonrpc: \"2.0\";\n method: string;\n params?: Record<string, unknown>;\n id: string | number;\n}\n\n/** JSON-RPC 2.0 response */\ninterface JsonRpcResponse {\n jsonrpc: \"2.0\";\n result?: unknown;\n error?: { code: number; message: string };\n id: string | number | null;\n}\n\n/**\n * HTTP client that forwards JSON-RPC 2.0 requests to the Cortex server.\n */\nexport class CortexHttpClient {\n private sessionId: string | null = null;\n private requestId = 0;\n\n constructor(\n private serverUrl: string,\n private apiKey: string,\n private endpoint: string = \"cortex\"\n ) {}\n\n /** Send an initialize request to establish a session */\n async initialize(): Promise<JsonRpcResponse> {\n const response = await this.sendRequest(\"initialize\", {\n protocolVersion: PROTOCOL_VERSION,\n capabilities: {},\n clientInfo: { name: \"cortex-mcp-proxy\", version: \"1.0.0\" },\n });\n\n // Send initialized notification (no id = notification, no response expected)\n await this.sendNotification(\"notifications/initialized\", {});\n\n return response;\n }\n\n /** List available tools */\n async listTools(): Promise<JsonRpcResponse> {\n return this.sendRequest(\"tools/list\", {});\n }\n\n /** Call a tool */\n async callTool(\n name: string,\n args: Record<string, unknown>\n ): Promise<JsonRpcResponse> {\n return this.sendRequest(\"tools/call\", { name, arguments: args });\n }\n\n /** Send a JSON-RPC request and return the response */\n private async sendRequest(\n method: string,\n params: Record<string, unknown>\n ): Promise<JsonRpcResponse> {\n const id = String(++this.requestId);\n const body: JsonRpcRequest = { jsonrpc: \"2.0\", method, params, id };\n\n const headers: Record<string, string> = {\n \"Content-Type\": \"application/json\",\n \"x-api-key\": this.apiKey,\n \"mcp-protocol-version\": PROTOCOL_VERSION,\n \"x-cortex-client\": \"cortex-mcp-stdio\",\n };\n\n if (this.sessionId) {\n headers[\"mcp-session-id\"] = this.sessionId;\n }\n\n const url = `${this.serverUrl}/mcp/${this.endpoint}`;\n const response = await fetch(url, {\n method: \"POST\",\n headers,\n body: JSON.stringify(body),\n signal: AbortSignal.timeout(60_000),\n });\n\n // Capture session ID from initialize\n const newSessionId = response.headers.get(\"mcp-session-id\");\n if (newSessionId) {\n this.sessionId = newSessionId;\n }\n\n if (!response.ok) {\n const text = await response.text();\n return {\n jsonrpc: \"2.0\",\n error: {\n code: -32000,\n message: this.humanReadableError(response.status, text),\n },\n id,\n };\n }\n\n return (await response.json()) as JsonRpcResponse;\n }\n\n /** Send a JSON-RPC notification (no response expected) */\n private async sendNotification(\n method: string,\n params: Record<string, unknown>\n ): Promise<void> {\n const body = { jsonrpc: \"2.0\", method, params };\n\n const headers: Record<string, string> = {\n \"Content-Type\": \"application/json\",\n \"x-api-key\": this.apiKey,\n \"mcp-protocol-version\": PROTOCOL_VERSION,\n \"x-cortex-client\": \"cortex-mcp-stdio\",\n };\n\n if (this.sessionId) {\n headers[\"mcp-session-id\"] = this.sessionId;\n }\n\n const url = `${this.serverUrl}/mcp/${this.endpoint}`;\n\n try {\n await fetch(url, {\n method: \"POST\",\n headers,\n body: JSON.stringify(body),\n signal: AbortSignal.timeout(10_000),\n });\n } catch {\n // Notifications are fire-and-forget\n }\n }\n\n /** Convert HTTP status codes to user-friendly messages */\n private humanReadableError(status: number, body: string): string {\n switch (status) {\n case 401:\n return \"Invalid API key. Check your key at https://aidentity.app/settings/keys\";\n case 403:\n return \"API key lacks MCP permissions. Create a new key with MCP access.\";\n case 404:\n return \"MCP endpoint not found. The server may be misconfigured.\";\n case 503:\n return \"MCP protocol is disabled on the server.\";\n default:\n return `Server error (${status}): ${body.slice(0, 200)}`;\n }\n }\n}\n","import { DEFAULT_API_KEY, DEFAULT_SERVER_URL } from \"../constants.js\";\nimport { readConfig } from \"../config/storage.js\";\nimport { startStdioServer } from \"../proxy/stdio-server.js\";\nimport { getEffectiveApiKey } from \"../auth/credentials.js\";\n\n/**\n * Start the stdio proxy server.\n * Reads API key from CORTEX_API_KEY env var or ~/.cortex-mcp/config.json.\n */\nexport async function runServe(): Promise<void> {\n // Resolve API key: env var > credentials > config file > default\n const config = readConfig();\n const serverUrl = config?.server || DEFAULT_SERVER_URL;\n const apiKey = getEffectiveApiKey();\n\n if (apiKey === DEFAULT_API_KEY) {\n process.stderr.write(\n \"Warning: Using shared API key. Personal MCPs (M365, Slack, etc.) \" +\n \"will not have access to your account.\\n\" +\n \"Run: npx @danainnovations/cortex-mcp@latest login\\n\\n\"\n );\n }\n\n // Start the stdio server (this blocks until the client disconnects)\n await startStdioServer({ serverUrl, apiKey });\n}\n","import { AVAILABLE_MCPS } from \"../constants.js\";\nimport { getConfigPath, readConfig } from \"../config/storage.js\";\nimport { readCredentials } from \"../auth/credentials.js\";\n\n/**\n * Show current Cortex MCP configuration.\n */\nexport function runStatus(): void {\n const config = readConfig();\n\n if (!config) {\n console.log(\"No configuration found. Run: npx @danainnovations/cortex-mcp setup\");\n return;\n }\n\n const maskedKey =\n config.apiKey.slice(0, 8) + \"****\" + config.apiKey.slice(-4);\n\n const creds = readCredentials();\n\n console.log(\"\");\n console.log(\" Cortex MCP Status\");\n console.log(\" -----------------\");\n\n if (creds) {\n console.log(` User: ${creds.name || creds.email}`);\n console.log(` Email: ${creds.email}`);\n } else {\n console.log(\" User: not logged in (using shared key)\");\n }\n\n console.log(` Config: ${getConfigPath()}`);\n console.log(` Server: ${config.server}`);\n console.log(` API Key: ${maskedKey}`);\n console.log(\"\");\n console.log(\" Enabled MCPs:\");\n\n for (const mcpName of config.mcps) {\n const mcp = AVAILABLE_MCPS.find((m) => m.name === mcpName);\n const display = mcp ? mcp.displayName : mcpName;\n console.log(` ${display.padEnd(15)} ${config.server}/mcp/${mcpName}`);\n }\n\n console.log(\"\");\n console.log(\" Configured Clients:\");\n\n if (config.configuredClients.length === 0) {\n console.log(\" (none)\");\n } else {\n for (const client of config.configuredClients) {\n console.log(` ${client}`);\n }\n }\n\n console.log(\"\");\n}\n","import { existsSync, unlinkSync, rmdirSync } from \"node:fs\";\nimport { resetClaudeDesktop, resetClaudeCode, resetCursor } from \"../config/clients.js\";\nimport { getConfigDir, getConfigPath } from \"../config/storage.js\";\n\n/**\n * Remove all Cortex MCP entries from configured clients and delete local config.\n */\nexport function runReset(): void {\n console.log(\"\");\n console.log(\" Resetting Cortex MCP configuration...\");\n\n // Reset Claude Desktop\n const desktopReset = resetClaudeDesktop();\n console.log(\n ` Claude Desktop: ${desktopReset ? \"entries removed\" : \"no entries found\"}`\n );\n\n // Reset Claude Code\n const codeReset = resetClaudeCode();\n console.log(\n ` Claude Code: ${codeReset ? \"entries removed\" : \"no entries found\"}`\n );\n\n // Reset Cursor\n const cursorReset = resetCursor();\n console.log(\n ` Cursor: ${cursorReset ? \"entries removed\" : \"no entries found\"}`\n );\n\n // Delete local config\n const configPath = getConfigPath();\n if (existsSync(configPath)) {\n unlinkSync(configPath);\n console.log(` Config file: removed`);\n }\n\n const configDir = getConfigDir();\n try {\n rmdirSync(configDir);\n } catch {\n // Directory not empty or doesn't exist — fine\n }\n\n console.log(\"\");\n console.log(\" Done. Restart your AI clients to apply changes.\");\n console.log(\" Note: Login credentials are preserved. Run 'cortex-mcp logout' to sign out.\");\n console.log(\"\");\n}\n","import { deleteCredentials, readCredentials } from \"../auth/credentials.js\";\n\nexport function runLogout(): void {\n const creds = readCredentials();\n\n if (!creds) {\n console.log(\"\");\n console.log(\" Not currently logged in.\");\n console.log(\"\");\n return;\n }\n\n deleteCredentials();\n\n console.log(\"\");\n console.log(` Logged out (was: ${creds.email})`);\n console.log(\" MCP tools will use the shared default key.\");\n console.log(\" Run 'cortex-mcp login' to sign in again.\");\n console.log(\"\");\n}\n","import { readCredentials } from \"../auth/credentials.js\";\n\nexport function runWhoami(): void {\n const creds = readCredentials();\n\n if (!creds) {\n console.log(\"\");\n console.log(\" Not logged in. Using shared default API key.\");\n console.log(\" Run 'cortex-mcp login' to authenticate.\");\n console.log(\"\");\n return;\n }\n\n console.log(\"\");\n console.log(\" Cortex MCP Account\");\n console.log(\" ------------------\");\n if (creds.name) {\n console.log(` Name: ${creds.name}`);\n }\n console.log(` Email: ${creds.email}`);\n console.log(` Authenticated: ${creds.authenticatedAt}`);\n console.log(\n ` API Key: ${creds.apiKey.slice(0, 8)}****${creds.apiKey.slice(-4)}`\n );\n console.log(\"\");\n}\n","import { AVAILABLE_MCPS, DEFAULT_SERVER_URL } from \"../constants.js\";\nimport { readConfig } from \"../config/storage.js\";\nimport { readCredentials } from \"../auth/credentials.js\";\n\nfunction log(msg: string): void {\n process.stderr.write(msg + \"\\n\");\n}\n\ninterface MCPConnection {\n id: string;\n mcp_name: string;\n provider: string;\n account_email: string | null;\n status: string;\n is_company_default: boolean;\n}\n\n/**\n * List OAuth connections for the authenticated user.\n */\nexport async function runConnections(): Promise<void> {\n const creds = readCredentials();\n if (!creds) {\n log(\"\");\n log(\" Not logged in. Run: cortex-mcp login\");\n log(\"\");\n process.exit(1);\n }\n\n const config = readConfig();\n const serverUrl = config?.server || DEFAULT_SERVER_URL;\n\n try {\n const resp = await fetch(`${serverUrl}/api/v1/oauth/connections`, {\n headers: { \"x-api-key\": creds.apiKey },\n });\n\n if (!resp.ok) {\n log(\"\");\n log(\" Error fetching connections.\");\n log(\"\");\n process.exit(1);\n }\n\n const data = (await resp.json()) as { connections: MCPConnection[] };\n const connections = data.connections || [];\n\n log(\"\");\n log(\" Cortex MCP Connections\");\n log(\" ----------------------\");\n\n // Show status for each available MCP\n for (const mcp of AVAILABLE_MCPS) {\n const conn = connections.find((c) => c.mcp_name === mcp.name);\n\n let statusText: string;\n if (!conn) {\n statusText = \"not connected\";\n } else if (conn.is_company_default) {\n statusText = \"(company default)\";\n } else {\n statusText = conn.account_email || \"connected\";\n }\n\n log(` ${mcp.displayName.padEnd(15)} ${statusText}`);\n }\n\n log(\"\");\n log(\" Connect an account: cortex-mcp connect <provider>\");\n log(\"\");\n } catch {\n log(\"\");\n log(\" Error: Could not reach Cortex server.\");\n log(\"\");\n process.exit(1);\n }\n}\n","import { AVAILABLE_MCPS, DEFAULT_SERVER_URL } from \"../constants.js\";\nimport { readConfig } from \"../config/storage.js\";\nimport { readCredentials } from \"../auth/credentials.js\";\n\nfunction log(msg: string): void {\n process.stderr.write(msg + \"\\n\");\n}\n\ninterface MCPConnection {\n id: string;\n mcp_name: string;\n provider: string;\n account_email: string | null;\n status: string;\n is_company_default: boolean;\n}\n\n/**\n * Disconnect a personal OAuth connection for a provider.\n */\nexport async function runDisconnect(provider: string): Promise<void> {\n const creds = readCredentials();\n if (!creds) {\n log(\"\");\n log(\" Not logged in. Run: cortex-mcp login\");\n log(\"\");\n process.exit(1);\n }\n\n // Validate provider\n const mcp = AVAILABLE_MCPS.find(\n (m) => m.name === provider || m.displayName.toLowerCase() === provider.toLowerCase()\n );\n if (!mcp) {\n log(\"\");\n log(` Unknown provider: ${provider}`);\n log(` Available: ${AVAILABLE_MCPS.map((m) => m.name).join(\", \")}`);\n log(\"\");\n process.exit(1);\n }\n\n const providerName = mcp.name;\n const displayName = mcp.displayName;\n const config = readConfig();\n const serverUrl = config?.server || DEFAULT_SERVER_URL;\n\n try {\n // List connections to find the user's personal connection\n const listResp = await fetch(`${serverUrl}/api/v1/oauth/connections`, {\n headers: { \"x-api-key\": creds.apiKey },\n });\n\n if (!listResp.ok) {\n log(\"\");\n log(\" Error fetching connections.\");\n log(\"\");\n process.exit(1);\n }\n\n const listData = (await listResp.json()) as {\n connections: MCPConnection[];\n };\n const match = (listData.connections || []).find(\n (c) => c.mcp_name === providerName && !c.is_company_default\n );\n\n if (!match) {\n log(\"\");\n log(` No personal connection found for ${displayName}.`);\n log(\"\");\n process.exit(1);\n }\n\n // Disconnect\n const resp = await fetch(\n `${serverUrl}/api/v1/oauth/connections/${match.id}/disconnect`,\n {\n method: \"POST\",\n headers: { \"x-api-key\": creds.apiKey },\n }\n );\n\n if (resp.ok) {\n log(\"\");\n log(` Disconnected from ${displayName}.`);\n log(\n ` ${displayName} tools will fall back to the company default token.`\n );\n log(\"\");\n } else {\n log(\"\");\n log(\" Error disconnecting. Please try again.\");\n log(\"\");\n process.exit(1);\n }\n } catch {\n log(\"\");\n log(\" Error: Could not reach Cortex server.\");\n log(\"\");\n process.exit(1);\n }\n}\n"],"mappings":"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","names":["readline","existsSync","readFileSync","writeFileSync","mkdirSync","existsSync","mkdirSync","readFileSync","writeFileSync","existsSync","mkdirSync","readFileSync","writeFileSync","join","join","existsSync","readFileSync","mkdirSync","writeFileSync","log","sleep","rl","ask","log","readFileSync","fileBuffer","readFileSync","existsSync","unlinkSync","existsSync","unlinkSync","log","log","DEFAULT_SERVER_URL","openBrowser"]}
1
+ {"version":3,"sources":["../bin/cli.ts","../src/cli/setup.ts","../src/config/storage.ts","../src/config/clients.ts","../src/auth/credentials.ts","../src/cli/login.ts","../src/cli/connect.ts","../src/cli/configure.ts","../src/proxy/stdio-server.ts","../src/proxy/http-client.ts","../src/cli/serve.ts","../src/cli/status.ts","../src/cli/reset.ts","../src/cli/logout.ts","../src/cli/whoami.ts","../src/cli/connections.ts","../src/cli/disconnect.ts"],"sourcesContent":["import { Command } from \"commander\";\nimport { runSetup } from \"../src/cli/setup.js\";\nimport { runConfigure } from \"../src/cli/configure.js\";\nimport { runServe } from \"../src/cli/serve.js\";\nimport { runStatus } from \"../src/cli/status.js\";\nimport { runReset } from \"../src/cli/reset.js\";\nimport { runLogin } from \"../src/cli/login.js\";\nimport { runLogout } from \"../src/cli/logout.js\";\nimport { runWhoami } from \"../src/cli/whoami.js\";\nimport { runConnect } from \"../src/cli/connect.js\";\nimport { runConnections } from \"../src/cli/connections.js\";\nimport { runDisconnect } from \"../src/cli/disconnect.js\";\n\nconst program = new Command();\n\nprogram\n .name(\"cortex-mcp\")\n .description(\n \"Connect your AI tools to Asana, GitHub, Microsoft 365, Monday.com, Salesforce, Vercel & Supabase via Cortex — supports Claude, Cursor, Codex & more\"\n )\n .version(\"1.0.0\");\n\nprogram\n .command(\"setup\")\n .description(\"Interactive setup wizard — configure MCPs and AI clients\")\n .option(\n \"--email <email>\",\n \"Company email (use if your Okta email differs from your directory email)\"\n )\n .action(async (options: { email?: string }) => {\n try {\n await runSetup(options.email);\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code === \"ERR_USE_AFTER_CLOSE\") {\n // readline closed — user pressed Ctrl+C\n process.exit(0);\n }\n console.error(\"Setup failed:\", err);\n process.exit(1);\n }\n });\n\nprogram\n .command(\"configure\")\n .description(\"Non-interactive configuration for a specific client\")\n .option(\"--key <key>\", \"Cortex API key (uses built-in default if not provided)\")\n .requiredOption(\n \"--client <client>\",\n \"Client to configure (claude-desktop, claude-code, cursor, codex, stdio)\"\n )\n .option(\n \"--mcps <mcps>\",\n \"Comma-separated MCP names (default: all)\",\n )\n .action(async (options) => {\n await runConfigure(options);\n });\n\nprogram\n .command(\"serve\")\n .description(\n \"Start stdio MCP proxy server (for OpenClaw and other stdio clients)\"\n )\n .action(async () => {\n await runServe();\n });\n\nprogram\n .command(\"status\")\n .description(\"Show current Cortex MCP configuration\")\n .action(() => {\n runStatus();\n });\n\nprogram\n .command(\"reset\")\n .description(\"Remove all Cortex MCP entries from AI clients\")\n .action(() => {\n runReset();\n });\n\nprogram\n .command(\"login\")\n .description(\"Sign in with your company Okta SSO account\")\n .option(\n \"--email <email>\",\n \"Company email (use if your Okta email differs from your directory email)\"\n )\n .action(async (options: { email?: string }) => {\n try {\n await runLogin(options.email);\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code === \"ERR_USE_AFTER_CLOSE\") {\n process.exit(0);\n }\n console.error(\"Login failed:\", err);\n process.exit(1);\n }\n });\n\nprogram\n .command(\"logout\")\n .description(\"Sign out and remove stored credentials\")\n .action(() => {\n runLogout();\n });\n\nprogram\n .command(\"whoami\")\n .description(\"Show current authenticated user\")\n .action(() => {\n runWhoami();\n });\n\nprogram\n .command(\"connect <provider>\")\n .description(\"Connect your personal account to an MCP service (e.g., asana)\")\n .action(async (provider: string) => {\n try {\n await runConnect(provider);\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code === \"ERR_USE_AFTER_CLOSE\") {\n process.exit(0);\n }\n console.error(\"Connect failed:\", err);\n process.exit(1);\n }\n });\n\nprogram\n .command(\"connections\")\n .description(\"List your OAuth connections to MCP services\")\n .action(async () => {\n try {\n await runConnections();\n } catch (err) {\n console.error(\"Failed:\", err);\n process.exit(1);\n }\n });\n\nprogram\n .command(\"disconnect <provider>\")\n .description(\"Remove your personal OAuth connection to an MCP service\")\n .action(async (provider: string) => {\n try {\n await runDisconnect(provider);\n } catch (err) {\n console.error(\"Disconnect failed:\", err);\n process.exit(1);\n }\n });\n\nprogram\n .command(\"connect-mobile\")\n .description(\"Connect Cortex to Claude on mobile — opens setup page in browser\")\n .action(async () => {\n const { DEFAULT_SERVER_URL } = await import(\"../src/constants.js\");\n const { openBrowser } = await import(\"../src/utils/browser.js\");\n const url = `${DEFAULT_SERVER_URL}/connect`;\n console.log(\"\\nOpening Cortex connect page...\");\n console.log(` ${url}\\n`);\n console.log(\"Follow the steps to connect Cortex to your Claude account.\");\n console.log(\"Once connected, tools will be available on web, desktop, and mobile.\\n\");\n await openBrowser(url);\n });\n\nprogram.parse();\n","import * as readline from \"node:readline\";\nimport {\n AVAILABLE_MCPS,\n DEFAULT_MCPS,\n DEFAULT_SERVER_URL,\n} from \"../constants.js\";\nimport { createConfig, writeConfig } from \"../config/storage.js\";\nimport {\n configureClaudeCode,\n configureClaudeDesktop,\n configureCodex,\n configureCursor,\n detectClients,\n generateStdioSnippet,\n} from \"../config/clients.js\";\nimport type { ClientType } from \"../config/types.js\";\nimport {\n deleteCredentials,\n getEffectiveApiKey,\n readCredentials,\n writeCredentials,\n} from \"../auth/credentials.js\";\nimport {\n loginWithSSO,\n showConnectionsAndAutoConnect,\n type LoginResult,\n} from \"./login.js\";\n\nconst rl = readline.createInterface({\n input: process.stdin,\n output: process.stderr,\n});\n\nfunction ask(question: string): Promise<string> {\n return new Promise((resolve) => {\n rl.question(question, (answer) => resolve(answer.trim()));\n });\n}\n\nfunction log(msg: string): void {\n process.stderr.write(msg + \"\\n\");\n}\n\ntype ApiKeyValidationResult = \"valid\" | \"invalid\" | \"unreachable\";\n\nasync function validateApiKey(\n apiKey: string,\n serverUrl: string,\n): Promise<ApiKeyValidationResult> {\n try {\n const resp = await fetch(`${serverUrl}/api/v1/oauth/connections`, {\n headers: { \"x-api-key\": apiKey },\n });\n\n if (resp.ok) {\n return \"valid\";\n }\n\n if (resp.status === 401 || resp.status === 403) {\n return \"invalid\";\n }\n\n return \"unreachable\";\n } catch {\n return \"unreachable\";\n }\n}\n\n/**\n * Interactive setup wizard. Guides the user through:\n * 1. Selecting MCPs\n * 2. Detecting and configuring AI clients\n * 3. Signing in via Okta SSO\n * 4. Connecting personal accounts (Asana)\n */\nexport async function runSetup(emailHint?: string): Promise<void> {\n let apiKey = getEffectiveApiKey();\n let creds = readCredentials();\n\n log(\"\");\n log(\" Cortex MCP Setup\");\n log(\" Connect your AI tools to Asana, GitHub, Monday.com, Salesforce, M365, Vercel & Supabase\");\n log(\"\");\n\n // ─────────────────────────────────────────\n // Step 1: Select MCPs\n // ─────────────────────────────────────────\n log(\" Step 1: Select MCPs\");\n log(\" Available MCPs (all enabled by default):\\n\");\n\n for (const mcp of AVAILABLE_MCPS) {\n log(` - ${mcp.displayName.padEnd(15)} ${mcp.description}`);\n }\n log(\"\");\n\n const mcpInput = await ask(\n ` MCPs to enable (comma-separated, or press Enter for all): `\n );\n\n let selectedMcps: string[];\n if (!mcpInput) {\n selectedMcps = [...DEFAULT_MCPS];\n log(\" All MCPs enabled.\\n\");\n } else {\n selectedMcps = mcpInput\n .split(\",\")\n .map((s) => s.trim().toLowerCase())\n .filter((s) =>\n AVAILABLE_MCPS.some(\n (m) => m.name === s || m.displayName.toLowerCase() === s\n )\n );\n\n // Map display names to internal names\n selectedMcps = selectedMcps.map((s) => {\n const found = AVAILABLE_MCPS.find(\n (m) => m.displayName.toLowerCase() === s\n );\n return found ? found.name : s;\n });\n\n if (selectedMcps.length === 0) {\n selectedMcps = [...DEFAULT_MCPS];\n log(\" No valid MCPs recognized. Enabling all.\\n\");\n } else {\n log(` Enabled: ${selectedMcps.join(\", \")}\\n`);\n }\n }\n\n // ─────────────────────────────────────────\n // Step 2: Detect and configure clients\n // ─────────────────────────────────────────\n log(\" Step 2: Configure AI Clients\\n\");\n\n const clients = detectClients();\n const configuredClients: ClientType[] = [];\n\n for (const client of clients) {\n if (!client.detected) {\n log(` ${client.name}: not detected, skipping`);\n continue;\n }\n\n const answer = await ask(` Configure ${client.name}? (Y/n): `);\n if (answer.toLowerCase() === \"n\") {\n log(` Skipping ${client.name}`);\n continue;\n }\n\n try {\n if (client.type === \"claude-desktop\") {\n configureClaudeDesktop(DEFAULT_SERVER_URL, apiKey, selectedMcps);\n log(` ${client.name}: configured`);\n configuredClients.push(client.type);\n } else if (client.type === \"claude-code\") {\n configureClaudeCode(DEFAULT_SERVER_URL, apiKey, selectedMcps);\n log(` ${client.name}: configured`);\n configuredClients.push(client.type);\n } else if (client.type === \"cursor\") {\n configureCursor(DEFAULT_SERVER_URL, apiKey, selectedMcps);\n log(` ${client.name}: configured`);\n configuredClients.push(client.type);\n } else if (client.type === \"codex\") {\n configureCodex(DEFAULT_SERVER_URL, apiKey, selectedMcps);\n log(` ${client.name}: configured`);\n configuredClients.push(client.type);\n }\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n log(` ${client.name}: failed \\u2014 ${msg}`);\n }\n }\n\n // Ask about stdio\n log(\"\");\n const stdioAnswer = await ask(\n \" Do you also need a config snippet for OpenClaw or other stdio clients? (y/N): \"\n );\n if (stdioAnswer.toLowerCase() === \"y\") {\n log(\"\\n Add this to your client's MCP config:\\n\");\n log(generateStdioSnippet(apiKey));\n log(\"\");\n configuredClients.push(\"stdio\");\n }\n\n // Save config (will update again after login with personal key)\n const config = createConfig(apiKey, selectedMcps);\n config.configuredClients = configuredClients;\n writeConfig(config);\n\n // ─────────────────────────────────────────\n // Step 3: Sign In\n // ─────────────────────────────────────────\n log(\"\");\n log(\" Step 3: Sign In\\n\");\n\n let shouldLogin = !creds;\n if (creds) {\n log(` Already signed in as ${creds.name || creds.email}`);\n\n const validation = await validateApiKey(creds.apiKey, DEFAULT_SERVER_URL);\n if (validation === \"invalid\") {\n log(\" Saved session is no longer valid. Re-authenticating...\");\n deleteCredentials();\n creds = null;\n shouldLogin = true;\n } else {\n apiKey = creds.apiKey;\n\n if (validation === \"unreachable\") {\n log(\" Warning: Could not validate saved session. Continuing with existing credentials.\");\n }\n }\n }\n\n if (shouldLogin) {\n log(\" Sign in with your company Okta SSO account.\");\n log(\"\");\n\n // Close readline before SSO (it uses stdin; browser flow doesn't need it)\n rl.close();\n\n let result: LoginResult = await loginWithSSO(DEFAULT_SERVER_URL, emailHint);\n\n // Handle email hint retry if AD verification failed\n if (result.status === \"needs_hint\") {\n let hintEmail: string;\n\n if (emailHint) {\n // --email was already provided; use it directly for retry\n hintEmail = emailHint;\n } else {\n log(\"\");\n log(\n ` Your SSO email (${result.ssoEmail}) was not found in the employee directory.`\n );\n log(\n \" This can happen if your Okta account uses a different email\"\n + \" than your company directory.\"\n );\n log(\"\");\n\n const hintRl = readline.createInterface({\n input: process.stdin,\n output: process.stderr,\n });\n\n hintEmail = await new Promise<string>((resolve) => {\n hintRl.question(\" Enter your company email address: \", (a) =>\n resolve(a.trim())\n );\n });\n hintRl.close();\n\n if (!hintEmail || !hintEmail.includes(\"@\")) {\n log(\" Invalid email. Run 'cortex-mcp login --email you@company.com' to try again.\");\n process.exit(1);\n }\n }\n\n log(\"\");\n log(\" Retrying with your company email. You'll need to complete SSO again.\");\n log(\"\");\n\n result = await loginWithSSO(DEFAULT_SERVER_URL, hintEmail);\n\n if (result.status === \"needs_hint\") {\n log(\"\");\n log(\" The provided email was also not found in the employee directory.\");\n log(\" Please verify your email and contact IT if the issue persists.\");\n process.exit(1);\n }\n }\n\n if (result.status !== \"success\") {\n log(\" Login failed. Run 'cortex-mcp login' to try again.\");\n process.exit(1);\n }\n\n const { apiKey: newKey, email, name } = result;\n apiKey = newKey;\n\n // Save credentials\n writeCredentials({\n apiKey: newKey,\n email,\n name,\n authenticatedAt: new Date().toISOString(),\n });\n\n log(` Authenticated as ${name || email}${name ? ` (${email})` : \"\"}`);\n log(\" Personal API key saved.\");\n\n // Update client configs with new personal key\n if (configuredClients.length > 0) {\n log(\"\");\n log(\" Updating clients with personal key:\");\n for (const clientType of configuredClients) {\n try {\n if (clientType === \"claude-desktop\") {\n configureClaudeDesktop(DEFAULT_SERVER_URL, newKey, selectedMcps);\n } else if (clientType === \"claude-code\") {\n configureClaudeCode(DEFAULT_SERVER_URL, newKey, selectedMcps);\n } else if (clientType === \"cursor\") {\n configureCursor(DEFAULT_SERVER_URL, newKey, selectedMcps);\n } else if (clientType === \"codex\") {\n configureCodex(DEFAULT_SERVER_URL, newKey, selectedMcps);\n }\n log(` ${clientType}: updated`);\n } catch {\n log(` ${clientType}: failed to update`);\n }\n }\n }\n\n // Update saved config with personal key\n config.apiKey = newKey;\n writeConfig(config);\n\n creds = readCredentials();\n }\n\n // ─────────────────────────────────────────\n // Step 4: Connect Accounts\n // ─────────────────────────────────────────\n log(\"\");\n log(\" Step 4: Connect Accounts (optional)\\n\");\n\n await showConnectionsAndAutoConnect(apiKey, DEFAULT_SERVER_URL);\n\n log(\" Setup complete! Restart your AI clients to see the new tools.\");\n log(` Config saved to ~/.cortex-mcp/config.json`);\n log(\"\");\n}\n","import { existsSync, mkdirSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport { CONFIG_DIR_NAME, CONFIG_FILE_NAME, DEFAULT_SERVER_URL } from \"../constants.js\";\nimport { getHomeDir } from \"../utils/platform.js\";\nimport type { CortexMcpConfig } from \"./types.js\";\n\n/** Get the config directory path */\nexport function getConfigDir(): string {\n return join(getHomeDir(), CONFIG_DIR_NAME);\n}\n\n/** Get the config file path */\nexport function getConfigPath(): string {\n return join(getConfigDir(), CONFIG_FILE_NAME);\n}\n\n/** Read the current config, or return null if none exists */\nexport function readConfig(): CortexMcpConfig | null {\n const path = getConfigPath();\n if (!existsSync(path)) return null;\n\n try {\n const raw = readFileSync(path, \"utf-8\");\n return JSON.parse(raw) as CortexMcpConfig;\n } catch {\n return null;\n }\n}\n\n/** Write config to disk (creates directory with 700 permissions, file with 600) */\nexport function writeConfig(config: CortexMcpConfig): void {\n const dir = getConfigDir();\n if (!existsSync(dir)) {\n mkdirSync(dir, { recursive: true, mode: 0o700 });\n }\n\n const path = getConfigPath();\n writeFileSync(path, JSON.stringify(config, null, 2) + \"\\n\", {\n mode: 0o600,\n });\n}\n\n/** Create a default config with the given API key and MCPs */\nexport function createConfig(\n apiKey: string,\n mcps: string[]\n): CortexMcpConfig {\n return {\n version: 1,\n server: DEFAULT_SERVER_URL,\n apiKey,\n mcps,\n configuredClients: [],\n };\n}\n","import { existsSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { dirname } from \"node:path\";\nimport { mkdirSync } from \"node:fs\";\nimport { execSync } from \"node:child_process\";\nimport { AVAILABLE_MCPS } from \"../constants.js\";\nimport {\n getClaudeDesktopConfigPath,\n getCodexConfigPath,\n getCursorConfigPath,\n} from \"../utils/platform.js\";\nimport type { ClientType, DetectedClient, HttpMcpEntry } from \"./types.js\";\n\n/**\n * Detect which AI clients are installed on this machine.\n */\nexport function detectClients(): DetectedClient[] {\n const clients: DetectedClient[] = [];\n\n // Claude Desktop\n const desktopPath = getClaudeDesktopConfigPath();\n const desktopDir = dirname(desktopPath);\n clients.push({\n type: \"claude-desktop\",\n name: \"Claude Desktop\",\n configPath: desktopPath,\n detected: existsSync(desktopDir),\n });\n\n // Claude Code\n let claudeCodeDetected = false;\n try {\n execSync(\"which claude\", { stdio: \"pipe\" });\n claudeCodeDetected = true;\n } catch {\n // claude CLI not in PATH\n }\n clients.push({\n type: \"claude-code\",\n name: \"Claude Code\",\n configPath: null,\n detected: claudeCodeDetected,\n });\n\n // Cursor\n const cursorPath = getCursorConfigPath();\n const cursorDir = dirname(cursorPath);\n clients.push({\n type: \"cursor\",\n name: \"Cursor\",\n configPath: cursorPath,\n detected: existsSync(cursorDir),\n });\n\n // OpenAI Codex\n const codexPath = getCodexConfigPath();\n const codexDir = dirname(codexPath);\n clients.push({\n type: \"codex\",\n name: \"Codex\",\n configPath: codexPath,\n detected: existsSync(codexDir),\n });\n\n return clients;\n}\n\n/**\n * Build per-MCP HTTP entries for a given server URL and API key.\n */\nexport function buildHttpEntries(\n serverUrl: string,\n apiKey: string,\n mcps: string[]\n): Record<string, HttpMcpEntry> {\n const entries: Record<string, HttpMcpEntry> = {};\n\n for (const mcp of AVAILABLE_MCPS) {\n if (!mcps.includes(mcp.name)) continue;\n entries[mcp.serverName] = {\n url: `${serverUrl}/mcp/${mcp.name}`,\n headers: { \"x-api-key\": apiKey },\n };\n }\n\n return entries;\n}\n\n/**\n * Configure Claude Desktop by merging a stdio proxy entry into its config file.\n * Uses command/args/env format (Claude Desktop does not support HTTP url/headers).\n * Preserves existing non-Cortex entries.\n */\nexport function configureClaudeDesktop(\n _serverUrl: string,\n apiKey: string,\n _mcps: string[]\n): void {\n const configPath = getClaudeDesktopConfigPath();\n const dir = dirname(configPath);\n\n // Ensure directory exists\n if (!existsSync(dir)) {\n mkdirSync(dir, { recursive: true });\n }\n\n // Read existing config or start fresh\n let config: Record<string, unknown> = {};\n if (existsSync(configPath)) {\n try {\n config = JSON.parse(readFileSync(configPath, \"utf-8\"));\n } catch {\n // Corrupted file — start fresh\n }\n }\n\n // Ensure mcpServers key exists\n if (!config.mcpServers || typeof config.mcpServers !== \"object\") {\n config.mcpServers = {};\n }\n\n const servers = config.mcpServers as Record<string, unknown>;\n\n // Remove existing cortex-* and cortex entries\n for (const key of Object.keys(servers)) {\n if (key.startsWith(\"cortex-\") || key === \"cortex\") {\n delete servers[key];\n }\n }\n\n // Add stdio proxy entry (Claude Desktop only supports command/args)\n // API key is read from ~/.cortex-mcp/credentials.json at runtime by the serve command,\n // so we don't bake it into the env (avoids stale key issues on re-login).\n servers[\"cortex\"] = {\n command: \"npx\",\n args: [\"-y\", \"@danainnovations/cortex-mcp@latest\", \"serve\"],\n };\n\n writeFileSync(configPath, JSON.stringify(config, null, 2) + \"\\n\");\n}\n\n/**\n * Configure Claude Code by running `claude mcp add` commands.\n */\nexport function configureClaudeCode(\n serverUrl: string,\n apiKey: string,\n mcps: string[]\n): void {\n for (const mcp of AVAILABLE_MCPS) {\n if (!mcps.includes(mcp.name)) continue;\n\n const url = `${serverUrl}/mcp/${mcp.name}`;\n\n // Remove existing entry first (ignore errors if it doesn't exist)\n try {\n execSync(`claude mcp remove ${mcp.serverName}`, { stdio: \"pipe\" });\n } catch {\n // Entry didn't exist — fine\n }\n\n execSync(\n `claude mcp add --transport http ${mcp.serverName} ${url} -H \"x-api-key: ${apiKey}\"`,\n { stdio: \"pipe\" }\n );\n }\n}\n\n/**\n * Configure Cursor by writing HTTP MCP entries to its config file.\n * Cursor supports HTTP transport natively.\n */\nexport function configureCursor(\n serverUrl: string,\n apiKey: string,\n mcps: string[]\n): void {\n const configPath = getCursorConfigPath();\n const dir = dirname(configPath);\n\n if (!existsSync(dir)) {\n mkdirSync(dir, { recursive: true });\n }\n\n let config: Record<string, unknown> = {};\n if (existsSync(configPath)) {\n try {\n config = JSON.parse(readFileSync(configPath, \"utf-8\"));\n } catch {\n // Corrupted file — start fresh\n }\n }\n\n if (!config.mcpServers || typeof config.mcpServers !== \"object\") {\n config.mcpServers = {};\n }\n\n const servers = config.mcpServers as Record<string, unknown>;\n\n // Remove existing cortex-* entries\n for (const key of Object.keys(servers)) {\n if (key.startsWith(\"cortex-\")) {\n delete servers[key];\n }\n }\n\n // Add new HTTP entries\n const entries = buildHttpEntries(serverUrl, apiKey, mcps);\n Object.assign(servers, entries);\n\n writeFileSync(configPath, JSON.stringify(config, null, 2) + \"\\n\");\n}\n\n/**\n * Generate a stdio config snippet for clients that need it (OpenClaw, etc.)\n */\nexport function generateStdioSnippet(_apiKey: string): string {\n const config = {\n mcpServers: {\n cortex: {\n command: \"npx\",\n args: [\"-y\", \"@danainnovations/cortex-mcp@latest\", \"serve\"],\n },\n },\n };\n return JSON.stringify(config, null, 2);\n}\n\n/**\n * Remove all cortex-* MCP entries from Claude Desktop config.\n */\nexport function resetClaudeDesktop(): boolean {\n const configPath = getClaudeDesktopConfigPath();\n if (!existsSync(configPath)) return false;\n\n try {\n const config = JSON.parse(readFileSync(configPath, \"utf-8\"));\n if (!config.mcpServers) return false;\n\n const servers = config.mcpServers as Record<string, unknown>;\n let removed = false;\n for (const key of Object.keys(servers)) {\n if (key.startsWith(\"cortex-\") || key === \"cortex\") {\n delete servers[key];\n removed = true;\n }\n }\n\n if (removed) {\n writeFileSync(configPath, JSON.stringify(config, null, 2) + \"\\n\");\n }\n return removed;\n } catch {\n return false;\n }\n}\n\n/**\n * Remove cortex MCP entries from Cursor config.\n */\nexport function resetCursor(): boolean {\n const configPath = getCursorConfigPath();\n if (!existsSync(configPath)) return false;\n\n try {\n const config = JSON.parse(readFileSync(configPath, \"utf-8\"));\n if (!config.mcpServers) return false;\n\n const servers = config.mcpServers as Record<string, unknown>;\n let removed = false;\n for (const key of Object.keys(servers)) {\n if (key.startsWith(\"cortex-\") || key === \"cortex\") {\n delete servers[key];\n removed = true;\n }\n }\n\n if (removed) {\n writeFileSync(configPath, JSON.stringify(config, null, 2) + \"\\n\");\n }\n return removed;\n } catch {\n return false;\n }\n}\n\n/**\n * Remove cortex MCP entries from Claude Code.\n */\nexport function resetClaudeCode(): boolean {\n let removed = false;\n for (const mcp of AVAILABLE_MCPS) {\n try {\n execSync(`claude mcp remove ${mcp.serverName}`, { stdio: \"pipe\" });\n removed = true;\n } catch {\n // Entry didn't exist\n }\n }\n return removed;\n}\n\n/**\n * Remove all TOML sections whose header matches [mcp_servers.cortex*].\n * A section runs from its [header] to the next [header] or EOF.\n */\nfunction removeCortexTomlSections(content: string): string {\n const lines = content.split(\"\\n\");\n const result: string[] = [];\n let skipping = false;\n\n for (const line of lines) {\n const trimmed = line.trim();\n // Detect any TOML section header\n if (trimmed.startsWith(\"[\")) {\n // Check if this is a cortex MCP section (including sub-tables like .http_headers)\n skipping = /^\\[mcp_servers\\.cortex[_-]/.test(trimmed)\n || trimmed === \"[mcp_servers.cortex]\";\n }\n if (!skipping) {\n result.push(line);\n }\n }\n\n return result.join(\"\\n\");\n}\n\n/**\n * Configure OpenAI Codex by writing MCP entries to ~/.codex/config.toml.\n * Uses Streamable HTTP transport with static http_headers for the API key.\n */\nexport function configureCodex(\n serverUrl: string,\n apiKey: string,\n mcps: string[]\n): void {\n const configPath = getCodexConfigPath();\n const dir = dirname(configPath);\n\n if (!existsSync(dir)) {\n mkdirSync(dir, { recursive: true });\n }\n\n let content = \"\";\n if (existsSync(configPath)) {\n try {\n content = readFileSync(configPath, \"utf-8\");\n } catch {\n // Corrupted file — start fresh\n }\n }\n\n // Remove existing cortex entries\n content = removeCortexTomlSections(content);\n\n // Build new TOML sections for each MCP\n const sections: string[] = [];\n for (const mcp of AVAILABLE_MCPS) {\n if (!mcps.includes(mcp.name)) continue;\n sections.push(`[mcp_servers.${mcp.serverName}]`);\n sections.push(`url = \"${serverUrl}/mcp/${mcp.name}\"`);\n sections.push(`[mcp_servers.${mcp.serverName}.http_headers]`);\n sections.push(`\"x-api-key\" = \"${apiKey}\"`);\n sections.push(\"\");\n }\n\n // Append to existing config\n const trimmed = content.trimEnd();\n const newContent = trimmed\n ? trimmed + \"\\n\\n\" + sections.join(\"\\n\") + \"\\n\"\n : sections.join(\"\\n\") + \"\\n\";\n\n writeFileSync(configPath, newContent);\n}\n\n/**\n * Remove cortex MCP entries from Codex config.\n */\nexport function resetCodex(): boolean {\n const configPath = getCodexConfigPath();\n if (!existsSync(configPath)) return false;\n\n try {\n const content = readFileSync(configPath, \"utf-8\");\n const cleaned = removeCortexTomlSections(content);\n\n if (cleaned.length < content.length) {\n writeFileSync(configPath, cleaned);\n return true;\n }\n return false;\n } catch {\n return false;\n }\n}\n\n/**\n * Configure a specific client type.\n */\nexport function configureClient(\n clientType: ClientType,\n serverUrl: string,\n apiKey: string,\n mcps: string[]\n): string {\n switch (clientType) {\n case \"claude-desktop\":\n configureClaudeDesktop(serverUrl, apiKey, mcps);\n return \"Claude Desktop configured\";\n case \"claude-code\":\n configureClaudeCode(serverUrl, apiKey, mcps);\n return \"Claude Code configured\";\n case \"cursor\":\n configureCursor(serverUrl, apiKey, mcps);\n return \"Cursor configured\";\n case \"codex\":\n configureCodex(serverUrl, apiKey, mcps);\n return \"Codex configured\";\n case \"stdio\":\n return (\n \"Add this to your client config:\\n\\n\" +\n generateStdioSnippet(apiKey)\n );\n }\n}\n","import { existsSync, mkdirSync, readFileSync, unlinkSync, writeFileSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport { CONFIG_DIR_NAME, CREDENTIALS_FILE_NAME, DEFAULT_API_KEY } from \"../constants.js\";\nimport { readConfig } from \"../config/storage.js\";\nimport { getHomeDir } from \"../utils/platform.js\";\n\n/** Stored credentials from a successful login */\nexport interface CortexCredentials {\n apiKey: string;\n email: string;\n name?: string;\n authenticatedAt: string; // ISO 8601\n}\n\n/** Get the credentials file path (~/.cortex-mcp/credentials.json) */\nexport function getCredentialsPath(): string {\n return join(getHomeDir(), CONFIG_DIR_NAME, CREDENTIALS_FILE_NAME);\n}\n\n/** Read stored credentials, or return null if not logged in */\nexport function readCredentials(): CortexCredentials | null {\n const path = getCredentialsPath();\n if (!existsSync(path)) return null;\n\n try {\n const raw = readFileSync(path, \"utf-8\");\n return JSON.parse(raw) as CortexCredentials;\n } catch {\n return null;\n }\n}\n\n/** Write credentials to disk (creates directory with 700, file with 600 permissions) */\nexport function writeCredentials(creds: CortexCredentials): void {\n const dir = join(getHomeDir(), CONFIG_DIR_NAME);\n if (!existsSync(dir)) {\n mkdirSync(dir, { recursive: true, mode: 0o700 });\n }\n\n const path = getCredentialsPath();\n writeFileSync(path, JSON.stringify(creds, null, 2) + \"\\n\", {\n mode: 0o600,\n });\n}\n\n/** Delete stored credentials */\nexport function deleteCredentials(): void {\n const path = getCredentialsPath();\n if (existsSync(path)) {\n unlinkSync(path);\n }\n}\n\n/**\n * Get the effective API key to use.\n * Priority: CORTEX_API_KEY env var > stored credentials > config file > default shared key\n */\nexport function getEffectiveApiKey(): string {\n // 1. Environment variable (highest priority)\n const envKey = process.env.CORTEX_API_KEY;\n if (envKey) return envKey;\n\n // 2. Personal credentials from login\n const creds = readCredentials();\n if (creds?.apiKey) return creds.apiKey;\n\n // 3. Config file (set during setup)\n const config = readConfig();\n if (config?.apiKey) return config.apiKey;\n\n // 4. Shared default key (fallback)\n return DEFAULT_API_KEY;\n}\n","import * as readline from \"node:readline\";\nimport { AVAILABLE_MCPS, DEFAULT_SERVER_URL } from \"../constants.js\";\nimport { readConfig, writeConfig } from \"../config/storage.js\";\nimport { configureClient } from \"../config/clients.js\";\nimport { readCredentials, writeCredentials } from \"../auth/credentials.js\";\nimport { openBrowser } from \"../utils/browser.js\";\nimport { connectProvider } from \"./connect.js\";\n\nfunction log(msg: string): void {\n process.stderr.write(msg + \"\\n\");\n}\n\nfunction sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n\nexport type LoginResult =\n | { status: \"success\"; apiKey: string; email: string; name?: string }\n | { status: \"needs_hint\"; ssoEmail: string }\n | { status: \"failed\" };\n\n/**\n * Core SSO login flow: initiate -> browser -> poll.\n * Reusable by both the `login` command and the setup wizard.\n *\n * Optionally accepts an emailHint for users whose Okta email\n * differs from their company directory email.\n */\nexport async function loginWithSSO(\n serverUrl: string,\n emailHint?: string,\n): Promise<LoginResult> {\n // Initiate auth flow\n let sessionId: string;\n let authUrl: string;\n let expiresIn: number;\n\n try {\n const body: Record<string, string> = {};\n if (emailHint) {\n body.email_hint = emailHint;\n }\n\n const resp = await fetch(`${serverUrl}/api/v1/auth/employee/initiate`, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify(body),\n });\n\n if (!resp.ok) {\n log(` Error: Failed to start authentication (HTTP ${resp.status})`);\n return { status: \"failed\" };\n }\n\n const data = (await resp.json()) as {\n session_id: string;\n auth_url: string;\n expires_in: number;\n };\n sessionId = data.session_id;\n authUrl = data.auth_url;\n expiresIn = data.expires_in;\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n log(` Error: Could not reach Cortex server at ${serverUrl}`);\n log(` ${msg}`);\n return { status: \"failed\" };\n }\n\n // Open browser\n log(\" Opening browser for Okta SSO login...\");\n await openBrowser(authUrl);\n log(\" If the browser didn't open, visit:\");\n log(` ${authUrl}`);\n log(\"\");\n\n // Poll for completion\n const deadline = Date.now() + expiresIn * 1000;\n process.stderr.write(\" Waiting for authentication\");\n\n while (Date.now() < deadline) {\n await sleep(3000);\n\n try {\n const resp = await fetch(\n `${serverUrl}/api/v1/auth/employee/poll/${sessionId}`\n );\n const result = (await resp.json()) as {\n status: string;\n api_key?: string;\n employee_name?: string;\n employee_email?: string;\n sso_email?: string;\n user_info?: { email?: string; name?: string };\n error_message?: string;\n };\n\n if (result.status === \"completed\") {\n process.stderr.write(\"\\n\\n\");\n\n const email =\n result.employee_email || result.user_info?.email || \"unknown\";\n const name = result.employee_name || result.user_info?.name || \"\";\n const apiKey = result.api_key || \"\";\n\n return { status: \"success\", apiKey, email, name: name || undefined };\n }\n\n if (result.status === \"expired\") {\n process.stderr.write(\"\\n\");\n log(\" Authentication session expired. Please try again.\");\n return { status: \"failed\" };\n }\n\n if (result.status === \"error\") {\n process.stderr.write(\"\\n\");\n\n // If AD verification failed and no hint was provided, signal for retry\n if (\n result.error_message === \"not_verified_employee\" &&\n !emailHint\n ) {\n return {\n status: \"needs_hint\",\n ssoEmail: result.sso_email || \"unknown\",\n };\n }\n\n log(\n ` Authentication failed: ${result.error_message || \"unknown error\"}`\n );\n return { status: \"failed\" };\n }\n\n // Still pending\n process.stderr.write(\".\");\n } catch {\n process.stderr.write(\"!\");\n }\n }\n\n process.stderr.write(\"\\n\");\n log(\" Timeout waiting for authentication. Please try again.\");\n return { status: \"failed\" };\n}\n\n/**\n * Show MCP connection status and auto-connect personal MCPs (e.g., Asana).\n */\nexport async function showConnectionsAndAutoConnect(\n apiKey: string,\n serverUrl: string,\n): Promise<void> {\n // Fetch existing connections\n let existingConnections: Array<{\n mcp_name: string;\n account_email: string | null;\n is_company_default: boolean;\n }> = [];\n\n try {\n const resp = await fetch(`${serverUrl}/api/v1/oauth/connections`, {\n headers: { \"x-api-key\": apiKey },\n });\n if (resp.ok) {\n const data = (await resp.json()) as {\n connections: typeof existingConnections;\n };\n existingConnections = data.connections || [];\n } else {\n log(\n ` Warning: Could not fetch current MCP connections (HTTP ${resp.status}).`\n );\n if (resp.status === 401 || resp.status === 403) {\n log(\" Warning: Authentication may be expired. Run 'cortex-mcp login' to refresh.\");\n }\n }\n } catch {\n log(\" Warning: Could not fetch current MCP connections due to a network error.\");\n }\n\n // Show MCP connections table\n log(\"\");\n log(\" MCP Connections\");\n log(\" \" + \"\\u2500\".repeat(45));\n\n const personalMcps: Array<{ name: string; displayName: string }> = [];\n\n for (const mcp of AVAILABLE_MCPS) {\n const conn = existingConnections.find((c) => c.mcp_name === mcp.name);\n\n if (mcp.authMode === \"company\") {\n log(` ${mcp.displayName.padEnd(15)} company default`);\n } else {\n // Personal auth required\n if (conn && !conn.is_company_default && conn.account_email) {\n log(` ${mcp.displayName.padEnd(15)} ${conn.account_email}`);\n } else {\n log(\n ` ${mcp.displayName.padEnd(15)} not connected (personal account required)`\n );\n personalMcps.push({ name: mcp.name, displayName: mcp.displayName });\n }\n }\n }\n\n log(\"\");\n\n // Auto-connect unconnected personal MCPs\n if (personalMcps.length === 0) {\n log(\" All accounts connected!\");\n log(\"\");\n return;\n }\n\n log(\" The following MCPs require a personal account to access your data.\");\n log(\" Skip any you don't have an account for — you can always connect later.\\n\");\n\n const rl = readline.createInterface({\n input: process.stdin,\n output: process.stderr,\n });\n\n const ask = (question: string): Promise<string> =>\n new Promise((resolve) => {\n rl.question(question, (answer) => resolve(answer.trim().toLowerCase()));\n });\n\n for (const mcp of personalMcps) {\n const answer = await ask(\n ` Connect ${mcp.displayName}? (Y/n/s to skip all): `\n );\n\n if (answer === \"s\") {\n log(\" Skipping remaining account connections.\");\n log(\" You can connect anytime with: cortex-mcp connect <provider>\\n\");\n break;\n }\n\n if (answer === \"n\") {\n log(` Skipped. Connect later with: cortex-mcp connect ${mcp.name}`);\n log(\"\");\n continue;\n }\n\n // Y or Enter — proceed with OAuth\n log(\"\");\n const success = await connectProvider(\n mcp.name,\n mcp.displayName,\n apiKey,\n serverUrl,\n \"installUrl\" in mcp ? (mcp.installUrl as string) : undefined,\n );\n\n if (!success) {\n log(\n ` You can connect later with: cortex-mcp connect ${mcp.name}`\n );\n }\n log(\"\");\n }\n\n rl.close();\n}\n\n/**\n * Prompt the user for their company email when Okta email doesn't match AD.\n */\nasync function promptForEmailHint(ssoEmail: string): Promise<string | null> {\n log(\"\");\n log(` Your SSO email (${ssoEmail}) was not found in the employee directory.`);\n log(\n \" This can happen if your Okta account uses a different email than your company directory.\"\n );\n log(\"\");\n\n const rl = readline.createInterface({\n input: process.stdin,\n output: process.stderr,\n });\n\n const answer = await new Promise<string>((resolve) => {\n rl.question(\" Enter your company email address: \", (a) =>\n resolve(a.trim())\n );\n });\n rl.close();\n\n if (!answer || !answer.includes(\"@\")) {\n log(\" Invalid email. Run 'cortex-mcp login --email you@company.com' to try again.\");\n return null;\n }\n\n return answer;\n}\n\n/**\n * Log in via Okta SSO to get a personal API key.\n * Opens the browser, polls for completion, stores credentials,\n * auto-reconfigures any previously set up AI clients,\n * and prompts to connect personal MCP accounts (e.g., Asana).\n *\n * @param emailHint Optional company email (via --email flag) when Okta email differs from AD\n */\nexport async function runLogin(emailHint?: string): Promise<void> {\n // 1. Check if already logged in\n const existing = readCredentials();\n if (existing) {\n log(\"\");\n log(` Already logged in as ${existing.name || existing.email}`);\n log(\" Run 'cortex-mcp logout' first to switch accounts.\");\n log(\"\");\n return;\n }\n\n const config = readConfig();\n const serverUrl = config?.server || DEFAULT_SERVER_URL;\n\n log(\"\");\n log(\" Cortex MCP Login\");\n log(\" Sign in with your company Okta SSO account\");\n log(\"\");\n\n // 2. Run SSO flow\n let result = await loginWithSSO(serverUrl, emailHint);\n\n // 3. Handle email hint retry if AD verification failed\n if (result.status === \"needs_hint\") {\n let hintEmail: string | null;\n\n if (emailHint) {\n // --email was already provided but SSO email still didn't match\n // (this shouldn't happen since hint is passed on first try, but handle it)\n hintEmail = emailHint;\n } else {\n hintEmail = await promptForEmailHint(result.ssoEmail);\n }\n\n if (!hintEmail) {\n process.exit(1);\n }\n\n log(\"\");\n log(\" Retrying with your company email. You'll need to complete SSO again.\");\n log(\"\");\n\n result = await loginWithSSO(serverUrl, hintEmail);\n\n if (result.status === \"needs_hint\") {\n log(\"\");\n log(\" The provided email was also not found in the employee directory.\");\n log(\" Please verify your email and contact IT if the issue persists.\");\n process.exit(1);\n }\n }\n\n if (result.status !== \"success\") {\n process.exit(1);\n }\n\n const { apiKey, email, name } = result;\n\n // 3. Save credentials\n writeCredentials({\n apiKey,\n email,\n name,\n authenticatedAt: new Date().toISOString(),\n });\n\n log(` Authenticated as ${name || email}${name ? ` (${email})` : \"\"}`);\n log(\" Personal API key saved.\");\n\n // 4. Auto-reconfigure existing clients and update saved config\n const existingConfig = readConfig();\n if (existingConfig) {\n // Always update the stored API key\n existingConfig.apiKey = apiKey;\n\n // Re-configure clients if any were previously set up\n if (existingConfig.configuredClients?.length > 0) {\n log(\"\");\n log(\" Updating configured clients:\");\n\n for (const clientType of existingConfig.configuredClients) {\n try {\n configureClient(\n clientType,\n existingConfig.server || DEFAULT_SERVER_URL,\n apiKey,\n existingConfig.mcps\n );\n log(` ${clientType}: updated`);\n } catch {\n log(` ${clientType}: failed to update`);\n }\n }\n }\n\n writeConfig(existingConfig);\n }\n\n // 5. Show MCP connection status and auto-connect personal MCPs\n await showConnectionsAndAutoConnect(apiKey, serverUrl);\n\n log(\" Done! Restart your AI clients to apply.\");\n log(\"\");\n}\n","import { AVAILABLE_MCPS, DEFAULT_SERVER_URL } from \"../constants.js\";\nimport { readConfig } from \"../config/storage.js\";\nimport { readCredentials } from \"../auth/credentials.js\";\nimport { openBrowser } from \"../utils/browser.js\";\n\nfunction log(msg: string): void {\n process.stderr.write(msg + \"\\n\");\n}\n\nfunction sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n\nfunction waitForEnter(): Promise<void> {\n return new Promise((resolve) => {\n process.stdin.setRawMode?.(false);\n process.stdin.resume();\n process.stdin.once(\"data\", () => {\n process.stdin.pause();\n resolve();\n });\n });\n}\n\n/**\n * Core OAuth connect flow: initiate -> browser -> poll.\n * Reusable by both the `connect` command and the post-login auto-connect.\n *\n * Returns true on success, false on failure/timeout.\n */\nexport async function connectProvider(\n providerName: string,\n displayName: string,\n apiKey: string,\n serverUrl: string,\n installUrl?: string,\n): Promise<boolean> {\n // 1. Initiate OAuth flow\n let sessionId: string;\n let authUrl: string;\n let expiresIn: number;\n\n try {\n const resp = await fetch(\n `${serverUrl}/api/v1/oauth/connect/${providerName}/initiate`,\n {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n \"x-api-key\": apiKey,\n },\n }\n );\n\n if (!resp.ok) {\n if (resp.status === 401) {\n log(\" Error: Your session has expired. Run 'cortex-mcp login' to re-authenticate.\");\n return false;\n }\n\n const err = (await resp.json().catch(() => ({}))) as { detail?: string };\n log(` Error: ${err.detail || `HTTP ${resp.status}`}`);\n return false;\n }\n\n const data = (await resp.json()) as {\n session_id: string;\n authorization_url: string;\n expires_in: number;\n };\n sessionId = data.session_id;\n authUrl = data.authorization_url;\n expiresIn = data.expires_in;\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n log(` Error: Could not reach Cortex server at ${serverUrl}`);\n log(` ${msg}`);\n return false;\n }\n\n // 2. App installation (Monday.com requires install before authorize)\n if (installUrl) {\n log(` First, install the ${displayName} app on your account...`);\n await openBrowser(installUrl);\n log(\" If the browser didn't open, visit:\");\n log(` ${installUrl}`);\n log(\"\");\n log(\" Press Enter once the app is installed...\");\n await waitForEnter();\n log(\"\");\n }\n\n // 3. Open browser\n log(` Opening browser for ${displayName} authorization...`);\n await openBrowser(authUrl);\n log(\" If the browser didn't open, visit:\");\n log(` ${authUrl}`);\n log(\"\");\n\n // 4. Poll for completion\n const deadline = Date.now() + expiresIn * 1000;\n process.stderr.write(\" Waiting for authorization\");\n\n while (Date.now() < deadline) {\n await sleep(3000);\n\n try {\n const resp = await fetch(\n `${serverUrl}/api/v1/oauth/connect/poll/${sessionId}`,\n {\n headers: {\n \"x-api-key\": apiKey,\n },\n }\n );\n const result = (await resp.json()) as {\n status: string;\n account_email?: string;\n account_name?: string;\n error_message?: string;\n };\n\n if (result.status === \"completed\") {\n process.stderr.write(\"\\n\\n\");\n const who = result.account_email || \"unknown\";\n log(` Connected as ${who}`);\n log(` ${displayName} tools will now use your personal account.`);\n log(\"\");\n return true;\n }\n\n if (result.status === \"expired\") {\n process.stderr.write(\"\\n\");\n log(\" Authorization session expired. Please try again.\");\n return false;\n }\n\n if (result.status === \"error\") {\n process.stderr.write(\"\\n\");\n log(\n ` Connection failed: ${result.error_message || \"unknown error\"}`\n );\n return false;\n }\n\n // Still pending\n process.stderr.write(\".\");\n } catch {\n process.stderr.write(\"!\");\n }\n }\n\n process.stderr.write(\"\\n\");\n log(\" Timeout waiting for authorization. Please try again.\");\n return false;\n}\n\n/**\n * Connect a personal OAuth account (e.g., Asana) via browser-based flow.\n * CLI command handler — validates credentials and delegates to connectProvider().\n */\nexport async function runConnect(provider: string): Promise<void> {\n // 1. Verify user is logged in\n const creds = readCredentials();\n if (!creds) {\n log(\"\");\n log(\" You must be logged in first.\");\n log(\" Run: cortex-mcp login\");\n log(\"\");\n process.exit(1);\n }\n\n // 2. Validate provider\n const mcp = AVAILABLE_MCPS.find(\n (m) => m.name === provider || m.displayName.toLowerCase() === provider.toLowerCase()\n );\n if (!mcp) {\n log(\"\");\n log(` Unknown provider: ${provider}`);\n log(` Available: ${AVAILABLE_MCPS.map((m) => m.name).join(\", \")}`);\n log(\"\");\n process.exit(1);\n }\n\n const config = readConfig();\n const serverUrl = config?.server || DEFAULT_SERVER_URL;\n\n log(\"\");\n log(` Cortex MCP — Connect ${mcp.displayName}`);\n log(` Link your personal ${mcp.displayName} account`);\n log(\"\");\n\n const success = await connectProvider(\n mcp.name,\n mcp.displayName,\n creds.apiKey,\n serverUrl,\n \"installUrl\" in mcp ? (mcp.installUrl as string) : undefined,\n );\n\n if (!success) {\n process.exit(1);\n }\n}\n","import { DEFAULT_MCPS, DEFAULT_SERVER_URL, MCP_NAMES } from \"../constants.js\";\nimport { getEffectiveApiKey } from \"../auth/credentials.js\";\nimport { createConfig, writeConfig } from \"../config/storage.js\";\nimport { configureClient } from \"../config/clients.js\";\nimport type { ClientType } from \"../config/types.js\";\n\ninterface ConfigureOptions {\n key?: string;\n mcps?: string;\n client: string;\n}\n\nconst VALID_CLIENTS: Record<string, ClientType> = {\n \"claude-desktop\": \"claude-desktop\",\n \"claude-code\": \"claude-code\",\n cursor: \"cursor\",\n codex: \"codex\",\n stdio: \"stdio\",\n};\n\n/**\n * Non-interactive configure command.\n * Writes config to a specific client.\n */\nexport async function runConfigure(options: ConfigureOptions): Promise<void> {\n const key = options.key || getEffectiveApiKey();\n const { client } = options;\n\n // Validate client\n const clientType = VALID_CLIENTS[client];\n if (!clientType) {\n console.error(\n `Unknown client: ${client}. Valid options: ${Object.keys(VALID_CLIENTS).join(\", \")}`\n );\n process.exit(1);\n }\n\n // Parse MCPs\n let selectedMcps: string[];\n if (options.mcps) {\n selectedMcps = options.mcps\n .split(\",\")\n .map((s) => s.trim())\n .filter((s) => MCP_NAMES.includes(s));\n\n if (selectedMcps.length === 0) {\n console.error(\n `No valid MCPs. Available: ${MCP_NAMES.join(\", \")}`\n );\n process.exit(1);\n }\n } else {\n selectedMcps = [...DEFAULT_MCPS];\n }\n\n // Configure\n try {\n const result = configureClient(\n clientType,\n DEFAULT_SERVER_URL,\n key,\n selectedMcps\n );\n console.log(result);\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n console.error(`Failed to configure ${client}: ${msg}`);\n process.exit(1);\n }\n\n // Save config\n const config = createConfig(key, selectedMcps);\n config.configuredClients = [clientType];\n writeConfig(config);\n\n console.log(`Config saved to ~/.cortex-mcp/config.json`);\n}\n","import { readFileSync, statSync } from \"node:fs\";\nimport { Server } from \"@modelcontextprotocol/sdk/server/index.js\";\nimport { StdioServerTransport } from \"@modelcontextprotocol/sdk/server/stdio.js\";\nimport {\n CallToolRequestSchema,\n ListToolsRequestSchema,\n} from \"@modelcontextprotocol/sdk/types.js\";\nimport { CortexHttpClient } from \"./http-client.js\";\n\ninterface StdioServerOptions {\n serverUrl: string;\n apiKey: string;\n /** Use \"cortex\" for composite endpoint, or a specific MCP name */\n endpoint?: string;\n}\n\n/** Tools that support local file_path → upload interception */\nconst UPLOAD_TOOLS = new Set([\"upload_file\", \"upload_file_to_sharepoint\"]);\n\n/** Max file size for inline base64 upload via JSON-RPC (3MB).\n * 3MB raw → 4MB base64 → safely within Vercel's ~4.5MB body limit. */\nconst INLINE_UPLOAD_MAX = 3 * 1024 * 1024;\n\n/**\n * Override upload tool schemas so the LLM only sees `file_path` (not `content`).\n * This forces the LLM to pass a local file path, which the proxy handles locally\n * — no base64 encoding by the LLM, no truncation, no corruption.\n */\nfunction overrideUploadToolSchema(\n tool: Record<string, unknown>\n): Record<string, unknown> {\n const name = tool.name as string;\n const baseName = name.includes(\"__\") ? name.split(\"__\").pop()! : name;\n\n if (baseName === \"upload_file\") {\n return {\n ...tool,\n description:\n \"Upload a local file to the user's OneDrive. \" +\n \"Provide the absolute local file path — the file is read \" +\n \"and uploaded automatically. Works with any file size.\",\n inputSchema: {\n type: \"object\",\n required: [\"file_path\", \"path\"],\n properties: {\n file_path: {\n type: \"string\",\n description:\n \"Absolute path to the local file to upload \" +\n \"(e.g. '/Users/name/Documents/report.xlsx')\",\n },\n path: {\n type: \"string\",\n description:\n \"Destination path in OneDrive \" +\n \"(e.g. 'Documents/report.xlsx')\",\n },\n content_type: {\n type: \"string\",\n description: \"MIME type. Defaults to 'application/octet-stream'\",\n },\n },\n },\n };\n }\n\n if (baseName === \"upload_file_to_sharepoint\") {\n return {\n ...tool,\n description:\n \"Upload a local file to a SharePoint document library. \" +\n \"Provide the absolute local file path — the file is read \" +\n \"and uploaded automatically.\",\n inputSchema: {\n type: \"object\",\n required: [\"file_path\", \"site_id\", \"path\"],\n properties: {\n file_path: {\n type: \"string\",\n description: \"Absolute path to the local file to upload\",\n },\n site_id: {\n type: \"string\",\n description: \"SharePoint site ID\",\n },\n path: {\n type: \"string\",\n description:\n \"Destination path in the site drive \" +\n \"(e.g. 'Shared Documents/report.pdf')\",\n },\n content_type: {\n type: \"string\",\n description: \"MIME type. Defaults to 'application/octet-stream'\",\n },\n },\n },\n };\n }\n\n return tool;\n}\n\n/**\n * Handle a file upload tool call locally by reading the file from disk.\n *\n * - Small files (≤3MB): base64-encode and forward as `content` param\n * - Large files (>3MB): get an upload session URL from backend, then\n * relay 2.5MB chunks through the backend's `upload_file_chunk` tool\n * (the backend has unrestricted internet; the proxy may be sandboxed)\n */\nasync function handleLocalFileUpload(\n cortex: CortexHttpClient,\n toolName: string,\n args: Record<string, unknown>\n): Promise<{ content: Array<{ type: string; text: string }>; isError: boolean }> {\n const filePath = args.file_path as string;\n\n // Validate file exists\n let fileSize: number;\n try {\n fileSize = statSync(filePath as string).size;\n } catch {\n return {\n content: [{ type: \"text\", text: JSON.stringify({\n success: false,\n error: `File not found: ${filePath}`,\n }) }],\n isError: true,\n };\n }\n\n if (fileSize <= INLINE_UPLOAD_MAX) {\n // Small file: read, base64-encode, and forward via normal JSON-RPC\n const fileBuffer = readFileSync(filePath);\n const base64Content = fileBuffer.toString(\"base64\");\n\n const forwardArgs: Record<string, unknown> = { ...args, content: base64Content };\n delete forwardArgs.file_path;\n\n console.error(\n `[cortex-mcp] ${toolName}: reading local file (${(fileSize / 1024).toFixed(1)}KB), forwarding as base64`\n );\n\n const response = await cortex.callTool(toolName, forwardArgs);\n\n if (response.error) {\n return {\n content: [{ type: \"text\", text: response.error.message }],\n isError: true,\n };\n }\n\n return response.result as {\n content: Array<{ type: string; text: string }>;\n isError: boolean;\n };\n }\n\n // Large file: use upload session to upload directly to Microsoft Graph\n console.error(\n `[cortex-mcp] ${toolName}: large file (${(fileSize / 1024 / 1024).toFixed(1)}MB), using upload session`\n );\n\n // Step 1: Get pre-authenticated upload URL from backend\n // Preserve composite prefix (e.g. \"m365__\") so the backend routes correctly\n const prefix = toolName.includes(\"__\") ? toolName.split(\"__\")[0] + \"__\" : \"\";\n const sessionResponse = await cortex.callTool(`${prefix}create_upload_session`, {\n path: args.path,\n });\n\n if (sessionResponse.error) {\n return {\n content: [{ type: \"text\", text: sessionResponse.error.message }],\n isError: true,\n };\n }\n\n const sessionResult = sessionResponse.result as {\n content: Array<{ type: string; text: string }>;\n };\n\n let sessionData: { uploadUrl?: string };\n try {\n sessionData = JSON.parse(sessionResult.content[0].text);\n } catch {\n return {\n content: [{ type: \"text\", text: JSON.stringify({\n success: false,\n error: \"Failed to parse upload session response from backend\",\n }) }],\n isError: true,\n };\n }\n\n const uploadUrl = sessionData.uploadUrl;\n if (!uploadUrl) {\n return {\n content: [{ type: \"text\", text: JSON.stringify({\n success: false,\n error: \"Backend did not return an uploadUrl\",\n }) }],\n isError: true,\n };\n }\n\n // Step 2: Upload file in chunks through the Cortex backend.\n // We relay via the backend (which has unrestricted internet) instead of\n // uploading directly to Graph — the proxy may be in a sandboxed VM that\n // blocks outbound connections to SharePoint/Microsoft Graph.\n const fileBuffer = readFileSync(filePath);\n const chunkSize = 2.5 * 1024 * 1024; // 2.5MB → ~3.33MB base64 → within Vercel 4.5MB limit\n const total = fileBuffer.length;\n let driveItem: Record<string, unknown> = {};\n\n for (let start = 0; start < total; start += chunkSize) {\n const end = Math.min(start + chunkSize, total);\n const chunk = fileBuffer.subarray(start, end);\n const chunkBase64 = Buffer.from(chunk).toString(\"base64\");\n\n console.error(\n `[cortex-mcp] Uploading chunk ${start}-${end - 1}/${total} via backend relay`\n );\n\n const chunkResponse = await cortex.callTool(`${prefix}upload_file_chunk`, {\n upload_url: uploadUrl,\n chunk: chunkBase64,\n range_start: start,\n range_end: end - 1,\n total_size: total,\n });\n\n if (chunkResponse.error) {\n return {\n content: [{ type: \"text\", text: chunkResponse.error.message }],\n isError: true,\n };\n }\n\n const chunkResult = chunkResponse.result as {\n content: Array<{ type: string; text: string }>;\n };\n\n let chunkData: Record<string, unknown>;\n try {\n chunkData = JSON.parse(chunkResult.content[0].text) as Record<string, unknown>;\n } catch {\n return {\n content: [{ type: \"text\", text: JSON.stringify({\n success: false,\n error: \"Failed to parse chunk upload response from backend\",\n }) }],\n isError: true,\n };\n }\n\n if (!chunkData.success) {\n return {\n content: [{ type: \"text\", text: JSON.stringify(chunkData) }],\n isError: true,\n };\n }\n\n // Final chunk (200/201) contains the DriveItem\n if (chunkData.status === 200 || chunkData.status === 201) {\n driveItem = (chunkData.data as Record<string, unknown>) ?? {};\n }\n }\n\n return {\n content: [{ type: \"text\", text: JSON.stringify({\n success: true,\n file: driveItem,\n message: `Uploaded '${args.path}' (${(fileSize / 1024 / 1024).toFixed(1)}MB) via upload session`,\n }) }],\n isError: false,\n };\n}\n\n/**\n * Start a stdio MCP server that proxies all requests to the hosted Cortex server.\n * This is used by clients that only support stdio transport (e.g., OpenClaw).\n */\nexport async function startStdioServer(\n options: StdioServerOptions\n): Promise<void> {\n const { serverUrl, apiKey, endpoint = \"cortex\" } = options;\n\n const cortex = new CortexHttpClient(serverUrl, apiKey, endpoint);\n\n const server = new Server(\n { name: \"cortex-mcp\", version: \"1.0.0\" },\n { capabilities: { tools: { listChanged: false } } }\n );\n\n // Lazy initialization — runs on first request, not at startup\n let initialized = false;\n\n async function ensureInitialized(): Promise<void> {\n if (initialized) return;\n try {\n console.error(\"[cortex-mcp] Initializing backend session...\");\n await cortex.initialize();\n console.error(\"[cortex-mcp] Backend session established.\");\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n console.error(`[cortex-mcp] Backend initialization failed: ${msg}`);\n // Continue anyway — tools/list and tools/call may still work without a session\n }\n initialized = true;\n }\n\n // Forward tools/list to Cortex\n server.setRequestHandler(ListToolsRequestSchema, async () => {\n await ensureInitialized();\n const response = await cortex.listTools();\n\n if (response.error) {\n throw new Error(response.error.message);\n }\n\n const result = response.result as { tools: Record<string, unknown>[] };\n const tools = (result.tools || []).map(overrideUploadToolSchema);\n return { tools };\n });\n\n // Forward tools/call to Cortex (with local file upload interception)\n server.setRequestHandler(CallToolRequestSchema, async (request) => {\n await ensureInitialized();\n const { name, arguments: args } = request.params;\n const typedArgs = (args ?? {}) as Record<string, unknown>;\n\n // Intercept upload tools with file_path — handle locally\n // Composite endpoint prefixes tool names with \"{mcp}__\", so match on suffix\n const baseName = name.includes(\"__\") ? name.split(\"__\").pop()! : name;\n if (UPLOAD_TOOLS.has(baseName) && typedArgs.file_path) {\n return handleLocalFileUpload(cortex, name, typedArgs);\n }\n\n const response = await cortex.callTool(name, typedArgs);\n\n if (response.error) {\n return {\n content: [{ type: \"text\" as const, text: response.error.message }],\n isError: true,\n };\n }\n\n const result = response.result as {\n content: Array<{ type: string; text: string }>;\n isError: boolean;\n };\n\n return result;\n });\n\n // Connect to stdio transport immediately — do NOT block on backend init\n console.error(\"[cortex-mcp] Starting stdio server...\");\n const transport = new StdioServerTransport();\n await server.connect(transport);\n console.error(\"[cortex-mcp] Stdio server connected.\");\n}\n","import { PROTOCOL_VERSION } from \"../constants.js\";\n\n/** JSON-RPC 2.0 request */\ninterface JsonRpcRequest {\n jsonrpc: \"2.0\";\n method: string;\n params?: Record<string, unknown>;\n id: string | number;\n}\n\n/** JSON-RPC 2.0 response */\ninterface JsonRpcResponse {\n jsonrpc: \"2.0\";\n result?: unknown;\n error?: { code: number; message: string };\n id: string | number | null;\n}\n\n/**\n * HTTP client that forwards JSON-RPC 2.0 requests to the Cortex server.\n */\nexport class CortexHttpClient {\n private sessionId: string | null = null;\n private requestId = 0;\n\n constructor(\n private serverUrl: string,\n private apiKey: string,\n private endpoint: string = \"cortex\"\n ) {}\n\n /** Send an initialize request to establish a session */\n async initialize(): Promise<JsonRpcResponse> {\n const response = await this.sendRequest(\"initialize\", {\n protocolVersion: PROTOCOL_VERSION,\n capabilities: {},\n clientInfo: { name: \"cortex-mcp-proxy\", version: \"1.0.0\" },\n });\n\n // Send initialized notification (no id = notification, no response expected)\n await this.sendNotification(\"notifications/initialized\", {});\n\n return response;\n }\n\n /** List available tools */\n async listTools(): Promise<JsonRpcResponse> {\n return this.sendRequest(\"tools/list\", {});\n }\n\n /** Call a tool */\n async callTool(\n name: string,\n args: Record<string, unknown>\n ): Promise<JsonRpcResponse> {\n return this.sendRequest(\"tools/call\", { name, arguments: args });\n }\n\n /** Send a JSON-RPC request and return the response */\n private async sendRequest(\n method: string,\n params: Record<string, unknown>\n ): Promise<JsonRpcResponse> {\n const id = String(++this.requestId);\n const body: JsonRpcRequest = { jsonrpc: \"2.0\", method, params, id };\n\n const headers: Record<string, string> = {\n \"Content-Type\": \"application/json\",\n \"x-api-key\": this.apiKey,\n \"mcp-protocol-version\": PROTOCOL_VERSION,\n \"x-cortex-client\": \"cortex-mcp-stdio\",\n };\n\n if (this.sessionId) {\n headers[\"mcp-session-id\"] = this.sessionId;\n }\n\n const url = `${this.serverUrl}/mcp/${this.endpoint}`;\n const response = await fetch(url, {\n method: \"POST\",\n headers,\n body: JSON.stringify(body),\n signal: AbortSignal.timeout(60_000),\n });\n\n // Capture session ID from initialize\n const newSessionId = response.headers.get(\"mcp-session-id\");\n if (newSessionId) {\n this.sessionId = newSessionId;\n }\n\n if (!response.ok) {\n const text = await response.text();\n return {\n jsonrpc: \"2.0\",\n error: {\n code: -32000,\n message: this.humanReadableError(response.status, text),\n },\n id,\n };\n }\n\n return (await response.json()) as JsonRpcResponse;\n }\n\n /** Send a JSON-RPC notification (no response expected) */\n private async sendNotification(\n method: string,\n params: Record<string, unknown>\n ): Promise<void> {\n const body = { jsonrpc: \"2.0\", method, params };\n\n const headers: Record<string, string> = {\n \"Content-Type\": \"application/json\",\n \"x-api-key\": this.apiKey,\n \"mcp-protocol-version\": PROTOCOL_VERSION,\n \"x-cortex-client\": \"cortex-mcp-stdio\",\n };\n\n if (this.sessionId) {\n headers[\"mcp-session-id\"] = this.sessionId;\n }\n\n const url = `${this.serverUrl}/mcp/${this.endpoint}`;\n\n try {\n await fetch(url, {\n method: \"POST\",\n headers,\n body: JSON.stringify(body),\n signal: AbortSignal.timeout(10_000),\n });\n } catch {\n // Notifications are fire-and-forget\n }\n }\n\n /** Convert HTTP status codes to user-friendly messages */\n private humanReadableError(status: number, body: string): string {\n switch (status) {\n case 401:\n return \"Invalid API key. Check your key at https://aidentity.app/settings/keys\";\n case 403:\n return \"API key lacks MCP permissions. Create a new key with MCP access.\";\n case 404:\n return \"MCP endpoint not found. The server may be misconfigured.\";\n case 503:\n return \"MCP protocol is disabled on the server.\";\n default:\n return `Server error (${status}): ${body.slice(0, 200)}`;\n }\n }\n}\n","import { DEFAULT_API_KEY, DEFAULT_SERVER_URL } from \"../constants.js\";\nimport { readConfig } from \"../config/storage.js\";\nimport { startStdioServer } from \"../proxy/stdio-server.js\";\nimport { getEffectiveApiKey } from \"../auth/credentials.js\";\n\n/**\n * Start the stdio proxy server.\n * Reads API key from CORTEX_API_KEY env var or ~/.cortex-mcp/config.json.\n */\nexport async function runServe(): Promise<void> {\n // Resolve API key: env var > credentials > config file > default\n const config = readConfig();\n const serverUrl = config?.server || DEFAULT_SERVER_URL;\n const apiKey = getEffectiveApiKey();\n\n if (apiKey === DEFAULT_API_KEY) {\n process.stderr.write(\n \"Warning: Using shared API key. Personal MCPs (M365, Slack, etc.) \" +\n \"will not have access to your account.\\n\" +\n \"Run: npx @danainnovations/cortex-mcp@latest login\\n\\n\"\n );\n }\n\n // Start the stdio server (this blocks until the client disconnects)\n await startStdioServer({ serverUrl, apiKey });\n}\n","import { AVAILABLE_MCPS } from \"../constants.js\";\nimport { getConfigPath, readConfig } from \"../config/storage.js\";\nimport { readCredentials } from \"../auth/credentials.js\";\n\n/**\n * Show current Cortex MCP configuration.\n */\nexport function runStatus(): void {\n const config = readConfig();\n\n if (!config) {\n console.log(\"No configuration found. Run: npx @danainnovations/cortex-mcp setup\");\n return;\n }\n\n const maskedKey =\n config.apiKey.slice(0, 8) + \"****\" + config.apiKey.slice(-4);\n\n const creds = readCredentials();\n\n console.log(\"\");\n console.log(\" Cortex MCP Status\");\n console.log(\" -----------------\");\n\n if (creds) {\n console.log(` User: ${creds.name || creds.email}`);\n console.log(` Email: ${creds.email}`);\n } else {\n console.log(\" User: not logged in (using shared key)\");\n }\n\n console.log(` Config: ${getConfigPath()}`);\n console.log(` Server: ${config.server}`);\n console.log(` API Key: ${maskedKey}`);\n console.log(\"\");\n console.log(\" Enabled MCPs:\");\n\n for (const mcpName of config.mcps) {\n const mcp = AVAILABLE_MCPS.find((m) => m.name === mcpName);\n const display = mcp ? mcp.displayName : mcpName;\n console.log(` ${display.padEnd(15)} ${config.server}/mcp/${mcpName}`);\n }\n\n console.log(\"\");\n console.log(\" Configured Clients:\");\n\n if (config.configuredClients.length === 0) {\n console.log(\" (none)\");\n } else {\n for (const client of config.configuredClients) {\n console.log(` ${client}`);\n }\n }\n\n console.log(\"\");\n}\n","import { existsSync, unlinkSync, rmdirSync } from \"node:fs\";\nimport { resetClaudeDesktop, resetClaudeCode, resetCodex, resetCursor } from \"../config/clients.js\";\nimport { getConfigDir, getConfigPath } from \"../config/storage.js\";\n\n/**\n * Remove all Cortex MCP entries from configured clients and delete local config.\n */\nexport function runReset(): void {\n console.log(\"\");\n console.log(\" Resetting Cortex MCP configuration...\");\n\n // Reset Claude Desktop\n const desktopReset = resetClaudeDesktop();\n console.log(\n ` Claude Desktop: ${desktopReset ? \"entries removed\" : \"no entries found\"}`\n );\n\n // Reset Claude Code\n const codeReset = resetClaudeCode();\n console.log(\n ` Claude Code: ${codeReset ? \"entries removed\" : \"no entries found\"}`\n );\n\n // Reset Cursor\n const cursorReset = resetCursor();\n console.log(\n ` Cursor: ${cursorReset ? \"entries removed\" : \"no entries found\"}`\n );\n\n // Reset Codex\n const codexReset = resetCodex();\n console.log(\n ` Codex: ${codexReset ? \"entries removed\" : \"no entries found\"}`\n );\n\n // Delete local config\n const configPath = getConfigPath();\n if (existsSync(configPath)) {\n unlinkSync(configPath);\n console.log(` Config file: removed`);\n }\n\n const configDir = getConfigDir();\n try {\n rmdirSync(configDir);\n } catch {\n // Directory not empty or doesn't exist — fine\n }\n\n console.log(\"\");\n console.log(\" Done. Restart your AI clients to apply changes.\");\n console.log(\" Note: Login credentials are preserved. Run 'cortex-mcp logout' to sign out.\");\n console.log(\"\");\n}\n","import { deleteCredentials, readCredentials } from \"../auth/credentials.js\";\n\nexport function runLogout(): void {\n const creds = readCredentials();\n\n if (!creds) {\n console.log(\"\");\n console.log(\" Not currently logged in.\");\n console.log(\"\");\n return;\n }\n\n deleteCredentials();\n\n console.log(\"\");\n console.log(` Logged out (was: ${creds.email})`);\n console.log(\" MCP tools will use the shared default key.\");\n console.log(\" Run 'cortex-mcp login' to sign in again.\");\n console.log(\"\");\n}\n","import { readCredentials } from \"../auth/credentials.js\";\n\nexport function runWhoami(): void {\n const creds = readCredentials();\n\n if (!creds) {\n console.log(\"\");\n console.log(\" Not logged in. Using shared default API key.\");\n console.log(\" Run 'cortex-mcp login' to authenticate.\");\n console.log(\"\");\n return;\n }\n\n console.log(\"\");\n console.log(\" Cortex MCP Account\");\n console.log(\" ------------------\");\n if (creds.name) {\n console.log(` Name: ${creds.name}`);\n }\n console.log(` Email: ${creds.email}`);\n console.log(` Authenticated: ${creds.authenticatedAt}`);\n console.log(\n ` API Key: ${creds.apiKey.slice(0, 8)}****${creds.apiKey.slice(-4)}`\n );\n console.log(\"\");\n}\n","import { AVAILABLE_MCPS, DEFAULT_SERVER_URL } from \"../constants.js\";\nimport { readConfig } from \"../config/storage.js\";\nimport { readCredentials } from \"../auth/credentials.js\";\n\nfunction log(msg: string): void {\n process.stderr.write(msg + \"\\n\");\n}\n\ninterface MCPConnection {\n id: string;\n mcp_name: string;\n provider: string;\n account_email: string | null;\n status: string;\n is_company_default: boolean;\n}\n\n/**\n * List OAuth connections for the authenticated user.\n */\nexport async function runConnections(): Promise<void> {\n const creds = readCredentials();\n if (!creds) {\n log(\"\");\n log(\" Not logged in. Run: cortex-mcp login\");\n log(\"\");\n process.exit(1);\n }\n\n const config = readConfig();\n const serverUrl = config?.server || DEFAULT_SERVER_URL;\n\n try {\n const resp = await fetch(`${serverUrl}/api/v1/oauth/connections`, {\n headers: { \"x-api-key\": creds.apiKey },\n });\n\n if (!resp.ok) {\n log(\"\");\n log(\" Error fetching connections.\");\n log(\"\");\n process.exit(1);\n }\n\n const data = (await resp.json()) as { connections: MCPConnection[] };\n const connections = data.connections || [];\n\n log(\"\");\n log(\" Cortex MCP Connections\");\n log(\" ----------------------\");\n\n // Show status for each available MCP\n for (const mcp of AVAILABLE_MCPS) {\n const conn = connections.find((c) => c.mcp_name === mcp.name);\n\n let statusText: string;\n if (!conn) {\n statusText = \"not connected\";\n } else if (conn.is_company_default) {\n statusText = \"(company default)\";\n } else {\n statusText = conn.account_email || \"connected\";\n }\n\n log(` ${mcp.displayName.padEnd(15)} ${statusText}`);\n }\n\n log(\"\");\n log(\" Connect an account: cortex-mcp connect <provider>\");\n log(\"\");\n } catch {\n log(\"\");\n log(\" Error: Could not reach Cortex server.\");\n log(\"\");\n process.exit(1);\n }\n}\n","import { AVAILABLE_MCPS, DEFAULT_SERVER_URL } from \"../constants.js\";\nimport { readConfig } from \"../config/storage.js\";\nimport { readCredentials } from \"../auth/credentials.js\";\n\nfunction log(msg: string): void {\n process.stderr.write(msg + \"\\n\");\n}\n\ninterface MCPConnection {\n id: string;\n mcp_name: string;\n provider: string;\n account_email: string | null;\n status: string;\n is_company_default: boolean;\n}\n\n/**\n * Disconnect a personal OAuth connection for a provider.\n */\nexport async function runDisconnect(provider: string): Promise<void> {\n const creds = readCredentials();\n if (!creds) {\n log(\"\");\n log(\" Not logged in. Run: cortex-mcp login\");\n log(\"\");\n process.exit(1);\n }\n\n // Validate provider\n const mcp = AVAILABLE_MCPS.find(\n (m) => m.name === provider || m.displayName.toLowerCase() === provider.toLowerCase()\n );\n if (!mcp) {\n log(\"\");\n log(` Unknown provider: ${provider}`);\n log(` Available: ${AVAILABLE_MCPS.map((m) => m.name).join(\", \")}`);\n log(\"\");\n process.exit(1);\n }\n\n const providerName = mcp.name;\n const displayName = mcp.displayName;\n const config = readConfig();\n const serverUrl = config?.server || DEFAULT_SERVER_URL;\n\n try {\n // List connections to find the user's personal connection\n const listResp = await fetch(`${serverUrl}/api/v1/oauth/connections`, {\n headers: { \"x-api-key\": creds.apiKey },\n });\n\n if (!listResp.ok) {\n log(\"\");\n log(\" Error fetching connections.\");\n log(\"\");\n process.exit(1);\n }\n\n const listData = (await listResp.json()) as {\n connections: MCPConnection[];\n };\n const match = (listData.connections || []).find(\n (c) => c.mcp_name === providerName && !c.is_company_default\n );\n\n if (!match) {\n log(\"\");\n log(` No personal connection found for ${displayName}.`);\n log(\"\");\n process.exit(1);\n }\n\n // Disconnect\n const resp = await fetch(\n `${serverUrl}/api/v1/oauth/connections/${match.id}/disconnect`,\n {\n method: \"POST\",\n headers: { \"x-api-key\": creds.apiKey },\n }\n );\n\n if (resp.ok) {\n log(\"\");\n log(` Disconnected from ${displayName}.`);\n log(\n ` ${displayName} tools will fall back to the company default token.`\n );\n log(\"\");\n } else {\n log(\"\");\n log(\" Error disconnecting. Please try again.\");\n log(\"\");\n process.exit(1);\n }\n } catch {\n log(\"\");\n log(\" Error: Could not reach Cortex server.\");\n log(\"\");\n process.exit(1);\n }\n}\n"],"mappings":"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","names":["readline","existsSync","readFileSync","writeFileSync","mkdirSync","existsSync","mkdirSync","readFileSync","writeFileSync","existsSync","mkdirSync","readFileSync","writeFileSync","join","join","existsSync","readFileSync","mkdirSync","writeFileSync","log","sleep","rl","ask","log","readFileSync","fileBuffer","readFileSync","existsSync","unlinkSync","existsSync","unlinkSync","log","log","DEFAULT_SERVER_URL","openBrowser"]}
package/dist/index.d.ts CHANGED
@@ -45,7 +45,7 @@ interface StdioServerOptions {
45
45
  declare function startStdioServer(options: StdioServerOptions): Promise<void>;
46
46
 
47
47
  /** Supported AI client types */
48
- type ClientType = "claude-desktop" | "claude-code" | "cursor" | "stdio";
48
+ type ClientType = "claude-desktop" | "claude-code" | "cursor" | "codex" | "stdio";
49
49
  /** Stored configuration */
50
50
  interface CortexMcpConfig {
51
51
  version: number;
package/dist/index.js CHANGED
@@ -478,6 +478,10 @@ function getCursorConfigPath() {
478
478
  const home = getHomeDir();
479
479
  return join(home, ".cursor", "mcp.json");
480
480
  }
481
+ function getCodexConfigPath() {
482
+ const home = getHomeDir();
483
+ return join(home, ".codex", "config.toml");
484
+ }
481
485
 
482
486
  // src/config/storage.ts
483
487
  function getConfigDir() {
@@ -551,6 +555,14 @@ function detectClients() {
551
555
  configPath: cursorPath,
552
556
  detected: existsSync2(cursorDir)
553
557
  });
558
+ const codexPath = getCodexConfigPath();
559
+ const codexDir = dirname(codexPath);
560
+ clients.push({
561
+ type: "codex",
562
+ name: "Codex",
563
+ configPath: codexPath,
564
+ detected: existsSync2(codexDir)
565
+ });
554
566
  return clients;
555
567
  }
556
568
  function buildHttpEntries(serverUrl, apiKey, mcps) {
@@ -643,6 +655,48 @@ function generateStdioSnippet(_apiKey) {
643
655
  };
644
656
  return JSON.stringify(config, null, 2);
645
657
  }
658
+ function removeCortexTomlSections(content) {
659
+ const lines = content.split("\n");
660
+ const result = [];
661
+ let skipping = false;
662
+ for (const line of lines) {
663
+ const trimmed = line.trim();
664
+ if (trimmed.startsWith("[")) {
665
+ skipping = /^\[mcp_servers\.cortex[_-]/.test(trimmed) || trimmed === "[mcp_servers.cortex]";
666
+ }
667
+ if (!skipping) {
668
+ result.push(line);
669
+ }
670
+ }
671
+ return result.join("\n");
672
+ }
673
+ function configureCodex(serverUrl, apiKey, mcps) {
674
+ const configPath = getCodexConfigPath();
675
+ const dir = dirname(configPath);
676
+ if (!existsSync2(dir)) {
677
+ mkdirSync2(dir, { recursive: true });
678
+ }
679
+ let content = "";
680
+ if (existsSync2(configPath)) {
681
+ try {
682
+ content = readFileSync3(configPath, "utf-8");
683
+ } catch {
684
+ }
685
+ }
686
+ content = removeCortexTomlSections(content);
687
+ const sections = [];
688
+ for (const mcp of AVAILABLE_MCPS) {
689
+ if (!mcps.includes(mcp.name)) continue;
690
+ sections.push(`[mcp_servers.${mcp.serverName}]`);
691
+ sections.push(`url = "${serverUrl}/mcp/${mcp.name}"`);
692
+ sections.push(`[mcp_servers.${mcp.serverName}.http_headers]`);
693
+ sections.push(`"x-api-key" = "${apiKey}"`);
694
+ sections.push("");
695
+ }
696
+ const trimmed = content.trimEnd();
697
+ const newContent = trimmed ? trimmed + "\n\n" + sections.join("\n") + "\n" : sections.join("\n") + "\n";
698
+ writeFileSync2(configPath, newContent);
699
+ }
646
700
  function configureClient(clientType, serverUrl, apiKey, mcps) {
647
701
  switch (clientType) {
648
702
  case "claude-desktop":
@@ -654,6 +708,9 @@ function configureClient(clientType, serverUrl, apiKey, mcps) {
654
708
  case "cursor":
655
709
  configureCursor(serverUrl, apiKey, mcps);
656
710
  return "Cursor configured";
711
+ case "codex":
712
+ configureCodex(serverUrl, apiKey, mcps);
713
+ return "Codex configured";
657
714
  case "stdio":
658
715
  return "Add this to your client config:\n\n" + generateStdioSnippet(apiKey);
659
716
  }
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/constants.ts","../src/proxy/http-client.ts","../src/proxy/stdio-server.ts","../src/config/storage.ts","../src/utils/platform.ts","../src/config/clients.ts","../src/utils/validation.ts","../src/auth/credentials.ts","../src/client/mcp-namespace.ts","../src/client/cortex-client.ts"],"sourcesContent":["/** Default Cortex server URL */\nexport const DEFAULT_SERVER_URL = \"https://cortex-bice.vercel.app\";\n\n/** MCP protocol version supported by Cortex (Streamable HTTP) */\nexport const PROTOCOL_VERSION = \"2025-03-26\";\n\n/** Available MCPs with their metadata */\nexport const AVAILABLE_MCPS = [\n {\n name: \"asana\",\n displayName: \"Asana\",\n description: \"Projects, tasks, teams, workspaces (17 tools)\",\n serverName: \"cortex-asana\",\n authMode: \"personal\" as const,\n },\n {\n name: \"github\",\n displayName: \"GitHub\",\n description: \"Repos, PRs, issues, branches, code review (30 tools)\",\n serverName: \"cortex-github\",\n authMode: \"company\" as const,\n },\n {\n name: \"vercel\",\n displayName: \"Vercel\",\n description: \"Deployments, projects, env vars (15 tools)\",\n serverName: \"cortex-vercel\",\n authMode: \"company\" as const,\n },\n {\n name: \"supabase\",\n displayName: \"Supabase\",\n description: \"Database, migrations, edge functions (20+ tools)\",\n serverName: \"cortex-supabase\",\n authMode: \"company\" as const,\n },\n {\n name: \"m365\",\n displayName: \"Microsoft 365\",\n description: \"Email, calendar, OneDrive, Teams, meetings, contacts, tasks, notes (33 tools)\",\n serverName: \"cortex-m365\",\n authMode: \"personal\" as const,\n },\n {\n name: \"mailchimp\",\n displayName: \"Mailchimp\",\n description: \"Audiences, contacts, campaigns, templates, analytics (28 tools)\",\n serverName: \"cortex-mailchimp\",\n authMode: \"personal\" as const,\n },\n {\n name: \"salesforce\",\n displayName: \"Salesforce\",\n description: \"CRM queries, records, reports, and org data (14 tools)\",\n serverName: \"cortex-salesforce\",\n authMode: \"personal\" as const,\n },\n {\n name: \"monday\",\n displayName: \"Monday.com\",\n description: \"Boards, items, groups, updates, workspaces (18 tools)\",\n serverName: \"cortex-monday\",\n authMode: \"personal\" as const,\n installUrl: \"https://auth.monday.com/oauth2/authorize?client_id=c8d2c70bd792a4c36c6f023c0b707517&response_type=install\",\n },\n {\n name: \"slack\",\n displayName: \"Slack\",\n description: \"Messaging, channels, search, reactions, bookmarks (22 tools)\",\n serverName: \"cortex-slack\",\n authMode: \"personal\" as const,\n },\n {\n name: \"powerbi\",\n displayName: \"Power BI\",\n description: \"Workspaces, datasets, push data, DAX queries, reports, dashboards (14 tools)\",\n serverName: \"cortex-powerbi\",\n authMode: \"personal\" as const,\n },\n {\n name: \"bestbuy\",\n displayName: \"Best Buy\",\n description: \"Product search, pricing, reviews, store locations (7 tools)\",\n serverName: \"cortex-bestbuy\",\n authMode: \"company\" as const,\n },\n] as const;\n\n/** All available MCP names */\nexport const MCP_NAMES: string[] = AVAILABLE_MCPS.map((m) => m.name);\n\n/** Default MCPs enabled on fresh setup */\nexport const DEFAULT_MCPS: string[] = [...MCP_NAMES];\n\n/** Shared API key embedded in the package (no user prompt needed) */\nexport const DEFAULT_API_KEY =\n \"ctx_07d37a81_9f7be06af38d04753090a4034f907a65ec06cd675ed26f65653898388e2d1709\";\n\n/** Config directory name */\nexport const CONFIG_DIR_NAME = \".cortex-mcp\";\n\n/** Config file name */\nexport const CONFIG_FILE_NAME = \"config.json\";\n\n/** Credentials file name (stores personal API key from login) */\nexport const CREDENTIALS_FILE_NAME = \"credentials.json\";\n","import { PROTOCOL_VERSION } from \"../constants.js\";\n\n/** JSON-RPC 2.0 request */\ninterface JsonRpcRequest {\n jsonrpc: \"2.0\";\n method: string;\n params?: Record<string, unknown>;\n id: string | number;\n}\n\n/** JSON-RPC 2.0 response */\ninterface JsonRpcResponse {\n jsonrpc: \"2.0\";\n result?: unknown;\n error?: { code: number; message: string };\n id: string | number | null;\n}\n\n/**\n * HTTP client that forwards JSON-RPC 2.0 requests to the Cortex server.\n */\nexport class CortexHttpClient {\n private sessionId: string | null = null;\n private requestId = 0;\n\n constructor(\n private serverUrl: string,\n private apiKey: string,\n private endpoint: string = \"cortex\"\n ) {}\n\n /** Send an initialize request to establish a session */\n async initialize(): Promise<JsonRpcResponse> {\n const response = await this.sendRequest(\"initialize\", {\n protocolVersion: PROTOCOL_VERSION,\n capabilities: {},\n clientInfo: { name: \"cortex-mcp-proxy\", version: \"1.0.0\" },\n });\n\n // Send initialized notification (no id = notification, no response expected)\n await this.sendNotification(\"notifications/initialized\", {});\n\n return response;\n }\n\n /** List available tools */\n async listTools(): Promise<JsonRpcResponse> {\n return this.sendRequest(\"tools/list\", {});\n }\n\n /** Call a tool */\n async callTool(\n name: string,\n args: Record<string, unknown>\n ): Promise<JsonRpcResponse> {\n return this.sendRequest(\"tools/call\", { name, arguments: args });\n }\n\n /** Send a JSON-RPC request and return the response */\n private async sendRequest(\n method: string,\n params: Record<string, unknown>\n ): Promise<JsonRpcResponse> {\n const id = String(++this.requestId);\n const body: JsonRpcRequest = { jsonrpc: \"2.0\", method, params, id };\n\n const headers: Record<string, string> = {\n \"Content-Type\": \"application/json\",\n \"x-api-key\": this.apiKey,\n \"mcp-protocol-version\": PROTOCOL_VERSION,\n \"x-cortex-client\": \"cortex-mcp-stdio\",\n };\n\n if (this.sessionId) {\n headers[\"mcp-session-id\"] = this.sessionId;\n }\n\n const url = `${this.serverUrl}/mcp/${this.endpoint}`;\n const response = await fetch(url, {\n method: \"POST\",\n headers,\n body: JSON.stringify(body),\n signal: AbortSignal.timeout(60_000),\n });\n\n // Capture session ID from initialize\n const newSessionId = response.headers.get(\"mcp-session-id\");\n if (newSessionId) {\n this.sessionId = newSessionId;\n }\n\n if (!response.ok) {\n const text = await response.text();\n return {\n jsonrpc: \"2.0\",\n error: {\n code: -32000,\n message: this.humanReadableError(response.status, text),\n },\n id,\n };\n }\n\n return (await response.json()) as JsonRpcResponse;\n }\n\n /** Send a JSON-RPC notification (no response expected) */\n private async sendNotification(\n method: string,\n params: Record<string, unknown>\n ): Promise<void> {\n const body = { jsonrpc: \"2.0\", method, params };\n\n const headers: Record<string, string> = {\n \"Content-Type\": \"application/json\",\n \"x-api-key\": this.apiKey,\n \"mcp-protocol-version\": PROTOCOL_VERSION,\n \"x-cortex-client\": \"cortex-mcp-stdio\",\n };\n\n if (this.sessionId) {\n headers[\"mcp-session-id\"] = this.sessionId;\n }\n\n const url = `${this.serverUrl}/mcp/${this.endpoint}`;\n\n try {\n await fetch(url, {\n method: \"POST\",\n headers,\n body: JSON.stringify(body),\n signal: AbortSignal.timeout(10_000),\n });\n } catch {\n // Notifications are fire-and-forget\n }\n }\n\n /** Convert HTTP status codes to user-friendly messages */\n private humanReadableError(status: number, body: string): string {\n switch (status) {\n case 401:\n return \"Invalid API key. Check your key at https://aidentity.app/settings/keys\";\n case 403:\n return \"API key lacks MCP permissions. Create a new key with MCP access.\";\n case 404:\n return \"MCP endpoint not found. The server may be misconfigured.\";\n case 503:\n return \"MCP protocol is disabled on the server.\";\n default:\n return `Server error (${status}): ${body.slice(0, 200)}`;\n }\n }\n}\n","import { readFileSync, statSync } from \"node:fs\";\nimport { Server } from \"@modelcontextprotocol/sdk/server/index.js\";\nimport { StdioServerTransport } from \"@modelcontextprotocol/sdk/server/stdio.js\";\nimport {\n CallToolRequestSchema,\n ListToolsRequestSchema,\n} from \"@modelcontextprotocol/sdk/types.js\";\nimport { CortexHttpClient } from \"./http-client.js\";\n\ninterface StdioServerOptions {\n serverUrl: string;\n apiKey: string;\n /** Use \"cortex\" for composite endpoint, or a specific MCP name */\n endpoint?: string;\n}\n\n/** Tools that support local file_path → upload interception */\nconst UPLOAD_TOOLS = new Set([\"upload_file\", \"upload_file_to_sharepoint\"]);\n\n/** Max file size for inline base64 upload via JSON-RPC (3MB).\n * 3MB raw → 4MB base64 → safely within Vercel's ~4.5MB body limit. */\nconst INLINE_UPLOAD_MAX = 3 * 1024 * 1024;\n\n/**\n * Override upload tool schemas so the LLM only sees `file_path` (not `content`).\n * This forces the LLM to pass a local file path, which the proxy handles locally\n * — no base64 encoding by the LLM, no truncation, no corruption.\n */\nfunction overrideUploadToolSchema(\n tool: Record<string, unknown>\n): Record<string, unknown> {\n const name = tool.name as string;\n const baseName = name.includes(\"__\") ? name.split(\"__\").pop()! : name;\n\n if (baseName === \"upload_file\") {\n return {\n ...tool,\n description:\n \"Upload a local file to the user's OneDrive. \" +\n \"Provide the absolute local file path — the file is read \" +\n \"and uploaded automatically. Works with any file size.\",\n inputSchema: {\n type: \"object\",\n required: [\"file_path\", \"path\"],\n properties: {\n file_path: {\n type: \"string\",\n description:\n \"Absolute path to the local file to upload \" +\n \"(e.g. '/Users/name/Documents/report.xlsx')\",\n },\n path: {\n type: \"string\",\n description:\n \"Destination path in OneDrive \" +\n \"(e.g. 'Documents/report.xlsx')\",\n },\n content_type: {\n type: \"string\",\n description: \"MIME type. Defaults to 'application/octet-stream'\",\n },\n },\n },\n };\n }\n\n if (baseName === \"upload_file_to_sharepoint\") {\n return {\n ...tool,\n description:\n \"Upload a local file to a SharePoint document library. \" +\n \"Provide the absolute local file path — the file is read \" +\n \"and uploaded automatically.\",\n inputSchema: {\n type: \"object\",\n required: [\"file_path\", \"site_id\", \"path\"],\n properties: {\n file_path: {\n type: \"string\",\n description: \"Absolute path to the local file to upload\",\n },\n site_id: {\n type: \"string\",\n description: \"SharePoint site ID\",\n },\n path: {\n type: \"string\",\n description:\n \"Destination path in the site drive \" +\n \"(e.g. 'Shared Documents/report.pdf')\",\n },\n content_type: {\n type: \"string\",\n description: \"MIME type. Defaults to 'application/octet-stream'\",\n },\n },\n },\n };\n }\n\n return tool;\n}\n\n/**\n * Handle a file upload tool call locally by reading the file from disk.\n *\n * - Small files (≤3MB): base64-encode and forward as `content` param\n * - Large files (>3MB): get an upload session URL from backend, then\n * relay 2.5MB chunks through the backend's `upload_file_chunk` tool\n * (the backend has unrestricted internet; the proxy may be sandboxed)\n */\nasync function handleLocalFileUpload(\n cortex: CortexHttpClient,\n toolName: string,\n args: Record<string, unknown>\n): Promise<{ content: Array<{ type: string; text: string }>; isError: boolean }> {\n const filePath = args.file_path as string;\n\n // Validate file exists\n let fileSize: number;\n try {\n fileSize = statSync(filePath as string).size;\n } catch {\n return {\n content: [{ type: \"text\", text: JSON.stringify({\n success: false,\n error: `File not found: ${filePath}`,\n }) }],\n isError: true,\n };\n }\n\n if (fileSize <= INLINE_UPLOAD_MAX) {\n // Small file: read, base64-encode, and forward via normal JSON-RPC\n const fileBuffer = readFileSync(filePath);\n const base64Content = fileBuffer.toString(\"base64\");\n\n const forwardArgs: Record<string, unknown> = { ...args, content: base64Content };\n delete forwardArgs.file_path;\n\n console.error(\n `[cortex-mcp] ${toolName}: reading local file (${(fileSize / 1024).toFixed(1)}KB), forwarding as base64`\n );\n\n const response = await cortex.callTool(toolName, forwardArgs);\n\n if (response.error) {\n return {\n content: [{ type: \"text\", text: response.error.message }],\n isError: true,\n };\n }\n\n return response.result as {\n content: Array<{ type: string; text: string }>;\n isError: boolean;\n };\n }\n\n // Large file: use upload session to upload directly to Microsoft Graph\n console.error(\n `[cortex-mcp] ${toolName}: large file (${(fileSize / 1024 / 1024).toFixed(1)}MB), using upload session`\n );\n\n // Step 1: Get pre-authenticated upload URL from backend\n // Preserve composite prefix (e.g. \"m365__\") so the backend routes correctly\n const prefix = toolName.includes(\"__\") ? toolName.split(\"__\")[0] + \"__\" : \"\";\n const sessionResponse = await cortex.callTool(`${prefix}create_upload_session`, {\n path: args.path,\n });\n\n if (sessionResponse.error) {\n return {\n content: [{ type: \"text\", text: sessionResponse.error.message }],\n isError: true,\n };\n }\n\n const sessionResult = sessionResponse.result as {\n content: Array<{ type: string; text: string }>;\n };\n\n let sessionData: { uploadUrl?: string };\n try {\n sessionData = JSON.parse(sessionResult.content[0].text);\n } catch {\n return {\n content: [{ type: \"text\", text: JSON.stringify({\n success: false,\n error: \"Failed to parse upload session response from backend\",\n }) }],\n isError: true,\n };\n }\n\n const uploadUrl = sessionData.uploadUrl;\n if (!uploadUrl) {\n return {\n content: [{ type: \"text\", text: JSON.stringify({\n success: false,\n error: \"Backend did not return an uploadUrl\",\n }) }],\n isError: true,\n };\n }\n\n // Step 2: Upload file in chunks through the Cortex backend.\n // We relay via the backend (which has unrestricted internet) instead of\n // uploading directly to Graph — the proxy may be in a sandboxed VM that\n // blocks outbound connections to SharePoint/Microsoft Graph.\n const fileBuffer = readFileSync(filePath);\n const chunkSize = 2.5 * 1024 * 1024; // 2.5MB → ~3.33MB base64 → within Vercel 4.5MB limit\n const total = fileBuffer.length;\n let driveItem: Record<string, unknown> = {};\n\n for (let start = 0; start < total; start += chunkSize) {\n const end = Math.min(start + chunkSize, total);\n const chunk = fileBuffer.subarray(start, end);\n const chunkBase64 = Buffer.from(chunk).toString(\"base64\");\n\n console.error(\n `[cortex-mcp] Uploading chunk ${start}-${end - 1}/${total} via backend relay`\n );\n\n const chunkResponse = await cortex.callTool(`${prefix}upload_file_chunk`, {\n upload_url: uploadUrl,\n chunk: chunkBase64,\n range_start: start,\n range_end: end - 1,\n total_size: total,\n });\n\n if (chunkResponse.error) {\n return {\n content: [{ type: \"text\", text: chunkResponse.error.message }],\n isError: true,\n };\n }\n\n const chunkResult = chunkResponse.result as {\n content: Array<{ type: string; text: string }>;\n };\n\n let chunkData: Record<string, unknown>;\n try {\n chunkData = JSON.parse(chunkResult.content[0].text) as Record<string, unknown>;\n } catch {\n return {\n content: [{ type: \"text\", text: JSON.stringify({\n success: false,\n error: \"Failed to parse chunk upload response from backend\",\n }) }],\n isError: true,\n };\n }\n\n if (!chunkData.success) {\n return {\n content: [{ type: \"text\", text: JSON.stringify(chunkData) }],\n isError: true,\n };\n }\n\n // Final chunk (200/201) contains the DriveItem\n if (chunkData.status === 200 || chunkData.status === 201) {\n driveItem = (chunkData.data as Record<string, unknown>) ?? {};\n }\n }\n\n return {\n content: [{ type: \"text\", text: JSON.stringify({\n success: true,\n file: driveItem,\n message: `Uploaded '${args.path}' (${(fileSize / 1024 / 1024).toFixed(1)}MB) via upload session`,\n }) }],\n isError: false,\n };\n}\n\n/**\n * Start a stdio MCP server that proxies all requests to the hosted Cortex server.\n * This is used by clients that only support stdio transport (e.g., OpenClaw).\n */\nexport async function startStdioServer(\n options: StdioServerOptions\n): Promise<void> {\n const { serverUrl, apiKey, endpoint = \"cortex\" } = options;\n\n const cortex = new CortexHttpClient(serverUrl, apiKey, endpoint);\n\n const server = new Server(\n { name: \"cortex-mcp\", version: \"1.0.0\" },\n { capabilities: { tools: { listChanged: false } } }\n );\n\n // Lazy initialization — runs on first request, not at startup\n let initialized = false;\n\n async function ensureInitialized(): Promise<void> {\n if (initialized) return;\n try {\n console.error(\"[cortex-mcp] Initializing backend session...\");\n await cortex.initialize();\n console.error(\"[cortex-mcp] Backend session established.\");\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n console.error(`[cortex-mcp] Backend initialization failed: ${msg}`);\n // Continue anyway — tools/list and tools/call may still work without a session\n }\n initialized = true;\n }\n\n // Forward tools/list to Cortex\n server.setRequestHandler(ListToolsRequestSchema, async () => {\n await ensureInitialized();\n const response = await cortex.listTools();\n\n if (response.error) {\n throw new Error(response.error.message);\n }\n\n const result = response.result as { tools: Record<string, unknown>[] };\n const tools = (result.tools || []).map(overrideUploadToolSchema);\n return { tools };\n });\n\n // Forward tools/call to Cortex (with local file upload interception)\n server.setRequestHandler(CallToolRequestSchema, async (request) => {\n await ensureInitialized();\n const { name, arguments: args } = request.params;\n const typedArgs = (args ?? {}) as Record<string, unknown>;\n\n // Intercept upload tools with file_path — handle locally\n // Composite endpoint prefixes tool names with \"{mcp}__\", so match on suffix\n const baseName = name.includes(\"__\") ? name.split(\"__\").pop()! : name;\n if (UPLOAD_TOOLS.has(baseName) && typedArgs.file_path) {\n return handleLocalFileUpload(cortex, name, typedArgs);\n }\n\n const response = await cortex.callTool(name, typedArgs);\n\n if (response.error) {\n return {\n content: [{ type: \"text\" as const, text: response.error.message }],\n isError: true,\n };\n }\n\n const result = response.result as {\n content: Array<{ type: string; text: string }>;\n isError: boolean;\n };\n\n return result;\n });\n\n // Connect to stdio transport immediately — do NOT block on backend init\n console.error(\"[cortex-mcp] Starting stdio server...\");\n const transport = new StdioServerTransport();\n await server.connect(transport);\n console.error(\"[cortex-mcp] Stdio server connected.\");\n}\n","import { existsSync, mkdirSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport { CONFIG_DIR_NAME, CONFIG_FILE_NAME, DEFAULT_SERVER_URL } from \"../constants.js\";\nimport { getHomeDir } from \"../utils/platform.js\";\nimport type { CortexMcpConfig } from \"./types.js\";\n\n/** Get the config directory path */\nexport function getConfigDir(): string {\n return join(getHomeDir(), CONFIG_DIR_NAME);\n}\n\n/** Get the config file path */\nexport function getConfigPath(): string {\n return join(getConfigDir(), CONFIG_FILE_NAME);\n}\n\n/** Read the current config, or return null if none exists */\nexport function readConfig(): CortexMcpConfig | null {\n const path = getConfigPath();\n if (!existsSync(path)) return null;\n\n try {\n const raw = readFileSync(path, \"utf-8\");\n return JSON.parse(raw) as CortexMcpConfig;\n } catch {\n return null;\n }\n}\n\n/** Write config to disk (creates directory with 700 permissions, file with 600) */\nexport function writeConfig(config: CortexMcpConfig): void {\n const dir = getConfigDir();\n if (!existsSync(dir)) {\n mkdirSync(dir, { recursive: true, mode: 0o700 });\n }\n\n const path = getConfigPath();\n writeFileSync(path, JSON.stringify(config, null, 2) + \"\\n\", {\n mode: 0o600,\n });\n}\n\n/** Create a default config with the given API key and MCPs */\nexport function createConfig(\n apiKey: string,\n mcps: string[]\n): CortexMcpConfig {\n return {\n version: 1,\n server: DEFAULT_SERVER_URL,\n apiKey,\n mcps,\n configuredClients: [],\n };\n}\n","import { homedir, platform } from \"node:os\";\nimport { join } from \"node:path\";\n\n/** Get the user's home directory */\nexport function getHomeDir(): string {\n return homedir();\n}\n\n/** Get the current platform */\nexport function getPlatform(): \"macos\" | \"windows\" | \"linux\" {\n const p = platform();\n if (p === \"darwin\") return \"macos\";\n if (p === \"win32\") return \"windows\";\n return \"linux\";\n}\n\n/**\n * Get the Claude Desktop config file path for the current platform.\n */\nexport function getClaudeDesktopConfigPath(): string {\n const home = getHomeDir();\n const p = getPlatform();\n\n switch (p) {\n case \"macos\":\n return join(\n home,\n \"Library\",\n \"Application Support\",\n \"Claude\",\n \"claude_desktop_config.json\"\n );\n case \"windows\":\n return join(\n process.env.APPDATA || join(home, \"AppData\", \"Roaming\"),\n \"Claude\",\n \"claude_desktop_config.json\"\n );\n case \"linux\":\n return join(home, \".config\", \"Claude\", \"claude_desktop_config.json\");\n }\n}\n\n/**\n * Get the Cursor MCP config file path for the current platform.\n */\nexport function getCursorConfigPath(): string {\n const home = getHomeDir();\n return join(home, \".cursor\", \"mcp.json\");\n}\n","import { existsSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { dirname } from \"node:path\";\nimport { mkdirSync } from \"node:fs\";\nimport { execSync } from \"node:child_process\";\nimport { AVAILABLE_MCPS } from \"../constants.js\";\nimport {\n getClaudeDesktopConfigPath,\n getCursorConfigPath,\n} from \"../utils/platform.js\";\nimport type { ClientType, DetectedClient, HttpMcpEntry } from \"./types.js\";\n\n/**\n * Detect which AI clients are installed on this machine.\n */\nexport function detectClients(): DetectedClient[] {\n const clients: DetectedClient[] = [];\n\n // Claude Desktop\n const desktopPath = getClaudeDesktopConfigPath();\n const desktopDir = dirname(desktopPath);\n clients.push({\n type: \"claude-desktop\",\n name: \"Claude Desktop\",\n configPath: desktopPath,\n detected: existsSync(desktopDir),\n });\n\n // Claude Code\n let claudeCodeDetected = false;\n try {\n execSync(\"which claude\", { stdio: \"pipe\" });\n claudeCodeDetected = true;\n } catch {\n // claude CLI not in PATH\n }\n clients.push({\n type: \"claude-code\",\n name: \"Claude Code\",\n configPath: null,\n detected: claudeCodeDetected,\n });\n\n // Cursor\n const cursorPath = getCursorConfigPath();\n const cursorDir = dirname(cursorPath);\n clients.push({\n type: \"cursor\",\n name: \"Cursor\",\n configPath: cursorPath,\n detected: existsSync(cursorDir),\n });\n\n return clients;\n}\n\n/**\n * Build per-MCP HTTP entries for a given server URL and API key.\n */\nexport function buildHttpEntries(\n serverUrl: string,\n apiKey: string,\n mcps: string[]\n): Record<string, HttpMcpEntry> {\n const entries: Record<string, HttpMcpEntry> = {};\n\n for (const mcp of AVAILABLE_MCPS) {\n if (!mcps.includes(mcp.name)) continue;\n entries[mcp.serverName] = {\n url: `${serverUrl}/mcp/${mcp.name}`,\n headers: { \"x-api-key\": apiKey },\n };\n }\n\n return entries;\n}\n\n/**\n * Configure Claude Desktop by merging a stdio proxy entry into its config file.\n * Uses command/args/env format (Claude Desktop does not support HTTP url/headers).\n * Preserves existing non-Cortex entries.\n */\nexport function configureClaudeDesktop(\n _serverUrl: string,\n apiKey: string,\n _mcps: string[]\n): void {\n const configPath = getClaudeDesktopConfigPath();\n const dir = dirname(configPath);\n\n // Ensure directory exists\n if (!existsSync(dir)) {\n mkdirSync(dir, { recursive: true });\n }\n\n // Read existing config or start fresh\n let config: Record<string, unknown> = {};\n if (existsSync(configPath)) {\n try {\n config = JSON.parse(readFileSync(configPath, \"utf-8\"));\n } catch {\n // Corrupted file — start fresh\n }\n }\n\n // Ensure mcpServers key exists\n if (!config.mcpServers || typeof config.mcpServers !== \"object\") {\n config.mcpServers = {};\n }\n\n const servers = config.mcpServers as Record<string, unknown>;\n\n // Remove existing cortex-* and cortex entries\n for (const key of Object.keys(servers)) {\n if (key.startsWith(\"cortex-\") || key === \"cortex\") {\n delete servers[key];\n }\n }\n\n // Add stdio proxy entry (Claude Desktop only supports command/args)\n // API key is read from ~/.cortex-mcp/credentials.json at runtime by the serve command,\n // so we don't bake it into the env (avoids stale key issues on re-login).\n servers[\"cortex\"] = {\n command: \"npx\",\n args: [\"-y\", \"@danainnovations/cortex-mcp@latest\", \"serve\"],\n };\n\n writeFileSync(configPath, JSON.stringify(config, null, 2) + \"\\n\");\n}\n\n/**\n * Configure Claude Code by running `claude mcp add` commands.\n */\nexport function configureClaudeCode(\n serverUrl: string,\n apiKey: string,\n mcps: string[]\n): void {\n for (const mcp of AVAILABLE_MCPS) {\n if (!mcps.includes(mcp.name)) continue;\n\n const url = `${serverUrl}/mcp/${mcp.name}`;\n\n // Remove existing entry first (ignore errors if it doesn't exist)\n try {\n execSync(`claude mcp remove ${mcp.serverName}`, { stdio: \"pipe\" });\n } catch {\n // Entry didn't exist — fine\n }\n\n execSync(\n `claude mcp add --transport http ${mcp.serverName} ${url} -H \"x-api-key: ${apiKey}\"`,\n { stdio: \"pipe\" }\n );\n }\n}\n\n/**\n * Configure Cursor by writing HTTP MCP entries to its config file.\n * Cursor supports HTTP transport natively.\n */\nexport function configureCursor(\n serverUrl: string,\n apiKey: string,\n mcps: string[]\n): void {\n const configPath = getCursorConfigPath();\n const dir = dirname(configPath);\n\n if (!existsSync(dir)) {\n mkdirSync(dir, { recursive: true });\n }\n\n let config: Record<string, unknown> = {};\n if (existsSync(configPath)) {\n try {\n config = JSON.parse(readFileSync(configPath, \"utf-8\"));\n } catch {\n // Corrupted file — start fresh\n }\n }\n\n if (!config.mcpServers || typeof config.mcpServers !== \"object\") {\n config.mcpServers = {};\n }\n\n const servers = config.mcpServers as Record<string, unknown>;\n\n // Remove existing cortex-* entries\n for (const key of Object.keys(servers)) {\n if (key.startsWith(\"cortex-\")) {\n delete servers[key];\n }\n }\n\n // Add new HTTP entries\n const entries = buildHttpEntries(serverUrl, apiKey, mcps);\n Object.assign(servers, entries);\n\n writeFileSync(configPath, JSON.stringify(config, null, 2) + \"\\n\");\n}\n\n/**\n * Generate a stdio config snippet for clients that need it (OpenClaw, etc.)\n */\nexport function generateStdioSnippet(_apiKey: string): string {\n const config = {\n mcpServers: {\n cortex: {\n command: \"npx\",\n args: [\"-y\", \"@danainnovations/cortex-mcp@latest\", \"serve\"],\n },\n },\n };\n return JSON.stringify(config, null, 2);\n}\n\n/**\n * Remove all cortex-* MCP entries from Claude Desktop config.\n */\nexport function resetClaudeDesktop(): boolean {\n const configPath = getClaudeDesktopConfigPath();\n if (!existsSync(configPath)) return false;\n\n try {\n const config = JSON.parse(readFileSync(configPath, \"utf-8\"));\n if (!config.mcpServers) return false;\n\n const servers = config.mcpServers as Record<string, unknown>;\n let removed = false;\n for (const key of Object.keys(servers)) {\n if (key.startsWith(\"cortex-\") || key === \"cortex\") {\n delete servers[key];\n removed = true;\n }\n }\n\n if (removed) {\n writeFileSync(configPath, JSON.stringify(config, null, 2) + \"\\n\");\n }\n return removed;\n } catch {\n return false;\n }\n}\n\n/**\n * Remove cortex MCP entries from Cursor config.\n */\nexport function resetCursor(): boolean {\n const configPath = getCursorConfigPath();\n if (!existsSync(configPath)) return false;\n\n try {\n const config = JSON.parse(readFileSync(configPath, \"utf-8\"));\n if (!config.mcpServers) return false;\n\n const servers = config.mcpServers as Record<string, unknown>;\n let removed = false;\n for (const key of Object.keys(servers)) {\n if (key.startsWith(\"cortex-\") || key === \"cortex\") {\n delete servers[key];\n removed = true;\n }\n }\n\n if (removed) {\n writeFileSync(configPath, JSON.stringify(config, null, 2) + \"\\n\");\n }\n return removed;\n } catch {\n return false;\n }\n}\n\n/**\n * Remove cortex MCP entries from Claude Code.\n */\nexport function resetClaudeCode(): boolean {\n let removed = false;\n for (const mcp of AVAILABLE_MCPS) {\n try {\n execSync(`claude mcp remove ${mcp.serverName}`, { stdio: \"pipe\" });\n removed = true;\n } catch {\n // Entry didn't exist\n }\n }\n return removed;\n}\n\n/**\n * Configure a specific client type.\n */\nexport function configureClient(\n clientType: ClientType,\n serverUrl: string,\n apiKey: string,\n mcps: string[]\n): string {\n switch (clientType) {\n case \"claude-desktop\":\n configureClaudeDesktop(serverUrl, apiKey, mcps);\n return \"Claude Desktop configured\";\n case \"claude-code\":\n configureClaudeCode(serverUrl, apiKey, mcps);\n return \"Claude Code configured\";\n case \"cursor\":\n configureCursor(serverUrl, apiKey, mcps);\n return \"Cursor configured\";\n case \"stdio\":\n return (\n \"Add this to your client config:\\n\\n\" +\n generateStdioSnippet(apiKey)\n );\n }\n}\n","/**\n * Validate that a string looks like a Cortex API key.\n * Format: ctx_{id}_{secret}\n */\nexport function isValidApiKey(key: string): boolean {\n return /^ctx_[a-zA-Z0-9]+_[a-zA-Z0-9]+$/.test(key.trim());\n}\n\n/**\n * Validate an API key against the Cortex server by sending an initialize request.\n * Returns true if the server responds with 200, false otherwise.\n */\nexport async function validateApiKeyRemote(\n serverUrl: string,\n apiKey: string\n): Promise<{ valid: boolean; error?: string }> {\n try {\n const response = await fetch(`${serverUrl}/mcp/github`, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n \"x-api-key\": apiKey,\n \"mcp-protocol-version\": \"2024-11-05\",\n },\n body: JSON.stringify({\n jsonrpc: \"2.0\",\n method: \"initialize\",\n params: {\n protocolVersion: \"2024-11-05\",\n capabilities: {},\n clientInfo: { name: \"cortex-mcp-setup\", version: \"1.0.0\" },\n },\n id: \"validate\",\n }),\n });\n\n if (response.status === 401 || response.status === 403) {\n return { valid: false, error: \"Invalid or expired API key\" };\n }\n if (!response.ok) {\n return { valid: false, error: `Server returned ${response.status}` };\n }\n return { valid: true };\n } catch {\n return { valid: false, error: \"Could not reach the Cortex server\" };\n }\n}\n","import { existsSync, mkdirSync, readFileSync, unlinkSync, writeFileSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport { CONFIG_DIR_NAME, CREDENTIALS_FILE_NAME, DEFAULT_API_KEY } from \"../constants.js\";\nimport { readConfig } from \"../config/storage.js\";\nimport { getHomeDir } from \"../utils/platform.js\";\n\n/** Stored credentials from a successful login */\nexport interface CortexCredentials {\n apiKey: string;\n email: string;\n name?: string;\n authenticatedAt: string; // ISO 8601\n}\n\n/** Get the credentials file path (~/.cortex-mcp/credentials.json) */\nexport function getCredentialsPath(): string {\n return join(getHomeDir(), CONFIG_DIR_NAME, CREDENTIALS_FILE_NAME);\n}\n\n/** Read stored credentials, or return null if not logged in */\nexport function readCredentials(): CortexCredentials | null {\n const path = getCredentialsPath();\n if (!existsSync(path)) return null;\n\n try {\n const raw = readFileSync(path, \"utf-8\");\n return JSON.parse(raw) as CortexCredentials;\n } catch {\n return null;\n }\n}\n\n/** Write credentials to disk (creates directory with 700, file with 600 permissions) */\nexport function writeCredentials(creds: CortexCredentials): void {\n const dir = join(getHomeDir(), CONFIG_DIR_NAME);\n if (!existsSync(dir)) {\n mkdirSync(dir, { recursive: true, mode: 0o700 });\n }\n\n const path = getCredentialsPath();\n writeFileSync(path, JSON.stringify(creds, null, 2) + \"\\n\", {\n mode: 0o600,\n });\n}\n\n/** Delete stored credentials */\nexport function deleteCredentials(): void {\n const path = getCredentialsPath();\n if (existsSync(path)) {\n unlinkSync(path);\n }\n}\n\n/**\n * Get the effective API key to use.\n * Priority: CORTEX_API_KEY env var > stored credentials > config file > default shared key\n */\nexport function getEffectiveApiKey(): string {\n // 1. Environment variable (highest priority)\n const envKey = process.env.CORTEX_API_KEY;\n if (envKey) return envKey;\n\n // 2. Personal credentials from login\n const creds = readCredentials();\n if (creds?.apiKey) return creds.apiKey;\n\n // 3. Config file (set during setup)\n const config = readConfig();\n if (config?.apiKey) return config.apiKey;\n\n // 4. Shared default key (fallback)\n return DEFAULT_API_KEY;\n}\n","import { CortexHttpClient } from \"../proxy/http-client.js\";\n\n/** Metadata for a single MCP tool */\nexport interface ToolInfo {\n name: string;\n description: string;\n inputSchema: Record<string, unknown>;\n}\n\n/** Base error class for all Cortex SDK errors */\nexport class CortexError extends Error {\n constructor(\n message: string,\n public readonly mcpName?: string\n ) {\n super(message);\n this.name = \"CortexError\";\n }\n}\n\n/**\n * Thrown when a tool executes but returns isError: true\n * (e.g., bad SOQL query, missing OAuth connection, invalid record ID).\n */\nexport class CortexToolError extends CortexError {\n constructor(\n message: string,\n public override readonly mcpName: string,\n public readonly toolName: string\n ) {\n super(message, mcpName);\n this.name = \"CortexToolError\";\n }\n}\n\n/**\n * Thrown on transport/auth failures — the tool never executed\n * (e.g., invalid API key, network error, server down).\n */\nexport class CortexNetworkError extends CortexError {\n constructor(\n message: string,\n public readonly code?: number,\n mcpName?: string\n ) {\n super(message, mcpName);\n this.name = \"CortexNetworkError\";\n }\n}\n\n/**\n * Provides a call interface for a single Cortex MCP.\n * Lazily initializes the underlying HTTP session on first use.\n */\nexport class MCPNamespace {\n private readonly client: CortexHttpClient;\n private initPromise: Promise<void> | null = null;\n\n constructor(\n public readonly mcpName: string,\n serverUrl: string,\n apiKey: string\n ) {\n this.client = new CortexHttpClient(serverUrl, apiKey, mcpName);\n }\n\n private async ensureInitialized(): Promise<void> {\n if (this.initPromise !== null) return this.initPromise;\n this.initPromise = this.doInit();\n return this.initPromise;\n }\n\n private async doInit(): Promise<void> {\n const response = await this.client.initialize();\n if (response.error) {\n this.initPromise = null;\n throw new CortexNetworkError(\n response.error.message,\n response.error.code,\n this.mcpName\n );\n }\n }\n\n /**\n * Call a tool on this MCP. Returns the parsed result.\n *\n * @example\n * const ns = new MCPNamespace('salesforce', serverUrl, apiKey);\n * const result = await ns.call('run_soql_query', {\n * query: 'SELECT Id, Name FROM Account LIMIT 10'\n * });\n */\n async call(\n toolName: string,\n args: Record<string, unknown> = {}\n ): Promise<unknown> {\n await this.ensureInitialized();\n const response = await this.client.callTool(toolName, args);\n\n if (response.error) {\n throw new CortexNetworkError(\n response.error.message,\n response.error.code,\n this.mcpName\n );\n }\n\n const result = response.result as {\n content: Array<{ type: string; text: string }>;\n isError?: boolean;\n };\n\n const text = result?.content?.[0]?.text ?? \"\";\n\n if (result?.isError) {\n throw new CortexToolError(text, this.mcpName, toolName);\n }\n\n return parseText(text);\n }\n\n /** List all tools available on this MCP. */\n async listTools(): Promise<ToolInfo[]> {\n await this.ensureInitialized();\n const response = await this.client.listTools();\n\n if (response.error) {\n throw new CortexNetworkError(\n response.error.message,\n response.error.code,\n this.mcpName\n );\n }\n\n const result = response.result as { tools: ToolInfo[] };\n return result?.tools ?? [];\n }\n\n /** Release the session. The next call() will re-initialize. */\n close(): void {\n this.initPromise = null;\n }\n}\n\n/** Parse text content — attempt JSON, fall back to raw string. */\nfunction parseText(text: string): unknown {\n if (!text) return text;\n try {\n return JSON.parse(text);\n } catch {\n return text;\n }\n}\n","import { getEffectiveApiKey } from \"../auth/credentials.js\";\nimport { DEFAULT_SERVER_URL } from \"../constants.js\";\nimport { MCPNamespace } from \"./mcp-namespace.js\";\n\nexport interface CortexClientOptions {\n /** API key. Defaults to auto-resolved key (env > credentials > config > shared). */\n apiKey?: string;\n /** Cortex server URL. Defaults to https://cortex-bice.vercel.app */\n serverUrl?: string;\n}\n\n/**\n * High-level SDK client for calling Cortex MCP tools from custom apps.\n * Auto-resolves credentials and lazily initializes per-MCP sessions.\n *\n * @example\n * ```typescript\n * import { CortexClient } from '@danainnovations/cortex-mcp';\n *\n * const cortex = new CortexClient();\n *\n * // Salesforce — no Connected App needed\n * const accounts = await cortex.salesforce.call('run_soql_query', {\n * query: 'SELECT Id, Name FROM Account LIMIT 10'\n * });\n *\n * // Microsoft 365\n * const emails = await cortex.m365.call('list_emails', { count: 5 });\n *\n * // GitHub\n * const repos = await cortex.github.call('list_repositories', { per_page: 5 });\n *\n * // Cleanup when done\n * cortex.close();\n * ```\n */\nexport class CortexClient {\n private readonly apiKey: string;\n private readonly serverUrl: string;\n private readonly namespaces = new Map<string, MCPNamespace>();\n\n constructor(options: CortexClientOptions = {}) {\n this.apiKey = options.apiKey ?? getEffectiveApiKey();\n this.serverUrl = options.serverUrl ?? DEFAULT_SERVER_URL;\n }\n\n get asana(): MCPNamespace {\n return this.getNamespace(\"asana\");\n }\n get github(): MCPNamespace {\n return this.getNamespace(\"github\");\n }\n get mailchimp(): MCPNamespace {\n return this.getNamespace(\"mailchimp\");\n }\n get vercel(): MCPNamespace {\n return this.getNamespace(\"vercel\");\n }\n get supabase(): MCPNamespace {\n return this.getNamespace(\"supabase\");\n }\n get m365(): MCPNamespace {\n return this.getNamespace(\"m365\");\n }\n get salesforce(): MCPNamespace {\n return this.getNamespace(\"salesforce\");\n }\n get monday(): MCPNamespace {\n return this.getNamespace(\"monday\");\n }\n get slack(): MCPNamespace {\n return this.getNamespace(\"slack\");\n }\n get powerbi(): MCPNamespace {\n return this.getNamespace(\"powerbi\");\n }\n get bestbuy(): MCPNamespace {\n return this.getNamespace(\"bestbuy\");\n }\n\n /**\n * Call any MCP tool when the MCP name is determined at runtime.\n *\n * @example\n * const result = await cortex.call('github', 'list_repositories', { per_page: 5 });\n */\n async call(\n mcpName: string,\n toolName: string,\n args: Record<string, unknown> = {}\n ): Promise<unknown> {\n return this.getNamespace(mcpName).call(toolName, args);\n }\n\n /**\n * Release all sessions. Safe to call multiple times.\n * The next call after close() will re-initialize automatically.\n */\n close(): void {\n for (const ns of this.namespaces.values()) {\n ns.close();\n }\n this.namespaces.clear();\n }\n\n private getNamespace(name: string): MCPNamespace {\n let ns = this.namespaces.get(name);\n if (!ns) {\n ns = new MCPNamespace(name, this.serverUrl, this.apiKey);\n this.namespaces.set(name, ns);\n }\n return ns;\n }\n}\n"],"mappings":"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","names":["fileBuffer","readFileSync","join","join","readFileSync","existsSync","readFileSync","writeFileSync","mkdirSync","existsSync","mkdirSync","readFileSync","writeFileSync","existsSync","mkdirSync","readFileSync","writeFileSync","join","join","existsSync","readFileSync"]}
1
+ {"version":3,"sources":["../src/constants.ts","../src/proxy/http-client.ts","../src/proxy/stdio-server.ts","../src/config/storage.ts","../src/utils/platform.ts","../src/config/clients.ts","../src/utils/validation.ts","../src/auth/credentials.ts","../src/client/mcp-namespace.ts","../src/client/cortex-client.ts"],"sourcesContent":["/** Default Cortex server URL */\nexport const DEFAULT_SERVER_URL = \"https://cortex-bice.vercel.app\";\n\n/** MCP protocol version supported by Cortex (Streamable HTTP) */\nexport const PROTOCOL_VERSION = \"2025-03-26\";\n\n/** Available MCPs with their metadata */\nexport const AVAILABLE_MCPS = [\n {\n name: \"asana\",\n displayName: \"Asana\",\n description: \"Projects, tasks, teams, workspaces (17 tools)\",\n serverName: \"cortex-asana\",\n authMode: \"personal\" as const,\n },\n {\n name: \"github\",\n displayName: \"GitHub\",\n description: \"Repos, PRs, issues, branches, code review (30 tools)\",\n serverName: \"cortex-github\",\n authMode: \"company\" as const,\n },\n {\n name: \"vercel\",\n displayName: \"Vercel\",\n description: \"Deployments, projects, env vars (15 tools)\",\n serverName: \"cortex-vercel\",\n authMode: \"company\" as const,\n },\n {\n name: \"supabase\",\n displayName: \"Supabase\",\n description: \"Database, migrations, edge functions (20+ tools)\",\n serverName: \"cortex-supabase\",\n authMode: \"company\" as const,\n },\n {\n name: \"m365\",\n displayName: \"Microsoft 365\",\n description: \"Email, calendar, OneDrive, Teams, meetings, contacts, tasks, notes (33 tools)\",\n serverName: \"cortex-m365\",\n authMode: \"personal\" as const,\n },\n {\n name: \"mailchimp\",\n displayName: \"Mailchimp\",\n description: \"Audiences, contacts, campaigns, templates, analytics (28 tools)\",\n serverName: \"cortex-mailchimp\",\n authMode: \"personal\" as const,\n },\n {\n name: \"salesforce\",\n displayName: \"Salesforce\",\n description: \"CRM queries, records, reports, and org data (14 tools)\",\n serverName: \"cortex-salesforce\",\n authMode: \"personal\" as const,\n },\n {\n name: \"monday\",\n displayName: \"Monday.com\",\n description: \"Boards, items, groups, updates, workspaces (18 tools)\",\n serverName: \"cortex-monday\",\n authMode: \"personal\" as const,\n installUrl: \"https://auth.monday.com/oauth2/authorize?client_id=c8d2c70bd792a4c36c6f023c0b707517&response_type=install\",\n },\n {\n name: \"slack\",\n displayName: \"Slack\",\n description: \"Messaging, channels, search, reactions, bookmarks (22 tools)\",\n serverName: \"cortex-slack\",\n authMode: \"personal\" as const,\n },\n {\n name: \"powerbi\",\n displayName: \"Power BI\",\n description: \"Workspaces, datasets, push data, DAX queries, reports, dashboards (14 tools)\",\n serverName: \"cortex-powerbi\",\n authMode: \"personal\" as const,\n },\n {\n name: \"bestbuy\",\n displayName: \"Best Buy\",\n description: \"Product search, pricing, reviews, store locations (7 tools)\",\n serverName: \"cortex-bestbuy\",\n authMode: \"company\" as const,\n },\n] as const;\n\n/** All available MCP names */\nexport const MCP_NAMES: string[] = AVAILABLE_MCPS.map((m) => m.name);\n\n/** Default MCPs enabled on fresh setup */\nexport const DEFAULT_MCPS: string[] = [...MCP_NAMES];\n\n/** Shared API key embedded in the package (no user prompt needed) */\nexport const DEFAULT_API_KEY =\n \"ctx_07d37a81_9f7be06af38d04753090a4034f907a65ec06cd675ed26f65653898388e2d1709\";\n\n/** Config directory name */\nexport const CONFIG_DIR_NAME = \".cortex-mcp\";\n\n/** Config file name */\nexport const CONFIG_FILE_NAME = \"config.json\";\n\n/** Credentials file name (stores personal API key from login) */\nexport const CREDENTIALS_FILE_NAME = \"credentials.json\";\n","import { PROTOCOL_VERSION } from \"../constants.js\";\n\n/** JSON-RPC 2.0 request */\ninterface JsonRpcRequest {\n jsonrpc: \"2.0\";\n method: string;\n params?: Record<string, unknown>;\n id: string | number;\n}\n\n/** JSON-RPC 2.0 response */\ninterface JsonRpcResponse {\n jsonrpc: \"2.0\";\n result?: unknown;\n error?: { code: number; message: string };\n id: string | number | null;\n}\n\n/**\n * HTTP client that forwards JSON-RPC 2.0 requests to the Cortex server.\n */\nexport class CortexHttpClient {\n private sessionId: string | null = null;\n private requestId = 0;\n\n constructor(\n private serverUrl: string,\n private apiKey: string,\n private endpoint: string = \"cortex\"\n ) {}\n\n /** Send an initialize request to establish a session */\n async initialize(): Promise<JsonRpcResponse> {\n const response = await this.sendRequest(\"initialize\", {\n protocolVersion: PROTOCOL_VERSION,\n capabilities: {},\n clientInfo: { name: \"cortex-mcp-proxy\", version: \"1.0.0\" },\n });\n\n // Send initialized notification (no id = notification, no response expected)\n await this.sendNotification(\"notifications/initialized\", {});\n\n return response;\n }\n\n /** List available tools */\n async listTools(): Promise<JsonRpcResponse> {\n return this.sendRequest(\"tools/list\", {});\n }\n\n /** Call a tool */\n async callTool(\n name: string,\n args: Record<string, unknown>\n ): Promise<JsonRpcResponse> {\n return this.sendRequest(\"tools/call\", { name, arguments: args });\n }\n\n /** Send a JSON-RPC request and return the response */\n private async sendRequest(\n method: string,\n params: Record<string, unknown>\n ): Promise<JsonRpcResponse> {\n const id = String(++this.requestId);\n const body: JsonRpcRequest = { jsonrpc: \"2.0\", method, params, id };\n\n const headers: Record<string, string> = {\n \"Content-Type\": \"application/json\",\n \"x-api-key\": this.apiKey,\n \"mcp-protocol-version\": PROTOCOL_VERSION,\n \"x-cortex-client\": \"cortex-mcp-stdio\",\n };\n\n if (this.sessionId) {\n headers[\"mcp-session-id\"] = this.sessionId;\n }\n\n const url = `${this.serverUrl}/mcp/${this.endpoint}`;\n const response = await fetch(url, {\n method: \"POST\",\n headers,\n body: JSON.stringify(body),\n signal: AbortSignal.timeout(60_000),\n });\n\n // Capture session ID from initialize\n const newSessionId = response.headers.get(\"mcp-session-id\");\n if (newSessionId) {\n this.sessionId = newSessionId;\n }\n\n if (!response.ok) {\n const text = await response.text();\n return {\n jsonrpc: \"2.0\",\n error: {\n code: -32000,\n message: this.humanReadableError(response.status, text),\n },\n id,\n };\n }\n\n return (await response.json()) as JsonRpcResponse;\n }\n\n /** Send a JSON-RPC notification (no response expected) */\n private async sendNotification(\n method: string,\n params: Record<string, unknown>\n ): Promise<void> {\n const body = { jsonrpc: \"2.0\", method, params };\n\n const headers: Record<string, string> = {\n \"Content-Type\": \"application/json\",\n \"x-api-key\": this.apiKey,\n \"mcp-protocol-version\": PROTOCOL_VERSION,\n \"x-cortex-client\": \"cortex-mcp-stdio\",\n };\n\n if (this.sessionId) {\n headers[\"mcp-session-id\"] = this.sessionId;\n }\n\n const url = `${this.serverUrl}/mcp/${this.endpoint}`;\n\n try {\n await fetch(url, {\n method: \"POST\",\n headers,\n body: JSON.stringify(body),\n signal: AbortSignal.timeout(10_000),\n });\n } catch {\n // Notifications are fire-and-forget\n }\n }\n\n /** Convert HTTP status codes to user-friendly messages */\n private humanReadableError(status: number, body: string): string {\n switch (status) {\n case 401:\n return \"Invalid API key. Check your key at https://aidentity.app/settings/keys\";\n case 403:\n return \"API key lacks MCP permissions. Create a new key with MCP access.\";\n case 404:\n return \"MCP endpoint not found. The server may be misconfigured.\";\n case 503:\n return \"MCP protocol is disabled on the server.\";\n default:\n return `Server error (${status}): ${body.slice(0, 200)}`;\n }\n }\n}\n","import { readFileSync, statSync } from \"node:fs\";\nimport { Server } from \"@modelcontextprotocol/sdk/server/index.js\";\nimport { StdioServerTransport } from \"@modelcontextprotocol/sdk/server/stdio.js\";\nimport {\n CallToolRequestSchema,\n ListToolsRequestSchema,\n} from \"@modelcontextprotocol/sdk/types.js\";\nimport { CortexHttpClient } from \"./http-client.js\";\n\ninterface StdioServerOptions {\n serverUrl: string;\n apiKey: string;\n /** Use \"cortex\" for composite endpoint, or a specific MCP name */\n endpoint?: string;\n}\n\n/** Tools that support local file_path → upload interception */\nconst UPLOAD_TOOLS = new Set([\"upload_file\", \"upload_file_to_sharepoint\"]);\n\n/** Max file size for inline base64 upload via JSON-RPC (3MB).\n * 3MB raw → 4MB base64 → safely within Vercel's ~4.5MB body limit. */\nconst INLINE_UPLOAD_MAX = 3 * 1024 * 1024;\n\n/**\n * Override upload tool schemas so the LLM only sees `file_path` (not `content`).\n * This forces the LLM to pass a local file path, which the proxy handles locally\n * — no base64 encoding by the LLM, no truncation, no corruption.\n */\nfunction overrideUploadToolSchema(\n tool: Record<string, unknown>\n): Record<string, unknown> {\n const name = tool.name as string;\n const baseName = name.includes(\"__\") ? name.split(\"__\").pop()! : name;\n\n if (baseName === \"upload_file\") {\n return {\n ...tool,\n description:\n \"Upload a local file to the user's OneDrive. \" +\n \"Provide the absolute local file path — the file is read \" +\n \"and uploaded automatically. Works with any file size.\",\n inputSchema: {\n type: \"object\",\n required: [\"file_path\", \"path\"],\n properties: {\n file_path: {\n type: \"string\",\n description:\n \"Absolute path to the local file to upload \" +\n \"(e.g. '/Users/name/Documents/report.xlsx')\",\n },\n path: {\n type: \"string\",\n description:\n \"Destination path in OneDrive \" +\n \"(e.g. 'Documents/report.xlsx')\",\n },\n content_type: {\n type: \"string\",\n description: \"MIME type. Defaults to 'application/octet-stream'\",\n },\n },\n },\n };\n }\n\n if (baseName === \"upload_file_to_sharepoint\") {\n return {\n ...tool,\n description:\n \"Upload a local file to a SharePoint document library. \" +\n \"Provide the absolute local file path — the file is read \" +\n \"and uploaded automatically.\",\n inputSchema: {\n type: \"object\",\n required: [\"file_path\", \"site_id\", \"path\"],\n properties: {\n file_path: {\n type: \"string\",\n description: \"Absolute path to the local file to upload\",\n },\n site_id: {\n type: \"string\",\n description: \"SharePoint site ID\",\n },\n path: {\n type: \"string\",\n description:\n \"Destination path in the site drive \" +\n \"(e.g. 'Shared Documents/report.pdf')\",\n },\n content_type: {\n type: \"string\",\n description: \"MIME type. Defaults to 'application/octet-stream'\",\n },\n },\n },\n };\n }\n\n return tool;\n}\n\n/**\n * Handle a file upload tool call locally by reading the file from disk.\n *\n * - Small files (≤3MB): base64-encode and forward as `content` param\n * - Large files (>3MB): get an upload session URL from backend, then\n * relay 2.5MB chunks through the backend's `upload_file_chunk` tool\n * (the backend has unrestricted internet; the proxy may be sandboxed)\n */\nasync function handleLocalFileUpload(\n cortex: CortexHttpClient,\n toolName: string,\n args: Record<string, unknown>\n): Promise<{ content: Array<{ type: string; text: string }>; isError: boolean }> {\n const filePath = args.file_path as string;\n\n // Validate file exists\n let fileSize: number;\n try {\n fileSize = statSync(filePath as string).size;\n } catch {\n return {\n content: [{ type: \"text\", text: JSON.stringify({\n success: false,\n error: `File not found: ${filePath}`,\n }) }],\n isError: true,\n };\n }\n\n if (fileSize <= INLINE_UPLOAD_MAX) {\n // Small file: read, base64-encode, and forward via normal JSON-RPC\n const fileBuffer = readFileSync(filePath);\n const base64Content = fileBuffer.toString(\"base64\");\n\n const forwardArgs: Record<string, unknown> = { ...args, content: base64Content };\n delete forwardArgs.file_path;\n\n console.error(\n `[cortex-mcp] ${toolName}: reading local file (${(fileSize / 1024).toFixed(1)}KB), forwarding as base64`\n );\n\n const response = await cortex.callTool(toolName, forwardArgs);\n\n if (response.error) {\n return {\n content: [{ type: \"text\", text: response.error.message }],\n isError: true,\n };\n }\n\n return response.result as {\n content: Array<{ type: string; text: string }>;\n isError: boolean;\n };\n }\n\n // Large file: use upload session to upload directly to Microsoft Graph\n console.error(\n `[cortex-mcp] ${toolName}: large file (${(fileSize / 1024 / 1024).toFixed(1)}MB), using upload session`\n );\n\n // Step 1: Get pre-authenticated upload URL from backend\n // Preserve composite prefix (e.g. \"m365__\") so the backend routes correctly\n const prefix = toolName.includes(\"__\") ? toolName.split(\"__\")[0] + \"__\" : \"\";\n const sessionResponse = await cortex.callTool(`${prefix}create_upload_session`, {\n path: args.path,\n });\n\n if (sessionResponse.error) {\n return {\n content: [{ type: \"text\", text: sessionResponse.error.message }],\n isError: true,\n };\n }\n\n const sessionResult = sessionResponse.result as {\n content: Array<{ type: string; text: string }>;\n };\n\n let sessionData: { uploadUrl?: string };\n try {\n sessionData = JSON.parse(sessionResult.content[0].text);\n } catch {\n return {\n content: [{ type: \"text\", text: JSON.stringify({\n success: false,\n error: \"Failed to parse upload session response from backend\",\n }) }],\n isError: true,\n };\n }\n\n const uploadUrl = sessionData.uploadUrl;\n if (!uploadUrl) {\n return {\n content: [{ type: \"text\", text: JSON.stringify({\n success: false,\n error: \"Backend did not return an uploadUrl\",\n }) }],\n isError: true,\n };\n }\n\n // Step 2: Upload file in chunks through the Cortex backend.\n // We relay via the backend (which has unrestricted internet) instead of\n // uploading directly to Graph — the proxy may be in a sandboxed VM that\n // blocks outbound connections to SharePoint/Microsoft Graph.\n const fileBuffer = readFileSync(filePath);\n const chunkSize = 2.5 * 1024 * 1024; // 2.5MB → ~3.33MB base64 → within Vercel 4.5MB limit\n const total = fileBuffer.length;\n let driveItem: Record<string, unknown> = {};\n\n for (let start = 0; start < total; start += chunkSize) {\n const end = Math.min(start + chunkSize, total);\n const chunk = fileBuffer.subarray(start, end);\n const chunkBase64 = Buffer.from(chunk).toString(\"base64\");\n\n console.error(\n `[cortex-mcp] Uploading chunk ${start}-${end - 1}/${total} via backend relay`\n );\n\n const chunkResponse = await cortex.callTool(`${prefix}upload_file_chunk`, {\n upload_url: uploadUrl,\n chunk: chunkBase64,\n range_start: start,\n range_end: end - 1,\n total_size: total,\n });\n\n if (chunkResponse.error) {\n return {\n content: [{ type: \"text\", text: chunkResponse.error.message }],\n isError: true,\n };\n }\n\n const chunkResult = chunkResponse.result as {\n content: Array<{ type: string; text: string }>;\n };\n\n let chunkData: Record<string, unknown>;\n try {\n chunkData = JSON.parse(chunkResult.content[0].text) as Record<string, unknown>;\n } catch {\n return {\n content: [{ type: \"text\", text: JSON.stringify({\n success: false,\n error: \"Failed to parse chunk upload response from backend\",\n }) }],\n isError: true,\n };\n }\n\n if (!chunkData.success) {\n return {\n content: [{ type: \"text\", text: JSON.stringify(chunkData) }],\n isError: true,\n };\n }\n\n // Final chunk (200/201) contains the DriveItem\n if (chunkData.status === 200 || chunkData.status === 201) {\n driveItem = (chunkData.data as Record<string, unknown>) ?? {};\n }\n }\n\n return {\n content: [{ type: \"text\", text: JSON.stringify({\n success: true,\n file: driveItem,\n message: `Uploaded '${args.path}' (${(fileSize / 1024 / 1024).toFixed(1)}MB) via upload session`,\n }) }],\n isError: false,\n };\n}\n\n/**\n * Start a stdio MCP server that proxies all requests to the hosted Cortex server.\n * This is used by clients that only support stdio transport (e.g., OpenClaw).\n */\nexport async function startStdioServer(\n options: StdioServerOptions\n): Promise<void> {\n const { serverUrl, apiKey, endpoint = \"cortex\" } = options;\n\n const cortex = new CortexHttpClient(serverUrl, apiKey, endpoint);\n\n const server = new Server(\n { name: \"cortex-mcp\", version: \"1.0.0\" },\n { capabilities: { tools: { listChanged: false } } }\n );\n\n // Lazy initialization — runs on first request, not at startup\n let initialized = false;\n\n async function ensureInitialized(): Promise<void> {\n if (initialized) return;\n try {\n console.error(\"[cortex-mcp] Initializing backend session...\");\n await cortex.initialize();\n console.error(\"[cortex-mcp] Backend session established.\");\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n console.error(`[cortex-mcp] Backend initialization failed: ${msg}`);\n // Continue anyway — tools/list and tools/call may still work without a session\n }\n initialized = true;\n }\n\n // Forward tools/list to Cortex\n server.setRequestHandler(ListToolsRequestSchema, async () => {\n await ensureInitialized();\n const response = await cortex.listTools();\n\n if (response.error) {\n throw new Error(response.error.message);\n }\n\n const result = response.result as { tools: Record<string, unknown>[] };\n const tools = (result.tools || []).map(overrideUploadToolSchema);\n return { tools };\n });\n\n // Forward tools/call to Cortex (with local file upload interception)\n server.setRequestHandler(CallToolRequestSchema, async (request) => {\n await ensureInitialized();\n const { name, arguments: args } = request.params;\n const typedArgs = (args ?? {}) as Record<string, unknown>;\n\n // Intercept upload tools with file_path — handle locally\n // Composite endpoint prefixes tool names with \"{mcp}__\", so match on suffix\n const baseName = name.includes(\"__\") ? name.split(\"__\").pop()! : name;\n if (UPLOAD_TOOLS.has(baseName) && typedArgs.file_path) {\n return handleLocalFileUpload(cortex, name, typedArgs);\n }\n\n const response = await cortex.callTool(name, typedArgs);\n\n if (response.error) {\n return {\n content: [{ type: \"text\" as const, text: response.error.message }],\n isError: true,\n };\n }\n\n const result = response.result as {\n content: Array<{ type: string; text: string }>;\n isError: boolean;\n };\n\n return result;\n });\n\n // Connect to stdio transport immediately — do NOT block on backend init\n console.error(\"[cortex-mcp] Starting stdio server...\");\n const transport = new StdioServerTransport();\n await server.connect(transport);\n console.error(\"[cortex-mcp] Stdio server connected.\");\n}\n","import { existsSync, mkdirSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport { CONFIG_DIR_NAME, CONFIG_FILE_NAME, DEFAULT_SERVER_URL } from \"../constants.js\";\nimport { getHomeDir } from \"../utils/platform.js\";\nimport type { CortexMcpConfig } from \"./types.js\";\n\n/** Get the config directory path */\nexport function getConfigDir(): string {\n return join(getHomeDir(), CONFIG_DIR_NAME);\n}\n\n/** Get the config file path */\nexport function getConfigPath(): string {\n return join(getConfigDir(), CONFIG_FILE_NAME);\n}\n\n/** Read the current config, or return null if none exists */\nexport function readConfig(): CortexMcpConfig | null {\n const path = getConfigPath();\n if (!existsSync(path)) return null;\n\n try {\n const raw = readFileSync(path, \"utf-8\");\n return JSON.parse(raw) as CortexMcpConfig;\n } catch {\n return null;\n }\n}\n\n/** Write config to disk (creates directory with 700 permissions, file with 600) */\nexport function writeConfig(config: CortexMcpConfig): void {\n const dir = getConfigDir();\n if (!existsSync(dir)) {\n mkdirSync(dir, { recursive: true, mode: 0o700 });\n }\n\n const path = getConfigPath();\n writeFileSync(path, JSON.stringify(config, null, 2) + \"\\n\", {\n mode: 0o600,\n });\n}\n\n/** Create a default config with the given API key and MCPs */\nexport function createConfig(\n apiKey: string,\n mcps: string[]\n): CortexMcpConfig {\n return {\n version: 1,\n server: DEFAULT_SERVER_URL,\n apiKey,\n mcps,\n configuredClients: [],\n };\n}\n","import { homedir, platform } from \"node:os\";\nimport { join } from \"node:path\";\n\n/** Get the user's home directory */\nexport function getHomeDir(): string {\n return homedir();\n}\n\n/** Get the current platform */\nexport function getPlatform(): \"macos\" | \"windows\" | \"linux\" {\n const p = platform();\n if (p === \"darwin\") return \"macos\";\n if (p === \"win32\") return \"windows\";\n return \"linux\";\n}\n\n/**\n * Get the Claude Desktop config file path for the current platform.\n */\nexport function getClaudeDesktopConfigPath(): string {\n const home = getHomeDir();\n const p = getPlatform();\n\n switch (p) {\n case \"macos\":\n return join(\n home,\n \"Library\",\n \"Application Support\",\n \"Claude\",\n \"claude_desktop_config.json\"\n );\n case \"windows\":\n return join(\n process.env.APPDATA || join(home, \"AppData\", \"Roaming\"),\n \"Claude\",\n \"claude_desktop_config.json\"\n );\n case \"linux\":\n return join(home, \".config\", \"Claude\", \"claude_desktop_config.json\");\n }\n}\n\n/**\n * Get the Cursor MCP config file path for the current platform.\n */\nexport function getCursorConfigPath(): string {\n const home = getHomeDir();\n return join(home, \".cursor\", \"mcp.json\");\n}\n\n/**\n * Get the OpenAI Codex config file path.\n */\nexport function getCodexConfigPath(): string {\n const home = getHomeDir();\n return join(home, \".codex\", \"config.toml\");\n}\n","import { existsSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { dirname } from \"node:path\";\nimport { mkdirSync } from \"node:fs\";\nimport { execSync } from \"node:child_process\";\nimport { AVAILABLE_MCPS } from \"../constants.js\";\nimport {\n getClaudeDesktopConfigPath,\n getCodexConfigPath,\n getCursorConfigPath,\n} from \"../utils/platform.js\";\nimport type { ClientType, DetectedClient, HttpMcpEntry } from \"./types.js\";\n\n/**\n * Detect which AI clients are installed on this machine.\n */\nexport function detectClients(): DetectedClient[] {\n const clients: DetectedClient[] = [];\n\n // Claude Desktop\n const desktopPath = getClaudeDesktopConfigPath();\n const desktopDir = dirname(desktopPath);\n clients.push({\n type: \"claude-desktop\",\n name: \"Claude Desktop\",\n configPath: desktopPath,\n detected: existsSync(desktopDir),\n });\n\n // Claude Code\n let claudeCodeDetected = false;\n try {\n execSync(\"which claude\", { stdio: \"pipe\" });\n claudeCodeDetected = true;\n } catch {\n // claude CLI not in PATH\n }\n clients.push({\n type: \"claude-code\",\n name: \"Claude Code\",\n configPath: null,\n detected: claudeCodeDetected,\n });\n\n // Cursor\n const cursorPath = getCursorConfigPath();\n const cursorDir = dirname(cursorPath);\n clients.push({\n type: \"cursor\",\n name: \"Cursor\",\n configPath: cursorPath,\n detected: existsSync(cursorDir),\n });\n\n // OpenAI Codex\n const codexPath = getCodexConfigPath();\n const codexDir = dirname(codexPath);\n clients.push({\n type: \"codex\",\n name: \"Codex\",\n configPath: codexPath,\n detected: existsSync(codexDir),\n });\n\n return clients;\n}\n\n/**\n * Build per-MCP HTTP entries for a given server URL and API key.\n */\nexport function buildHttpEntries(\n serverUrl: string,\n apiKey: string,\n mcps: string[]\n): Record<string, HttpMcpEntry> {\n const entries: Record<string, HttpMcpEntry> = {};\n\n for (const mcp of AVAILABLE_MCPS) {\n if (!mcps.includes(mcp.name)) continue;\n entries[mcp.serverName] = {\n url: `${serverUrl}/mcp/${mcp.name}`,\n headers: { \"x-api-key\": apiKey },\n };\n }\n\n return entries;\n}\n\n/**\n * Configure Claude Desktop by merging a stdio proxy entry into its config file.\n * Uses command/args/env format (Claude Desktop does not support HTTP url/headers).\n * Preserves existing non-Cortex entries.\n */\nexport function configureClaudeDesktop(\n _serverUrl: string,\n apiKey: string,\n _mcps: string[]\n): void {\n const configPath = getClaudeDesktopConfigPath();\n const dir = dirname(configPath);\n\n // Ensure directory exists\n if (!existsSync(dir)) {\n mkdirSync(dir, { recursive: true });\n }\n\n // Read existing config or start fresh\n let config: Record<string, unknown> = {};\n if (existsSync(configPath)) {\n try {\n config = JSON.parse(readFileSync(configPath, \"utf-8\"));\n } catch {\n // Corrupted file — start fresh\n }\n }\n\n // Ensure mcpServers key exists\n if (!config.mcpServers || typeof config.mcpServers !== \"object\") {\n config.mcpServers = {};\n }\n\n const servers = config.mcpServers as Record<string, unknown>;\n\n // Remove existing cortex-* and cortex entries\n for (const key of Object.keys(servers)) {\n if (key.startsWith(\"cortex-\") || key === \"cortex\") {\n delete servers[key];\n }\n }\n\n // Add stdio proxy entry (Claude Desktop only supports command/args)\n // API key is read from ~/.cortex-mcp/credentials.json at runtime by the serve command,\n // so we don't bake it into the env (avoids stale key issues on re-login).\n servers[\"cortex\"] = {\n command: \"npx\",\n args: [\"-y\", \"@danainnovations/cortex-mcp@latest\", \"serve\"],\n };\n\n writeFileSync(configPath, JSON.stringify(config, null, 2) + \"\\n\");\n}\n\n/**\n * Configure Claude Code by running `claude mcp add` commands.\n */\nexport function configureClaudeCode(\n serverUrl: string,\n apiKey: string,\n mcps: string[]\n): void {\n for (const mcp of AVAILABLE_MCPS) {\n if (!mcps.includes(mcp.name)) continue;\n\n const url = `${serverUrl}/mcp/${mcp.name}`;\n\n // Remove existing entry first (ignore errors if it doesn't exist)\n try {\n execSync(`claude mcp remove ${mcp.serverName}`, { stdio: \"pipe\" });\n } catch {\n // Entry didn't exist — fine\n }\n\n execSync(\n `claude mcp add --transport http ${mcp.serverName} ${url} -H \"x-api-key: ${apiKey}\"`,\n { stdio: \"pipe\" }\n );\n }\n}\n\n/**\n * Configure Cursor by writing HTTP MCP entries to its config file.\n * Cursor supports HTTP transport natively.\n */\nexport function configureCursor(\n serverUrl: string,\n apiKey: string,\n mcps: string[]\n): void {\n const configPath = getCursorConfigPath();\n const dir = dirname(configPath);\n\n if (!existsSync(dir)) {\n mkdirSync(dir, { recursive: true });\n }\n\n let config: Record<string, unknown> = {};\n if (existsSync(configPath)) {\n try {\n config = JSON.parse(readFileSync(configPath, \"utf-8\"));\n } catch {\n // Corrupted file — start fresh\n }\n }\n\n if (!config.mcpServers || typeof config.mcpServers !== \"object\") {\n config.mcpServers = {};\n }\n\n const servers = config.mcpServers as Record<string, unknown>;\n\n // Remove existing cortex-* entries\n for (const key of Object.keys(servers)) {\n if (key.startsWith(\"cortex-\")) {\n delete servers[key];\n }\n }\n\n // Add new HTTP entries\n const entries = buildHttpEntries(serverUrl, apiKey, mcps);\n Object.assign(servers, entries);\n\n writeFileSync(configPath, JSON.stringify(config, null, 2) + \"\\n\");\n}\n\n/**\n * Generate a stdio config snippet for clients that need it (OpenClaw, etc.)\n */\nexport function generateStdioSnippet(_apiKey: string): string {\n const config = {\n mcpServers: {\n cortex: {\n command: \"npx\",\n args: [\"-y\", \"@danainnovations/cortex-mcp@latest\", \"serve\"],\n },\n },\n };\n return JSON.stringify(config, null, 2);\n}\n\n/**\n * Remove all cortex-* MCP entries from Claude Desktop config.\n */\nexport function resetClaudeDesktop(): boolean {\n const configPath = getClaudeDesktopConfigPath();\n if (!existsSync(configPath)) return false;\n\n try {\n const config = JSON.parse(readFileSync(configPath, \"utf-8\"));\n if (!config.mcpServers) return false;\n\n const servers = config.mcpServers as Record<string, unknown>;\n let removed = false;\n for (const key of Object.keys(servers)) {\n if (key.startsWith(\"cortex-\") || key === \"cortex\") {\n delete servers[key];\n removed = true;\n }\n }\n\n if (removed) {\n writeFileSync(configPath, JSON.stringify(config, null, 2) + \"\\n\");\n }\n return removed;\n } catch {\n return false;\n }\n}\n\n/**\n * Remove cortex MCP entries from Cursor config.\n */\nexport function resetCursor(): boolean {\n const configPath = getCursorConfigPath();\n if (!existsSync(configPath)) return false;\n\n try {\n const config = JSON.parse(readFileSync(configPath, \"utf-8\"));\n if (!config.mcpServers) return false;\n\n const servers = config.mcpServers as Record<string, unknown>;\n let removed = false;\n for (const key of Object.keys(servers)) {\n if (key.startsWith(\"cortex-\") || key === \"cortex\") {\n delete servers[key];\n removed = true;\n }\n }\n\n if (removed) {\n writeFileSync(configPath, JSON.stringify(config, null, 2) + \"\\n\");\n }\n return removed;\n } catch {\n return false;\n }\n}\n\n/**\n * Remove cortex MCP entries from Claude Code.\n */\nexport function resetClaudeCode(): boolean {\n let removed = false;\n for (const mcp of AVAILABLE_MCPS) {\n try {\n execSync(`claude mcp remove ${mcp.serverName}`, { stdio: \"pipe\" });\n removed = true;\n } catch {\n // Entry didn't exist\n }\n }\n return removed;\n}\n\n/**\n * Remove all TOML sections whose header matches [mcp_servers.cortex*].\n * A section runs from its [header] to the next [header] or EOF.\n */\nfunction removeCortexTomlSections(content: string): string {\n const lines = content.split(\"\\n\");\n const result: string[] = [];\n let skipping = false;\n\n for (const line of lines) {\n const trimmed = line.trim();\n // Detect any TOML section header\n if (trimmed.startsWith(\"[\")) {\n // Check if this is a cortex MCP section (including sub-tables like .http_headers)\n skipping = /^\\[mcp_servers\\.cortex[_-]/.test(trimmed)\n || trimmed === \"[mcp_servers.cortex]\";\n }\n if (!skipping) {\n result.push(line);\n }\n }\n\n return result.join(\"\\n\");\n}\n\n/**\n * Configure OpenAI Codex by writing MCP entries to ~/.codex/config.toml.\n * Uses Streamable HTTP transport with static http_headers for the API key.\n */\nexport function configureCodex(\n serverUrl: string,\n apiKey: string,\n mcps: string[]\n): void {\n const configPath = getCodexConfigPath();\n const dir = dirname(configPath);\n\n if (!existsSync(dir)) {\n mkdirSync(dir, { recursive: true });\n }\n\n let content = \"\";\n if (existsSync(configPath)) {\n try {\n content = readFileSync(configPath, \"utf-8\");\n } catch {\n // Corrupted file — start fresh\n }\n }\n\n // Remove existing cortex entries\n content = removeCortexTomlSections(content);\n\n // Build new TOML sections for each MCP\n const sections: string[] = [];\n for (const mcp of AVAILABLE_MCPS) {\n if (!mcps.includes(mcp.name)) continue;\n sections.push(`[mcp_servers.${mcp.serverName}]`);\n sections.push(`url = \"${serverUrl}/mcp/${mcp.name}\"`);\n sections.push(`[mcp_servers.${mcp.serverName}.http_headers]`);\n sections.push(`\"x-api-key\" = \"${apiKey}\"`);\n sections.push(\"\");\n }\n\n // Append to existing config\n const trimmed = content.trimEnd();\n const newContent = trimmed\n ? trimmed + \"\\n\\n\" + sections.join(\"\\n\") + \"\\n\"\n : sections.join(\"\\n\") + \"\\n\";\n\n writeFileSync(configPath, newContent);\n}\n\n/**\n * Remove cortex MCP entries from Codex config.\n */\nexport function resetCodex(): boolean {\n const configPath = getCodexConfigPath();\n if (!existsSync(configPath)) return false;\n\n try {\n const content = readFileSync(configPath, \"utf-8\");\n const cleaned = removeCortexTomlSections(content);\n\n if (cleaned.length < content.length) {\n writeFileSync(configPath, cleaned);\n return true;\n }\n return false;\n } catch {\n return false;\n }\n}\n\n/**\n * Configure a specific client type.\n */\nexport function configureClient(\n clientType: ClientType,\n serverUrl: string,\n apiKey: string,\n mcps: string[]\n): string {\n switch (clientType) {\n case \"claude-desktop\":\n configureClaudeDesktop(serverUrl, apiKey, mcps);\n return \"Claude Desktop configured\";\n case \"claude-code\":\n configureClaudeCode(serverUrl, apiKey, mcps);\n return \"Claude Code configured\";\n case \"cursor\":\n configureCursor(serverUrl, apiKey, mcps);\n return \"Cursor configured\";\n case \"codex\":\n configureCodex(serverUrl, apiKey, mcps);\n return \"Codex configured\";\n case \"stdio\":\n return (\n \"Add this to your client config:\\n\\n\" +\n generateStdioSnippet(apiKey)\n );\n }\n}\n","/**\n * Validate that a string looks like a Cortex API key.\n * Format: ctx_{id}_{secret}\n */\nexport function isValidApiKey(key: string): boolean {\n return /^ctx_[a-zA-Z0-9]+_[a-zA-Z0-9]+$/.test(key.trim());\n}\n\n/**\n * Validate an API key against the Cortex server by sending an initialize request.\n * Returns true if the server responds with 200, false otherwise.\n */\nexport async function validateApiKeyRemote(\n serverUrl: string,\n apiKey: string\n): Promise<{ valid: boolean; error?: string }> {\n try {\n const response = await fetch(`${serverUrl}/mcp/github`, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n \"x-api-key\": apiKey,\n \"mcp-protocol-version\": \"2024-11-05\",\n },\n body: JSON.stringify({\n jsonrpc: \"2.0\",\n method: \"initialize\",\n params: {\n protocolVersion: \"2024-11-05\",\n capabilities: {},\n clientInfo: { name: \"cortex-mcp-setup\", version: \"1.0.0\" },\n },\n id: \"validate\",\n }),\n });\n\n if (response.status === 401 || response.status === 403) {\n return { valid: false, error: \"Invalid or expired API key\" };\n }\n if (!response.ok) {\n return { valid: false, error: `Server returned ${response.status}` };\n }\n return { valid: true };\n } catch {\n return { valid: false, error: \"Could not reach the Cortex server\" };\n }\n}\n","import { existsSync, mkdirSync, readFileSync, unlinkSync, writeFileSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport { CONFIG_DIR_NAME, CREDENTIALS_FILE_NAME, DEFAULT_API_KEY } from \"../constants.js\";\nimport { readConfig } from \"../config/storage.js\";\nimport { getHomeDir } from \"../utils/platform.js\";\n\n/** Stored credentials from a successful login */\nexport interface CortexCredentials {\n apiKey: string;\n email: string;\n name?: string;\n authenticatedAt: string; // ISO 8601\n}\n\n/** Get the credentials file path (~/.cortex-mcp/credentials.json) */\nexport function getCredentialsPath(): string {\n return join(getHomeDir(), CONFIG_DIR_NAME, CREDENTIALS_FILE_NAME);\n}\n\n/** Read stored credentials, or return null if not logged in */\nexport function readCredentials(): CortexCredentials | null {\n const path = getCredentialsPath();\n if (!existsSync(path)) return null;\n\n try {\n const raw = readFileSync(path, \"utf-8\");\n return JSON.parse(raw) as CortexCredentials;\n } catch {\n return null;\n }\n}\n\n/** Write credentials to disk (creates directory with 700, file with 600 permissions) */\nexport function writeCredentials(creds: CortexCredentials): void {\n const dir = join(getHomeDir(), CONFIG_DIR_NAME);\n if (!existsSync(dir)) {\n mkdirSync(dir, { recursive: true, mode: 0o700 });\n }\n\n const path = getCredentialsPath();\n writeFileSync(path, JSON.stringify(creds, null, 2) + \"\\n\", {\n mode: 0o600,\n });\n}\n\n/** Delete stored credentials */\nexport function deleteCredentials(): void {\n const path = getCredentialsPath();\n if (existsSync(path)) {\n unlinkSync(path);\n }\n}\n\n/**\n * Get the effective API key to use.\n * Priority: CORTEX_API_KEY env var > stored credentials > config file > default shared key\n */\nexport function getEffectiveApiKey(): string {\n // 1. Environment variable (highest priority)\n const envKey = process.env.CORTEX_API_KEY;\n if (envKey) return envKey;\n\n // 2. Personal credentials from login\n const creds = readCredentials();\n if (creds?.apiKey) return creds.apiKey;\n\n // 3. Config file (set during setup)\n const config = readConfig();\n if (config?.apiKey) return config.apiKey;\n\n // 4. Shared default key (fallback)\n return DEFAULT_API_KEY;\n}\n","import { CortexHttpClient } from \"../proxy/http-client.js\";\n\n/** Metadata for a single MCP tool */\nexport interface ToolInfo {\n name: string;\n description: string;\n inputSchema: Record<string, unknown>;\n}\n\n/** Base error class for all Cortex SDK errors */\nexport class CortexError extends Error {\n constructor(\n message: string,\n public readonly mcpName?: string\n ) {\n super(message);\n this.name = \"CortexError\";\n }\n}\n\n/**\n * Thrown when a tool executes but returns isError: true\n * (e.g., bad SOQL query, missing OAuth connection, invalid record ID).\n */\nexport class CortexToolError extends CortexError {\n constructor(\n message: string,\n public override readonly mcpName: string,\n public readonly toolName: string\n ) {\n super(message, mcpName);\n this.name = \"CortexToolError\";\n }\n}\n\n/**\n * Thrown on transport/auth failures — the tool never executed\n * (e.g., invalid API key, network error, server down).\n */\nexport class CortexNetworkError extends CortexError {\n constructor(\n message: string,\n public readonly code?: number,\n mcpName?: string\n ) {\n super(message, mcpName);\n this.name = \"CortexNetworkError\";\n }\n}\n\n/**\n * Provides a call interface for a single Cortex MCP.\n * Lazily initializes the underlying HTTP session on first use.\n */\nexport class MCPNamespace {\n private readonly client: CortexHttpClient;\n private initPromise: Promise<void> | null = null;\n\n constructor(\n public readonly mcpName: string,\n serverUrl: string,\n apiKey: string\n ) {\n this.client = new CortexHttpClient(serverUrl, apiKey, mcpName);\n }\n\n private async ensureInitialized(): Promise<void> {\n if (this.initPromise !== null) return this.initPromise;\n this.initPromise = this.doInit();\n return this.initPromise;\n }\n\n private async doInit(): Promise<void> {\n const response = await this.client.initialize();\n if (response.error) {\n this.initPromise = null;\n throw new CortexNetworkError(\n response.error.message,\n response.error.code,\n this.mcpName\n );\n }\n }\n\n /**\n * Call a tool on this MCP. Returns the parsed result.\n *\n * @example\n * const ns = new MCPNamespace('salesforce', serverUrl, apiKey);\n * const result = await ns.call('run_soql_query', {\n * query: 'SELECT Id, Name FROM Account LIMIT 10'\n * });\n */\n async call(\n toolName: string,\n args: Record<string, unknown> = {}\n ): Promise<unknown> {\n await this.ensureInitialized();\n const response = await this.client.callTool(toolName, args);\n\n if (response.error) {\n throw new CortexNetworkError(\n response.error.message,\n response.error.code,\n this.mcpName\n );\n }\n\n const result = response.result as {\n content: Array<{ type: string; text: string }>;\n isError?: boolean;\n };\n\n const text = result?.content?.[0]?.text ?? \"\";\n\n if (result?.isError) {\n throw new CortexToolError(text, this.mcpName, toolName);\n }\n\n return parseText(text);\n }\n\n /** List all tools available on this MCP. */\n async listTools(): Promise<ToolInfo[]> {\n await this.ensureInitialized();\n const response = await this.client.listTools();\n\n if (response.error) {\n throw new CortexNetworkError(\n response.error.message,\n response.error.code,\n this.mcpName\n );\n }\n\n const result = response.result as { tools: ToolInfo[] };\n return result?.tools ?? [];\n }\n\n /** Release the session. The next call() will re-initialize. */\n close(): void {\n this.initPromise = null;\n }\n}\n\n/** Parse text content — attempt JSON, fall back to raw string. */\nfunction parseText(text: string): unknown {\n if (!text) return text;\n try {\n return JSON.parse(text);\n } catch {\n return text;\n }\n}\n","import { getEffectiveApiKey } from \"../auth/credentials.js\";\nimport { DEFAULT_SERVER_URL } from \"../constants.js\";\nimport { MCPNamespace } from \"./mcp-namespace.js\";\n\nexport interface CortexClientOptions {\n /** API key. Defaults to auto-resolved key (env > credentials > config > shared). */\n apiKey?: string;\n /** Cortex server URL. Defaults to https://cortex-bice.vercel.app */\n serverUrl?: string;\n}\n\n/**\n * High-level SDK client for calling Cortex MCP tools from custom apps.\n * Auto-resolves credentials and lazily initializes per-MCP sessions.\n *\n * @example\n * ```typescript\n * import { CortexClient } from '@danainnovations/cortex-mcp';\n *\n * const cortex = new CortexClient();\n *\n * // Salesforce — no Connected App needed\n * const accounts = await cortex.salesforce.call('run_soql_query', {\n * query: 'SELECT Id, Name FROM Account LIMIT 10'\n * });\n *\n * // Microsoft 365\n * const emails = await cortex.m365.call('list_emails', { count: 5 });\n *\n * // GitHub\n * const repos = await cortex.github.call('list_repositories', { per_page: 5 });\n *\n * // Cleanup when done\n * cortex.close();\n * ```\n */\nexport class CortexClient {\n private readonly apiKey: string;\n private readonly serverUrl: string;\n private readonly namespaces = new Map<string, MCPNamespace>();\n\n constructor(options: CortexClientOptions = {}) {\n this.apiKey = options.apiKey ?? getEffectiveApiKey();\n this.serverUrl = options.serverUrl ?? DEFAULT_SERVER_URL;\n }\n\n get asana(): MCPNamespace {\n return this.getNamespace(\"asana\");\n }\n get github(): MCPNamespace {\n return this.getNamespace(\"github\");\n }\n get mailchimp(): MCPNamespace {\n return this.getNamespace(\"mailchimp\");\n }\n get vercel(): MCPNamespace {\n return this.getNamespace(\"vercel\");\n }\n get supabase(): MCPNamespace {\n return this.getNamespace(\"supabase\");\n }\n get m365(): MCPNamespace {\n return this.getNamespace(\"m365\");\n }\n get salesforce(): MCPNamespace {\n return this.getNamespace(\"salesforce\");\n }\n get monday(): MCPNamespace {\n return this.getNamespace(\"monday\");\n }\n get slack(): MCPNamespace {\n return this.getNamespace(\"slack\");\n }\n get powerbi(): MCPNamespace {\n return this.getNamespace(\"powerbi\");\n }\n get bestbuy(): MCPNamespace {\n return this.getNamespace(\"bestbuy\");\n }\n\n /**\n * Call any MCP tool when the MCP name is determined at runtime.\n *\n * @example\n * const result = await cortex.call('github', 'list_repositories', { per_page: 5 });\n */\n async call(\n mcpName: string,\n toolName: string,\n args: Record<string, unknown> = {}\n ): Promise<unknown> {\n return this.getNamespace(mcpName).call(toolName, args);\n }\n\n /**\n * Release all sessions. Safe to call multiple times.\n * The next call after close() will re-initialize automatically.\n */\n close(): void {\n for (const ns of this.namespaces.values()) {\n ns.close();\n }\n this.namespaces.clear();\n }\n\n private getNamespace(name: string): MCPNamespace {\n let ns = this.namespaces.get(name);\n if (!ns) {\n ns = new MCPNamespace(name, this.serverUrl, this.apiKey);\n this.namespaces.set(name, ns);\n }\n return ns;\n }\n}\n"],"mappings":"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","names":["fileBuffer","readFileSync","join","join","readFileSync","existsSync","readFileSync","writeFileSync","mkdirSync","existsSync","mkdirSync","readFileSync","writeFileSync","existsSync","mkdirSync","readFileSync","writeFileSync","existsSync","mkdirSync","readFileSync","writeFileSync","join","join","existsSync","readFileSync"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@danainnovations/cortex-mcp",
3
- "version": "1.0.58",
3
+ "version": "1.0.59",
4
4
  "description": "Connect your AI tools to Asana, GitHub, Microsoft 365, Monday.com, Salesforce, Slack, Vercel & Supabase MCPs via Cortex",
5
5
  "type": "module",
6
6
  "bin": {
@@ -1,8 +0,0 @@
1
- #!/usr/bin/env node
2
- import {
3
- openBrowser
4
- } from "./chunk-JWMGLAAN.js";
5
- export {
6
- openBrowser
7
- };
8
- //# sourceMappingURL=browser-LPEABS5F.js.map