@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 +137 -25
- package/dist/cli.js.map +1 -1
- package/dist/index.d.ts +7 -2
- package/dist/index.js +29 -0
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
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.
|
|
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
|
|
1038
|
-
|
|
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
|
-
//
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
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
|
-
//
|
|
1050
|
-
if (
|
|
1081
|
+
// Disabled (coming soon) section
|
|
1082
|
+
if (disabledMcps.length > 0) {
|
|
1051
1083
|
html += '<div class="mcp-section">';
|
|
1052
|
-
html += '<div class="mcp-section-title">
|
|
1084
|
+
html += '<div class="mcp-section-title">Coming soon</div>';
|
|
1053
1085
|
html += '<div class="mcp-list">';
|
|
1054
|
-
html +=
|
|
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
|
|
1061
|
-
container.querySelectorAll('.mcp-item:not(.
|
|
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' : '') +
|
|
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">✓</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 ? '✓' : '✗') + '</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) {
|