@mcpcloud/cli 0.9.1 → 0.10.0-next-20260715004701
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 +350 -142
- package/dist/index.js +500 -198
- package/package.json +3 -2
package/dist/index.js
CHANGED
|
@@ -1972,6 +1972,9 @@ function configFile() {
|
|
|
1972
1972
|
return join(configDir(), "config.json");
|
|
1973
1973
|
}
|
|
1974
1974
|
var DEFAULT_PROFILE_NAME = "default";
|
|
1975
|
+
var DEFAULT_BASE_URL = "https://majestic-lobster-858.convex.site";
|
|
1976
|
+
var PRODUCTION_BASE_URL = DEFAULT_BASE_URL;
|
|
1977
|
+
var DEFAULT_APP_URL = "https://mcpcloud.sh";
|
|
1975
1978
|
|
|
1976
1979
|
class MissingApiKeyError extends Error {
|
|
1977
1980
|
constructor() {
|
|
@@ -2100,6 +2103,14 @@ function getActiveProfileName() {
|
|
|
2100
2103
|
const first = Object.keys(persisted.profiles ?? {})[0];
|
|
2101
2104
|
return first ?? saved;
|
|
2102
2105
|
}
|
|
2106
|
+
function resolveActiveProfile() {
|
|
2107
|
+
if (profileOverride)
|
|
2108
|
+
return { name: profileOverride, source: "flag" };
|
|
2109
|
+
const fromEnv = process.env["MCPCLOUD_PROFILE"]?.trim();
|
|
2110
|
+
if (fromEnv)
|
|
2111
|
+
return { name: fromEnv, source: "env" };
|
|
2112
|
+
return { name: getActiveProfileName(), source: "config" };
|
|
2113
|
+
}
|
|
2103
2114
|
function getActiveProfile(persisted, name) {
|
|
2104
2115
|
return persisted.profiles?.[name] ?? {};
|
|
2105
2116
|
}
|
|
@@ -2121,11 +2132,26 @@ function writeConfig(config) {
|
|
|
2121
2132
|
function getApiKey() {
|
|
2122
2133
|
return process.env["MCPCLOUD_API_KEY"] ?? readConfig().apiKey;
|
|
2123
2134
|
}
|
|
2135
|
+
function resolveBaseUrl() {
|
|
2136
|
+
if (baseUrlOverride)
|
|
2137
|
+
return { url: baseUrlOverride, source: "flag" };
|
|
2138
|
+
const env = process.env["MCPCLOUD_BASE_URL"]?.trim();
|
|
2139
|
+
if (env)
|
|
2140
|
+
return { url: env, source: "env" };
|
|
2141
|
+
const profile = readConfig().baseUrl;
|
|
2142
|
+
if (profile)
|
|
2143
|
+
return { url: profile, source: "profile" };
|
|
2144
|
+
return { url: DEFAULT_BASE_URL, source: "default" };
|
|
2145
|
+
}
|
|
2124
2146
|
function getBaseUrl() {
|
|
2125
|
-
|
|
2126
|
-
|
|
2127
|
-
|
|
2128
|
-
|
|
2147
|
+
return resolveBaseUrl().url;
|
|
2148
|
+
}
|
|
2149
|
+
function isProductionBaseUrl(url) {
|
|
2150
|
+
try {
|
|
2151
|
+
return new URL(url).host === new URL(PRODUCTION_BASE_URL).host;
|
|
2152
|
+
} catch {
|
|
2153
|
+
return false;
|
|
2154
|
+
}
|
|
2129
2155
|
}
|
|
2130
2156
|
function requireApiKey() {
|
|
2131
2157
|
const key = getApiKey();
|
|
@@ -2152,10 +2178,10 @@ function getAppUrl() {
|
|
|
2152
2178
|
if (host === "localhost" || host === "127.0.0.1")
|
|
2153
2179
|
return "http://localhost:4000";
|
|
2154
2180
|
if (host.endsWith(".convex.site") || host.endsWith(".convex.cloud"))
|
|
2155
|
-
return
|
|
2181
|
+
return DEFAULT_APP_URL;
|
|
2156
2182
|
} catch {}
|
|
2157
2183
|
}
|
|
2158
|
-
return
|
|
2184
|
+
return DEFAULT_APP_URL;
|
|
2159
2185
|
}
|
|
2160
2186
|
function listProfiles() {
|
|
2161
2187
|
const persisted = readPersistedConfig();
|
|
@@ -2386,12 +2412,20 @@ function getRetryDelayMs(err) {
|
|
|
2386
2412
|
}
|
|
2387
2413
|
return 250 + Math.floor(Math.random() * 250);
|
|
2388
2414
|
}
|
|
2415
|
+
var GATEWAY_STATUS_MESSAGES = {
|
|
2416
|
+
502: "The gateway returned no response (HTTP 502 Bad Gateway). A long-running request — such as a first deploy that is still generating and uploading the bundle — can exceed the gateway timeout even though the operation keeps running server-side. Retry in a few seconds; for a deploy, re-run with `--wait` or follow progress with `mcp deployments logs <id> --follow`.",
|
|
2417
|
+
503: "The service is temporarily unavailable (HTTP 503 Service Unavailable). This is usually transient — retry in a few seconds.",
|
|
2418
|
+
504: "The gateway timed out waiting for the server (HTTP 504 Gateway Timeout). A long-running request may still be processing server-side. Retry in a few seconds; for a deploy, re-run with `--wait` or follow progress with `mcp deployments logs <id> --follow`."
|
|
2419
|
+
};
|
|
2420
|
+
function synthesizeStatusMessage(status, statusText) {
|
|
2421
|
+
return GATEWAY_STATUS_MESSAGES[status] ?? (statusText || `HTTP ${status}`);
|
|
2422
|
+
}
|
|
2389
2423
|
async function parseErrorBody(res) {
|
|
2390
2424
|
const headerRequestId = res.headers.get("x-request-id") ?? undefined;
|
|
2391
2425
|
const retryAfter = parseRetryAfter(res.headers.get("retry-after"));
|
|
2392
2426
|
const fallback = {
|
|
2393
2427
|
code: `http_${res.status}`,
|
|
2394
|
-
message: res.
|
|
2428
|
+
message: synthesizeStatusMessage(res.status, res.statusText)
|
|
2395
2429
|
};
|
|
2396
2430
|
if (headerRequestId)
|
|
2397
2431
|
fallback.requestId = headerRequestId;
|
|
@@ -2834,7 +2868,12 @@ var ERROR_REMEDIATION = {
|
|
|
2834
2868
|
invalid_status: "Invalid --status. Check the command help for accepted values.",
|
|
2835
2869
|
deployment_not_found: "No such deployment in this org. Verify with `mcp servers list`.",
|
|
2836
2870
|
server_not_found: "No such server in this org. Verify with `mcp servers list`.",
|
|
2871
|
+
artifact_not_found: "No such server/artifact in that project. If you switched servers, stale .mcpcloud/state.json can cause this — run `mcp dev init` to re-select.",
|
|
2872
|
+
bundle_not_found: "The server has no generated bundle yet. Run `mcp servers generate <id>` or deploy once, then retry.",
|
|
2837
2873
|
missing_deployment_id: "Pass --deployment <id> or look it up with `mcp servers list`.",
|
|
2874
|
+
http_502: "The API gateway dropped the request. Retry once; if it persists, check https://mcpcloud.sh/status.",
|
|
2875
|
+
http_503: "Service temporarily unavailable. Honor Retry-After if present, then retry.",
|
|
2876
|
+
http_504: "The request timed out at the gateway. Retry; long operations may still be running — check with the matching `get` command.",
|
|
2838
2877
|
rate_limited: "Rate limit hit. Honor the Retry-After header and retry.",
|
|
2839
2878
|
rate_limit_exceeded: "Rate limit hit. Wait the Retry-After interval before retrying.",
|
|
2840
2879
|
quota_exceeded: "Plan quota exceeded. Check usage in the dashboard or upgrade.",
|
|
@@ -2868,6 +2907,14 @@ function getRemediation(code) {
|
|
|
2868
2907
|
return;
|
|
2869
2908
|
return ERROR_REMEDIATION[code];
|
|
2870
2909
|
}
|
|
2910
|
+
var DOCS_ORIGIN = "https://mcpcloud.sh";
|
|
2911
|
+
function absolutizeDocsUrl(url) {
|
|
2912
|
+
if (!url)
|
|
2913
|
+
return url;
|
|
2914
|
+
if (/^[a-z][a-z0-9+.-]*:\/\//i.test(url))
|
|
2915
|
+
return url;
|
|
2916
|
+
return `${DOCS_ORIGIN}${url.startsWith("/") ? "" : "/"}${url}`;
|
|
2917
|
+
}
|
|
2871
2918
|
function describeError(err) {
|
|
2872
2919
|
if (err instanceof McpCloudApiError) {
|
|
2873
2920
|
const out = {
|
|
@@ -2877,8 +2924,11 @@ function describeError(err) {
|
|
|
2877
2924
|
};
|
|
2878
2925
|
if (err.error.requestId)
|
|
2879
2926
|
out.requestId = err.error.requestId;
|
|
2880
|
-
if (err.error.docsUrl)
|
|
2881
|
-
|
|
2927
|
+
if (err.error.docsUrl) {
|
|
2928
|
+
const docsUrl = absolutizeDocsUrl(err.error.docsUrl);
|
|
2929
|
+
if (docsUrl)
|
|
2930
|
+
out.docsUrl = docsUrl;
|
|
2931
|
+
}
|
|
2882
2932
|
if (err.error.details)
|
|
2883
2933
|
out.details = err.error.details;
|
|
2884
2934
|
return out;
|
|
@@ -3371,6 +3421,16 @@ function previewKey(key) {
|
|
|
3371
3421
|
return `${key.slice(0, 4)}…`;
|
|
3372
3422
|
return `${key.slice(0, 8)}…${key.slice(-4)}`;
|
|
3373
3423
|
}
|
|
3424
|
+
function profileSourceLabel(source) {
|
|
3425
|
+
switch (source) {
|
|
3426
|
+
case "flag":
|
|
3427
|
+
return "--profile flag";
|
|
3428
|
+
case "env":
|
|
3429
|
+
return "MCPCLOUD_PROFILE";
|
|
3430
|
+
case "config":
|
|
3431
|
+
return "config default";
|
|
3432
|
+
}
|
|
3433
|
+
}
|
|
3374
3434
|
function registerAuthCommands(program2) {
|
|
3375
3435
|
program2.command("login").description("Sign in via browser (default) or paste an API key").option("--key <apiKey>", "Save this key directly (skips browser + prompt)").option("--paste", "Skip the browser flow and prompt for an API key instead").option("--no-browser", "Alias for --paste").option("--port <number>", "Loopback port to receive the callback (default: auto)").option("--app-url <url>", "Override the dashboard origin for this run (default: from MCPCLOUD_APP_URL or config)").option("--timeout <seconds>", "How long to wait for the browser flow (default 300)").addHelpText("after", [
|
|
3376
3436
|
"",
|
|
@@ -3510,12 +3570,17 @@ function registerAuthCommands(program2) {
|
|
|
3510
3570
|
`)).action(runAction(async () => {
|
|
3511
3571
|
const me = await api.get("/api/v1/me");
|
|
3512
3572
|
const orgs = await api.get("/api/v1/organizations");
|
|
3573
|
+
const profile = resolveActiveProfile();
|
|
3574
|
+
const baseUrl = getBaseUrl();
|
|
3575
|
+
const isProd = isProductionBaseUrl(baseUrl);
|
|
3513
3576
|
if (isJsonMode()) {
|
|
3514
3577
|
printJson({
|
|
3515
3578
|
user: me.user,
|
|
3516
3579
|
authMethod: me.authMethod,
|
|
3517
3580
|
apiKey: me.apiKey,
|
|
3518
|
-
|
|
3581
|
+
profile: { name: profile.name, source: profile.source },
|
|
3582
|
+
baseUrl,
|
|
3583
|
+
isProductionBaseUrl: isProd,
|
|
3519
3584
|
defaultOrganizationId: me.defaultOrganizationId,
|
|
3520
3585
|
organizations: orgs.organizations
|
|
3521
3586
|
});
|
|
@@ -3526,7 +3591,8 @@ function registerAuthCommands(program2) {
|
|
|
3526
3591
|
user: me.user.email ?? me.user.name ?? me.user.id,
|
|
3527
3592
|
"auth method": me.authMethod ?? "—",
|
|
3528
3593
|
"api key": apiKeyDisplay,
|
|
3529
|
-
|
|
3594
|
+
profile: `${profile.name} (${profileSourceLabel(profile.source)})`,
|
|
3595
|
+
"base url": isProd ? `${baseUrl} (production)` : baseUrl,
|
|
3530
3596
|
"default org": me.defaultOrganizationId ?? "—",
|
|
3531
3597
|
"org count": orgs.organizations.length
|
|
3532
3598
|
});
|
|
@@ -3875,13 +3941,24 @@ var TERMINAL_STAGES = new Set([
|
|
|
3875
3941
|
"terminated"
|
|
3876
3942
|
]);
|
|
3877
3943
|
var TERMINAL_LEVELS = new Set(["success", "failure", "error"]);
|
|
3944
|
+
var TERMINAL_DEPLOYMENT_STATUSES = new Set([
|
|
3945
|
+
"active",
|
|
3946
|
+
"failed",
|
|
3947
|
+
"paused",
|
|
3948
|
+
"undeployed"
|
|
3949
|
+
]);
|
|
3950
|
+
function isTerminalDeploymentStatus(status) {
|
|
3951
|
+
return status !== undefined && TERMINAL_DEPLOYMENT_STATUSES.has(status);
|
|
3952
|
+
}
|
|
3878
3953
|
function isTerminalEvent(event) {
|
|
3879
3954
|
if (TERMINAL_STAGES.has(event.stage))
|
|
3880
3955
|
return true;
|
|
3881
3956
|
if (TERMINAL_LEVELS.has(event.level))
|
|
3882
3957
|
return true;
|
|
3883
3958
|
const m = event.message.toLowerCase();
|
|
3884
|
-
if (m.includes("deployment active"))
|
|
3959
|
+
if (m.includes("deployment is active") || m.includes("deployment active"))
|
|
3960
|
+
return true;
|
|
3961
|
+
if (m.includes("deployment failed"))
|
|
3885
3962
|
return true;
|
|
3886
3963
|
if (m.includes("deploy succeeded") || m.includes("deploy failed"))
|
|
3887
3964
|
return true;
|
|
@@ -4513,24 +4590,28 @@ function registerServerLifecycleCommands(servers) {
|
|
|
4513
4590
|
let terminalEvent = null;
|
|
4514
4591
|
let waitDone = !opts.wait;
|
|
4515
4592
|
if (opts.wait) {
|
|
4516
|
-
|
|
4517
|
-
|
|
4518
|
-
|
|
4519
|
-
|
|
4520
|
-
|
|
4521
|
-
|
|
4522
|
-
|
|
4523
|
-
|
|
4524
|
-
|
|
4525
|
-
|
|
4526
|
-
|
|
4593
|
+
if (isTerminalDeploymentStatus(dep.status)) {
|
|
4594
|
+
waitDone = true;
|
|
4595
|
+
} else {
|
|
4596
|
+
const totalTimeoutMs = Math.max(10, Number.parseInt(opts.waitTimeout, 10) || 300) * 1000;
|
|
4597
|
+
if (!isJsonMode()) {
|
|
4598
|
+
printStep(`Following events for ${c.bold(dep.deploymentId)} (timeout ${Math.round(totalTimeoutMs / 1000)}s)…`);
|
|
4599
|
+
}
|
|
4600
|
+
const result = await followDeploymentEvents({
|
|
4601
|
+
organizationId: orgId,
|
|
4602
|
+
deploymentId: dep.deploymentId,
|
|
4603
|
+
totalTimeoutMs,
|
|
4604
|
+
onEvent: (event) => {
|
|
4605
|
+
if (!isJsonMode()) {
|
|
4606
|
+
printInfo(formatEventLine2(event));
|
|
4607
|
+
}
|
|
4527
4608
|
}
|
|
4609
|
+
});
|
|
4610
|
+
terminalEvent = result.terminalEvent;
|
|
4611
|
+
waitDone = result.done;
|
|
4612
|
+
if (!waitDone && !isJsonMode()) {
|
|
4613
|
+
printError(`Deploy did not reach a terminal state within ${Math.round(totalTimeoutMs / 1000)}s. Check \`mcp deployments get ${dep.deploymentId}\` and \`mcp deployments health ${dep.deploymentId}\`, or tail \`mcp deployments logs ${dep.deploymentId} --follow\`.`);
|
|
4528
4614
|
}
|
|
4529
|
-
});
|
|
4530
|
-
terminalEvent = result.terminalEvent;
|
|
4531
|
-
waitDone = result.done;
|
|
4532
|
-
if (!waitDone && !isJsonMode()) {
|
|
4533
|
-
printError(`Deploy did not reach a terminal state within ${Math.round(totalTimeoutMs / 1000)}s. Run \`mcp --json servers test-runs get ${dep.deploymentId}\` (or the dashboard) to keep watching.`);
|
|
4534
4615
|
}
|
|
4535
4616
|
}
|
|
4536
4617
|
if (isJsonMode()) {
|
|
@@ -4542,7 +4623,7 @@ function registerServerLifecycleCommands(servers) {
|
|
|
4542
4623
|
printSuccess(`Deployment ${c.bold(dep.deploymentId)} created.`);
|
|
4543
4624
|
printKeyValue({
|
|
4544
4625
|
id: dep.deploymentId,
|
|
4545
|
-
url: dep.deploymentUrl,
|
|
4626
|
+
...dep.deploymentUrl ? { url: dep.deploymentUrl } : {},
|
|
4546
4627
|
target: dep.target,
|
|
4547
4628
|
"access mode": dep.accessMode,
|
|
4548
4629
|
status: dep.status,
|
|
@@ -4552,6 +4633,9 @@ function registerServerLifecycleCommands(servers) {
|
|
|
4552
4633
|
"terminal at": formatDate(terminalEvent.timestamp)
|
|
4553
4634
|
} : {}
|
|
4554
4635
|
});
|
|
4636
|
+
if (!opts.wait && dep.status === "queued") {
|
|
4637
|
+
printInfo(`Deploy is running in the background — follow with \`mcp deployments get ${dep.deploymentId}\` or rerun with --wait.`);
|
|
4638
|
+
}
|
|
4555
4639
|
if (opts.wait && !waitDone)
|
|
4556
4640
|
throw new CliExitError(1);
|
|
4557
4641
|
}));
|
|
@@ -4643,23 +4727,27 @@ function registerServerLifecycleCommands(servers) {
|
|
|
4643
4727
|
let terminalEvent = null;
|
|
4644
4728
|
let waitDone = !opts.wait;
|
|
4645
4729
|
if (opts.wait) {
|
|
4646
|
-
|
|
4647
|
-
|
|
4648
|
-
|
|
4649
|
-
|
|
4650
|
-
|
|
4651
|
-
|
|
4652
|
-
|
|
4653
|
-
|
|
4654
|
-
|
|
4655
|
-
|
|
4656
|
-
|
|
4730
|
+
if (isTerminalDeploymentStatus(dep.status)) {
|
|
4731
|
+
waitDone = true;
|
|
4732
|
+
} else {
|
|
4733
|
+
const totalTimeoutMs = Math.max(10, Number.parseInt(opts.waitTimeout, 10) || 300) * 1000;
|
|
4734
|
+
if (!isJsonMode()) {
|
|
4735
|
+
printStep(`Following events for ${c.bold(dep.deploymentId)}…`);
|
|
4736
|
+
}
|
|
4737
|
+
const r = await followDeploymentEvents({
|
|
4738
|
+
organizationId: orgId,
|
|
4739
|
+
deploymentId: dep.deploymentId,
|
|
4740
|
+
totalTimeoutMs,
|
|
4741
|
+
onEvent: (event) => {
|
|
4742
|
+
if (!isJsonMode())
|
|
4743
|
+
printInfo(formatEventLine2(event));
|
|
4744
|
+
}
|
|
4745
|
+
});
|
|
4746
|
+
terminalEvent = r.terminalEvent;
|
|
4747
|
+
waitDone = r.done;
|
|
4748
|
+
if (!waitDone && !isJsonMode()) {
|
|
4749
|
+
printError(`Deploy did not reach a terminal state within ${Math.round(totalTimeoutMs / 1000)}s. Check \`mcp deployments get ${dep.deploymentId}\` and \`mcp deployments health ${dep.deploymentId}\`, or tail \`mcp deployments logs ${dep.deploymentId} --follow\`.`);
|
|
4657
4750
|
}
|
|
4658
|
-
});
|
|
4659
|
-
terminalEvent = r.terminalEvent;
|
|
4660
|
-
waitDone = r.done;
|
|
4661
|
-
if (!waitDone && !isJsonMode()) {
|
|
4662
|
-
printError(`Deploy did not reach a terminal state within ${Math.round(totalTimeoutMs / 1000)}s.`);
|
|
4663
4751
|
}
|
|
4664
4752
|
}
|
|
4665
4753
|
if (isJsonMode()) {
|
|
@@ -4678,7 +4766,7 @@ function registerServerLifecycleCommands(servers) {
|
|
|
4678
4766
|
printSuccess(`Deployment ${c.bold(dep.deploymentId)} created.`);
|
|
4679
4767
|
printKeyValue({
|
|
4680
4768
|
id: dep.deploymentId,
|
|
4681
|
-
url: dep.deploymentUrl,
|
|
4769
|
+
...dep.deploymentUrl ? { url: dep.deploymentUrl } : {},
|
|
4682
4770
|
target: dep.target,
|
|
4683
4771
|
"access mode": dep.accessMode,
|
|
4684
4772
|
status: dep.status,
|
|
@@ -4688,6 +4776,9 @@ function registerServerLifecycleCommands(servers) {
|
|
|
4688
4776
|
"terminal at": formatDate(terminalEvent.timestamp)
|
|
4689
4777
|
} : {}
|
|
4690
4778
|
});
|
|
4779
|
+
if (!opts.wait && dep.status === "queued") {
|
|
4780
|
+
printInfo(`Deploy is running in the background — follow with \`mcp deployments get ${dep.deploymentId}\` or rerun with --wait.`);
|
|
4781
|
+
}
|
|
4691
4782
|
if (opts.wait && !waitDone)
|
|
4692
4783
|
throw new CliExitError(1);
|
|
4693
4784
|
}));
|
|
@@ -5533,6 +5624,9 @@ import { dirname as dirname5, join as join8 } from "node:path";
|
|
|
5533
5624
|
// src/lib/dev/state.ts
|
|
5534
5625
|
import { existsSync as existsSync7, mkdirSync as mkdirSync5, readFileSync as readFileSync6, writeFileSync as writeFileSync4 } from "node:fs";
|
|
5535
5626
|
import { join as join6, resolve as resolve5 } from "node:path";
|
|
5627
|
+
function cachedStateMatchesTarget(cached2, target) {
|
|
5628
|
+
return cached2 !== null && cached2.serverId === target.serverId && cached2.organizationId === target.organizationId;
|
|
5629
|
+
}
|
|
5536
5630
|
function devRoot(cwd) {
|
|
5537
5631
|
return join6(cwd, ".mcpcloud");
|
|
5538
5632
|
}
|
|
@@ -7441,7 +7535,7 @@ function diffLine2(label, applied, suggested) {
|
|
|
7441
7535
|
// src/commands/tools.ts
|
|
7442
7536
|
function registerToolCommands(program2) {
|
|
7443
7537
|
const tools = program2.command("tools").description("Inspect and edit tools on a project or server");
|
|
7444
|
-
tools.command("list").description("List tools for a project
|
|
7538
|
+
tools.command("list").description("List tools for a project, or scope to a single server with --server").option("--org <organizationId>", "Organization ID").option("--project <projectId>", "List every tool in this project").option("--server <serverId>", "List only the tools that belong to this server (the CLI resolves its project, fetches the project tools, then filters to this server)").action(runAction(async (opts) => {
|
|
7445
7539
|
const orgId = await resolveOrgId(opts.org);
|
|
7446
7540
|
if (!opts.project && !opts.server) {
|
|
7447
7541
|
throw new Error("Pass either --project <projectId> or --server <serverId>.");
|
|
@@ -7458,10 +7552,11 @@ function registerToolCommands(program2) {
|
|
|
7458
7552
|
organizationId: orgId,
|
|
7459
7553
|
projectId
|
|
7460
7554
|
});
|
|
7461
|
-
|
|
7555
|
+
const rows = opts.server ? data.tools.filter((t) => t.serverId === opts.server) : data.tools;
|
|
7556
|
+
printList(rows.map((t) => ({
|
|
7462
7557
|
name: t.name,
|
|
7463
|
-
method: t.method,
|
|
7464
|
-
path: t.path,
|
|
7558
|
+
method: t.endpoint?.method ?? t.method ?? "—",
|
|
7559
|
+
path: t.endpoint?.path ?? t.path ?? "—",
|
|
7465
7560
|
enrichment: t.enrichmentStatus ?? "—",
|
|
7466
7561
|
description: t.description.slice(0, 60) + (t.description.length > 60 ? "…" : "")
|
|
7467
7562
|
})), [
|
|
@@ -7470,7 +7565,7 @@ function registerToolCommands(program2) {
|
|
|
7470
7565
|
{ key: "path", label: "Path", width: 32 },
|
|
7471
7566
|
{ key: "enrichment", label: "Enrichment", width: 12 },
|
|
7472
7567
|
{ key: "description", label: "Description", width: 60 }
|
|
7473
|
-
], data);
|
|
7568
|
+
], opts.server ? { ...data, tools: rows } : data);
|
|
7474
7569
|
}));
|
|
7475
7570
|
registerToolsShowCommand(tools);
|
|
7476
7571
|
registerToolsDiffCommand(tools);
|
|
@@ -9035,7 +9130,7 @@ function previewKey2(key) {
|
|
|
9035
9130
|
}
|
|
9036
9131
|
function registerConfigCommands(program2) {
|
|
9037
9132
|
const config = program2.command("config").description("Manage CLI configuration in ~/.mcpcloud/config.json");
|
|
9038
|
-
|
|
9133
|
+
const showActiveProfile = runAction(() => {
|
|
9039
9134
|
const cfg = readConfig();
|
|
9040
9135
|
const profile2 = getActiveProfileName();
|
|
9041
9136
|
const safe = {
|
|
@@ -9052,14 +9147,16 @@ function registerConfigCommands(program2) {
|
|
|
9052
9147
|
printKeyValue({
|
|
9053
9148
|
path: safe.path,
|
|
9054
9149
|
profile: safe.profile,
|
|
9055
|
-
"base url": safe.baseUrl ?? "—",
|
|
9150
|
+
"base url": safe.baseUrl ?? "— (built-in default)",
|
|
9056
9151
|
"app url": cfg.appUrl ?? "— (auto-derived)",
|
|
9057
9152
|
"default org": safe.defaultOrganizationId ?? "—",
|
|
9058
9153
|
"api key": safe.apiKeyPreview ?? "—",
|
|
9059
9154
|
editor: cfg.editorCommand ?? "code",
|
|
9060
9155
|
"editor open": cfg.editorOpenPreference ?? "ask"
|
|
9061
9156
|
});
|
|
9062
|
-
})
|
|
9157
|
+
});
|
|
9158
|
+
config.command("show").description("Print the active profile (API key is redacted)").action(showActiveProfile);
|
|
9159
|
+
config.command("current").description("Alias for `config show` — print the active profile").action(showActiveProfile);
|
|
9063
9160
|
config.command("set-url <url>").description("Save the API base URL to ~/.mcpcloud/config.json").action(runAction((url) => {
|
|
9064
9161
|
try {
|
|
9065
9162
|
new URL(url);
|
|
@@ -9629,7 +9726,7 @@ async function runDevReplay(opts) {
|
|
|
9629
9726
|
printInfo("No matching records in .mcpcloud/inspector/. Use --from / --since / --filter, or run something first.");
|
|
9630
9727
|
return;
|
|
9631
9728
|
}
|
|
9632
|
-
const baseUrl = opts.url ??
|
|
9729
|
+
const baseUrl = opts.url ?? resolveBaseUrl2(cwd);
|
|
9633
9730
|
if (!opts.dryRun && !baseUrl) {
|
|
9634
9731
|
printError("No running mcp dev session in this directory. Start `mcp dev`, or pass --url <baseUrl>.");
|
|
9635
9732
|
throw new CliExitError(1);
|
|
@@ -9707,7 +9804,7 @@ function parseLimit(raw) {
|
|
|
9707
9804
|
}
|
|
9708
9805
|
return n;
|
|
9709
9806
|
}
|
|
9710
|
-
function
|
|
9807
|
+
function resolveBaseUrl2(cwd) {
|
|
9711
9808
|
const sessions = listSessions().filter((s) => s.cwd === cwd);
|
|
9712
9809
|
if (sessions.length === 0)
|
|
9713
9810
|
return null;
|
|
@@ -11220,8 +11317,13 @@ async function fetchBundle(args) {
|
|
|
11220
11317
|
} catch {
|
|
11221
11318
|
body = null;
|
|
11222
11319
|
}
|
|
11223
|
-
const
|
|
11224
|
-
|
|
11320
|
+
const envelope = body?.error;
|
|
11321
|
+
const requestId = envelope?.requestId ?? res.headers?.get?.("x-request-id") ?? null;
|
|
11322
|
+
throw new McpCloudApiError(res.status, {
|
|
11323
|
+
code: envelope?.code ?? `http_${res.status}`,
|
|
11324
|
+
message: envelope?.message ?? `Bundle download failed (${res.status}).`,
|
|
11325
|
+
...requestId ? { requestId } : {}
|
|
11326
|
+
});
|
|
11225
11327
|
}
|
|
11226
11328
|
const text = await res.text();
|
|
11227
11329
|
const parsed = JSON.parse(text);
|
|
@@ -25781,7 +25883,7 @@ if (!root) throw new Error("Missing #root mount node");
|
|
|
25781
25883
|
clientExports.createRoot(root).render(
|
|
25782
25884
|
/* @__PURE__ */ jsxRuntimeExports.jsx(reactExports.StrictMode, { children: /* @__PURE__ */ jsxRuntimeExports.jsx(App, {}) })
|
|
25783
25885
|
);</script>
|
|
25784
|
-
<style rel="stylesheet" crossorigin>/*! tailwindcss v4.3.
|
|
25886
|
+
<style rel="stylesheet" crossorigin>/*! tailwindcss v4.3.2 | MIT License | https://tailwindcss.com */
|
|
25785
25887
|
@layer properties {
|
|
25786
25888
|
@supports (((-webkit-hyphens: none)) and (not (margin-trim: inline))) or ((-moz-orient: inline) and (not (color: rgb(from red r g b)))) {
|
|
25787
25889
|
*, :before, :after, ::backdrop {
|
|
@@ -26116,7 +26218,7 @@ clientExports.createRoot(root).render(
|
|
|
26116
26218
|
}
|
|
26117
26219
|
|
|
26118
26220
|
.top-0 {
|
|
26119
|
-
top:
|
|
26221
|
+
top: 0;
|
|
26120
26222
|
}
|
|
26121
26223
|
|
|
26122
26224
|
.z-10 {
|
|
@@ -26124,7 +26226,7 @@ clientExports.createRoot(root).render(
|
|
|
26124
26226
|
}
|
|
26125
26227
|
|
|
26126
26228
|
.m-0 {
|
|
26127
|
-
margin:
|
|
26229
|
+
margin: 0;
|
|
26128
26230
|
}
|
|
26129
26231
|
|
|
26130
26232
|
.mx-auto {
|
|
@@ -26136,7 +26238,7 @@ clientExports.createRoot(root).render(
|
|
|
26136
26238
|
}
|
|
26137
26239
|
|
|
26138
26240
|
.mt-1 {
|
|
26139
|
-
margin-top:
|
|
26241
|
+
margin-top: var(--spacing);
|
|
26140
26242
|
}
|
|
26141
26243
|
|
|
26142
26244
|
.mt-3 {
|
|
@@ -26144,7 +26246,7 @@ clientExports.createRoot(root).render(
|
|
|
26144
26246
|
}
|
|
26145
26247
|
|
|
26146
26248
|
.mb-1 {
|
|
26147
|
-
margin-bottom:
|
|
26249
|
+
margin-bottom: var(--spacing);
|
|
26148
26250
|
}
|
|
26149
26251
|
|
|
26150
26252
|
.mb-2\\.5 {
|
|
@@ -26152,7 +26254,7 @@ clientExports.createRoot(root).render(
|
|
|
26152
26254
|
}
|
|
26153
26255
|
|
|
26154
26256
|
.ml-1 {
|
|
26155
|
-
margin-left:
|
|
26257
|
+
margin-left: var(--spacing);
|
|
26156
26258
|
}
|
|
26157
26259
|
|
|
26158
26260
|
.ml-2 {
|
|
@@ -26201,7 +26303,7 @@ clientExports.createRoot(root).render(
|
|
|
26201
26303
|
}
|
|
26202
26304
|
|
|
26203
26305
|
.min-w-0 {
|
|
26204
|
-
min-width:
|
|
26306
|
+
min-width: 0;
|
|
26205
26307
|
}
|
|
26206
26308
|
|
|
26207
26309
|
.min-w-\\[240px\\] {
|
|
@@ -26253,7 +26355,7 @@ clientExports.createRoot(root).render(
|
|
|
26253
26355
|
}
|
|
26254
26356
|
|
|
26255
26357
|
.gap-1 {
|
|
26256
|
-
gap:
|
|
26358
|
+
gap: var(--spacing);
|
|
26257
26359
|
}
|
|
26258
26360
|
|
|
26259
26361
|
.gap-1\\.5 {
|
|
@@ -26329,7 +26431,7 @@ clientExports.createRoot(root).render(
|
|
|
26329
26431
|
}
|
|
26330
26432
|
|
|
26331
26433
|
.p-0 {
|
|
26332
|
-
padding:
|
|
26434
|
+
padding: 0;
|
|
26333
26435
|
}
|
|
26334
26436
|
|
|
26335
26437
|
.p-2 {
|
|
@@ -26341,7 +26443,7 @@ clientExports.createRoot(root).render(
|
|
|
26341
26443
|
}
|
|
26342
26444
|
|
|
26343
26445
|
.px-1 {
|
|
26344
|
-
padding-inline:
|
|
26446
|
+
padding-inline: var(--spacing);
|
|
26345
26447
|
}
|
|
26346
26448
|
|
|
26347
26449
|
.px-1\\.5 {
|
|
@@ -26369,7 +26471,7 @@ clientExports.createRoot(root).render(
|
|
|
26369
26471
|
}
|
|
26370
26472
|
|
|
26371
26473
|
.py-1 {
|
|
26372
|
-
padding-block:
|
|
26474
|
+
padding-block: var(--spacing);
|
|
26373
26475
|
}
|
|
26374
26476
|
|
|
26375
26477
|
.py-2 {
|
|
@@ -27495,8 +27597,12 @@ async function prepareDev(opts) {
|
|
|
27495
27597
|
const env = envFile(cwd);
|
|
27496
27598
|
const backups = backupsDir(cwd);
|
|
27497
27599
|
const cached2 = readState(cwd);
|
|
27498
|
-
|
|
27499
|
-
|
|
27600
|
+
const cacheIsForTarget = cachedStateMatchesTarget(cached2, {
|
|
27601
|
+
serverId: opts.serverId,
|
|
27602
|
+
organizationId: opts.organizationId
|
|
27603
|
+
});
|
|
27604
|
+
let projectId = cacheIsForTarget ? cached2.projectId : undefined;
|
|
27605
|
+
let serverName = cacheIsForTarget ? cached2.serverName : undefined;
|
|
27500
27606
|
let gitNative = false;
|
|
27501
27607
|
let repoDir;
|
|
27502
27608
|
const gitLink = opts.offline ? null : await resolveServerGitLink({
|
|
@@ -28463,7 +28569,8 @@ async function runDev(opts) {
|
|
|
28463
28569
|
const cwd = process.cwd();
|
|
28464
28570
|
const cached2 = readState(cwd);
|
|
28465
28571
|
let serverId = opts.server ?? cached2?.serverId;
|
|
28466
|
-
|
|
28572
|
+
const serverCameFromCache = !opts.server && Boolean(cached2?.serverId);
|
|
28573
|
+
let organizationId = opts.org ?? (serverCameFromCache ? cached2?.organizationId ?? undefined : undefined);
|
|
28467
28574
|
if (!opts.server && cached2?.serverId && canRunInteractive()) {
|
|
28468
28575
|
const choice = await promptResumeOrSwitch({
|
|
28469
28576
|
serverId: cached2.serverId,
|
|
@@ -29575,19 +29682,15 @@ function checkActiveProfile() {
|
|
|
29575
29682
|
ms: Date.now() - t0
|
|
29576
29683
|
};
|
|
29577
29684
|
}
|
|
29685
|
+
var BASE_URL_SOURCE_LABEL = {
|
|
29686
|
+
flag: "--base-url flag",
|
|
29687
|
+
env: "env var",
|
|
29688
|
+
profile: "profile",
|
|
29689
|
+
default: "built-in default"
|
|
29690
|
+
};
|
|
29578
29691
|
function checkBaseUrl() {
|
|
29579
29692
|
const t0 = Date.now();
|
|
29580
|
-
const
|
|
29581
|
-
const fromConfig = readConfig().baseUrl;
|
|
29582
|
-
const url = fromOverride ?? fromConfig;
|
|
29583
|
-
if (!url) {
|
|
29584
|
-
return {
|
|
29585
|
-
name: "Base URL",
|
|
29586
|
-
status: "fail",
|
|
29587
|
-
detail: "Not configured. Run `mcp config set-url <url>` or set MCPCLOUD_BASE_URL.",
|
|
29588
|
-
ms: Date.now() - t0
|
|
29589
|
-
};
|
|
29590
|
-
}
|
|
29693
|
+
const { url, source } = resolveBaseUrl();
|
|
29591
29694
|
try {
|
|
29592
29695
|
new URL(url);
|
|
29593
29696
|
} catch {
|
|
@@ -29598,11 +29701,11 @@ function checkBaseUrl() {
|
|
|
29598
29701
|
ms: Date.now() - t0
|
|
29599
29702
|
};
|
|
29600
29703
|
}
|
|
29601
|
-
const
|
|
29704
|
+
const prodMarker = isProductionBaseUrl(url) ? " (production)" : "";
|
|
29602
29705
|
return {
|
|
29603
29706
|
name: "Base URL",
|
|
29604
29707
|
status: "pass",
|
|
29605
|
-
detail: `${url} (from ${source})`,
|
|
29708
|
+
detail: `${url}${prodMarker} (from ${BASE_URL_SOURCE_LABEL[source]})`,
|
|
29606
29709
|
ms: Date.now() - t0
|
|
29607
29710
|
};
|
|
29608
29711
|
}
|
|
@@ -30006,7 +30109,7 @@ function registerHelpCommand(program2) {
|
|
|
30006
30109
|
});
|
|
30007
30110
|
}
|
|
30008
30111
|
|
|
30009
|
-
// src/commands/init.ts
|
|
30112
|
+
// src/commands/init-shared.ts
|
|
30010
30113
|
import { createInterface as createInterface2 } from "node:readline";
|
|
30011
30114
|
function prompt2(question) {
|
|
30012
30115
|
if (isNonInteractive()) {
|
|
@@ -30022,7 +30125,10 @@ function prompt2(question) {
|
|
|
30022
30125
|
}
|
|
30023
30126
|
async function pickProject(orgId, override) {
|
|
30024
30127
|
if (override) {
|
|
30025
|
-
const data = await api.get("/api/v1/project", {
|
|
30128
|
+
const data = await api.get("/api/v1/project", {
|
|
30129
|
+
organizationId: orgId,
|
|
30130
|
+
projectId: override
|
|
30131
|
+
});
|
|
30026
30132
|
return { project: data.project, created: false };
|
|
30027
30133
|
}
|
|
30028
30134
|
const list = await api.get("/api/v1/projects", { organizationId: orgId, limit: "25" });
|
|
@@ -30075,67 +30181,15 @@ async function pickServerName(override) {
|
|
|
30075
30181
|
throw new Error("Server name must not be empty.");
|
|
30076
30182
|
return name;
|
|
30077
30183
|
}
|
|
30078
|
-
function
|
|
30079
|
-
|
|
30080
|
-
|
|
30081
|
-
|
|
30082
|
-
|
|
30083
|
-
|
|
30084
|
-
" generated server, then optionally --deploy [--wait].",
|
|
30085
|
-
"",
|
|
30086
|
-
"Examples:",
|
|
30087
|
-
" $ mcp init",
|
|
30088
|
-
' $ mcp init --org org_acme --project proj_123 --name "Stripe MCP"',
|
|
30089
|
-
" $ mcp init --from-spec ./openapi.yaml --project proj_123",
|
|
30090
|
-
" $ mcp init --from-spec https://api.example.com/openapi.json --project proj_123 --deploy --wait"
|
|
30091
|
-
].join(`
|
|
30092
|
-
`)).action(runAction(async (opts) => {
|
|
30093
|
-
const orgId = await resolveOrgId(opts.org);
|
|
30094
|
-
if (opts.fromSpec) {
|
|
30095
|
-
await runSpecInit({ orgId, opts });
|
|
30096
|
-
return;
|
|
30097
|
-
}
|
|
30098
|
-
if (!isJsonMode()) {
|
|
30099
|
-
const orgs = await api.get("/api/v1/organizations");
|
|
30100
|
-
const org = orgs.organizations.find((o) => o.id === orgId);
|
|
30101
|
-
printStep(`Using organization ${c.bold(org?.name ?? orgId)} ${c.dim("(" + orgId + ")")}`);
|
|
30102
|
-
}
|
|
30103
|
-
const { project, created: projectCreated } = await pickProject(orgId, opts.project);
|
|
30104
|
-
if (!isJsonMode()) {
|
|
30105
|
-
if (projectCreated) {
|
|
30106
|
-
printSuccess(`Project ${c.bold(project.name)} created (${project.id}).`);
|
|
30107
|
-
} else {
|
|
30108
|
-
printStep(`Using project ${c.bold(project.name)} ${c.dim("(" + project.id + ")")}`);
|
|
30109
|
-
}
|
|
30110
|
-
}
|
|
30111
|
-
const serverName = await pickServerName(opts.name);
|
|
30112
|
-
if (!isJsonMode()) {
|
|
30113
|
-
printStep(`Creating server skeleton ${c.bold(serverName)}…`);
|
|
30114
|
-
}
|
|
30115
|
-
const serverData = await api.post("/api/v1/servers", {
|
|
30116
|
-
organizationId: orgId,
|
|
30117
|
-
projectId: project.id,
|
|
30118
|
-
name: serverName
|
|
30119
|
-
});
|
|
30120
|
-
const server = serverData.server;
|
|
30121
|
-
if (isJsonMode()) {
|
|
30122
|
-
printJson({
|
|
30123
|
-
organizationId: orgId,
|
|
30124
|
-
project,
|
|
30125
|
-
projectCreated,
|
|
30126
|
-
server
|
|
30127
|
-
});
|
|
30128
|
-
return;
|
|
30129
|
-
}
|
|
30130
|
-
printSuccess(`Server ${c.bold(server.id)} ready.`);
|
|
30131
|
-
printInfo("");
|
|
30132
|
-
printInfo("Next steps:");
|
|
30133
|
-
printInfo(` 1. Import an API spec: \`mcp servers ingest --project ${project.id} --spec ./openapi.yaml\``);
|
|
30134
|
-
printInfo(` ${c.dim("(or re-run `mcp init --from-spec ./openapi.yaml` for the guided flow)")}`);
|
|
30135
|
-
printInfo(` 2. Run \`mcp dev --spec ./openapi.yaml\` to iterate locally.`);
|
|
30136
|
-
printInfo(` 3. \`mcp servers deploy ${server.id} --wait\` to ship it.`);
|
|
30137
|
-
}));
|
|
30184
|
+
function reportProject(project, created) {
|
|
30185
|
+
if (isJsonMode())
|
|
30186
|
+
return;
|
|
30187
|
+
if (created) {
|
|
30188
|
+
printSuccess(`Project ${c.bold(project.name)} created (${project.id}).`);
|
|
30189
|
+
}
|
|
30138
30190
|
}
|
|
30191
|
+
|
|
30192
|
+
// src/commands/init-spec.ts
|
|
30139
30193
|
function validateSourceType2(value) {
|
|
30140
30194
|
if (value === undefined)
|
|
30141
30195
|
return;
|
|
@@ -30145,6 +30199,52 @@ function validateSourceType2(value) {
|
|
|
30145
30199
|
}
|
|
30146
30200
|
return v2;
|
|
30147
30201
|
}
|
|
30202
|
+
async function deployIngestedServer(args) {
|
|
30203
|
+
return await api.post("/api/v1/server/deploy", {
|
|
30204
|
+
organizationId: args.orgId,
|
|
30205
|
+
projectId: args.projectId,
|
|
30206
|
+
serverId: args.serverId,
|
|
30207
|
+
target: "workersDev",
|
|
30208
|
+
accessMode: "public",
|
|
30209
|
+
runtimeConfig: {
|
|
30210
|
+
upstreamBaseUrl: null,
|
|
30211
|
+
upstreamApiKey: null,
|
|
30212
|
+
upstreamApiKeyHeader: null,
|
|
30213
|
+
upstreamApiKeyPrefix: null,
|
|
30214
|
+
upstreamCustomHeaders: null,
|
|
30215
|
+
additionalPlainTextBindings: null,
|
|
30216
|
+
additionalSecretBindings: null
|
|
30217
|
+
}
|
|
30218
|
+
});
|
|
30219
|
+
}
|
|
30220
|
+
async function runDeployStep(args) {
|
|
30221
|
+
const { orgId, projectId, serverId, opts } = args;
|
|
30222
|
+
if (!isJsonMode())
|
|
30223
|
+
printStep(`Deploying ${c.bold(serverId)}…`);
|
|
30224
|
+
const deployData = await deployIngestedServer({ orgId, projectId, serverId });
|
|
30225
|
+
const dep = deployData.deployment;
|
|
30226
|
+
let waitDone = !opts.wait;
|
|
30227
|
+
let terminalEvent = null;
|
|
30228
|
+
if (opts.wait) {
|
|
30229
|
+
if (isTerminalDeploymentStatus(dep.status)) {
|
|
30230
|
+
waitDone = true;
|
|
30231
|
+
} else {
|
|
30232
|
+
const totalTimeoutMs = Math.max(10, Number.parseInt(opts.waitTimeout, 10) || 300) * 1000;
|
|
30233
|
+
const followed = await followDeploymentEvents({
|
|
30234
|
+
organizationId: orgId,
|
|
30235
|
+
deploymentId: dep.deploymentId,
|
|
30236
|
+
totalTimeoutMs,
|
|
30237
|
+
onEvent: (event) => {
|
|
30238
|
+
if (!isJsonMode())
|
|
30239
|
+
printInfo(formatEventLine(event));
|
|
30240
|
+
}
|
|
30241
|
+
});
|
|
30242
|
+
waitDone = followed.done;
|
|
30243
|
+
terminalEvent = followed.terminalEvent;
|
|
30244
|
+
}
|
|
30245
|
+
}
|
|
30246
|
+
return { deployment: dep, waitDone, terminalEvent };
|
|
30247
|
+
}
|
|
30148
30248
|
async function runSpecInit(args) {
|
|
30149
30249
|
const { orgId, opts } = args;
|
|
30150
30250
|
if (opts.name && !isJsonMode()) {
|
|
@@ -30153,46 +30253,36 @@ async function runSpecInit(args) {
|
|
|
30153
30253
|
const sourceType = validateSourceType2(opts.sourceType);
|
|
30154
30254
|
const payload = await readSpecSource(opts.fromSpec, sourceType);
|
|
30155
30255
|
const { project, created: projectCreated } = await pickProject(orgId, opts.project);
|
|
30156
|
-
|
|
30157
|
-
printSuccess(`Project ${c.bold(project.name)} created (${project.id}).`);
|
|
30158
|
-
}
|
|
30256
|
+
reportProject(project, projectCreated);
|
|
30159
30257
|
if (!isJsonMode()) {
|
|
30160
30258
|
printStep(`Importing ${c.bold(payload.sourceType)} spec into ${c.bold(project.name)}…`);
|
|
30161
30259
|
}
|
|
30162
|
-
const ingest = await api.post("/api/v1/server/ingest", buildIngestBody({
|
|
30163
|
-
organizationId: orgId,
|
|
30164
|
-
projectId: project.id,
|
|
30165
|
-
payload
|
|
30166
|
-
}));
|
|
30260
|
+
const ingest = await api.post("/api/v1/server/ingest", buildIngestBody({ organizationId: orgId, projectId: project.id, payload }));
|
|
30167
30261
|
const server = ingest.server;
|
|
30168
30262
|
if (!isJsonMode()) {
|
|
30169
30263
|
printSuccess(`Server ${c.bold(server.id)} created from spec.`);
|
|
30170
30264
|
}
|
|
30171
30265
|
let deployResult = null;
|
|
30172
30266
|
if (opts.deploy) {
|
|
30173
|
-
|
|
30174
|
-
|
|
30175
|
-
|
|
30176
|
-
|
|
30177
|
-
|
|
30178
|
-
|
|
30179
|
-
let waitDone = !opts.wait;
|
|
30180
|
-
let terminalEvent = null;
|
|
30181
|
-
if (opts.wait) {
|
|
30182
|
-
const totalTimeoutMs = Math.max(10, Number.parseInt(opts.waitTimeout, 10) || 300) * 1000;
|
|
30183
|
-
const followed = await followDeploymentEvents({
|
|
30184
|
-
organizationId: orgId,
|
|
30185
|
-
deploymentId: deployData.deployment.deploymentId,
|
|
30186
|
-
totalTimeoutMs,
|
|
30187
|
-
onEvent: (event) => {
|
|
30188
|
-
if (!isJsonMode())
|
|
30189
|
-
printInfo(formatEventLine(event));
|
|
30190
|
-
}
|
|
30267
|
+
try {
|
|
30268
|
+
deployResult = await runDeployStep({
|
|
30269
|
+
orgId,
|
|
30270
|
+
projectId: project.id,
|
|
30271
|
+
serverId: server.id,
|
|
30272
|
+
opts
|
|
30191
30273
|
});
|
|
30192
|
-
|
|
30193
|
-
|
|
30274
|
+
} catch (err) {
|
|
30275
|
+
reportDeployFailure({
|
|
30276
|
+
serverId: server.id,
|
|
30277
|
+
projectId: project.id,
|
|
30278
|
+
project,
|
|
30279
|
+
projectCreated,
|
|
30280
|
+
apiSource: ingest.apiSource,
|
|
30281
|
+
server,
|
|
30282
|
+
err
|
|
30283
|
+
});
|
|
30284
|
+
throw err;
|
|
30194
30285
|
}
|
|
30195
|
-
deployResult = { deployment: deployData.deployment, waitDone, terminalEvent };
|
|
30196
30286
|
}
|
|
30197
30287
|
if (isJsonMode()) {
|
|
30198
30288
|
printJson({
|
|
@@ -30208,21 +30298,7 @@ async function runSpecInit(args) {
|
|
|
30208
30298
|
return;
|
|
30209
30299
|
}
|
|
30210
30300
|
if (deployResult) {
|
|
30211
|
-
|
|
30212
|
-
printSuccess(`Deployment ${c.bold(dep.deploymentId)} created.`);
|
|
30213
|
-
printKeyValue({
|
|
30214
|
-
"server id": server.id,
|
|
30215
|
-
"deployment id": dep.deploymentId,
|
|
30216
|
-
url: dep.deploymentUrl ?? "—",
|
|
30217
|
-
target: dep.target,
|
|
30218
|
-
"access mode": dep.accessMode,
|
|
30219
|
-
status: dep.status
|
|
30220
|
-
});
|
|
30221
|
-
if (opts.wait && !deployResult.waitDone) {
|
|
30222
|
-
printError(`Deploy did not reach a terminal state in time. Watch with \`mcp deployments logs ${dep.deploymentId} --follow\`.`);
|
|
30223
|
-
throw new CliExitError(1);
|
|
30224
|
-
}
|
|
30225
|
-
printStep(`Try it: \`mcp invoke ${server.id} <tool>\`.`);
|
|
30301
|
+
reportDeploySuccess({ serverId: server.id, result: deployResult, opts });
|
|
30226
30302
|
return;
|
|
30227
30303
|
}
|
|
30228
30304
|
printInfo("");
|
|
@@ -30230,6 +30306,111 @@ async function runSpecInit(args) {
|
|
|
30230
30306
|
printStep(`Generate the bundle: \`mcp servers generate ${server.id} --out ./build\``);
|
|
30231
30307
|
printStep(`Deploy it: \`mcp servers deploy ${server.id} --wait\``);
|
|
30232
30308
|
}
|
|
30309
|
+
function resumeDeployCommand(serverId, projectId) {
|
|
30310
|
+
return `mcp servers deploy ${serverId} --project ${projectId} --wait`;
|
|
30311
|
+
}
|
|
30312
|
+
function reportDeployFailure(args) {
|
|
30313
|
+
const resume = resumeDeployCommand(args.serverId, args.projectId);
|
|
30314
|
+
if (isJsonMode()) {
|
|
30315
|
+
const message = args.err instanceof Error ? args.err.message : String(args.err);
|
|
30316
|
+
printJson({
|
|
30317
|
+
project: args.project,
|
|
30318
|
+
projectCreated: args.projectCreated,
|
|
30319
|
+
apiSource: args.apiSource,
|
|
30320
|
+
server: args.server,
|
|
30321
|
+
deploy: null,
|
|
30322
|
+
deployFailed: true,
|
|
30323
|
+
deployError: { message },
|
|
30324
|
+
resumeCommand: resume
|
|
30325
|
+
});
|
|
30326
|
+
return;
|
|
30327
|
+
}
|
|
30328
|
+
printError(`Server ${c.bold(args.serverId)} was created, but the deploy step failed.`);
|
|
30329
|
+
printInfo("");
|
|
30330
|
+
printInfo("Created so far:");
|
|
30331
|
+
printKeyValue({ "server id": args.serverId, "project id": args.projectId });
|
|
30332
|
+
printInfo("");
|
|
30333
|
+
printInfo(`Resume the deploy once the cause is cleared:`);
|
|
30334
|
+
printStep(resume);
|
|
30335
|
+
printInfo("");
|
|
30336
|
+
}
|
|
30337
|
+
function reportDeploySuccess(args) {
|
|
30338
|
+
const { serverId, result, opts } = args;
|
|
30339
|
+
const dep = result.deployment;
|
|
30340
|
+
printSuccess(`Deployment ${c.bold(dep.deploymentId)} created.`);
|
|
30341
|
+
printKeyValue({
|
|
30342
|
+
"server id": serverId,
|
|
30343
|
+
"deployment id": dep.deploymentId,
|
|
30344
|
+
url: dep.deploymentUrl ?? "—",
|
|
30345
|
+
target: dep.target,
|
|
30346
|
+
"access mode": dep.accessMode,
|
|
30347
|
+
status: dep.status
|
|
30348
|
+
});
|
|
30349
|
+
if (opts.wait && !result.waitDone) {
|
|
30350
|
+
printError(`Deploy did not reach a terminal state in time. Check \`mcp deployments get ${dep.deploymentId}\` and \`mcp deployments health ${dep.deploymentId}\`, or tail \`mcp deployments logs ${dep.deploymentId} --follow\`.`);
|
|
30351
|
+
throw new CliExitError(1);
|
|
30352
|
+
}
|
|
30353
|
+
printStep(`Try it: \`mcp invoke ${serverId} <tool>\`.`);
|
|
30354
|
+
}
|
|
30355
|
+
|
|
30356
|
+
// src/commands/init.ts
|
|
30357
|
+
function registerInitCommand(program2) {
|
|
30358
|
+
program2.command("init").description("Guided onboarding: pick org → pick/create project → create a server (empty skeleton, or generated from an OpenAPI/GraphQL spec via --from-spec)").option("--org <organizationId>", "Organization ID").option("--project <projectId>", "Reuse an existing project instead of creating one").option("--name <serverName>", "Name for the new server (skeleton path only)").option("--from-spec <file|url>", "Build from an OpenAPI spec (local file, http(s) URL, or @- for stdin), or — with --source-type graphql — a GraphQL endpoint URL to introspect").option("--source-type <type>", `Override spec classification: ${SOURCE_TYPES.join(" | ")} (OpenAPI auto-detected; graphql requires an endpoint URL)`).option("--deploy", "After importing the spec, deploy the server").option("--wait", "With --deploy, follow events until the deploy is terminal").option("--wait-timeout <seconds>", "Max seconds to wait for a terminal deploy state (default 300)", "300").addHelpText("after", [
|
|
30359
|
+
"",
|
|
30360
|
+
"Two modes:",
|
|
30361
|
+
" Skeleton (default): resolve org → pick/create project → create an empty server.",
|
|
30362
|
+
" Spec (--from-spec): resolve org → pick/create project → ingest the spec into a",
|
|
30363
|
+
" generated server, then optionally --deploy [--wait].",
|
|
30364
|
+
"",
|
|
30365
|
+
"Examples:",
|
|
30366
|
+
" $ mcp init",
|
|
30367
|
+
' $ mcp init --org org_acme --project proj_123 --name "Stripe MCP"',
|
|
30368
|
+
" $ mcp init --from-spec ./openapi.yaml --project proj_123",
|
|
30369
|
+
" $ mcp init --from-spec https://api.example.com/openapi.json --project proj_123 --deploy --wait"
|
|
30370
|
+
].join(`
|
|
30371
|
+
`)).action(runAction(runInit));
|
|
30372
|
+
}
|
|
30373
|
+
async function runInit(opts) {
|
|
30374
|
+
const orgId = await resolveOrgId(opts.org);
|
|
30375
|
+
if (opts.fromSpec) {
|
|
30376
|
+
await runSpecInit({ orgId, opts });
|
|
30377
|
+
return;
|
|
30378
|
+
}
|
|
30379
|
+
await runSkeletonInit({ orgId, opts });
|
|
30380
|
+
}
|
|
30381
|
+
async function runSkeletonInit(args) {
|
|
30382
|
+
const { orgId, opts } = args;
|
|
30383
|
+
if (!isJsonMode()) {
|
|
30384
|
+
const orgs = await api.get("/api/v1/organizations");
|
|
30385
|
+
const org = orgs.organizations.find((o) => o.id === orgId);
|
|
30386
|
+
printStep(`Using organization ${c.bold(org?.name ?? orgId)} ${c.dim("(" + orgId + ")")}`);
|
|
30387
|
+
}
|
|
30388
|
+
const { project, created: projectCreated } = await pickProject(orgId, opts.project);
|
|
30389
|
+
if (!isJsonMode()) {
|
|
30390
|
+
if (projectCreated) {
|
|
30391
|
+
printSuccess(`Project ${c.bold(project.name)} created (${project.id}).`);
|
|
30392
|
+
} else {
|
|
30393
|
+
printStep(`Using project ${c.bold(project.name)} ${c.dim("(" + project.id + ")")}`);
|
|
30394
|
+
}
|
|
30395
|
+
}
|
|
30396
|
+
const serverName = await pickServerName(opts.name);
|
|
30397
|
+
if (!isJsonMode()) {
|
|
30398
|
+
printStep(`Creating server skeleton ${c.bold(serverName)}…`);
|
|
30399
|
+
}
|
|
30400
|
+
const serverData = await api.post("/api/v1/servers", { organizationId: orgId, projectId: project.id, name: serverName });
|
|
30401
|
+
const server = serverData.server;
|
|
30402
|
+
if (isJsonMode()) {
|
|
30403
|
+
printJson({ organizationId: orgId, project, projectCreated, server });
|
|
30404
|
+
return;
|
|
30405
|
+
}
|
|
30406
|
+
printSuccess(`Server ${c.bold(server.id)} ready.`);
|
|
30407
|
+
printInfo("");
|
|
30408
|
+
printInfo("Next steps:");
|
|
30409
|
+
printInfo(` 1. Import an API spec: \`mcp servers ingest --project ${project.id} --spec ./openapi.yaml\``);
|
|
30410
|
+
printInfo(` ${c.dim("(or re-run `mcp init --from-spec ./openapi.yaml` for the guided flow)")}`);
|
|
30411
|
+
printInfo(` 2. Run \`mcp dev --spec ./openapi.yaml\` to iterate locally.`);
|
|
30412
|
+
printInfo(` 3. \`mcp servers deploy ${server.id} --wait\` to ship it.`);
|
|
30413
|
+
}
|
|
30233
30414
|
|
|
30234
30415
|
// src/commands/installation.ts
|
|
30235
30416
|
function registerInstallationCommands(program2) {
|
|
@@ -30920,6 +31101,7 @@ function registerUsageCommands(program2) {
|
|
|
30920
31101
|
allowed: t.allowedCount,
|
|
30921
31102
|
"billable invocations": usageData.usage.invocations?.billableCount ?? t.allowedToolCallCount ?? 0,
|
|
30922
31103
|
"invocation cost": formatMicros(usageData.usage.invocations?.billedMicros),
|
|
31104
|
+
"projected monthly": formatMicros(usageData.usage.invocations?.projectedMonthlyMicros),
|
|
30923
31105
|
"rate-limited": t.rateLimitedCount,
|
|
30924
31106
|
unauthorized: t.unauthorizedCount,
|
|
30925
31107
|
failed: t.failedCount,
|
|
@@ -31127,6 +31309,73 @@ function registerOrgCommands(program2) {
|
|
|
31127
31309
|
}));
|
|
31128
31310
|
}
|
|
31129
31311
|
|
|
31312
|
+
// src/commands/connections.ts
|
|
31313
|
+
async function readKeyFromStdin() {
|
|
31314
|
+
const chunks = [];
|
|
31315
|
+
for await (const chunk of process.stdin) {
|
|
31316
|
+
chunks.push(Buffer.from(chunk));
|
|
31317
|
+
}
|
|
31318
|
+
return Buffer.concat(chunks).toString("utf8").trim();
|
|
31319
|
+
}
|
|
31320
|
+
function registerConnectionsCommands(program2) {
|
|
31321
|
+
const connections = program2.command("connections").description("Manage your per-server upstream API keys (BYOK) from the terminal").addHelpText("after", [
|
|
31322
|
+
"",
|
|
31323
|
+
"Examples:",
|
|
31324
|
+
" $ mcp connections list",
|
|
31325
|
+
" $ mcp connections add <serverId> --key sk_live_…",
|
|
31326
|
+
' $ echo "$UPSTREAM_KEY" | mcp connections add <serverId> --key-stdin',
|
|
31327
|
+
" $ mcp connections remove <serverId>"
|
|
31328
|
+
].join(`
|
|
31329
|
+
`));
|
|
31330
|
+
connections.command("list").description("List your stored upstream keys across servers (hints only)").action(runAction(async () => {
|
|
31331
|
+
const data = await api.get("/api/v1/upstream-key");
|
|
31332
|
+
if (isJsonMode()) {
|
|
31333
|
+
printJson(data);
|
|
31334
|
+
return;
|
|
31335
|
+
}
|
|
31336
|
+
printList(data.keys.map((entry) => ({
|
|
31337
|
+
server: entry.serverName ?? entry.serverId,
|
|
31338
|
+
key: `••••${entry.keyHint}`,
|
|
31339
|
+
status: entry.status,
|
|
31340
|
+
"last used": entry.lastUsedAt ? formatDate(entry.lastUsedAt) : "—",
|
|
31341
|
+
updated: formatDate(entry.updatedAt)
|
|
31342
|
+
})), [
|
|
31343
|
+
{ key: "server", label: "Server", width: 32 },
|
|
31344
|
+
{ key: "key", label: "Key", width: 10 },
|
|
31345
|
+
{ key: "status", label: "Status", width: 10 },
|
|
31346
|
+
{ key: "last used", label: "Last used", width: 22 },
|
|
31347
|
+
{ key: "updated", label: "Updated", width: 22 }
|
|
31348
|
+
], data);
|
|
31349
|
+
}));
|
|
31350
|
+
connections.command("add <serverId>").description("Save (or replace) your upstream API key for a server — rotation is just adding again").option("--key <apiKey>", "The upstream API key (visible in shell history)").option("--key-stdin", "Read the key from stdin instead (recommended for CI)").action(runAction(async (serverId, opts) => {
|
|
31351
|
+
const apiKey = opts.keyStdin ? await readKeyFromStdin() : opts.key ?? "";
|
|
31352
|
+
if (!apiKey.trim()) {
|
|
31353
|
+
throw new Error("Provide the key via --key <apiKey> or pipe it with --key-stdin.");
|
|
31354
|
+
}
|
|
31355
|
+
const data = await api.post("/api/v1/upstream-key", { serverId, apiKey });
|
|
31356
|
+
if (isJsonMode()) {
|
|
31357
|
+
printJson(data);
|
|
31358
|
+
return;
|
|
31359
|
+
}
|
|
31360
|
+
printKeyValue({
|
|
31361
|
+
saved: String(data.saved),
|
|
31362
|
+
key: `••••${data.keyHint}`,
|
|
31363
|
+
note: "Stored encrypted; your next tool call uses it immediately."
|
|
31364
|
+
});
|
|
31365
|
+
}));
|
|
31366
|
+
connections.command("remove <serverId>").description("Revoke your stored upstream key for a server").action(runAction(async (serverId) => {
|
|
31367
|
+
const data = await api.delete("/api/v1/upstream-key", { serverId });
|
|
31368
|
+
if (isJsonMode()) {
|
|
31369
|
+
printJson(data);
|
|
31370
|
+
return;
|
|
31371
|
+
}
|
|
31372
|
+
printKeyValue({
|
|
31373
|
+
revoked: String(data.revoked),
|
|
31374
|
+
note: data.revoked ? "Tool calls will prompt for a fresh key on next use." : "No active key was stored for this server."
|
|
31375
|
+
});
|
|
31376
|
+
}));
|
|
31377
|
+
}
|
|
31378
|
+
|
|
31130
31379
|
// src/lib/plugins.ts
|
|
31131
31380
|
import { spawn as spawn7 } from "node:child_process";
|
|
31132
31381
|
import {
|
|
@@ -35733,7 +35982,7 @@ function registerUpdateCommand(program2) {
|
|
|
35733
35982
|
// src/create-program.ts
|
|
35734
35983
|
function createProgram() {
|
|
35735
35984
|
const program2 = new Command;
|
|
35736
|
-
program2.name("mcp").description("The official CLI for MCPCloud — manage projects, MCP servers, skills, and API keys from the terminal").version(getCliVersion(), "-v, --version", "Print the CLI version").option("--json", "Output raw JSON (useful for scripting)").option("--base-url <url>", "API base URL for this invocation. Falls back to MCPCLOUD_BASE_URL
|
|
35985
|
+
program2.name("mcp").description("The official CLI for MCPCloud — manage projects, MCP servers, skills, and API keys from the terminal").version(getCliVersion(), "-v, --version", "Print the CLI version").option("--json", "Output raw JSON (useful for scripting)").option("--base-url <url>", "API base URL for this invocation. Falls back to MCPCLOUD_BASE_URL, `mcp config set-url`, then the built-in MCPCloud production default.").option("--profile <name>", "Run against a named config profile for this invocation (overrides MCPCLOUD_PROFILE and the saved current profile).").option("--ci", "Force CI mode for this invocation. Auto-detected when CI=true. Disables color, swaps Unicode glyphs for ASCII, refuses interactive prompts, and always surfaces request IDs.").option("--warnings-as-errors", "Exit non-zero if any warning is emitted during the command (CI ergonomics).").option("--non-interactive", "Refuse interactive prompts (fail fast on missing input) without the color/glyph changes of --ci.").option("--quiet", "Suppress success/step/info chrome; data and errors still print. Pairs with exit codes for health/existence gates.").option("--format <mode>", "Output format for list commands: table (default), tsv, jsonl, json.").option("--no-table", "Shorthand for --format tsv. Tab-separated rows for awk/cut/grep pipelines.").option("--field <names>", "Comma-separated list of fields to include in list output (repeatable).", (value, prev) => prev ? [...prev, value] : [value]).option("--filter <key=substring>", "Substring filter for list rows (repeatable). Case-insensitive.", (value, prev) => prev ? [...prev, value] : [value]).option("--idempotency-key <key>", "Stable Idempotency-Key for mutations (1–255 ASCII chars, no whitespace). When omitted, the CLI auto-generates a UUID per invocation so internal retries on transient failures stay safe.").option("--debug", "Print every HTTP request/response with secrets redacted. Equivalent to MCPCLOUD_LOG=debug.").hook("preAction", (thisCommand) => {
|
|
35737
35986
|
const opts = thisCommand.optsWithGlobals();
|
|
35738
35987
|
setJsonMode(Boolean(opts.json));
|
|
35739
35988
|
setBaseUrlOverride(opts.baseUrl);
|
|
@@ -35753,21 +36002,22 @@ function createProgram() {
|
|
|
35753
36002
|
}).addHelpText("after", [
|
|
35754
36003
|
"",
|
|
35755
36004
|
"Environment variables:",
|
|
35756
|
-
" MCPCLOUD_API_KEY API key used for authentication (
|
|
35757
|
-
" MCPCLOUD_BASE_URL API base URL (
|
|
36005
|
+
" MCPCLOUD_API_KEY API key used for authentication (or run `mcp login`)",
|
|
36006
|
+
" MCPCLOUD_BASE_URL Override the API base URL (defaults to MCPCloud production)",
|
|
35758
36007
|
" MCPCLOUD_ORG_ID Default organization ID",
|
|
35759
36008
|
' MCPCLOUD_PROFILE Active config profile name (default: "default")',
|
|
35760
36009
|
" CI When truthy, enables CI mode automatically (no color, ASCII glyphs, no prompts)",
|
|
35761
36010
|
"",
|
|
35762
36011
|
"Examples:",
|
|
35763
|
-
" $
|
|
35764
|
-
" $ mcp config set-url https://your-deployment.example.com # persist it",
|
|
35765
|
-
" $ mcp login",
|
|
36012
|
+
" $ mcp login # sign in (production, out of the box)",
|
|
35766
36013
|
" $ mcp whoami",
|
|
35767
36014
|
" $ mcp skills connect skill_123 --agent claude-code --apply",
|
|
35768
36015
|
" $ mcp --json servers list",
|
|
35769
36016
|
" $ mcp servers list --field id,name --format jsonl",
|
|
35770
|
-
" $ mcp servers list --filter status=active --no-table"
|
|
36017
|
+
" $ mcp servers list --filter status=active --no-table",
|
|
36018
|
+
"",
|
|
36019
|
+
"Self-host / staging: point the CLI elsewhere with MCPCLOUD_BASE_URL,",
|
|
36020
|
+
"`mcp config set-url <url>`, or --base-url <url> (each overrides the default)."
|
|
35771
36021
|
].join(`
|
|
35772
36022
|
`));
|
|
35773
36023
|
registerAuthCommands(program2);
|
|
@@ -35781,6 +36031,7 @@ function createProgram() {
|
|
|
35781
36031
|
registerDeploymentCommands(program2);
|
|
35782
36032
|
registerOrgCommands(program2);
|
|
35783
36033
|
registerUsageCommands(program2);
|
|
36034
|
+
registerConnectionsCommands(program2);
|
|
35784
36035
|
registerMetricsCommands(program2);
|
|
35785
36036
|
registerDevCommand(program2);
|
|
35786
36037
|
registerCompletionCommand(program2);
|
|
@@ -35798,8 +36049,59 @@ function createProgram() {
|
|
|
35798
36049
|
return program2;
|
|
35799
36050
|
}
|
|
35800
36051
|
|
|
36052
|
+
// src/lib/first-run.ts
|
|
36053
|
+
function shouldShowFirstRunGreeting(input) {
|
|
36054
|
+
if (input.hasCommand)
|
|
36055
|
+
return false;
|
|
36056
|
+
if (!input.isTty)
|
|
36057
|
+
return false;
|
|
36058
|
+
if (input.ciMode)
|
|
36059
|
+
return false;
|
|
36060
|
+
if (input.jsonMode)
|
|
36061
|
+
return false;
|
|
36062
|
+
if (input.authenticated)
|
|
36063
|
+
return false;
|
|
36064
|
+
if (input.hasSavedConfig)
|
|
36065
|
+
return false;
|
|
36066
|
+
return true;
|
|
36067
|
+
}
|
|
36068
|
+
function argvHasCommand(argv) {
|
|
36069
|
+
return argv.slice(2).some((token) => !token.startsWith("-"));
|
|
36070
|
+
}
|
|
36071
|
+
function firstRunGreeting() {
|
|
36072
|
+
return [
|
|
36073
|
+
"Welcome to MCPCloud — turn an API spec into a deployed MCP server.",
|
|
36074
|
+
"",
|
|
36075
|
+
"Get started:",
|
|
36076
|
+
" 1. mcp login Sign in (opens your browser)",
|
|
36077
|
+
" 2. mcp init Scaffold a server from an OpenAPI / GraphQL spec",
|
|
36078
|
+
" 3. mcp servers deploy Ship it to the edge",
|
|
36079
|
+
"",
|
|
36080
|
+
"Run `mcp --help` for the full command reference.",
|
|
36081
|
+
""
|
|
36082
|
+
].join(`
|
|
36083
|
+
`);
|
|
36084
|
+
}
|
|
36085
|
+
|
|
35801
36086
|
// src/index.ts
|
|
36087
|
+
function maybeGreetFirstRun(argv) {
|
|
36088
|
+
const cfg = readConfig();
|
|
36089
|
+
const show = shouldShowFirstRunGreeting({
|
|
36090
|
+
hasCommand: argvHasCommand(argv),
|
|
36091
|
+
isTty: Boolean(process.stdout.isTTY),
|
|
36092
|
+
ciMode: isCiEnv() || argv.includes("--ci"),
|
|
36093
|
+
jsonMode: argv.includes("--json"),
|
|
36094
|
+
authenticated: Boolean(getApiKey()),
|
|
36095
|
+
hasSavedConfig: Boolean(cfg.baseUrl || cfg.apiKey || cfg.defaultOrganizationId)
|
|
36096
|
+
});
|
|
36097
|
+
if (!show)
|
|
36098
|
+
return false;
|
|
36099
|
+
process.stdout.write(firstRunGreeting());
|
|
36100
|
+
return true;
|
|
36101
|
+
}
|
|
35802
36102
|
async function main() {
|
|
36103
|
+
if (maybeGreetFirstRun(process.argv))
|
|
36104
|
+
return;
|
|
35803
36105
|
const program2 = createProgram();
|
|
35804
36106
|
if (process.env["MCPSH_DISABLE_PLUGINS"] !== "1") {
|
|
35805
36107
|
await loadPlugins(program2);
|