@cubis/foundry 0.3.41 → 0.3.43
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/README.md +24 -5
- package/bin/cubis.js +254 -11
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -32,7 +32,7 @@ Skill install default is profile-based:
|
|
|
32
32
|
|
|
33
33
|
- Workflow files (`/plan`, `/create`, etc.)
|
|
34
34
|
- Skill folders
|
|
35
|
-
- Codex callable wrapper skills (
|
|
35
|
+
- Codex callable wrapper skills ($workflow-*, $agent-*)
|
|
36
36
|
- Platform rule files (`AGENTS.md`, `GEMINI.md`, etc.)
|
|
37
37
|
- Engineering artifacts in workspace (`ENGINEERING_RULES.md`, `TECH.md`)
|
|
38
38
|
- Managed MCP config for Postman and Stitch
|
|
@@ -145,7 +145,7 @@ Postman and Stitch now support multiple named profiles with active selection.
|
|
|
145
145
|
"runtime": "docker",
|
|
146
146
|
"fallback": "local",
|
|
147
147
|
"docker": {
|
|
148
|
-
"image": "ghcr.io/
|
|
148
|
+
"image": "ghcr.io/cubetiq/foundry-mcp:<package-version>",
|
|
149
149
|
"updatePolicy": "pinned"
|
|
150
150
|
},
|
|
151
151
|
"catalog": {
|
|
@@ -286,7 +286,7 @@ MCP runtime flags (install):
|
|
|
286
286
|
cbx workflows install --platform codex --bundle agent-environment-setup --postman \
|
|
287
287
|
--mcp-runtime docker \
|
|
288
288
|
--mcp-fallback local \
|
|
289
|
-
--mcp-image ghcr.io/
|
|
289
|
+
--mcp-image ghcr.io/cubetiq/foundry-mcp:<package-version> \
|
|
290
290
|
--mcp-update-policy pinned \
|
|
291
291
|
--mcp-build-local # optional: build image locally instead of docker pull
|
|
292
292
|
```
|
|
@@ -323,10 +323,10 @@ MCP Docker runtime commands:
|
|
|
323
323
|
cbx mcp runtime status --scope global --name cbx-mcp
|
|
324
324
|
|
|
325
325
|
# Start runtime container (pull/build image first as needed)
|
|
326
|
-
cbx mcp runtime up --scope global --name cbx-mcp --port 3310
|
|
326
|
+
cbx mcp runtime up --scope global --name cbx-mcp --port 3310 --fallback local
|
|
327
327
|
|
|
328
328
|
# Recreate existing container
|
|
329
|
-
cbx mcp runtime up --scope global --name cbx-mcp --replace
|
|
329
|
+
cbx mcp runtime up --scope global --name cbx-mcp --replace --fallback local
|
|
330
330
|
|
|
331
331
|
# Stop/remove runtime container
|
|
332
332
|
cbx mcp runtime down --name cbx-mcp
|
|
@@ -382,6 +382,10 @@ cbx workflows config --scope global --show
|
|
|
382
382
|
cbx workflows config --scope global --edit
|
|
383
383
|
cbx workflows config --scope global --workspace-id "<workspace-id>"
|
|
384
384
|
cbx workflows config --scope global --clear-workspace-id
|
|
385
|
+
|
|
386
|
+
# Switch MCP runtime preference quickly
|
|
387
|
+
cbx workflows config --scope project --mcp-runtime local
|
|
388
|
+
cbx workflows config --scope project --mcp-runtime docker --mcp-fallback local
|
|
385
389
|
```
|
|
386
390
|
|
|
387
391
|
`--show` now includes computed `status`:
|
|
@@ -462,6 +466,21 @@ If `~/.agents/skills` is missing, runtime still starts but will warn and skill d
|
|
|
462
466
|
- `cbx mcp serve --transport stdio` runs local stdio transport for command-based MCP clients.
|
|
463
467
|
- Prefer stdio command server entries (`cubis-foundry`) for direct client integrations; use Docker runtime for explicit HTTP endpoint use cases.
|
|
464
468
|
|
|
469
|
+
### Docker endpoint resets at `127.0.0.1:<port>/mcp`
|
|
470
|
+
|
|
471
|
+
If Docker runtime starts but MCP endpoint is unreachable:
|
|
472
|
+
|
|
473
|
+
```bash
|
|
474
|
+
# Check health and hints
|
|
475
|
+
cbx mcp runtime status --scope project --name cbx-mcp
|
|
476
|
+
|
|
477
|
+
# Switch this project to local runtime
|
|
478
|
+
cbx workflows config --scope project --mcp-runtime local
|
|
479
|
+
|
|
480
|
+
# Use direct local server path
|
|
481
|
+
cbx mcp serve --transport stdio --scope auto
|
|
482
|
+
```
|
|
483
|
+
|
|
465
484
|
### Duplicate skills shown in UI after older installs
|
|
466
485
|
|
|
467
486
|
Installer now auto-cleans nested duplicate skills (for example duplicates under `postman/*`).
|
package/bin/cubis.js
CHANGED
|
@@ -177,7 +177,7 @@ const MCP_UPDATE_POLICIES = new Set(["pinned", "latest"]);
|
|
|
177
177
|
const DEFAULT_MCP_RUNTIME = "docker";
|
|
178
178
|
const DEFAULT_MCP_FALLBACK = "local";
|
|
179
179
|
const DEFAULT_MCP_UPDATE_POLICY = "pinned";
|
|
180
|
-
const DEFAULT_MCP_DOCKER_IMAGE =
|
|
180
|
+
const DEFAULT_MCP_DOCKER_IMAGE = `ghcr.io/cubetiq/foundry-mcp:${CLI_VERSION}`;
|
|
181
181
|
const DEFAULT_MCP_DOCKER_CONTAINER_NAME = "cbx-mcp";
|
|
182
182
|
const DEFAULT_MCP_DOCKER_HOST_PORT = 3310;
|
|
183
183
|
const MCP_DOCKER_CONTAINER_PORT = 3100;
|
|
@@ -2512,7 +2512,7 @@ function escapeRegExp(value) {
|
|
|
2512
2512
|
|
|
2513
2513
|
function rewriteCodexWorkflowAgentReferences(sourceBody, agentIds) {
|
|
2514
2514
|
if (!sourceBody || !Array.isArray(agentIds) || agentIds.length === 0)
|
|
2515
|
-
return sourceBody;
|
|
2515
|
+
return normalizeCodexWrapperMentions(sourceBody);
|
|
2516
2516
|
|
|
2517
2517
|
let rewritten = sourceBody;
|
|
2518
2518
|
const sortedAgentIds = unique(agentIds.filter(Boolean)).sort(
|
|
@@ -2530,14 +2530,23 @@ function rewriteCodexWorkflowAgentReferences(sourceBody, agentIds) {
|
|
|
2530
2530
|
);
|
|
2531
2531
|
}
|
|
2532
2532
|
|
|
2533
|
-
return rewritten;
|
|
2533
|
+
return normalizeCodexWrapperMentions(rewritten);
|
|
2534
2534
|
}
|
|
2535
2535
|
|
|
2536
2536
|
function rewriteCodexAgentSkillReferences(sourceBody) {
|
|
2537
2537
|
if (!sourceBody) return sourceBody;
|
|
2538
2538
|
// Agent source files live under platforms/*/agents, but wrapper skills live
|
|
2539
2539
|
// under .agents/skills/agent-*. Rebase ../skills/<id> links accordingly.
|
|
2540
|
-
|
|
2540
|
+
const rebased = sourceBody.replace(/\(\.\.\/skills\//g, "(../");
|
|
2541
|
+
return normalizeCodexWrapperMentions(rebased);
|
|
2542
|
+
}
|
|
2543
|
+
|
|
2544
|
+
function normalizeCodexWrapperMentions(sourceBody) {
|
|
2545
|
+
if (!sourceBody) return sourceBody;
|
|
2546
|
+
return sourceBody.replace(
|
|
2547
|
+
/`\$(workflow|agent)-([A-Za-z0-9_-]+|\*)`/g,
|
|
2548
|
+
(_match, kind, id) => `$${kind}-${id}`,
|
|
2549
|
+
);
|
|
2541
2550
|
}
|
|
2542
2551
|
|
|
2543
2552
|
async function parseWorkflowMetadata(filePath) {
|
|
@@ -7103,6 +7112,49 @@ async function writeConfigFile({
|
|
|
7103
7112
|
: "created";
|
|
7104
7113
|
}
|
|
7105
7114
|
|
|
7115
|
+
async function persistMcpRuntimePreference({
|
|
7116
|
+
scope,
|
|
7117
|
+
runtime,
|
|
7118
|
+
fallback = null,
|
|
7119
|
+
cwd = process.cwd(),
|
|
7120
|
+
generatedBy = "cbx mcp runtime up",
|
|
7121
|
+
}) {
|
|
7122
|
+
const { configPath, existing, existingValue } = await loadConfigForScope({
|
|
7123
|
+
scope,
|
|
7124
|
+
cwd,
|
|
7125
|
+
});
|
|
7126
|
+
if (!existing.exists || !existingValue) {
|
|
7127
|
+
return {
|
|
7128
|
+
action: "skipped",
|
|
7129
|
+
configPath,
|
|
7130
|
+
reason: "config-missing",
|
|
7131
|
+
};
|
|
7132
|
+
}
|
|
7133
|
+
const next = prepareConfigDocument(existingValue, {
|
|
7134
|
+
scope,
|
|
7135
|
+
generatedBy,
|
|
7136
|
+
});
|
|
7137
|
+
if (!next.mcp || typeof next.mcp !== "object" || Array.isArray(next.mcp)) {
|
|
7138
|
+
next.mcp = {};
|
|
7139
|
+
}
|
|
7140
|
+
next.mcp.runtime = runtime;
|
|
7141
|
+
next.mcp.effectiveRuntime = runtime;
|
|
7142
|
+
if (fallback) {
|
|
7143
|
+
next.mcp.fallback = fallback;
|
|
7144
|
+
}
|
|
7145
|
+
const action = await writeConfigFile({
|
|
7146
|
+
configPath,
|
|
7147
|
+
nextConfig: next,
|
|
7148
|
+
existingExists: existing.exists,
|
|
7149
|
+
dryRun: false,
|
|
7150
|
+
});
|
|
7151
|
+
return {
|
|
7152
|
+
action,
|
|
7153
|
+
configPath,
|
|
7154
|
+
reason: null,
|
|
7155
|
+
};
|
|
7156
|
+
}
|
|
7157
|
+
|
|
7106
7158
|
function toProfileEnvSuffix(profileName) {
|
|
7107
7159
|
const normalized =
|
|
7108
7160
|
normalizeCredentialProfileName(profileName) || DEFAULT_CREDENTIAL_PROFILE_NAME;
|
|
@@ -7633,6 +7685,8 @@ async function runWorkflowConfig(options) {
|
|
|
7633
7685
|
const hasWorkspaceIdOption = opts.workspaceId !== undefined;
|
|
7634
7686
|
const wantsClearWorkspaceId = Boolean(opts.clearWorkspaceId);
|
|
7635
7687
|
const wantsInteractiveEdit = Boolean(opts.edit);
|
|
7688
|
+
const hasMcpRuntimeOption = opts.mcpRuntime !== undefined;
|
|
7689
|
+
const hasMcpFallbackOption = opts.mcpFallback !== undefined;
|
|
7636
7690
|
|
|
7637
7691
|
if (hasWorkspaceIdOption && wantsClearWorkspaceId) {
|
|
7638
7692
|
throw new Error(
|
|
@@ -7641,7 +7695,11 @@ async function runWorkflowConfig(options) {
|
|
|
7641
7695
|
}
|
|
7642
7696
|
|
|
7643
7697
|
const wantsMutation =
|
|
7644
|
-
hasWorkspaceIdOption ||
|
|
7698
|
+
hasWorkspaceIdOption ||
|
|
7699
|
+
wantsClearWorkspaceId ||
|
|
7700
|
+
wantsInteractiveEdit ||
|
|
7701
|
+
hasMcpRuntimeOption ||
|
|
7702
|
+
hasMcpFallbackOption;
|
|
7645
7703
|
const showOnly = Boolean(opts.show) || !wantsMutation;
|
|
7646
7704
|
const { configPath, existing, existingValue } = await loadConfigForScope({
|
|
7647
7705
|
scope,
|
|
@@ -7683,6 +7741,18 @@ async function runWorkflowConfig(options) {
|
|
|
7683
7741
|
if (wantsClearWorkspaceId) {
|
|
7684
7742
|
workspaceId = null;
|
|
7685
7743
|
}
|
|
7744
|
+
const mcpRuntime = hasMcpRuntimeOption
|
|
7745
|
+
? normalizeMcpRuntime(
|
|
7746
|
+
opts.mcpRuntime,
|
|
7747
|
+
normalizeMcpRuntime(next.mcp?.runtime, DEFAULT_MCP_RUNTIME),
|
|
7748
|
+
)
|
|
7749
|
+
: null;
|
|
7750
|
+
const mcpFallback = hasMcpFallbackOption
|
|
7751
|
+
? normalizeMcpFallback(
|
|
7752
|
+
opts.mcpFallback,
|
|
7753
|
+
normalizeMcpFallback(next.mcp?.fallback, DEFAULT_MCP_FALLBACK),
|
|
7754
|
+
)
|
|
7755
|
+
: null;
|
|
7686
7756
|
|
|
7687
7757
|
activeProfile.workspaceId = workspaceId;
|
|
7688
7758
|
const updatedProfiles = postmanState.profiles.map((profile) =>
|
|
@@ -7704,6 +7774,17 @@ async function runWorkflowConfig(options) {
|
|
|
7704
7774
|
});
|
|
7705
7775
|
upsertNormalizedPostmanConfig(next, updatedPostmanState);
|
|
7706
7776
|
|
|
7777
|
+
if (!next.mcp || typeof next.mcp !== "object" || Array.isArray(next.mcp)) {
|
|
7778
|
+
next.mcp = {};
|
|
7779
|
+
}
|
|
7780
|
+
if (hasMcpRuntimeOption) {
|
|
7781
|
+
next.mcp.runtime = mcpRuntime;
|
|
7782
|
+
next.mcp.effectiveRuntime = mcpRuntime;
|
|
7783
|
+
}
|
|
7784
|
+
if (hasMcpFallbackOption) {
|
|
7785
|
+
next.mcp.fallback = mcpFallback;
|
|
7786
|
+
}
|
|
7787
|
+
|
|
7707
7788
|
if (parseStoredStitchConfig(next)) {
|
|
7708
7789
|
upsertNormalizedStitchConfig(next, parseStoredStitchConfig(next));
|
|
7709
7790
|
}
|
|
@@ -7720,6 +7801,13 @@ async function runWorkflowConfig(options) {
|
|
|
7720
7801
|
console.log(
|
|
7721
7802
|
`postman.defaultWorkspaceId: ${workspaceId === null ? "null" : workspaceId}`,
|
|
7722
7803
|
);
|
|
7804
|
+
if (hasMcpRuntimeOption) {
|
|
7805
|
+
console.log(`mcp.runtime: ${mcpRuntime}`);
|
|
7806
|
+
console.log(`mcp.effectiveRuntime: ${mcpRuntime}`);
|
|
7807
|
+
}
|
|
7808
|
+
if (hasMcpFallbackOption) {
|
|
7809
|
+
console.log(`mcp.fallback: ${mcpFallback}`);
|
|
7810
|
+
}
|
|
7723
7811
|
if (Boolean(opts.showAfter)) {
|
|
7724
7812
|
const payload = buildConfigShowPayload(next);
|
|
7725
7813
|
console.log(JSON.stringify(payload, null, 2));
|
|
@@ -7792,8 +7880,13 @@ async function sendMcpJsonRpcRequest({
|
|
|
7792
7880
|
});
|
|
7793
7881
|
const text = await response.text();
|
|
7794
7882
|
if (!response.ok) {
|
|
7883
|
+
const parsedError = parseMcpJsonRpcResponse(text);
|
|
7884
|
+
const serverMessage =
|
|
7885
|
+
normalizePostmanApiKey(parsedError?.error?.message) ||
|
|
7886
|
+
normalizePostmanApiKey(parsedError?.message);
|
|
7887
|
+
const detail = serverMessage ? ` (${serverMessage})` : "";
|
|
7795
7888
|
throw new Error(
|
|
7796
|
-
`MCP request failed (${method}): HTTP ${response.status} ${response.statusText}`,
|
|
7889
|
+
`MCP request failed (${method}): HTTP ${response.status} ${response.statusText}${detail}`,
|
|
7797
7890
|
);
|
|
7798
7891
|
}
|
|
7799
7892
|
const parsed = parseMcpJsonRpcResponse(text);
|
|
@@ -7806,6 +7899,75 @@ async function sendMcpJsonRpcRequest({
|
|
|
7806
7899
|
};
|
|
7807
7900
|
}
|
|
7808
7901
|
|
|
7902
|
+
function sleepMs(ms) {
|
|
7903
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
7904
|
+
}
|
|
7905
|
+
|
|
7906
|
+
async function waitForMcpEndpointReady({
|
|
7907
|
+
url,
|
|
7908
|
+
headers = {},
|
|
7909
|
+
timeoutMs = 15000,
|
|
7910
|
+
intervalMs = 500,
|
|
7911
|
+
}) {
|
|
7912
|
+
const startedAt = Date.now();
|
|
7913
|
+
let lastError = null;
|
|
7914
|
+
|
|
7915
|
+
while (Date.now() - startedAt < timeoutMs) {
|
|
7916
|
+
let sessionId = null;
|
|
7917
|
+
try {
|
|
7918
|
+
const init = await sendMcpJsonRpcRequest({
|
|
7919
|
+
url,
|
|
7920
|
+
method: "initialize",
|
|
7921
|
+
id: `cbx-runtime-init-${Date.now()}`,
|
|
7922
|
+
params: {
|
|
7923
|
+
protocolVersion: "2025-06-18",
|
|
7924
|
+
capabilities: {},
|
|
7925
|
+
clientInfo: {
|
|
7926
|
+
name: "cbx-runtime",
|
|
7927
|
+
version: CLI_VERSION,
|
|
7928
|
+
},
|
|
7929
|
+
},
|
|
7930
|
+
headers,
|
|
7931
|
+
});
|
|
7932
|
+
sessionId = init.sessionId;
|
|
7933
|
+
await sendMcpJsonRpcRequest({
|
|
7934
|
+
url,
|
|
7935
|
+
method: "notifications/initialized",
|
|
7936
|
+
params: {},
|
|
7937
|
+
headers,
|
|
7938
|
+
sessionId,
|
|
7939
|
+
});
|
|
7940
|
+
return true;
|
|
7941
|
+
} catch (error) {
|
|
7942
|
+
const message = String(error?.message || "").toLowerCase();
|
|
7943
|
+
if (message.includes("already initialized")) {
|
|
7944
|
+
return true;
|
|
7945
|
+
}
|
|
7946
|
+
lastError = error;
|
|
7947
|
+
} finally {
|
|
7948
|
+
if (sessionId) {
|
|
7949
|
+
try {
|
|
7950
|
+
await fetch(url, {
|
|
7951
|
+
method: "DELETE",
|
|
7952
|
+
headers: {
|
|
7953
|
+
...headers,
|
|
7954
|
+
"mcp-session-id": sessionId,
|
|
7955
|
+
},
|
|
7956
|
+
});
|
|
7957
|
+
} catch {
|
|
7958
|
+
// best effort
|
|
7959
|
+
}
|
|
7960
|
+
}
|
|
7961
|
+
}
|
|
7962
|
+
await sleepMs(intervalMs);
|
|
7963
|
+
}
|
|
7964
|
+
|
|
7965
|
+
const suffix = lastError ? ` (${lastError.message})` : "";
|
|
7966
|
+
throw new Error(
|
|
7967
|
+
`MCP endpoint readiness check timed out after ${timeoutMs}ms${suffix}`,
|
|
7968
|
+
);
|
|
7969
|
+
}
|
|
7970
|
+
|
|
7809
7971
|
async function discoverUpstreamTools({
|
|
7810
7972
|
service,
|
|
7811
7973
|
url,
|
|
@@ -8319,9 +8481,23 @@ async function runMcpRuntimeStatus(options) {
|
|
|
8319
8481
|
containerPort: MCP_DOCKER_CONTAINER_PORT,
|
|
8320
8482
|
cwd,
|
|
8321
8483
|
})) || DEFAULT_MCP_DOCKER_HOST_PORT;
|
|
8322
|
-
|
|
8323
|
-
|
|
8324
|
-
|
|
8484
|
+
const endpoint = `http://127.0.0.1:${hostPort}/mcp`;
|
|
8485
|
+
console.log(`Endpoint: ${endpoint}`);
|
|
8486
|
+
try {
|
|
8487
|
+
await waitForMcpEndpointReady({
|
|
8488
|
+
url: endpoint,
|
|
8489
|
+
timeoutMs: 5000,
|
|
8490
|
+
intervalMs: 500,
|
|
8491
|
+
});
|
|
8492
|
+
console.log("Endpoint health: ready");
|
|
8493
|
+
} catch (error) {
|
|
8494
|
+
console.log(`Endpoint health: unreachable (${error.message})`);
|
|
8495
|
+
if (defaults.defaults.fallback === "local") {
|
|
8496
|
+
console.log(
|
|
8497
|
+
`Hint: switch config to local runtime: cbx workflows config --scope ${scope} --mcp-runtime local`,
|
|
8498
|
+
);
|
|
8499
|
+
}
|
|
8500
|
+
}
|
|
8325
8501
|
}
|
|
8326
8502
|
} catch (error) {
|
|
8327
8503
|
console.error(`\nError: ${error.message}`);
|
|
@@ -8343,6 +8519,10 @@ async function runMcpRuntimeUp(options) {
|
|
|
8343
8519
|
opts.updatePolicy,
|
|
8344
8520
|
defaults.defaults.updatePolicy,
|
|
8345
8521
|
);
|
|
8522
|
+
const fallback = normalizeMcpFallback(
|
|
8523
|
+
opts.fallback,
|
|
8524
|
+
defaults.defaults.fallback,
|
|
8525
|
+
);
|
|
8346
8526
|
const buildLocal = hasCliFlag("--build-local")
|
|
8347
8527
|
? true
|
|
8348
8528
|
: defaults.defaults.buildLocal;
|
|
@@ -8396,7 +8576,17 @@ async function runMcpRuntimeUp(options) {
|
|
|
8396
8576
|
if (skillsRootExists) {
|
|
8397
8577
|
dockerArgs.push("-v", `${skillsRoot}:/workflows/skills:ro`);
|
|
8398
8578
|
}
|
|
8399
|
-
dockerArgs.push(
|
|
8579
|
+
dockerArgs.push(
|
|
8580
|
+
image,
|
|
8581
|
+
"--transport",
|
|
8582
|
+
"http",
|
|
8583
|
+
"--host",
|
|
8584
|
+
"0.0.0.0",
|
|
8585
|
+
"--port",
|
|
8586
|
+
String(MCP_DOCKER_CONTAINER_PORT),
|
|
8587
|
+
"--scope",
|
|
8588
|
+
"global",
|
|
8589
|
+
);
|
|
8400
8590
|
await execFile(
|
|
8401
8591
|
"docker",
|
|
8402
8592
|
dockerArgs,
|
|
@@ -8412,6 +8602,7 @@ async function runMcpRuntimeUp(options) {
|
|
|
8412
8602
|
console.log(`Image: ${image}`);
|
|
8413
8603
|
console.log(`Image prepare: ${prepared.action}`);
|
|
8414
8604
|
console.log(`Update policy: ${updatePolicy}`);
|
|
8605
|
+
console.log(`Fallback: ${fallback}`);
|
|
8415
8606
|
console.log(`Build local: ${buildLocal ? "yes" : "no"}`);
|
|
8416
8607
|
console.log(`Mount: ${cbxRoot} -> /root/.cbx`);
|
|
8417
8608
|
if (skillsRootExists) {
|
|
@@ -8421,7 +8612,51 @@ async function runMcpRuntimeUp(options) {
|
|
|
8421
8612
|
}
|
|
8422
8613
|
console.log(`Port: ${hostPort}:${MCP_DOCKER_CONTAINER_PORT}`);
|
|
8423
8614
|
console.log(`Status: ${running ? running.status : "started"}`);
|
|
8424
|
-
|
|
8615
|
+
const endpoint = `http://127.0.0.1:${hostPort}/mcp`;
|
|
8616
|
+
console.log(`Endpoint: ${endpoint}`);
|
|
8617
|
+
try {
|
|
8618
|
+
await waitForMcpEndpointReady({
|
|
8619
|
+
url: endpoint,
|
|
8620
|
+
timeoutMs: 20000,
|
|
8621
|
+
intervalMs: 500,
|
|
8622
|
+
});
|
|
8623
|
+
console.log("Endpoint health: ready");
|
|
8624
|
+
} catch (error) {
|
|
8625
|
+
if (fallback === "skip") {
|
|
8626
|
+
runtimeWarnings.push(
|
|
8627
|
+
`Endpoint health check failed but continuing because --fallback=skip. (${error.message})`,
|
|
8628
|
+
);
|
|
8629
|
+
} else if (fallback === "local") {
|
|
8630
|
+
await execFile("docker", ["rm", "-f", containerName], { cwd }).catch(
|
|
8631
|
+
() => {},
|
|
8632
|
+
);
|
|
8633
|
+
runtimeWarnings.push(
|
|
8634
|
+
`Docker endpoint was unreachable and runtime fell back to local. (${error.message})`,
|
|
8635
|
+
);
|
|
8636
|
+
const persisted = await persistMcpRuntimePreference({
|
|
8637
|
+
scope,
|
|
8638
|
+
runtime: "local",
|
|
8639
|
+
fallback,
|
|
8640
|
+
cwd,
|
|
8641
|
+
generatedBy: "cbx mcp runtime up",
|
|
8642
|
+
});
|
|
8643
|
+
if (persisted.reason === "config-missing") {
|
|
8644
|
+
runtimeWarnings.push(
|
|
8645
|
+
`No cbx config found at ${persisted.configPath}; runtime preference was not persisted.`,
|
|
8646
|
+
);
|
|
8647
|
+
} else {
|
|
8648
|
+
runtimeWarnings.push(
|
|
8649
|
+
`Updated runtime preference in ${persisted.configPath} (${persisted.action}).`,
|
|
8650
|
+
);
|
|
8651
|
+
}
|
|
8652
|
+
console.log("Endpoint health: fallback-to-local");
|
|
8653
|
+
console.log("Local command: cbx mcp serve --transport stdio --scope auto");
|
|
8654
|
+
} else {
|
|
8655
|
+
throw new Error(
|
|
8656
|
+
`MCP endpoint is unreachable at ${endpoint}. ${error.message}`,
|
|
8657
|
+
);
|
|
8658
|
+
}
|
|
8659
|
+
}
|
|
8425
8660
|
if (runtimeWarnings.length > 0) {
|
|
8426
8661
|
console.log("Warnings:");
|
|
8427
8662
|
for (const warning of runtimeWarnings) {
|
|
@@ -8759,6 +8994,8 @@ const workflowsConfigCommand = workflowsCommand
|
|
|
8759
8994
|
.option("--edit", "edit Postman default workspace ID interactively")
|
|
8760
8995
|
.option("--workspace-id <id|null>", "set postman.defaultWorkspaceId")
|
|
8761
8996
|
.option("--clear-workspace-id", "set postman.defaultWorkspaceId to null")
|
|
8997
|
+
.option("--mcp-runtime <runtime>", "set mcp.runtime: docker|local")
|
|
8998
|
+
.option("--mcp-fallback <fallback>", "set mcp.fallback: local|fail|skip")
|
|
8762
8999
|
.option("--show-after", "print JSON after update")
|
|
8763
9000
|
.option("--dry-run", "preview changes without writing files")
|
|
8764
9001
|
.action(runWorkflowConfig);
|
|
@@ -8859,6 +9096,8 @@ const skillsConfigCommand = skillsCommand
|
|
|
8859
9096
|
.option("--edit", "edit Postman default workspace ID interactively")
|
|
8860
9097
|
.option("--workspace-id <id|null>", "set postman.defaultWorkspaceId")
|
|
8861
9098
|
.option("--clear-workspace-id", "set postman.defaultWorkspaceId to null")
|
|
9099
|
+
.option("--mcp-runtime <runtime>", "set mcp.runtime: docker|local")
|
|
9100
|
+
.option("--mcp-fallback <fallback>", "set mcp.fallback: local|fail|skip")
|
|
8862
9101
|
.option("--show-after", "print JSON after update")
|
|
8863
9102
|
.option("--dry-run", "preview changes without writing files")
|
|
8864
9103
|
.action(async (options) => {
|
|
@@ -8949,6 +9188,10 @@ mcpRuntimeCommand
|
|
|
8949
9188
|
)
|
|
8950
9189
|
.option("--image <image:tag>", "docker image to run")
|
|
8951
9190
|
.option("--update-policy <policy>", "pinned|latest")
|
|
9191
|
+
.option(
|
|
9192
|
+
"--fallback <fallback>",
|
|
9193
|
+
"when endpoint is unreachable: local|fail|skip",
|
|
9194
|
+
)
|
|
8952
9195
|
.option(
|
|
8953
9196
|
"--build-local",
|
|
8954
9197
|
"build MCP Docker image from local package mcp/ directory instead of pulling",
|