@danainnovations/cortex-mcp 1.0.73 → 1.0.75

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli.js CHANGED
@@ -399,6 +399,21 @@ function getWizardHtml() {
399
399
  .mcp-item.user-connected { border-color: rgba(76, 175, 80, 0.4); cursor: default; }
400
400
  .mcp-item.user-connected .mcp-check { background: #4CAF50; border-color: #4CAF50; }
401
401
  .mcp-item.user-connected .mcp-check-icon { display: block; }
402
+ .mcp-item.disabled { opacity: 0.4; cursor: not-allowed; pointer-events: none; }
403
+ .mcp-item.disabled .mcp-check { background: transparent; border-color: rgba(255,255,255,0.1); }
404
+ .mcp-coming-soon-label {
405
+ position: absolute;
406
+ top: 6px;
407
+ right: 8px;
408
+ font-size: 9px;
409
+ font-weight: 600;
410
+ text-transform: uppercase;
411
+ letter-spacing: 0.5px;
412
+ color: rgba(255, 255, 255, 0.35);
413
+ background: rgba(255, 255, 255, 0.06);
414
+ padding: 2px 6px;
415
+ border-radius: 4px;
416
+ }
402
417
  .mcp-connected-badge {
403
418
  display: block;
404
419
  font-size: 11px;
@@ -842,6 +857,7 @@ function getWizardHtml() {
842
857
  vscode: '<svg viewBox="0 0 16 16"><path d="M11.5 1L5 7l-3-2.5L1 5l3.5 3L1 11l1 .5L5 9l6.5 6 2.5-1V2z"/></svg>',
843
858
  antigravity: '<svg viewBox="0 0 16 16"><path d="M8 1l2 5h5l-4 3 1.5 5L8 11l-4.5 3L5 9 1 6h5z"/></svg>',
844
859
  codex: '<svg viewBox="0 0 16 16"><circle cx="8" cy="8" r="3" fill="none" stroke="currentColor" stroke-width="1.5"/><path d="M8 1v3M8 12v3M1 8h3M12 8h3" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/></svg>',
860
+ perplexity: '<svg viewBox="0 0 16 16"><circle cx="8" cy="8" r="6" fill="none" stroke="currentColor" stroke-width="1.2"/><path d="M8 2v12M2 8h12M4 4l8 8M12 4l-8 8" stroke="currentColor" stroke-width="1" stroke-linecap="round"/></svg>',
845
861
  stdio: '<svg viewBox="0 0 16 16"><path d="M2 3h12a1 1 0 011 1v8a1 1 0 01-1 1H2a1 1 0 01-1-1V4a1 1 0 011-1zm1 2v6h10V5H3z"/></svg>',
846
862
  };
847
863
 
@@ -852,7 +868,8 @@ function getWizardHtml() {
852
868
  var data = await resp.json();
853
869
  state.credentials = data.credentials;
854
870
  state.availableMcps = data.availableMcps || [];
855
- state.selectedMcps = ['github', 'supabase', 'vercel'];
871
+ state.enabledMcps = data.enabledMcps || ['m365'];
872
+ state.selectedMcps = (data.enabledMcps || ['m365']).slice();
856
873
  state.detectedClients = data.detectedClients || [];
857
874
  state.configuredClients = (data.config && data.config.configuredClients) || [];
858
875
  } catch (err) {
@@ -1005,7 +1022,6 @@ function getWizardHtml() {
1005
1022
  }
1006
1023
 
1007
1024
  // \u2500\u2500 Step 3: Select MCPs \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
1008
- var REQUIRED_MCPS = ['github', 'supabase', 'vercel', 'databricks', 'bestbuy'];
1009
1025
 
1010
1026
  var MCP_TOOLTIPS = {
1011
1027
  asana: 'Manage projects, tasks, and team workflows',
@@ -1025,6 +1041,18 @@ function getWizardHtml() {
1025
1041
  async function renderMcps() {
1026
1042
  var container = document.getElementById('mcp-list-container');
1027
1043
 
1044
+ // Fetch per-user available MCPs (uses API key from login)
1045
+ try {
1046
+ var userResp = await fetch('/api/user-mcps');
1047
+ var userData = await userResp.json();
1048
+ if (userData.mcps && userData.mcps.length > 0) {
1049
+ state.enabledMcps = userData.mcps.map(function(m) { return m.name; });
1050
+ state.selectedMcps = state.enabledMcps.slice();
1051
+ }
1052
+ } catch (e) {
1053
+ // Fall back to global enabledMcps from initial state
1054
+ }
1055
+
1028
1056
  // Fetch existing OAuth connections to show connected status
1029
1057
  try {
1030
1058
  var resp = await fetch('/api/connections');
@@ -1034,31 +1062,35 @@ function getWizardHtml() {
1034
1062
  state.connections = state.connections || [];
1035
1063
  }
1036
1064
 
1037
- var requiredMcps = state.availableMcps.filter(function(m) { return REQUIRED_MCPS.indexOf(m.name) !== -1; });
1038
- var optionalMcps = state.availableMcps.filter(function(m) { return REQUIRED_MCPS.indexOf(m.name) === -1; });
1065
+ var enabledList = (state.enabledMcps && state.enabledMcps.length > 0)
1066
+ ? state.enabledMcps : ['m365'];
1067
+ var enabledMcps = state.availableMcps.filter(function(m) { return enabledList.indexOf(m.name) !== -1; });
1068
+ var disabledMcps = state.availableMcps.filter(function(m) { return enabledList.indexOf(m.name) === -1; });
1039
1069
 
1040
1070
  var html = '';
1041
1071
 
1042
- // Core section
1043
- html += '<div class="mcp-section">';
1044
- html += '<div class="mcp-section-title">Core (always enabled)</div>';
1045
- html += '<div class="mcp-list">';
1046
- html += requiredMcps.map(function(mcp) { return renderMcpItem(mcp, true); }).join('');
1047
- html += '</div></div>';
1072
+ // Enabled section
1073
+ if (enabledMcps.length > 0) {
1074
+ html += '<div class="mcp-section">';
1075
+ html += '<div class="mcp-section-title">Available integrations</div>';
1076
+ html += '<div class="mcp-list">';
1077
+ html += enabledMcps.map(function(mcp) { return renderMcpItem(mcp, false, false); }).join('');
1078
+ html += '</div></div>';
1079
+ }
1048
1080
 
1049
- // Optional section
1050
- if (optionalMcps.length > 0) {
1081
+ // Disabled (coming soon) section
1082
+ if (disabledMcps.length > 0) {
1051
1083
  html += '<div class="mcp-section">';
1052
- html += '<div class="mcp-section-title">Optional integrations</div>';
1084
+ html += '<div class="mcp-section-title">Coming soon</div>';
1053
1085
  html += '<div class="mcp-list">';
1054
- html += optionalMcps.map(function(mcp) { return renderMcpItem(mcp, false); }).join('');
1086
+ html += disabledMcps.map(function(mcp) { return renderMcpItem(mcp, false, true); }).join('');
1055
1087
  html += '</div></div>';
1056
1088
  }
1057
1089
 
1058
1090
  container.innerHTML = html;
1059
1091
 
1060
- // Attach click handlers to optional items
1061
- container.querySelectorAll('.mcp-item:not(.required):not(.user-connected)').forEach(function(item) {
1092
+ // Attach click handlers to enabled items only (not disabled, not user-connected)
1093
+ container.querySelectorAll('.mcp-item:not(.disabled):not(.user-connected)').forEach(function(item) {
1062
1094
  item.addEventListener('click', function(e) {
1063
1095
  e.preventDefault();
1064
1096
  var cb = item.querySelector('input[type="checkbox"]');
@@ -1068,16 +1100,17 @@ function getWizardHtml() {
1068
1100
  });
1069
1101
  }
1070
1102
 
1071
- function renderMcpItem(mcp, isRequired) {
1103
+ function renderMcpItem(mcp, isRequired, isDisabled) {
1072
1104
  var icon = MCP_ICONS[mcp.name] || '';
1073
1105
  var conn = (state.connections || []).find(function(c) { return c.mcp_name === mcp.name; });
1074
- var isConnected = conn && !conn.is_company_default && conn.account_email;
1075
- var checked = isRequired || isConnected || state.selectedMcps.indexOf(mcp.name) !== -1;
1106
+ var isConnected = !isDisabled && conn && !conn.is_company_default && conn.account_email;
1107
+ var checked = !isDisabled && (isRequired || isConnected || state.selectedMcps.indexOf(mcp.name) !== -1);
1076
1108
  return (
1077
1109
  '<label class="mcp-item' + (checked ? ' checked' : '') + (isRequired ? ' required' : '') +
1078
- (isConnected ? ' user-connected' : '') + '" data-mcp="' + mcp.name + '">' +
1110
+ (isConnected ? ' user-connected' : '') +
1111
+ (isDisabled ? ' disabled' : '') + '" data-mcp="' + mcp.name + '">' +
1079
1112
  (MCP_TOOLTIPS[mcp.name] ? '<span class="mcp-tooltip">' + MCP_TOOLTIPS[mcp.name] + '</span>' : '') +
1080
- '<input type="checkbox" value="' + mcp.name + '"' + (checked ? ' checked' : '') + (isConnected ? ' disabled' : '') + '>' +
1113
+ '<input type="checkbox" value="' + mcp.name + '"' + (checked ? ' checked' : '') + ((isConnected || isDisabled) ? ' disabled' : '') + '>' +
1081
1114
  (icon ? '<div class="mcp-icon">' + icon + '</div>' : '') +
1082
1115
  '<div class="mcp-check"><span class="mcp-check-icon">&#10003;</span></div>' +
1083
1116
  '<div class="mcp-info">' +
@@ -1089,14 +1122,14 @@ function getWizardHtml() {
1089
1122
  '</div>' +
1090
1123
  (isRequired ? '<span class="mcp-required-label">Required</span>' : '') +
1091
1124
  (isConnected && !isRequired ? '<span class="mcp-connected-label">Connected</span>' : '') +
1125
+ (isDisabled ? '<span class="mcp-coming-soon-label">Coming Soon</span>' : '') +
1092
1126
  '</label>'
1093
1127
  );
1094
1128
  }
1095
1129
 
1096
1130
  function saveMcps() {
1097
- var checkboxes = document.querySelectorAll('.mcp-item input[type="checkbox"]');
1131
+ var checkboxes = document.querySelectorAll('.mcp-item:not(.disabled) input[type="checkbox"]');
1098
1132
  var selected = Array.from(checkboxes).filter(function(cb) { return cb.checked; }).map(function(cb) { return cb.value; });
1099
- REQUIRED_MCPS.forEach(function(name) { if (selected.indexOf(name) === -1) selected.push(name); });
1100
1133
  state.selectedMcps = selected;
1101
1134
  goToStep('clients');
1102
1135
  }
@@ -1186,8 +1219,8 @@ function getWizardHtml() {
1186
1219
  '<span>' + (r.success ? '&#10003;' : '&#10007;') + '</span>' +
1187
1220
  '<span>' + escapeHtml(r.client) + ': ' + (r.success ? 'Configured' : r.error || 'Failed') + '</span>' +
1188
1221
  '</div>';
1189
- // Show copyable snippet for stdio/OpenClaw
1190
- if (r.client === 'stdio' && r.success && r.message) {
1222
+ // Show copyable snippet for stdio/OpenClaw and Perplexity instructions
1223
+ if ((r.client === 'stdio' || r.client === 'perplexity') && r.success && r.message) {
1191
1224
  var snippet = r.message.replace(/^Add this to your client config:\\n\\n/, '');
1192
1225
  html += '<div class="stdio-snippet">' +
1193
1226
  '<button class="copy-btn" onclick="copySnippet(this)">Copy</button>' +
@@ -1478,6 +1511,13 @@ function detectClients() {
1478
1511
  configPath: codexPath,
1479
1512
  detected: codexDetected
1480
1513
  });
1514
+ const perplexityDir = join(home, "Library", "Containers", "ai.perplexity.mac");
1515
+ clients.push({
1516
+ type: "perplexity",
1517
+ name: "Perplexity Computer",
1518
+ configPath: null,
1519
+ detected: getPlatform() === "macos" && existsSync(perplexityDir)
1520
+ });
1481
1521
  clients.push({
1482
1522
  type: "stdio",
1483
1523
  name: "OpenClaw (stdio)",
@@ -1650,6 +1690,25 @@ http_headers = { "x-api-key" = "${apiKey}" }`
1650
1690
  const newContent = (cleaned ? cleaned + "\n\n" : "") + tomlEntries.join("\n\n") + "\n";
1651
1691
  writeFileSync(configPath, newContent);
1652
1692
  }
1693
+ function configurePerplexity(serverUrl, _apiKey, mcps) {
1694
+ const lines = [
1695
+ "Add each MCP as a separate connector in Perplexity:",
1696
+ " Settings \u2192 Connectors \u2192 Add custom connector",
1697
+ ""
1698
+ ];
1699
+ for (const mcp of AVAILABLE_MCPS) {
1700
+ if (!mcps.includes(mcp.name)) continue;
1701
+ lines.push(`\u2500\u2500 ${mcp.displayName} \u2500\u2500`);
1702
+ lines.push(` Name: Cortex ${mcp.displayName}`);
1703
+ lines.push(` MCP server URL: ${serverUrl}/mcp/${mcp.name}`);
1704
+ lines.push(` Authentication: OAuth`);
1705
+ lines.push(` Client ID: perplexity`);
1706
+ lines.push(` Client Secret: (leave empty)`);
1707
+ lines.push(` Transport: Streamable HTTP`);
1708
+ lines.push("");
1709
+ }
1710
+ return lines.join("\n");
1711
+ }
1653
1712
  function generateStdioSnippet(_apiKey) {
1654
1713
  const isWindows = getPlatform() === "windows";
1655
1714
  const config = {
@@ -1758,6 +1817,8 @@ function configureClient(clientType, serverUrl, apiKey, mcps) {
1758
1817
  case "codex":
1759
1818
  configureCodex(serverUrl, apiKey, mcps);
1760
1819
  return "Codex configured";
1820
+ case "perplexity":
1821
+ return configurePerplexity(serverUrl, apiKey, mcps);
1761
1822
  case "stdio":
1762
1823
  return "Add this to your client config:\n\n" + generateStdioSnippet(apiKey);
1763
1824
  }
@@ -1876,11 +1937,25 @@ async function handleApiRoute(path, searchParams, req, res, options, onComplete)
1876
1937
  const creds = readCredentials();
1877
1938
  const config = readConfig();
1878
1939
  const clients = detectClients();
1940
+ let enabledMcps = ["m365"];
1941
+ try {
1942
+ const setupResp = await fetch(
1943
+ `${options.serverUrl}/api/v1/mcps/setup-enabled`
1944
+ );
1945
+ if (setupResp.ok) {
1946
+ const setupData = await setupResp.json();
1947
+ if (Array.isArray(setupData.enabled)) {
1948
+ enabledMcps = setupData.enabled;
1949
+ }
1950
+ }
1951
+ } catch {
1952
+ }
1879
1953
  json(res, {
1880
1954
  credentials: creds ? { email: creds.email, name: creds.name } : null,
1881
1955
  config,
1882
1956
  apiKey: getState().apiKey,
1883
1957
  defaultMcps: [...DEFAULT_MCPS],
1958
+ enabledMcps,
1884
1959
  availableMcps: AVAILABLE_MCPS.map((m) => ({
1885
1960
  name: m.name,
1886
1961
  displayName: m.displayName,
@@ -1940,6 +2015,42 @@ async function handleApiRoute(path, searchParams, req, res, options, onComplete)
1940
2015
  }
1941
2016
  return true;
1942
2017
  }
2018
+ if (path === "/api/user-mcps" && method === "GET") {
2019
+ const apiKey = getState().apiKey;
2020
+ if (!apiKey) {
2021
+ json(res, { mcps: [] });
2022
+ return true;
2023
+ }
2024
+ try {
2025
+ const resp = await fetch(
2026
+ `${options.serverUrl}/api/v1/mcps/user-available`,
2027
+ { headers: { "x-api-key": apiKey } }
2028
+ );
2029
+ if (resp.ok) {
2030
+ const data = await resp.json();
2031
+ json(res, data);
2032
+ } else {
2033
+ json(res, {
2034
+ mcps: AVAILABLE_MCPS.map((m) => ({
2035
+ name: m.name,
2036
+ displayName: m.displayName,
2037
+ authMode: m.authMode,
2038
+ connected: false
2039
+ }))
2040
+ });
2041
+ }
2042
+ } catch {
2043
+ json(res, {
2044
+ mcps: AVAILABLE_MCPS.map((m) => ({
2045
+ name: m.name,
2046
+ displayName: m.displayName,
2047
+ authMode: m.authMode,
2048
+ connected: false
2049
+ }))
2050
+ });
2051
+ }
2052
+ return true;
2053
+ }
1943
2054
  if (path === "/api/clients/configure" && method === "POST") {
1944
2055
  const body = await parseBody(req);
1945
2056
  const clients = body.clients || [];
@@ -2153,6 +2264,7 @@ var VALID_CLIENTS = {
2153
2264
  "claude-code": "claude-code",
2154
2265
  cursor: "cursor",
2155
2266
  codex: "codex",
2267
+ perplexity: "perplexity",
2156
2268
  stdio: "stdio"
2157
2269
  };
2158
2270
  async function runConfigure(options) {