@algosuite/vo-mcp 0.2.0-beta.59 → 0.2.0-beta.61
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/ci/check-local-pr-overlap.js +117 -7
- package/dist/cli.js +210 -52
- package/dist/cli.js.map +4 -4
- package/dist/index.js +184 -42
- package/dist/index.js.map +4 -4
- package/dist/install-cli.js +68 -6
- package/dist/install-cli.js.map +3 -3
- package/dist/runner-cli.js +777 -325
- package/dist/runner-cli.js.map +4 -4
- package/package.json +1 -1
package/dist/install-cli.js
CHANGED
|
@@ -546,6 +546,43 @@ function installCodexMcpConfigAt(configPath, cliPath, controlPlaneUrl, log, mana
|
|
|
546
546
|
log(`\u2713 Wrote AlgoHQ MCP to Codex: ${configPath}`);
|
|
547
547
|
}
|
|
548
548
|
|
|
549
|
+
// src/remote-mcp-entry.ts
|
|
550
|
+
var REMOTE_MCP_SERVER_KEY = "vo-mcp-remote";
|
|
551
|
+
var REMOTE_MCP_TOKEN_ENV = "VO_MCP_REMOTE_TOKEN";
|
|
552
|
+
var REMOTE_MCP_ENDPOINT_PATH = "/api/v1/mcp";
|
|
553
|
+
var REMOTE_MCP_AUTH_HEADER = `Bearer \${${REMOTE_MCP_TOKEN_ENV}}`;
|
|
554
|
+
function remoteMcpOptIn(env) {
|
|
555
|
+
return (env["VO_REMOTE_MCP"] ?? "").trim() === "1";
|
|
556
|
+
}
|
|
557
|
+
function remoteMcpUrl(controlPlaneUrl) {
|
|
558
|
+
return `${controlPlaneUrl.trim().replace(/\/+$/, "")}${REMOTE_MCP_ENDPOINT_PATH}`;
|
|
559
|
+
}
|
|
560
|
+
function buildRemoteMcpEntry(controlPlaneUrl) {
|
|
561
|
+
return {
|
|
562
|
+
type: "http",
|
|
563
|
+
url: remoteMcpUrl(controlPlaneUrl),
|
|
564
|
+
headers: { Authorization: REMOTE_MCP_AUTH_HEADER }
|
|
565
|
+
};
|
|
566
|
+
}
|
|
567
|
+
function asRecord(value) {
|
|
568
|
+
return typeof value === "object" && value !== null && !Array.isArray(value) ? value : null;
|
|
569
|
+
}
|
|
570
|
+
function isManagedRemoteMcpEntry(value) {
|
|
571
|
+
const entry = asRecord(value);
|
|
572
|
+
if (!entry) return false;
|
|
573
|
+
if (entry["type"] !== "http") return false;
|
|
574
|
+
const url = entry["url"];
|
|
575
|
+
if (typeof url !== "string" || !url.endsWith(REMOTE_MCP_ENDPOINT_PATH)) return false;
|
|
576
|
+
const headers = asRecord(entry["headers"]);
|
|
577
|
+
return headers?.["Authorization"] === REMOTE_MCP_AUTH_HEADER;
|
|
578
|
+
}
|
|
579
|
+
function remoteMcpEntryIsCurrent(value, desired) {
|
|
580
|
+
const entry = asRecord(value);
|
|
581
|
+
if (!entry) return false;
|
|
582
|
+
const headers = asRecord(entry["headers"]);
|
|
583
|
+
return entry["type"] === desired.type && entry["url"] === desired.url && headers?.["Authorization"] === desired.headers["Authorization"];
|
|
584
|
+
}
|
|
585
|
+
|
|
549
586
|
// src/autostart.ts
|
|
550
587
|
import { homedir as homedir3, platform as platform2 } from "node:os";
|
|
551
588
|
import { isAbsolute as isAbsolute2, join as join5 } from "node:path";
|
|
@@ -810,7 +847,20 @@ function resolveVoMcpCliPath() {
|
|
|
810
847
|
}
|
|
811
848
|
var INSTALL_LAUNCHER = { sticky: false, onlyExisting: false };
|
|
812
849
|
var HEAL_LAUNCHER = { sticky: true, onlyExisting: true };
|
|
813
|
-
function
|
|
850
|
+
function reconcileRemoteEntry(mcpServers, remote) {
|
|
851
|
+
const existing = mcpServers[REMOTE_MCP_SERVER_KEY];
|
|
852
|
+
if (remote) {
|
|
853
|
+
return {
|
|
854
|
+
fragment: { [REMOTE_MCP_SERVER_KEY]: remote },
|
|
855
|
+
current: remoteMcpEntryIsCurrent(existing, remote)
|
|
856
|
+
};
|
|
857
|
+
}
|
|
858
|
+
if (existing !== void 0 && isManagedRemoteMcpEntry(existing)) {
|
|
859
|
+
return { fragment: { [REMOTE_MCP_SERVER_KEY]: void 0 }, current: false };
|
|
860
|
+
}
|
|
861
|
+
return { fragment: {}, current: true };
|
|
862
|
+
}
|
|
863
|
+
function installMcpConfigAt(configPath, cliPath, controlPlaneUrl, log, label, launcher = { launcherPath: null, ...INSTALL_LAUNCHER }, remote = null) {
|
|
814
864
|
if (launcher.onlyExisting && !existsSync6(configPath)) return;
|
|
815
865
|
const read = readClaudeConfig(configPath);
|
|
816
866
|
if (read.kind === "invalid" || read.kind === "empty" && launcher.onlyExisting) {
|
|
@@ -824,8 +874,9 @@ function installMcpConfigAt(configPath, cliPath, controlPlaneUrl, log, label, la
|
|
|
824
874
|
const voEntry = managedEntry ?? mcpServers["vo"];
|
|
825
875
|
const { launcherPath } = launcher;
|
|
826
876
|
const fallbackCli = chooseFallbackCli(voEntry?.env?.[MCP_FALLBACK_CLI_ENV], cliPath, launcher.sticky, launcherPath ? dirname4(launcherPath) : null);
|
|
827
|
-
const
|
|
828
|
-
|
|
877
|
+
const localCurrent = launcherPath ? !isStaleVoMcpEntry(voEntry, launcherPath, fallbackCli) : Boolean(voEntry?.args?.some((a) => a.includes(cliPath)));
|
|
878
|
+
const remoteState = reconcileRemoteEntry(mcpServers, remote);
|
|
879
|
+
if (localCurrent && remoteState.current) {
|
|
829
880
|
log(` ${label} already current: ${configPath}`);
|
|
830
881
|
return;
|
|
831
882
|
}
|
|
@@ -845,7 +896,11 @@ function installMcpConfigAt(configPath, cliPath, controlPlaneUrl, log, label, la
|
|
|
845
896
|
...preservedEnv,
|
|
846
897
|
...launcherPath && fallbackCli ? { [MCP_FALLBACK_CLI_ENV]: fallbackCli } : {}
|
|
847
898
|
}
|
|
848
|
-
}
|
|
899
|
+
},
|
|
900
|
+
// Additive remote entry (11.3 slice A) — or the removal of one we wrote,
|
|
901
|
+
// when the operator has opted back out. Spread LAST so it can delete its
|
|
902
|
+
// own key; it never names 'vo-mcp', so the stdio entry above is safe.
|
|
903
|
+
...remoteState.fragment
|
|
849
904
|
}
|
|
850
905
|
};
|
|
851
906
|
if (readMtime !== null && (!existsSync6(configPath) || statSync3(configPath).mtimeMs !== readMtime)) {
|
|
@@ -854,6 +909,12 @@ function installMcpConfigAt(configPath, cliPath, controlPlaneUrl, log, label, la
|
|
|
854
909
|
}
|
|
855
910
|
writeClaudeConfig(configPath, merged);
|
|
856
911
|
log(`\u2713 Wrote vo-mcp to ${label}: ${configPath}`);
|
|
912
|
+
if (remote) {
|
|
913
|
+
log(` + remote MCP entry '${REMOTE_MCP_SERVER_KEY}' \u2192 ${remote.url} (serves vo_skill_list; every other tool stays on the local vo-mcp entry)`);
|
|
914
|
+
log(` Set ${REMOTE_MCP_TOKEN_ENV} in your environment to authenticate it \u2014 no token is written to this file.`);
|
|
915
|
+
} else if (!remoteState.current) {
|
|
916
|
+
log(` - removed the remote MCP entry '${REMOTE_MCP_SERVER_KEY}' (VO_REMOTE_MCP is not set to 1)`);
|
|
917
|
+
}
|
|
857
918
|
}
|
|
858
919
|
function installMcpConfig(log, env, mode = "install") {
|
|
859
920
|
const home = env["HOME"]?.trim() || env["USERPROFILE"]?.trim() || homedir4();
|
|
@@ -861,6 +922,7 @@ function installMcpConfig(log, env, mode = "install") {
|
|
|
861
922
|
const plat = platform3();
|
|
862
923
|
const cliPath = resolveVoMcpCliPath();
|
|
863
924
|
const controlPlaneUrl = env["VO_CONTROL_PLANE_URL"]?.trim() || DEFAULT_CONTROL_PLANE_URL2;
|
|
925
|
+
const remote = remoteMcpOptIn(env) ? buildRemoteMcpEntry(controlPlaneUrl) : null;
|
|
864
926
|
const launcherPath = writeMcpLauncherForEnv(env, log, { platform: plat, home });
|
|
865
927
|
const launcher = { launcherPath, ...mode === "heal" ? HEAL_LAUNCHER : INSTALL_LAUNCHER };
|
|
866
928
|
const leg = (label, run) => {
|
|
@@ -871,8 +933,8 @@ function installMcpConfig(log, env, mode = "install") {
|
|
|
871
933
|
log(` \u26A0 ${label}: could not update the MCP registration \u2014 ${err instanceof Error ? err.message : String(err)}`);
|
|
872
934
|
}
|
|
873
935
|
};
|
|
874
|
-
leg("Claude Code CLI", () => installMcpConfigAt(resolveCodeConfigPath(home), cliPath, controlPlaneUrl, log, "Claude Code CLI", launcher));
|
|
875
|
-
leg("Claude Desktop", () => installMcpConfigAt(resolveDesktopConfigPath(home, plat, appData), cliPath, controlPlaneUrl, log, "Claude Desktop", launcher));
|
|
936
|
+
leg("Claude Code CLI", () => installMcpConfigAt(resolveCodeConfigPath(home), cliPath, controlPlaneUrl, log, "Claude Code CLI", launcher, remote));
|
|
937
|
+
leg("Claude Desktop", () => installMcpConfigAt(resolveDesktopConfigPath(home, plat, appData), cliPath, controlPlaneUrl, log, "Claude Desktop", launcher, remote));
|
|
876
938
|
const codexPath = resolveCodexConfigPath(home);
|
|
877
939
|
if (launcher.onlyExisting && !existsSync6(codexPath)) return;
|
|
878
940
|
leg("Codex", () => {
|