@mcpcloud/cli 0.17.2 → 0.18.0

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.
Files changed (3) hide show
  1. package/README.md +15 -1
  2. package/dist/index.js +945 -202
  3. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -5180,6 +5180,68 @@ async function resolveOrgId(orgId) {
5180
5180
  return first.id;
5181
5181
  }
5182
5182
 
5183
+ // src/lib/paginate.ts
5184
+ var MAX_PAGE_SIZE = 100;
5185
+ var MAX_PAGES = 200;
5186
+ async function fetchAllPages(path, params, key, options = {}) {
5187
+ const items = [];
5188
+ let cursor = null;
5189
+ for (let page = 0;page < MAX_PAGES; page += 1) {
5190
+ const remaining = options.max === undefined ? MAX_PAGE_SIZE : options.max - items.length;
5191
+ if (remaining <= 0)
5192
+ break;
5193
+ const data = await api.get(path, {
5194
+ ...params,
5195
+ limit: String(Math.min(MAX_PAGE_SIZE, remaining)),
5196
+ ...cursor ? { cursor } : {}
5197
+ });
5198
+ const rows = data[key];
5199
+ if (Array.isArray(rows))
5200
+ items.push(...rows);
5201
+ const next = typeof data.nextCursor === "string" ? data.nextCursor : null;
5202
+ if (data.hasMore !== true || !next)
5203
+ break;
5204
+ cursor = next;
5205
+ }
5206
+ return options.max === undefined ? items : items.slice(0, options.max);
5207
+ }
5208
+ async function fetchAllPagesWithEnvelope(path, params, key, options = {}) {
5209
+ let envelope = {};
5210
+ let captured = false;
5211
+ const rows = [];
5212
+ let cursor = null;
5213
+ for (let page = 0;page < MAX_PAGES; page += 1) {
5214
+ const remaining = options.max === undefined ? MAX_PAGE_SIZE : options.max - rows.length;
5215
+ if (remaining <= 0)
5216
+ break;
5217
+ const data = await api.get(path, {
5218
+ ...params,
5219
+ limit: String(Math.min(MAX_PAGE_SIZE, remaining)),
5220
+ ...cursor ? { cursor } : {}
5221
+ });
5222
+ if (!captured) {
5223
+ const { nextCursor: _n, hasMore: _h, ...rest } = data;
5224
+ envelope = rest;
5225
+ captured = true;
5226
+ }
5227
+ const pageRows = data[key];
5228
+ if (Array.isArray(pageRows))
5229
+ rows.push(...pageRows);
5230
+ const next = typeof data.nextCursor === "string" ? data.nextCursor : null;
5231
+ if (data.hasMore !== true || !next)
5232
+ break;
5233
+ cursor = next;
5234
+ }
5235
+ const capped = options.max === undefined ? rows : rows.slice(0, options.max);
5236
+ return { rows: capped, payload: { ...envelope, [key]: capped } };
5237
+ }
5238
+ function parseRowCap(raw) {
5239
+ if (raw === undefined)
5240
+ return;
5241
+ const parsed = Number.parseInt(raw, 10);
5242
+ return Number.isInteger(parsed) && parsed > 0 ? parsed : undefined;
5243
+ }
5244
+
5183
5245
  // src/lib/resolve-match.ts
5184
5246
  var ID_SHAPE = /^[a-z0-9]{32}$/;
5185
5247
  function isIdShape(ref) {
@@ -5392,25 +5454,21 @@ async function probeById(spec, scope, id) {
5392
5454
  });
5393
5455
  }
5394
5456
  function candidateSlug(kind, row) {
5457
+ if (typeof row.slug === "string" && row.slug.trim()) {
5458
+ return row.slug.trim().toLowerCase();
5459
+ }
5395
5460
  if (kind === "server") {
5396
5461
  return deriveServerSlug(typeof row.deploymentUrl === "string" ? row.deploymentUrl : undefined);
5397
5462
  }
5398
- if (kind === "project" && typeof row.slug === "string" && row.slug.trim()) {
5399
- return row.slug.trim().toLowerCase();
5400
- }
5401
5463
  return;
5402
5464
  }
5403
5465
  async function loadCandidates(kind, spec, scope) {
5404
5466
  const params = {
5405
- organizationId: scope.organizationId,
5406
- limit: "100"
5467
+ organizationId: scope.organizationId
5407
5468
  };
5408
5469
  if (scope.projectId && kind !== "project")
5409
5470
  params["projectId"] = scope.projectId;
5410
- const data = await api.get(spec.listPath, params);
5411
- const rows = data?.[spec.listKey];
5412
- if (!Array.isArray(rows))
5413
- return [];
5471
+ const rows = await fetchAllPages(spec.listPath, params, spec.listKey);
5414
5472
  return rows.filter((row) => typeof row?.id === "string").map((row) => ({
5415
5473
  id: row.id,
5416
5474
  name: typeof row.name === "string" ? row.name : "",
@@ -6245,11 +6303,8 @@ function registerProjectCommands(program2) {
6245
6303
  ].join(`
6246
6304
  `)).action(runAction(async (opts) => {
6247
6305
  const orgId = await resolveOrgId(opts.org);
6248
- const data = await api.get("/api/v1/projects", {
6249
- organizationId: orgId,
6250
- limit: opts.limit
6251
- });
6252
- printList(data.projects.map((p2) => ({
6306
+ const { rows: projectRows, payload } = await fetchAllPagesWithEnvelope("/api/v1/projects", { organizationId: orgId }, "projects", { max: parseRowCap(opts.limit) });
6307
+ printList(projectRows.map((p2) => ({
6253
6308
  id: p2.id,
6254
6309
  name: p2.name,
6255
6310
  slug: p2.slug,
@@ -6261,7 +6316,7 @@ function registerProjectCommands(program2) {
6261
6316
  { key: "slug", label: "Slug", width: 20 },
6262
6317
  { key: "servers", label: "Servers", width: 8 },
6263
6318
  { key: "created", label: "Created", width: 20 }
6264
- ], data);
6319
+ ], payload);
6265
6320
  }));
6266
6321
  projects.command("get <project>").description("Get details for a single project (accepts id or name)").option("--org <organizationId>", "Organization ID").action(runAction(async (projectRef, opts) => {
6267
6322
  const orgId = await resolveOrgId(opts.org);
@@ -6634,8 +6689,483 @@ async function tailDeploymentLogs(args) {
6634
6689
  }
6635
6690
  }
6636
6691
 
6692
+ // src/commands/servers-deps.ts
6693
+ var DEPS_PATH = "/api/v1/server/dependencies";
6694
+ function reportApiError(err, action) {
6695
+ if (err instanceof McpCloudApiError) {
6696
+ printError(`${action} failed (HTTP ${err.status}): ${err.error.message}`);
6697
+ const reason = err.error.details?.reason;
6698
+ if (typeof reason === "string") {
6699
+ printInfo(` ${c.dim("reason:")} ${reason}`);
6700
+ }
6701
+ } else {
6702
+ printError(`${action} failed: ${err instanceof Error ? err.message : String(err)}`);
6703
+ }
6704
+ throw new CliExitError(1);
6705
+ }
6706
+ function printDependencies(deps) {
6707
+ if (deps.length === 0) {
6708
+ printInfo(c.dim(" No dependencies. Add one with `mcp servers deps add`."));
6709
+ return;
6710
+ }
6711
+ printList(deps.map((dep) => ({
6712
+ id: dep.id,
6713
+ child: dep.childName ?? dep.childServerId ?? "—",
6714
+ prefix: dep.toolPrefix,
6715
+ tools: dep.includedTools ? dep.includedTools.join(", ") : "all",
6716
+ enabled: dep.enabled ? "yes" : "no"
6717
+ })), [
6718
+ { key: "id", label: "ID", width: 34 },
6719
+ { key: "child", label: "Child", width: 26 },
6720
+ { key: "prefix", label: "Prefix", width: 16 },
6721
+ { key: "tools", label: "Tools", width: 28 },
6722
+ { key: "enabled", label: "Enabled", width: 8 }
6723
+ ], { dependencies: deps });
6724
+ }
6725
+ function registerServerDepsCommands(servers) {
6726
+ const deps = servers.command("deps").description("Compose another server's tools into this one (list / add / rm)");
6727
+ deps.command("list [server]").description("List the servers this one composes.").option("--org <organizationId>", "Organization ID").action(runAction(async (server, opts) => {
6728
+ const orgId = await resolveOrgId(opts.org);
6729
+ const serverId = await resolveServerId(requireServer(server), orgId);
6730
+ try {
6731
+ const data = await api.get(DEPS_PATH, {
6732
+ organizationId: orgId,
6733
+ serverId
6734
+ });
6735
+ if (isJsonMode()) {
6736
+ printJson(data);
6737
+ return;
6738
+ }
6739
+ printDependencies(data.dependencies);
6740
+ } catch (err) {
6741
+ reportApiError(err, "Listing dependencies");
6742
+ }
6743
+ }));
6744
+ deps.command("add <server> <child>").description("Compose <child>'s tools into <server>. Both accept an id, name or slug.").option("--org <organizationId>", "Organization ID").option("--prefix <prefix>", "Prefix for the re-exposed tool names (defaults to the child's slug).").option("--tools <names>", "Comma-separated child tool names to expose; omit for all of them.").addHelpText("after", [
6745
+ "",
6746
+ "Examples:",
6747
+ " $ mcp servers deps add my-api billing-api",
6748
+ " $ mcp servers deps add my-api billing-api --prefix billing_",
6749
+ " $ mcp servers deps add my-api billing-api --tools getCharges,createRefund"
6750
+ ].join(`
6751
+ `)).action(runAction(async (server, child, opts) => {
6752
+ const orgId = await resolveOrgId(opts.org);
6753
+ const serverId = await resolveServerId(server, orgId);
6754
+ const childServerId = await resolveServerId(child, orgId);
6755
+ const includedTools = (opts.tools ?? "").split(",").map((name) => name.trim()).filter(Boolean);
6756
+ try {
6757
+ const data = await api.post(DEPS_PATH, {
6758
+ organizationId: orgId,
6759
+ serverId,
6760
+ childServerId,
6761
+ ...opts.prefix ? { toolPrefix: opts.prefix } : {},
6762
+ ...includedTools.length > 0 ? { includedTools } : {}
6763
+ });
6764
+ if (isJsonMode()) {
6765
+ printJson({ ok: true, ...data });
6766
+ return;
6767
+ }
6768
+ const dep = data.dependency;
6769
+ printSuccess(`Composed ${c.bold(dep.childName ?? child)} into ${c.bold(server)} ${c.dim(`(prefix ${dep.toolPrefix})`)}`);
6770
+ printInfo(` ${c.dim("Its tools appear on the parent as")} ${c.bold(`${dep.toolPrefix}<tool>`)} ${c.dim("after the next policy sync — no redeploy needed.")}`);
6771
+ } catch (err) {
6772
+ reportApiError(err, "Binding the dependency");
6773
+ }
6774
+ }));
6775
+ deps.command("rm <server> <dependencyId>").description("Remove a composed dependency (id from `deps list`).").option("--org <organizationId>", "Organization ID").action(runAction(async (server, dependencyId, opts) => {
6776
+ const orgId = await resolveOrgId(opts.org);
6777
+ const serverId = await resolveServerId(server, orgId);
6778
+ try {
6779
+ const data = await api.delete(`${DEPS_PATH}?organizationId=${encodeURIComponent(orgId)}&serverId=${encodeURIComponent(serverId)}&dependencyId=${encodeURIComponent(dependencyId)}`);
6780
+ if (isJsonMode()) {
6781
+ printJson({ ok: true, ...data });
6782
+ return;
6783
+ }
6784
+ printSuccess(`Removed ${c.bold(data.removed.childName ?? data.removed.id)} ${c.dim(`(prefix ${data.removed.toolPrefix})`)}`);
6785
+ } catch (err) {
6786
+ reportApiError(err, "Removing the dependency");
6787
+ }
6788
+ }));
6789
+ }
6790
+ function requireServer(server) {
6791
+ if (server)
6792
+ return server;
6793
+ printError("Name the server whose dependencies you want to list.");
6794
+ throw new CliExitError(1);
6795
+ }
6796
+
6797
+ // src/commands/servers-prompts.ts
6798
+ import { readFileSync as readFileSync3 } from "node:fs";
6799
+
6800
+ // src/lib/server-scope.ts
6801
+ async function resolveServerScope(serverRef, org) {
6802
+ const organizationId = await resolveOrgId(org);
6803
+ const serverId = await resolveServerId(serverRef, organizationId);
6804
+ const detail = await api.get("/api/v1/server", {
6805
+ organizationId,
6806
+ serverId
6807
+ });
6808
+ return {
6809
+ organizationId,
6810
+ projectId: detail.server.projectId,
6811
+ serverId,
6812
+ serverName: detail.server.name
6813
+ };
6814
+ }
6815
+
6816
+ // src/commands/servers-prompts.ts
6817
+ var PROMPT_PATH = "/api/v1/server/prompt";
6818
+ function reportApiError2(err, action) {
6819
+ if (err instanceof McpCloudApiError) {
6820
+ printError(`${action} failed (HTTP ${err.status}): ${err.error.message}`);
6821
+ const details = err.error.details;
6822
+ if (typeof details?.field === "string") {
6823
+ printInfo(` ${c.dim("field:")} ${details.field}`);
6824
+ }
6825
+ } else {
6826
+ printError(`${action} failed: ${err instanceof Error ? err.message : String(err)}`);
6827
+ }
6828
+ throw new CliExitError(1);
6829
+ }
6830
+ function countArguments(argumentsJson) {
6831
+ try {
6832
+ const parsed = JSON.parse(argumentsJson || "[]");
6833
+ return Array.isArray(parsed) ? String(parsed.length) : "?";
6834
+ } catch {
6835
+ return "?";
6836
+ }
6837
+ }
6838
+ function readTemplate(opts) {
6839
+ if (opts.templateFile)
6840
+ return readFileSync3(opts.templateFile, "utf8");
6841
+ if (opts.template !== undefined)
6842
+ return opts.template;
6843
+ printError("A template is required — pass --template <markdown> or --template-file <path>.");
6844
+ throw new CliExitError(1);
6845
+ }
6846
+ function registerServerPromptCommands(servers) {
6847
+ const prompts = servers.command("prompts").description("Author the prompts a client reads as this server’s workflows (list / set / rm)");
6848
+ prompts.command("list <server>").description("List the prompts authored on a server.").option("--org <organizationId>", "Organization ID").action(runAction(async (server, opts) => {
6849
+ const scope = await resolveServerScope(server, opts.org);
6850
+ try {
6851
+ const data = await api.get(PROMPT_PATH, {
6852
+ organizationId: scope.organizationId,
6853
+ projectId: scope.projectId,
6854
+ serverId: scope.serverId
6855
+ });
6856
+ if (isJsonMode()) {
6857
+ printJson(data);
6858
+ return;
6859
+ }
6860
+ if (data.prompts.length === 0) {
6861
+ printInfo(c.dim(" No prompts. Add one with `mcp servers prompts set`."));
6862
+ return;
6863
+ }
6864
+ printList(data.prompts.map((prompt2) => ({
6865
+ name: prompt2.name,
6866
+ args: countArguments(prompt2.argumentsJson),
6867
+ description: prompt2.description ?? "—"
6868
+ })), [
6869
+ { key: "name", label: "NAME", width: 28 },
6870
+ { key: "args", label: "ARGS", width: 6 },
6871
+ { key: "description", label: "DESCRIPTION", width: 48 }
6872
+ ]);
6873
+ } catch (err) {
6874
+ reportApiError2(err, "Listing prompts");
6875
+ }
6876
+ }));
6877
+ prompts.command("set <server> <name>").description("Create or replace a prompt by name. Re-running with the same name updates it.").option("--org <organizationId>", "Organization ID").option("--template <markdown>", "Prompt body, inline").option("--template-file <path>", "Prompt body, read from a file").option("--arguments <json>", "JSON array of {name, description, required}; defaults to []").option("--description <text>", "What the prompt is for").addHelpText("after", [
6878
+ "",
6879
+ "Examples:",
6880
+ " $ mcp servers prompts set my-api triage --template-file ./triage.md",
6881
+ ` $ mcp servers prompts set my-api triage --template 'Summarize {{issue}}.' \\`,
6882
+ ` --arguments '[{"name":"issue","required":true}]'`,
6883
+ "",
6884
+ "Notes:",
6885
+ " --arguments is validated strictly. A placeholder in the template that",
6886
+ " is not a declared argument is reported, not refused — clients cannot",
6887
+ " fill those in."
6888
+ ].join(`
6889
+ `)).action(runAction(async (server, name, opts) => {
6890
+ const scope = await resolveServerScope(server, opts.org);
6891
+ const templateMarkdown = readTemplate(opts);
6892
+ try {
6893
+ const data = await api.put(PROMPT_PATH, {
6894
+ argumentsJson: opts.arguments ?? "[]",
6895
+ description: opts.description ?? null,
6896
+ name,
6897
+ organizationId: scope.organizationId,
6898
+ projectId: scope.projectId,
6899
+ serverId: scope.serverId,
6900
+ templateMarkdown
6901
+ });
6902
+ if (isJsonMode()) {
6903
+ printJson(data);
6904
+ return;
6905
+ }
6906
+ printSuccess(`${data.prompt.replaced ? "Updated" : "Created"} prompt ${c.bold(name)} on ${scope.serverName}.`);
6907
+ for (const notice of data.notices ?? []) {
6908
+ printWarn(notice.message);
6909
+ }
6910
+ printInfo(c.dim(" Not live yet: run `mcp servers generate <server> --store`, then deploy."));
6911
+ } catch (err) {
6912
+ reportApiError2(err, "Saving the prompt");
6913
+ }
6914
+ }));
6915
+ prompts.command("rm <server> <name>").description("Remove a prompt by name.").option("--org <organizationId>", "Organization ID").action(runAction(async (server, name, opts) => {
6916
+ const scope = await resolveServerScope(server, opts.org);
6917
+ try {
6918
+ const data = await api.delete(`${PROMPT_PATH}?organizationId=${encodeURIComponent(scope.organizationId)}&projectId=${encodeURIComponent(scope.projectId)}&serverId=${encodeURIComponent(scope.serverId)}&name=${encodeURIComponent(name)}`);
6919
+ if (isJsonMode()) {
6920
+ printJson(data);
6921
+ return;
6922
+ }
6923
+ printSuccess(`Removed prompt ${c.bold(name)}.`);
6924
+ } catch (err) {
6925
+ reportApiError2(err, "Removing the prompt");
6926
+ }
6927
+ }));
6928
+ }
6929
+
6930
+ // src/commands/servers-resources.ts
6931
+ import { readFileSync as readFileSync4 } from "node:fs";
6932
+ var RESOURCE_PATH = "/api/v1/server/resource";
6933
+ function reportApiError3(err, action) {
6934
+ if (err instanceof McpCloudApiError) {
6935
+ printError(`${action} failed (HTTP ${err.status}): ${err.error.message}`);
6936
+ } else {
6937
+ printError(`${action} failed: ${err instanceof Error ? err.message : String(err)}`);
6938
+ }
6939
+ throw new CliExitError(1);
6940
+ }
6941
+ function registerServerResourceCommands(servers) {
6942
+ const resources = servers.command("resources").description("Author the resources this server exposes to clients (list / set / rm)");
6943
+ resources.command("list <server>").description("List the resources authored on a server.").option("--org <organizationId>", "Organization ID").action(runAction(async (server, opts) => {
6944
+ const scope = await resolveServerScope(server, opts.org);
6945
+ try {
6946
+ const data = await api.get(RESOURCE_PATH, {
6947
+ organizationId: scope.organizationId,
6948
+ projectId: scope.projectId,
6949
+ serverId: scope.serverId
6950
+ });
6951
+ if (isJsonMode()) {
6952
+ printJson(data);
6953
+ return;
6954
+ }
6955
+ if (data.resources.length === 0) {
6956
+ printInfo(c.dim(" No resources. Add one with `mcp servers resources set`."));
6957
+ return;
6958
+ }
6959
+ printList(data.resources.map((resource) => ({
6960
+ uri: resource.uri,
6961
+ name: resource.name,
6962
+ type: resource.resourceType,
6963
+ mime: resource.mimeType
6964
+ })), [
6965
+ { key: "uri", label: "URI", width: 40 },
6966
+ { key: "name", label: "NAME", width: 24 },
6967
+ { key: "type", label: "TYPE", width: 9 },
6968
+ { key: "mime", label: "MIME", width: 20 }
6969
+ ]);
6970
+ } catch (err) {
6971
+ reportApiError3(err, "Listing resources");
6972
+ }
6973
+ }));
6974
+ resources.command("set <server> <uri>").description("Create or replace a resource by URI. Re-running with the same URI updates it.").option("--org <organizationId>", "Organization ID").option("--name <name>", "Human-readable name (defaults to the URI)").option("--description <text>", "What the resource holds").option("--mime <type>", "MIME type", "text/markdown").option("--content <text>", "Body of a static resource, inline").option("--content-file <path>", "Body of a static resource, from a file").option("--upstream <template>", "Upstream path template — makes this a DYNAMIC resource fetched per read").addHelpText("after", [
6975
+ "",
6976
+ "Examples:",
6977
+ " $ mcp servers resources set my-api docs://api/limits --content-file ./limits.md",
6978
+ " $ mcp servers resources set my-api docs://api/status --upstream /status",
6979
+ "",
6980
+ "Notes:",
6981
+ " A resource is static (a body you supply) or dynamic (fetched from the",
6982
+ " upstream on each read). Passing --upstream makes it dynamic; otherwise",
6983
+ " content is required."
6984
+ ].join(`
6985
+ `)).action(runAction(async (server, uri, opts) => {
6986
+ const scope = await resolveServerScope(server, opts.org);
6987
+ const staticContent = opts.contentFile ? readFileSync4(opts.contentFile, "utf8") : opts.content ?? null;
6988
+ const resourceType = opts.upstream ? "dynamic" : "static";
6989
+ if (resourceType === "static" && !staticContent?.trim()) {
6990
+ printError("A static resource needs a body — pass --content or --content-file, or --upstream to make it dynamic.");
6991
+ throw new CliExitError(1);
6992
+ }
6993
+ try {
6994
+ const data = await api.put(RESOURCE_PATH, {
6995
+ description: opts.description ?? null,
6996
+ mimeType: opts.mime ?? "text/markdown",
6997
+ name: opts.name ?? uri,
6998
+ organizationId: scope.organizationId,
6999
+ projectId: scope.projectId,
7000
+ resourceType,
7001
+ serverId: scope.serverId,
7002
+ staticContent,
7003
+ upstreamPathTemplate: opts.upstream ?? null,
7004
+ uri
7005
+ });
7006
+ if (isJsonMode()) {
7007
+ printJson(data);
7008
+ return;
7009
+ }
7010
+ printSuccess(`${data.resource.replaced ? "Updated" : "Created"} ${resourceType} resource ${c.bold(uri)} on ${scope.serverName}.`);
7011
+ printInfo(c.dim(" Not live yet: run `mcp servers generate <server> --store`, then deploy."));
7012
+ } catch (err) {
7013
+ reportApiError3(err, "Saving the resource");
7014
+ }
7015
+ }));
7016
+ resources.command("rm <server> <uri>").description("Remove a resource by URI.").option("--org <organizationId>", "Organization ID").action(runAction(async (server, uri, opts) => {
7017
+ const scope = await resolveServerScope(server, opts.org);
7018
+ try {
7019
+ const data = await api.delete(`${RESOURCE_PATH}?organizationId=${encodeURIComponent(scope.organizationId)}&projectId=${encodeURIComponent(scope.projectId)}&serverId=${encodeURIComponent(scope.serverId)}&uri=${encodeURIComponent(uri)}`);
7020
+ if (isJsonMode()) {
7021
+ printJson(data);
7022
+ return;
7023
+ }
7024
+ printSuccess(`Removed resource ${c.bold(uri)}.`);
7025
+ } catch (err) {
7026
+ reportApiError3(err, "Removing the resource");
7027
+ }
7028
+ }));
7029
+ }
7030
+
7031
+ // src/commands/servers-shape.ts
7032
+ var SCORE_PATH = "/api/v1/server/usability-score";
7033
+ var SHAPE_PATH = "/api/v1/server/shape";
7034
+ function reportApiError4(err, action) {
7035
+ if (err instanceof McpCloudApiError) {
7036
+ printError(`${action} failed (HTTP ${err.status}): ${err.error.message}`);
7037
+ } else {
7038
+ printError(`${action} failed: ${err instanceof Error ? err.message : String(err)}`);
7039
+ }
7040
+ throw new CliExitError(1);
7041
+ }
7042
+ function formatPercent(value) {
7043
+ return typeof value === "number" ? `${Math.round(value * 100)}%` : "—";
7044
+ }
7045
+ function registerServerShapingCommands(servers) {
7046
+ servers.command("score <server>").description("Score whether an agent handed this catalog picks the right tool (starts a run, or reads the last one)").option("--org <organizationId>", "Organization ID").option("--start", "Start a new scoring run instead of reading the last").option("--runs <count>", "Runs to average, 2-5 (default 3)").addHelpText("after", [
7047
+ "",
7048
+ "Examples:",
7049
+ " $ mcp servers score my-api # read the last score",
7050
+ " $ mcp servers score my-api --start # start a new run",
7051
+ "",
7052
+ "Notes:",
7053
+ " A score is reported WITH its spread across runs. A move smaller than",
7054
+ " the spread is noise, not an improvement.",
7055
+ " Starting a run makes one model call per scenario per run and returns",
7056
+ " immediately; read the result with the same command."
7057
+ ].join(`
7058
+ `)).action(runAction(async (server, opts) => {
7059
+ const scope = await resolveServerScope(server, opts.org);
7060
+ const query = {
7061
+ organizationId: scope.organizationId,
7062
+ projectId: scope.projectId,
7063
+ serverId: scope.serverId
7064
+ };
7065
+ if (opts.start) {
7066
+ try {
7067
+ const data = await api.post(SCORE_PATH, {
7068
+ ...query,
7069
+ ...opts.runs ? { runCount: Number(opts.runs) } : {}
7070
+ });
7071
+ if (isJsonMode()) {
7072
+ printJson(data);
7073
+ return;
7074
+ }
7075
+ printSuccess(`Scoring started for ${scope.serverName}.`);
7076
+ printInfo(c.dim(` ${data.message}`));
7077
+ } catch (err) {
7078
+ reportApiError4(err, "Starting the scoring run");
7079
+ }
7080
+ return;
7081
+ }
7082
+ try {
7083
+ const data = await api.get(SCORE_PATH, query);
7084
+ if (isJsonMode()) {
7085
+ printJson(data);
7086
+ return;
7087
+ }
7088
+ if (data.batch.length === 0) {
7089
+ printInfo(c.dim(" Not measured yet. Run `mcp servers score <server> --start`."));
7090
+ return;
7091
+ }
7092
+ const accuracies = data.batch.map((run) => run.accuracy).filter((value) => value !== null);
7093
+ const min = Math.min(...accuracies);
7094
+ const max = Math.max(...accuracies);
7095
+ const mean = accuracies.reduce((sum, value) => sum + value, 0) / accuracies.length;
7096
+ printSuccess(`${formatPercent(mean)} ±${formatPercent(max - min)} across ${data.batch.length} runs`);
7097
+ printInfo(c.dim(` ${data.batch[0]?.scored ?? 0} scenarios · ${data.catalogSize ?? "—"} tools · judged by ${data.modelKey ?? "—"}`));
7098
+ } catch (err) {
7099
+ reportApiError4(err, "Reading the score");
7100
+ }
7101
+ }));
7102
+ servers.command("shape <server>").description("Propose task-shaped tools over this server’s endpoints (starts a run, or reads the last one)").option("--org <organizationId>", "Organization ID").option("--start", "Start a new shaping run instead of reading the last").addHelpText("after", [
7103
+ "",
7104
+ "Examples:",
7105
+ " $ mcp servers shape my-api --start # propose task tools",
7106
+ " $ mcp servers shape my-api # read the proposals",
7107
+ "",
7108
+ "Notes:",
7109
+ " Proposals are inspectable artifacts. Nothing is created until a",
7110
+ " proposal is accepted in the dashboard."
7111
+ ].join(`
7112
+ `)).action(runAction(async (server, opts) => {
7113
+ const scope = await resolveServerScope(server, opts.org);
7114
+ const query = {
7115
+ organizationId: scope.organizationId,
7116
+ projectId: scope.projectId,
7117
+ serverId: scope.serverId
7118
+ };
7119
+ if (opts.start) {
7120
+ try {
7121
+ const data = await api.post(SHAPE_PATH, query);
7122
+ if (isJsonMode()) {
7123
+ printJson(data);
7124
+ return;
7125
+ }
7126
+ printSuccess(`Shaping started for ${scope.serverName}.`);
7127
+ printInfo(c.dim(` ${data.message}`));
7128
+ } catch (err) {
7129
+ reportApiError4(err, "Starting the shaping run");
7130
+ }
7131
+ return;
7132
+ }
7133
+ try {
7134
+ const data = await api.get(SHAPE_PATH, query);
7135
+ if (isJsonMode()) {
7136
+ printJson(data);
7137
+ return;
7138
+ }
7139
+ if (!data.run) {
7140
+ printInfo(c.dim(" No shaping run yet. Run `mcp servers shape <server> --start`."));
7141
+ return;
7142
+ }
7143
+ const reviewable = data.proposals.filter((p2) => !p2.rejectionReason);
7144
+ const refused = data.proposals.filter((p2) => p2.rejectionReason);
7145
+ printList(reviewable.map((proposal) => ({
7146
+ name: proposal.name,
7147
+ effect: proposal.effectClass ?? "—",
7148
+ plan: JSON.parse(proposal.planJson).map((step) => step.operationName).join(" → ")
7149
+ })), [
7150
+ { key: "name", label: "PROPOSAL", width: 30 },
7151
+ { key: "effect", label: "EFFECT", width: 16 },
7152
+ { key: "plan", label: "PLAN", width: 46 }
7153
+ ]);
7154
+ if (refused.length > 0) {
7155
+ printWarn(`${refused.length} proposal${refused.length === 1 ? "" : "s"} refused by validation: ${refused.map((p2) => p2.name).join(", ")}`);
7156
+ }
7157
+ if (data.run.failedClusterKeys.length > 0) {
7158
+ printWarn(`${data.run.failedClusterKeys.length} endpoint group(s) produced nothing: ${data.run.failedClusterKeys.join(", ")}`);
7159
+ }
7160
+ printInfo(c.dim(" Accept a proposal in the dashboard; nothing is created here."));
7161
+ } catch (err) {
7162
+ reportApiError4(err, "Reading shaping proposals");
7163
+ }
7164
+ }));
7165
+ }
7166
+
6637
7167
  // src/commands/servers-env.ts
6638
- import { existsSync as existsSync3, readFileSync as readFileSync3 } from "node:fs";
7168
+ import { existsSync as existsSync3, readFileSync as readFileSync5 } from "node:fs";
6639
7169
  import { resolve } from "node:path";
6640
7170
  function registerServerEnvCommands(servers) {
6641
7171
  const env = servers.command("env").description("Manage server runtime environment bindings (encrypted secrets injected by the proxy).");
@@ -6784,7 +7314,7 @@ async function resolveSetValue(args) {
6784
7314
  printError(`--from-file path not found: ${path}`);
6785
7315
  throw new CliExitError(1);
6786
7316
  }
6787
- return readFileSync3(path, "utf-8");
7317
+ return readFileSync5(path, "utf-8");
6788
7318
  }
6789
7319
  return await readStdin();
6790
7320
  }
@@ -6940,7 +7470,7 @@ function registerServerSandboxVariableCommands(servers) {
6940
7470
  }
6941
7471
 
6942
7472
  // src/lib/mcp-invoke.ts
6943
- import { existsSync as existsSync4, readFileSync as readFileSync4 } from "node:fs";
7473
+ import { existsSync as existsSync4, readFileSync as readFileSync6 } from "node:fs";
6944
7474
  import { resolve as resolve2 } from "node:path";
6945
7475
  var DEFAULT_TIMEOUT_MS3 = 60000;
6946
7476
  var invokeRequestId = 1;
@@ -7160,7 +7690,7 @@ async function parseToolArguments(opts) {
7160
7690
  if (!existsSync4(filePath)) {
7161
7691
  return { ok: false, reason: "file-not-found", path: filePath };
7162
7692
  }
7163
- source = readFileSync4(filePath, "utf-8");
7693
+ source = readFileSync6(filePath, "utf-8");
7164
7694
  } else {
7165
7695
  source = raw;
7166
7696
  }
@@ -7709,7 +8239,7 @@ function formatDeploymentExposure(deployment) {
7709
8239
  import { createHash as createHash2 } from "node:crypto";
7710
8240
  import {
7711
8241
  existsSync as existsSync5,
7712
- readFileSync as readFileSync5,
8242
+ readFileSync as readFileSync7,
7713
8243
  watch as fsWatch
7714
8244
  } from "node:fs";
7715
8245
  import { dirname as dirname3 } from "node:path";
@@ -7763,7 +8293,7 @@ function summarizeDiff(diff) {
7763
8293
  `) };
7764
8294
  }
7765
8295
  function readSpecFile(specPath) {
7766
- const content = readFileSync5(specPath, "utf-8");
8296
+ const content = readFileSync7(specPath, "utf-8");
7767
8297
  return { content, hash: hashSpecContent(content) };
7768
8298
  }
7769
8299
  function watchSpecFile(options) {
@@ -7783,7 +8313,7 @@ function watchSpecFile(options) {
7783
8313
  return;
7784
8314
  let content;
7785
8315
  try {
7786
- content = readFileSync5(options.specPath, "utf-8");
8316
+ content = readFileSync7(options.specPath, "utf-8");
7787
8317
  } catch {
7788
8318
  return;
7789
8319
  }
@@ -8418,7 +8948,7 @@ function registerServerMutationCommands(servers) {
8418
8948
  }
8419
8949
 
8420
8950
  // src/lib/spec-pipeline.ts
8421
- import { existsSync as existsSync7, mkdirSync as mkdirSync4, readFileSync as readFileSync6, writeFileSync as writeFileSync3 } from "node:fs";
8951
+ import { existsSync as existsSync7, mkdirSync as mkdirSync4, readFileSync as readFileSync8, writeFileSync as writeFileSync3 } from "node:fs";
8422
8952
  import { dirname as dirname4, join as join5, resolve as resolve5 } from "node:path";
8423
8953
  var SOURCE_TYPES = ["openapi", "graphql", "url"];
8424
8954
  function isHttpUrl(value) {
@@ -8451,7 +8981,7 @@ async function readSpecSource(spec, override, options = {}) {
8451
8981
  if (!existsSync7(filePath)) {
8452
8982
  throw new Error(`Spec file not found: ${filePath}`);
8453
8983
  }
8454
- content = readFileSync6(filePath, "utf-8");
8984
+ content = readFileSync8(filePath, "utf-8");
8455
8985
  pathHint = filePath;
8456
8986
  }
8457
8987
  if (!content.trim()) {
@@ -8542,7 +9072,7 @@ function registerServerSpecCommands(servers) {
8542
9072
  });
8543
9073
  printStep(`Next: \`mcp servers generate ${data.server.id} --out ./out\` or \`mcp servers deploy ${data.server.id} --wait\`.`);
8544
9074
  }));
8545
- servers.command("generate <server>").description("Generate the server's TypeScript bundle (the exact code `deploy` ships) and optionally write it to disk — a dry-run for the codegen path. Wraps POST /api/v1/server/generate.").option("--org <organizationId>", "Organization ID").option("--project <project>", "Project (id or name; looked up from the server when omitted)").option("--out <dir>", "Write the generated files to this directory instead of just summarizing").addHelpText("after", [
9075
+ servers.command("generate <server>").description("Generate the server's TypeScript bundle (the exact code `deploy` ships) and optionally write it to disk — a dry-run for the codegen path. Wraps POST /api/v1/server/generate.").option("--org <organizationId>", "Organization ID").option("--project <project>", "Project (id or name; looked up from the server when omitted)").option("--out <dir>", "Write the generated files to this directory instead of just summarizing").option("--store", "Persist the bundle as the one `deploy` will ship. Required after editing prompts, resources or tool metadata: deploy reuses a server's existing bundle unchanged, so without this the change never reaches the deployed worker.").addHelpText("after", [
8546
9076
  "",
8547
9077
  "Notes:",
8548
9078
  " Codegen runs on the builder Worker (arch-evolution P7f). If generate",
@@ -8551,6 +9081,7 @@ function registerServerSpecCommands(servers) {
8551
9081
  "Examples:",
8552
9082
  " $ mcp servers generate srv_123 # summarize the bundle",
8553
9083
  " $ mcp servers generate srv_123 --out ./build # write files to disk",
9084
+ " $ mcp servers generate srv_123 --store # make it the bundle deploy ships",
8554
9085
  " $ mcp --json servers generate srv_123 | jq '.bundle.files[].path'"
8555
9086
  ].join(`
8556
9087
  `)).action(runAction(async (serverRef, opts) => {
@@ -8564,7 +9095,23 @@ function registerServerSpecCommands(servers) {
8564
9095
  if (!isJsonMode()) {
8565
9096
  printStep(`Generating bundle for ${c.bold(serverId)}…`);
8566
9097
  }
8567
- const data = await api.post("/api/v1/server/generate", { organizationId: orgId, projectId, serverId });
9098
+ const data = await api.post("/api/v1/server/generate", {
9099
+ organizationId: orgId,
9100
+ projectId,
9101
+ serverId,
9102
+ ...opts.store ? { store: true } : {}
9103
+ });
9104
+ if (!isJsonMode() && data.storeHint) {
9105
+ printWarn(data.storeHint);
9106
+ }
9107
+ if (!data.bundle) {
9108
+ if (isJsonMode()) {
9109
+ printJson(data);
9110
+ return;
9111
+ }
9112
+ printSuccess(data.stored ? `Stored the bundle for ${c.bold(data.server.name)} — deploy now ships it.` : `Generated for ${c.bold(data.server.name)} (${data.generationStatus ?? "no files returned"}).`);
9113
+ return;
9114
+ }
8568
9115
  if (opts.out) {
8569
9116
  const written = writeBundleToDisk(data.bundle, opts.out);
8570
9117
  if (isJsonMode()) {
@@ -8599,7 +9146,7 @@ function registerServerSpecCommands(servers) {
8599
9146
  }
8600
9147
 
8601
9148
  // src/commands/servers-test-authoring.ts
8602
- import { readFileSync as readFileSync7 } from "node:fs";
9149
+ import { readFileSync as readFileSync9 } from "node:fs";
8603
9150
  var EXECUTION_PROFILES = [
8604
9151
  "mockBindings",
8605
9152
  "previewBindings",
@@ -8617,9 +9164,9 @@ function parseTimeoutMs(value, fallbackMs) {
8617
9164
  }
8618
9165
  function readValueOption(raw) {
8619
9166
  if (raw === "@-")
8620
- return readFileSync7(0, "utf8");
9167
+ return readFileSync9(0, "utf8");
8621
9168
  if (raw.startsWith("@"))
8622
- return readFileSync7(raw.slice(1), "utf8");
9169
+ return readFileSync9(raw.slice(1), "utf8");
8623
9170
  return raw;
8624
9171
  }
8625
9172
  async function resolveServerAndProject(serverRef, org) {
@@ -8979,6 +9526,10 @@ function registerServerTestCommands(servers) {
8979
9526
  // src/commands/servers.ts
8980
9527
  function registerServerCommands(program2) {
8981
9528
  const servers = program2.command("servers").description("Manage MCP servers");
9529
+ registerServerDepsCommands(servers);
9530
+ registerServerPromptCommands(servers);
9531
+ registerServerResourceCommands(servers);
9532
+ registerServerShapingCommands(servers);
8982
9533
  registerServerEnvCommands(servers);
8983
9534
  registerServerSandboxVariableCommands(servers);
8984
9535
  registerServerGetCommand(servers);
@@ -8998,14 +9549,11 @@ function registerServerCommands(program2) {
8998
9549
  `)).action(runAction(async (opts) => {
8999
9550
  const orgId = await resolveOrgId(opts.org);
9000
9551
  const projectId = await resolveOptionalProjectId(opts.project, orgId);
9001
- const params = {
9002
- organizationId: orgId,
9003
- limit: opts.limit
9004
- };
9552
+ const params = { organizationId: orgId };
9005
9553
  if (projectId)
9006
9554
  params["projectId"] = projectId;
9007
- const data = await api.get("/api/v1/servers", params);
9008
- printList(data.servers.map((s) => ({
9555
+ const { rows: serverRows, payload } = await fetchAllPagesWithEnvelope("/api/v1/servers", params, "servers", { max: parseRowCap(opts.limit) });
9556
+ printList(serverRows.map((s) => ({
9009
9557
  id: s.id,
9010
9558
  name: s.name,
9011
9559
  slug: deriveServerSlug(s.deploymentUrl) ?? "—",
@@ -9021,7 +9569,7 @@ function registerServerCommands(program2) {
9021
9569
  { key: "status", label: "Status", width: 10 },
9022
9570
  { key: "version", label: "Version", width: 8 },
9023
9571
  { key: "deployed", label: "Last Deployed", width: 22 }
9024
- ], data);
9572
+ ], payload);
9025
9573
  }));
9026
9574
  servers.command("logs <server>").description("Show recent deployment events for a server's latest deployment").option("--org <organizationId>", "Organization ID").option("--limit <n>", "Number of recent events (default 50)", parsePositiveIntOption("limit"), "50").option("--follow", "Tail new events as they arrive (long-poll). Ctrl-C to stop.").option("--since <when>", "Only show events after this point. Accepts relative (5m, 1h, 30s), Unix-ms, or ISO-8601.").option("--follow-timeout <seconds>", "Maximum seconds to keep --follow open before exiting (default: 1 hour).", "3600").action(runAction(async (serverRef, opts) => {
9027
9575
  const orgId = await resolveOrgId(opts.org);
@@ -9150,14 +9698,14 @@ function registerServerCommands(program2) {
9150
9698
  }
9151
9699
 
9152
9700
  // src/commands/tools-diff.ts
9153
- import { existsSync as existsSync11, readFileSync as readFileSync11 } from "node:fs";
9701
+ import { existsSync as existsSync11, readFileSync as readFileSync13 } from "node:fs";
9154
9702
  import { relative } from "node:path";
9155
9703
 
9156
9704
  // src/lib/dev/handlers-sync.ts
9157
9705
  import {
9158
9706
  existsSync as existsSync10,
9159
9707
  mkdirSync as mkdirSync7,
9160
- readFileSync as readFileSync10,
9708
+ readFileSync as readFileSync12,
9161
9709
  statSync,
9162
9710
  writeFileSync as writeFileSync6
9163
9711
  } from "node:fs";
@@ -9165,7 +9713,7 @@ import { createHash as createHash3 } from "node:crypto";
9165
9713
  import { dirname as dirname5, join as join8 } from "node:path";
9166
9714
 
9167
9715
  // src/lib/dev/state.ts
9168
- import { existsSync as existsSync8, mkdirSync as mkdirSync5, readFileSync as readFileSync8, writeFileSync as writeFileSync4 } from "node:fs";
9716
+ import { existsSync as existsSync8, mkdirSync as mkdirSync5, readFileSync as readFileSync10, writeFileSync as writeFileSync4 } from "node:fs";
9169
9717
  import { join as join6, resolve as resolve6 } from "node:path";
9170
9718
  function cachedStateMatchesTarget(cached2, target) {
9171
9719
  return cached2 !== null && cached2.serverId === target.serverId && cached2.organizationId === target.organizationId;
@@ -9194,7 +9742,7 @@ function readState(cwd) {
9194
9742
  if (!existsSync8(path))
9195
9743
  return null;
9196
9744
  try {
9197
- const parsed = JSON.parse(readFileSync8(path, "utf-8"));
9745
+ const parsed = JSON.parse(readFileSync10(path, "utf-8"));
9198
9746
  if (!parsed || typeof parsed !== "object")
9199
9747
  return null;
9200
9748
  const s = parsed;
@@ -9235,7 +9783,7 @@ function ensureGitignore(cwd) {
9235
9783
  import {
9236
9784
  existsSync as existsSync9,
9237
9785
  mkdirSync as mkdirSync6,
9238
- readFileSync as readFileSync9,
9786
+ readFileSync as readFileSync11,
9239
9787
  readdirSync,
9240
9788
  rmSync,
9241
9789
  writeFileSync as writeFileSync5
@@ -9449,7 +9997,7 @@ function readToolsState(devRootDir, serverId) {
9449
9997
  if (!existsSync9(file))
9450
9998
  return null;
9451
9999
  try {
9452
- const parsed = JSON.parse(readFileSync9(file, "utf-8"));
10000
+ const parsed = JSON.parse(readFileSync11(file, "utf-8"));
9453
10001
  if (!parsed || typeof parsed !== "object")
9454
10002
  return null;
9455
10003
  const s = parsed;
@@ -9529,7 +10077,7 @@ function readLocalTool(devRootDir, serverId, toolName) {
9529
10077
  const stateEntry = state?.tools[toolName];
9530
10078
  if (!stateEntry)
9531
10079
  return null;
9532
- const view = parseToolMarkdown(readFileSync9(filePath, "utf-8"));
10080
+ const view = parseToolMarkdown(readFileSync11(filePath, "utf-8"));
9533
10081
  return {
9534
10082
  view,
9535
10083
  cloudId: stateEntry.id,
@@ -9592,6 +10140,7 @@ async function pushLocalToolEdit(args) {
9592
10140
  kind: "patched",
9593
10141
  updatedAt: result.tool.updatedAt,
9594
10142
  changedFields: result.patchedFields,
10143
+ notices: result.notices ?? [],
9595
10144
  view: local.view
9596
10145
  };
9597
10146
  } catch (err) {
@@ -9622,11 +10171,8 @@ function toolNameFromWatcherPath(rel) {
9622
10171
  return rel.slice(0, -3);
9623
10172
  }
9624
10173
  async function fetchToolsForServer(args) {
9625
- const data = await api.get("/api/v1/project/tools", {
9626
- organizationId: args.organizationId,
9627
- projectId: args.projectId
9628
- });
9629
- return data.tools.filter((t) => t.serverId === args.serverId).map((t) => ({
10174
+ const tools = await fetchAllPages("/api/v1/project/tools", { organizationId: args.organizationId, projectId: args.projectId }, "tools");
10175
+ return tools.filter((t) => t.serverId === args.serverId).map((t) => ({
9630
10176
  id: t.id,
9631
10177
  serverId: t.serverId,
9632
10178
  name: t.name,
@@ -9680,7 +10226,7 @@ async function pushLocalHandlerEdit(args) {
9680
10226
  if (!resolved) {
9681
10227
  return { kind: "unknown-tool", slug: args.slug };
9682
10228
  }
9683
- const source = readFileSync10(filePath, "utf-8");
10229
+ const source = readFileSync12(filePath, "utf-8");
9684
10230
  const hash = hashSource(source);
9685
10231
  if (lastPushedHash.get(filePath) === hash) {
9686
10232
  return { kind: "noop" };
@@ -9839,7 +10385,7 @@ function inspectLocalHandler(args) {
9839
10385
  if (!existsSync10(filePath))
9840
10386
  return { kind: "no-local-file" };
9841
10387
  const cached2 = lastPushedHash.get(filePath);
9842
- const onDisk = hashSource(readFileSync10(filePath, "utf-8"));
10388
+ const onDisk = hashSource(readFileSync12(filePath, "utf-8"));
9843
10389
  if (cached2 !== undefined) {
9844
10390
  return cached2 === onDisk ? { kind: "matches-cache" } : { kind: "differs-from-cache" };
9845
10391
  }
@@ -9984,7 +10530,7 @@ function buildMetadataDiff(args) {
9984
10530
  let local = null;
9985
10531
  let parseError = null;
9986
10532
  try {
9987
- local = parseToolMarkdown(readFileSync11(filePath, "utf-8"));
10533
+ local = parseToolMarkdown(readFileSync13(filePath, "utf-8"));
9988
10534
  } catch (err) {
9989
10535
  parseError = err instanceof Error ? err.message : String(err);
9990
10536
  }
@@ -10027,7 +10573,7 @@ async function buildHandlerDiff(args) {
10027
10573
  const slug = handlerSlugFromToolName(args.toolName);
10028
10574
  const filePath = `${serverBundleHandlersDir(args.devRootDir)}/${slug}.ts`;
10029
10575
  const hasLocal = existsSync11(filePath);
10030
- const localContent = hasLocal ? readFileSync11(filePath, "utf-8") : null;
10576
+ const localContent = hasLocal ? readFileSync13(filePath, "utf-8") : null;
10031
10577
  const localPath = hasLocal ? relative(args.cwd, filePath) || filePath : null;
10032
10578
  const changed = hasLocal ? localContent !== cloudResult.snapshot.content : true;
10033
10579
  return {
@@ -10142,7 +10688,7 @@ import { join as join10, relative as relative2 } from "node:path";
10142
10688
 
10143
10689
  // src/lib/editor-shell.ts
10144
10690
  import { spawn as spawn2 } from "node:child_process";
10145
- import { existsSync as existsSync12, readFileSync as readFileSync12 } from "node:fs";
10691
+ import { existsSync as existsSync12, readFileSync as readFileSync14 } from "node:fs";
10146
10692
  import { platform as platform2 } from "node:os";
10147
10693
  import { delimiter, join as join9 } from "node:path";
10148
10694
  var DEFAULT_FALLBACKS = ["vi"];
@@ -10228,7 +10774,7 @@ async function runEditor(args) {
10228
10774
  message: `${command} exited with code ${exitCode}. The file may be unsaved; re-run after fixing.`
10229
10775
  };
10230
10776
  }
10231
- const contents = readFileSync12(args.filePath, "utf-8");
10777
+ const contents = readFileSync14(args.filePath, "utf-8");
10232
10778
  return { ok: true, contents, command };
10233
10779
  }
10234
10780
 
@@ -10368,32 +10914,271 @@ function normalizeTool(raw) {
10368
10914
  };
10369
10915
  }
10370
10916
  async function fetchEnrichedToolDetail(args) {
10371
- const data = await api.get("/api/v1/project/tools", {
10372
- organizationId: args.organizationId,
10373
- projectId: args.projectId
10374
- });
10375
- const match = data.tools.find((t) => t.id === args.toolId);
10917
+ const tools = await fetchAllPages("/api/v1/project/tools", { organizationId: args.organizationId, projectId: args.projectId }, "tools");
10918
+ const match = tools.find((t) => t.id === args.toolId);
10376
10919
  return match ? normalizeTool(match) : null;
10377
10920
  }
10378
10921
  async function fetchEnrichedToolByName(args) {
10379
- const data = await api.get("/api/v1/project/tools", {
10380
- organizationId: args.organizationId,
10381
- projectId: args.projectId
10382
- });
10383
- const match = data.tools.find((t) => t.serverId === args.serverId && t.name === args.toolName);
10922
+ const tools = await fetchAllPages("/api/v1/project/tools", { organizationId: args.organizationId, projectId: args.projectId }, "tools");
10923
+ const match = tools.find((t) => t.serverId === args.serverId && t.name === args.toolName);
10384
10924
  return match ? normalizeTool(match) : null;
10385
10925
  }
10386
10926
 
10927
+ // src/commands/tools-enrich-batch.ts
10928
+ var POLL_INTERVAL_MS = 2000;
10929
+ var MS_PER_TOOL = 3 * 60 * 1000;
10930
+ var MIN_POLL_TIMEOUT_MS = 10 * 60 * 1000;
10931
+ var MAX_POLL_TIMEOUT_MS = 90 * 60 * 1000;
10932
+ function pollTimeoutMsForJob(total) {
10933
+ const scaled = Math.max(0, total) * MS_PER_TOOL;
10934
+ return Math.min(MAX_POLL_TIMEOUT_MS, Math.max(MIN_POLL_TIMEOUT_MS, scaled));
10935
+ }
10936
+ function sleep(ms) {
10937
+ return new Promise((resolve7) => setTimeout(resolve7, ms));
10938
+ }
10939
+ async function runToolsEnrichAll(args) {
10940
+ const toolIds = await resolveOnlyToolIds(args);
10941
+ let job;
10942
+ try {
10943
+ const started = await api.post("/api/v1/server/enrich", {
10944
+ organizationId: args.ctx.organizationId,
10945
+ projectId: args.ctx.projectId,
10946
+ serverId: args.ctx.serverId,
10947
+ apply: args.apply,
10948
+ ...toolIds ? { toolIds } : {},
10949
+ ...args.modelId ? { modelId: args.modelId } : {}
10950
+ });
10951
+ job = started.job;
10952
+ } catch (err) {
10953
+ if (err instanceof McpCloudApiError) {
10954
+ printError(`Enrichment job failed to start (HTTP ${err.status}): ${err.error.message}`);
10955
+ } else {
10956
+ printError(`Enrichment job failed to start: ${err instanceof Error ? err.message : String(err)}`);
10957
+ }
10958
+ throw new CliExitError(1);
10959
+ }
10960
+ if (!args.wait) {
10961
+ if (isJsonMode()) {
10962
+ printJson({ ok: true, job, waited: false });
10963
+ return;
10964
+ }
10965
+ printSuccess(`Queued ${job.total} tool${job.total === 1 ? "" : "s"} ${c.dim(`(job ${job.id})`)}`);
10966
+ printInfo(` ${c.dim("Poll with:")} ${c.bold(`mcp tools enrich --all --job ${job.id}`)}`);
10967
+ return;
10968
+ }
10969
+ if (!isJsonMode()) {
10970
+ printStep(`Enriching ${job.total} tool${job.total === 1 ? "" : "s"}${args.modelId ? c.dim(` (model ${args.modelId})`) : ""}…`);
10971
+ }
10972
+ const finalJob = await pollUntilTerminal(args.ctx, job);
10973
+ reportJob(finalJob, args.apply);
10974
+ }
10975
+ async function pollEnrichmentJob(ctx, jobId) {
10976
+ const job = await fetchJob(ctx, jobId);
10977
+ if (job.status === "queued" || job.status === "running") {
10978
+ reportJob(await pollUntilTerminal(ctx, job), job.total > 0);
10979
+ return;
10980
+ }
10981
+ reportJob(job, true);
10982
+ }
10983
+ async function fetchJob(ctx, jobId) {
10984
+ try {
10985
+ const data = await api.get("/api/v1/server/enrich", {
10986
+ organizationId: ctx.organizationId,
10987
+ jobId
10988
+ });
10989
+ return data.job;
10990
+ } catch (err) {
10991
+ if (err instanceof McpCloudApiError) {
10992
+ printError(`Could not read job ${jobId} (HTTP ${err.status}): ${err.error.message}`);
10993
+ } else {
10994
+ printError(`Could not read job ${jobId}: ${err instanceof Error ? err.message : String(err)}`);
10995
+ }
10996
+ throw new CliExitError(1);
10997
+ }
10998
+ }
10999
+ async function pollUntilTerminal(ctx, initial) {
11000
+ const timeoutMs = pollTimeoutMsForJob(initial.total);
11001
+ const deadline = Date.now() + timeoutMs;
11002
+ let job = initial;
11003
+ let lastCompleted = -1;
11004
+ while (job.status === "queued" || job.status === "running") {
11005
+ if (Date.now() > deadline) {
11006
+ printWarn(`Still running after ${Math.round(timeoutMs / 60000)} minutes — the job continues server-side.`);
11007
+ printInfo(` ${c.dim("Poll with:")} ${c.bold(`mcp tools enrich --all --job ${job.id}`)}`);
11008
+ throw new CliExitError(0);
11009
+ }
11010
+ await sleep(POLL_INTERVAL_MS);
11011
+ job = await fetchJob(ctx, job.id);
11012
+ if (!isJsonMode() && job.completed !== lastCompleted) {
11013
+ lastCompleted = job.completed;
11014
+ printInfo(c.dim(` ${job.completed}/${job.total} done · ${job.failed} failed`));
11015
+ }
11016
+ }
11017
+ return job;
11018
+ }
11019
+ function reportJob(job, applied) {
11020
+ const results = job.results ?? [];
11021
+ if (isJsonMode()) {
11022
+ printJson({ ok: job.failed === 0 && job.status === "completed", job });
11023
+ if (job.failed > 0 || job.status === "failed")
11024
+ throw new CliExitError(1);
11025
+ return;
11026
+ }
11027
+ if (job.status === "failed") {
11028
+ printError(`Enrichment job failed: ${job.error ?? "unknown error"}`);
11029
+ printInfo(c.dim(` ${job.succeeded} of ${job.total} tools completed before it stopped.`));
11030
+ throw new CliExitError(1);
11031
+ }
11032
+ const cachedCount = results.filter((entry) => entry.cached).length;
11033
+ if (job.failed === 0) {
11034
+ printSuccess(`Enriched ${job.succeeded} tool${job.succeeded === 1 ? "" : "s"} ${c.dim(`(${cachedCount} cached · ${applied ? "applied" : "proposed only"})`)}`);
11035
+ } else {
11036
+ printWarn(`Enriched ${job.succeeded} of ${job.total}; ${job.failed} failed ${c.dim(`(${cachedCount} cached)`)}`);
11037
+ for (const entry of results.filter((r) => r.status === "failed")) {
11038
+ printInfo(` ${c.dim("✗")} ${entry.toolName}: ${entry.error ?? "unknown error"}`);
11039
+ }
11040
+ }
11041
+ const writeFailures = results.filter((r) => r.status === "succeeded" && r.error);
11042
+ if (writeFailures.length > 0) {
11043
+ printWarn(`${writeFailures.length} enrichment${writeFailures.length === 1 ? "" : "s"} ran but could not be applied:`);
11044
+ for (const entry of writeFailures) {
11045
+ printInfo(` ${c.dim("!")} ${entry.toolName}: ${entry.error}`);
11046
+ }
11047
+ }
11048
+ if (job.failed > 0)
11049
+ throw new CliExitError(1);
11050
+ }
11051
+ async function resolveOnlyToolIds(args) {
11052
+ if (args.only.length === 0)
11053
+ return null;
11054
+ const list = await fetchToolsForServer(args.ctx);
11055
+ const byName = new Map(list.map((tool) => [tool.name, tool.id]));
11056
+ const ids = [];
11057
+ const missing = [];
11058
+ for (const name of args.only) {
11059
+ const id = byName.get(name);
11060
+ if (id)
11061
+ ids.push(id);
11062
+ else
11063
+ missing.push(name);
11064
+ }
11065
+ if (missing.length > 0) {
11066
+ printError(`Not found on this server: ${missing.join(", ")}`);
11067
+ if (list.length > 0) {
11068
+ const sample = list.slice(0, 5).map((tool) => tool.name).join(", ");
11069
+ printInfo(` ${c.dim("Available:")} ${sample}${list.length > 5 ? c.dim(`, +${list.length - 5} more`) : ""}`);
11070
+ }
11071
+ throw new CliExitError(1);
11072
+ }
11073
+ return ids;
11074
+ }
11075
+
11076
+ // src/commands/tools-enrich-apply.ts
11077
+ function printSuggestion(tool, suggestion) {
11078
+ const sDesc = suggestion.enrichedDescription?.trim() || null;
11079
+ const sTags = suggestion.suggestedTags ?? [];
11080
+ const sRisk = suggestion.riskClassification?.riskClass ?? null;
11081
+ const sIdem = suggestion.riskClassification?.idempotent ?? null;
11082
+ printInfo(c.bold("Suggested vs applied:"));
11083
+ printInfo(diffRow("description", tool.description, sDesc));
11084
+ printInfo(diffRow("tags", tool.semanticTags.join(", ") || null, sTags.join(", ") || null));
11085
+ printInfo(diffRow("riskClass", tool.riskClass, sRisk));
11086
+ printInfo(diffRow("idempotent", tool.idempotent === null ? null : String(tool.idempotent), sIdem === null ? null : String(sIdem)));
11087
+ }
11088
+ function diffRow(label, applied, suggested) {
11089
+ const left = c.dim(` ${label.padEnd(14)}`);
11090
+ if (applied === suggested) {
11091
+ return `${left}${c.dim(applied ?? "(none)")} ${c.dim("(unchanged)")}`;
11092
+ }
11093
+ return `${left}${applied ?? c.dim("(none)")} ${c.dim("→")} ${c.bold(suggested ?? c.dim("(clear)"))}`;
11094
+ }
11095
+ async function applySuggestion(tool, ctx) {
11096
+ if (!tool.enrichment) {
11097
+ return { ok: false, message: "No suggestion to apply." };
11098
+ }
11099
+ const desc = tool.enrichment.enrichedDescription?.trim() ?? null;
11100
+ const tags = tool.enrichment.suggestedTags;
11101
+ const risk = tool.enrichment.riskClassification?.riskClass ?? null;
11102
+ const idem = tool.enrichment.riskClassification?.idempotent ?? null;
11103
+ try {
11104
+ const result = await api.patch("/api/v1/server/tool", {
11105
+ organizationId: ctx.organizationId,
11106
+ projectId: ctx.projectId,
11107
+ serverId: ctx.serverId,
11108
+ toolId: tool.id,
11109
+ expectedUpdatedAt: tool.updatedAt,
11110
+ description: desc,
11111
+ semanticTags: tags,
11112
+ riskClass: risk,
11113
+ idempotent: idem
11114
+ });
11115
+ return {
11116
+ ok: true,
11117
+ updatedAt: result.tool.updatedAt,
11118
+ changedFields: result.patchedFields
11119
+ };
11120
+ } catch (err) {
11121
+ if (err instanceof McpCloudApiError) {
11122
+ if (err.error.code === "tool_metadata_conflict") {
11123
+ return {
11124
+ ok: false,
11125
+ message: `Conflict — the tool was modified by someone else after enrichment. Run \`mcp tools pull ${tool.name}\` and rerun \`mcp tools enrich ${tool.name} --apply\`.`
11126
+ };
11127
+ }
11128
+ return {
11129
+ ok: false,
11130
+ message: `Apply failed (HTTP ${err.status}): ${err.error.message}`
11131
+ };
11132
+ }
11133
+ return {
11134
+ ok: false,
11135
+ message: `Apply failed: ${err instanceof Error ? err.message : String(err)}`
11136
+ };
11137
+ }
11138
+ }
11139
+
10387
11140
  // src/commands/tools-enrich.ts
10388
11141
  function registerToolsEnrichCommand(tools) {
10389
- tools.command("enrich <name>").description("Run AI enrichment for a tool. Prints the suggested vs applied diff; pass --apply to push the suggestion to the cloud.").option("--org <organizationId>", "Organization ID (defaults to .mcpcloud/state.json)").option("--server <server>", "Server (id, name, or slug; defaults to .mcpcloud/state.json)").option("--apply", "Apply the suggestion immediately (PATCH /api/v1/server/tool with the suggested values).").option("--model <id>", "Use a specific model ID for the rewrite (defaults to org / dashboard config)").addHelpText("after", [
11142
+ tools.command("enrich [name]").description("Run AI enrichment for one tool (prints the suggested vs applied diff), or for the whole server with --all.").option("--org <organizationId>", "Organization ID (defaults to .mcpcloud/state.json)").option("--server <server>", "Server (id, name, or slug; defaults to .mcpcloud/state.json)").option("--all", "Enrich every tool on the server as one background job, applying each result. One request, not one per tool.").option("--only <names>", "With --all: comma-separated tool names to limit the job to.").option("--no-apply", "With --all: generate suggestions without writing them onto the tools.").option("--no-wait", "With --all: print the job id and exit instead of following it.").option("--job <jobId>", "Poll an enrichment job started earlier.").option("--apply", "Apply the suggestion immediately (PATCH /api/v1/server/tool with the suggested values).").option("--model <id>", "Use a specific model ID for the rewrite (defaults to org / dashboard config)").addHelpText("after", [
10390
11143
  "",
10391
11144
  "Examples:",
10392
11145
  " $ mcp tools enrich get_user # generate + show suggestion",
10393
11146
  " $ mcp tools enrich get_user --apply # generate + push to cloud",
10394
- " $ mcp tools enrich get_user --model abc123"
11147
+ " $ mcp tools enrich --all # whole server, one job",
11148
+ " $ mcp tools enrich --all --only a,b # just these two",
11149
+ " $ mcp tools enrich --all --no-wait # queue it and get the job id",
11150
+ " $ mcp tools enrich --job job_abc123 # follow a job started earlier"
10395
11151
  ].join(`
10396
11152
  `)).action(runAction(async (name, opts) => {
11153
+ const batchMode = Boolean(opts.all) || Boolean(opts.job);
11154
+ if (name && batchMode) {
11155
+ printError("Pass a tool name or --all/--job, not both.");
11156
+ throw new CliExitError(1);
11157
+ }
11158
+ if (!name && !batchMode) {
11159
+ printError("Name a tool to enrich, or pass --all for every tool on the server.");
11160
+ throw new CliExitError(1);
11161
+ }
11162
+ if (batchMode) {
11163
+ const ctx = await resolveToolsContext({
11164
+ orgOverride: opts.org,
11165
+ serverOverride: opts.server
11166
+ });
11167
+ if (!ctx)
11168
+ return;
11169
+ if (opts.job) {
11170
+ await pollEnrichmentJob(ctx, opts.job);
11171
+ return;
11172
+ }
11173
+ await runToolsEnrichAll({
11174
+ ctx,
11175
+ only: (opts.only ?? "").split(",").map((entry) => entry.trim()).filter((entry) => entry.length > 0),
11176
+ apply: opts.apply !== false,
11177
+ modelId: opts.model,
11178
+ wait: opts.wait !== false
11179
+ });
11180
+ return;
11181
+ }
10397
11182
  await runToolsEnrich({
10398
11183
  toolName: name,
10399
11184
  orgOverride: opts.org,
@@ -10430,6 +11215,7 @@ async function runToolsEnrich(args) {
10430
11215
  projectId: ctx.projectId,
10431
11216
  serverId: ctx.serverId,
10432
11217
  toolId: target.id,
11218
+ apply: false,
10433
11219
  ...args.modelId ? { modelId: args.modelId } : {}
10434
11220
  });
10435
11221
  } catch (err) {
@@ -10496,68 +11282,6 @@ async function runToolsEnrich(args) {
10496
11282
  printSuccess(`Applied ${c.bold(args.toolName)} ${c.dim(`(${applyResult.changedFields.length} field${applyResult.changedFields.length === 1 ? "" : "s"} patched)`)}`);
10497
11283
  printInfo(` ${c.dim("Run")} ${c.bold(`mcp tools pull ${args.toolName}`)} ${c.dim("to refresh your local copy.")}`);
10498
11284
  }
10499
- function printSuggestion(tool, suggestion) {
10500
- const sDesc = suggestion.enrichedDescription?.trim() || null;
10501
- const sTags = suggestion.suggestedTags ?? [];
10502
- const sRisk = suggestion.riskClassification?.riskClass ?? null;
10503
- const sIdem = suggestion.riskClassification?.idempotent ?? null;
10504
- printInfo(c.bold("Suggested vs applied:"));
10505
- printInfo(diffRow("description", tool.description, sDesc));
10506
- printInfo(diffRow("tags", tool.semanticTags.join(", ") || null, sTags.join(", ") || null));
10507
- printInfo(diffRow("riskClass", tool.riskClass, sRisk));
10508
- printInfo(diffRow("idempotent", tool.idempotent === null ? null : String(tool.idempotent), sIdem === null ? null : String(sIdem)));
10509
- }
10510
- function diffRow(label, applied, suggested) {
10511
- const left = c.dim(` ${label.padEnd(14)}`);
10512
- if (applied === suggested) {
10513
- return `${left}${c.dim(applied ?? "(none)")} ${c.dim("(unchanged)")}`;
10514
- }
10515
- return `${left}${applied ?? c.dim("(none)")} ${c.dim("→")} ${c.bold(suggested ?? c.dim("(clear)"))}`;
10516
- }
10517
- async function applySuggestion(tool, ctx) {
10518
- if (!tool.enrichment) {
10519
- return { ok: false, message: "No suggestion to apply." };
10520
- }
10521
- const desc = tool.enrichment.enrichedDescription?.trim() ?? null;
10522
- const tags = tool.enrichment.suggestedTags;
10523
- const risk = tool.enrichment.riskClassification?.riskClass ?? null;
10524
- const idem = tool.enrichment.riskClassification?.idempotent ?? null;
10525
- try {
10526
- const result = await api.patch("/api/v1/server/tool", {
10527
- organizationId: ctx.organizationId,
10528
- projectId: ctx.projectId,
10529
- serverId: ctx.serverId,
10530
- toolId: tool.id,
10531
- expectedUpdatedAt: tool.updatedAt,
10532
- description: desc,
10533
- semanticTags: tags,
10534
- riskClass: risk,
10535
- idempotent: idem
10536
- });
10537
- return {
10538
- ok: true,
10539
- updatedAt: result.tool.updatedAt,
10540
- changedFields: result.patchedFields
10541
- };
10542
- } catch (err) {
10543
- if (err instanceof McpCloudApiError) {
10544
- if (err.error.code === "tool_metadata_conflict") {
10545
- return {
10546
- ok: false,
10547
- message: `Conflict — the tool was modified by someone else after enrichment. Run \`mcp tools pull ${tool.name}\` and rerun \`mcp tools enrich ${tool.name} --apply\`.`
10548
- };
10549
- }
10550
- return {
10551
- ok: false,
10552
- message: `Apply failed (HTTP ${err.status}): ${err.error.message}`
10553
- };
10554
- }
10555
- return {
10556
- ok: false,
10557
- message: `Apply failed: ${err instanceof Error ? err.message : String(err)}`
10558
- };
10559
- }
10560
- }
10561
11285
 
10562
11286
  // src/commands/tools-handlers.ts
10563
11287
  var STATUS_LABEL = {
@@ -11077,7 +11801,6 @@ function diffLine2(label, applied, suggested) {
11077
11801
  }
11078
11802
 
11079
11803
  // src/commands/tools.ts
11080
- var PROJECT_TOOLS_PAGE_LIMIT = 100;
11081
11804
  function registerToolCommands(program2) {
11082
11805
  const tools = program2.command("tools").description("Inspect and edit tools on a project or server");
11083
11806
  tools.command("list").description("List tools for a project, or scope to a single server with --server").option("--org <organizationId>", "Organization ID").option("--project <project>", "List every tool in this project (id or name)").option("--server <server>", "List only the tools that belong to this server — id, name, or slug (the CLI resolves its project, fetches the project tools, then filters to this server)").action(runAction(async (opts) => {
@@ -11097,13 +11820,8 @@ function registerToolCommands(program2) {
11097
11820
  });
11098
11821
  projectId = serverData.server.projectId;
11099
11822
  }
11100
- const data = await api.get("/api/v1/project/tools", {
11101
- limit: String(PROJECT_TOOLS_PAGE_LIMIT),
11102
- organizationId: orgId,
11103
- projectId
11104
- });
11105
- const truncated = data.tools.length >= PROJECT_TOOLS_PAGE_LIMIT;
11106
- const rows = resolvedServerId ? data.tools.filter((t) => t.serverId === resolvedServerId) : data.tools;
11823
+ const { rows: allTools, payload } = await fetchAllPagesWithEnvelope("/api/v1/project/tools", { organizationId: orgId, projectId }, "tools");
11824
+ const rows = resolvedServerId ? allTools.filter((t) => t.serverId === resolvedServerId) : allTools;
11107
11825
  printList(rows.map((t) => ({
11108
11826
  name: t.name,
11109
11827
  method: t.endpoint?.method ?? t.method ?? "—",
@@ -11116,10 +11834,7 @@ function registerToolCommands(program2) {
11116
11834
  { key: "path", label: "Path", width: 32 },
11117
11835
  { key: "enrichment", label: "Enrichment", width: 12 },
11118
11836
  { key: "description", label: "Description", width: 60 }
11119
- ], resolvedServerId ? { ...data, tools: rows, truncated } : { ...data, truncated });
11120
- if (truncated) {
11121
- printWarn(`Showing the first ${PROJECT_TOOLS_PAGE_LIMIT} tools — this project has more. ` + "Filter with --server, or read them from the deployed endpoint with `mcp invoke <server> --list`.");
11122
- }
11837
+ ], resolvedServerId ? { ...payload, tools: rows } : payload);
11123
11838
  }));
11124
11839
  registerToolsShowCommand(tools);
11125
11840
  registerToolsDiffCommand(tools);
@@ -11281,13 +11996,13 @@ function isAgentKey(value) {
11281
11996
  }
11282
11997
 
11283
11998
  // src/commands/skills-lifecycle.ts
11284
- import { readFileSync as readFileSync13 } from "node:fs";
11999
+ import { readFileSync as readFileSync15 } from "node:fs";
11285
12000
  function readValueOption2(raw) {
11286
12001
  if (raw === "@-") {
11287
- return readFileSync13(0, "utf8");
12002
+ return readFileSync15(0, "utf8");
11288
12003
  }
11289
12004
  if (raw.startsWith("@")) {
11290
- return readFileSync13(raw.slice(1), "utf8");
12005
+ return readFileSync15(raw.slice(1), "utf8");
11291
12006
  }
11292
12007
  return raw;
11293
12008
  }
@@ -11667,7 +12382,7 @@ function registerSkillMutationCommands(skills) {
11667
12382
  }
11668
12383
 
11669
12384
  // src/commands/skills-test-authoring.ts
11670
- import { readFileSync as readFileSync14 } from "node:fs";
12385
+ import { readFileSync as readFileSync16 } from "node:fs";
11671
12386
  var FIXTURE_MODES = [
11672
12387
  "baseline",
11673
12388
  "validationFailure",
@@ -11676,9 +12391,9 @@ var FIXTURE_MODES = [
11676
12391
  ];
11677
12392
  function readValueOption3(raw) {
11678
12393
  if (raw === "@-")
11679
- return readFileSync14(0, "utf8");
12394
+ return readFileSync16(0, "utf8");
11680
12395
  if (raw.startsWith("@"))
11681
- return readFileSync14(raw.slice(1), "utf8");
12396
+ return readFileSync16(raw.slice(1), "utf8");
11682
12397
  return raw;
11683
12398
  }
11684
12399
  function parseAssertionsOption(raw) {
@@ -12247,14 +12962,11 @@ function registerSkillCommands(program2) {
12247
12962
  `)).action(runAction(async (opts) => {
12248
12963
  const orgId = await resolveOrgId(opts.org);
12249
12964
  const projectId = await resolveOptionalProjectId(opts.project, orgId);
12250
- const params = {
12251
- organizationId: orgId,
12252
- limit: opts.limit
12253
- };
12965
+ const params = { organizationId: orgId };
12254
12966
  if (projectId)
12255
12967
  params["projectId"] = projectId;
12256
- const data = await api.get("/api/v1/skills", params);
12257
- printList(data.skills.map((s) => ({
12968
+ const { rows: skillRows, payload } = await fetchAllPagesWithEnvelope("/api/v1/skills", params, "skills", { max: parseRowCap(opts.limit) });
12969
+ printList(skillRows.map((s) => ({
12258
12970
  id: s.id,
12259
12971
  name: s.name,
12260
12972
  project: s.projectName,
@@ -12268,7 +12980,7 @@ function registerSkillCommands(program2) {
12268
12980
  { key: "status", label: "Status", width: 10 },
12269
12981
  { key: "version", label: "Version", width: 8 },
12270
12982
  { key: "updated", label: "Updated", width: 22 }
12271
- ], data);
12983
+ ], payload);
12272
12984
  }));
12273
12985
  skills.command("get <skill>").description("Get details for a single skill (accepts id or name)").option("--org <organizationId>", "Organization ID").action(runAction(async (skillRef, opts) => {
12274
12986
  const orgId = await resolveOrgId(opts.org);
@@ -12526,7 +13238,7 @@ import { join as join18, relative as relative6 } from "node:path";
12526
13238
  import {
12527
13239
  existsSync as existsSync14,
12528
13240
  mkdirSync as mkdirSync9,
12529
- readFileSync as readFileSync15,
13241
+ readFileSync as readFileSync17,
12530
13242
  rmSync as rmSync2,
12531
13243
  writeFileSync as writeFileSync8
12532
13244
  } from "node:fs";
@@ -12663,7 +13375,7 @@ import { spawnSync } from "node:child_process";
12663
13375
  import {
12664
13376
  existsSync as existsSync15,
12665
13377
  mkdirSync as mkdirSync10,
12666
- readFileSync as readFileSync16,
13378
+ readFileSync as readFileSync18,
12667
13379
  writeFileSync as writeFileSync9
12668
13380
  } from "node:fs";
12669
13381
  import { dirname as dirname8, join as join13 } from "node:path";
@@ -12740,7 +13452,7 @@ function isGitAvailable() {
12740
13452
  }
12741
13453
  function applyLocalExcludes(repoDir) {
12742
13454
  const excludePath = join13(repoDir, ".git", "info", "exclude");
12743
- const existing = existsSync15(excludePath) ? readFileSync16(excludePath, "utf-8") : "";
13455
+ const existing = existsSync15(excludePath) ? readFileSync18(excludePath, "utf-8") : "";
12744
13456
  const next = mergeLocalExcludes(existing);
12745
13457
  if (next === null)
12746
13458
  return;
@@ -28038,6 +28750,12 @@ function buildHostScript(options) {
28038
28750
  ``,
28039
28751
  `async function main() {`,
28040
28752
  ` const env = loadEnv()`,
28753
+ ` try {`,
28754
+ ` const rt = await import('@mcpcloud/runtime/node')`,
28755
+ ` if (typeof rt.registerNodeCodeModeEngine === 'function') rt.registerNodeCodeModeEngine()`,
28756
+ ` } catch (err) {`,
28757
+ ` console.error('[mcp dev] code mode unavailable locally:', err?.message ?? err)`,
28758
+ ` }`,
28041
28759
  ` const mod = await import(pathToFileURL(new URL(ENTRY, import.meta.url).pathname).href)`,
28042
28760
  ` const handler = mod.default`,
28043
28761
  ` if (!handler || typeof handler.fetch !== 'function') {`,
@@ -28108,7 +28826,7 @@ import {
28108
28826
  appendFileSync as appendFileSync2,
28109
28827
  existsSync as existsSync18,
28110
28828
  mkdirSync as mkdirSync13,
28111
- readFileSync as readFileSync17,
28829
+ readFileSync as readFileSync19,
28112
28830
  readdirSync as readdirSync2,
28113
28831
  renameSync,
28114
28832
  statSync as statSync2
@@ -28160,7 +28878,7 @@ function readAll(dir) {
28160
28878
  for (const path of [...listRotatedFiles(dir), activeFilePath(dir)]) {
28161
28879
  if (!existsSync18(path))
28162
28880
  continue;
28163
- out.push(...parseLines(readFileSync17(path, "utf-8")));
28881
+ out.push(...parseLines(readFileSync19(path, "utf-8")));
28164
28882
  }
28165
28883
  return out;
28166
28884
  }
@@ -28427,8 +29145,9 @@ async function prepareDev(opts) {
28427
29145
 
28428
29146
  // src/lib/dev/tree-sync.ts
28429
29147
  import { createHash as createHash4 } from "node:crypto";
28430
- import { existsSync as existsSync21, mkdirSync as mkdirSync14, readdirSync as readdirSync3, readFileSync as readFileSync18, writeFileSync as writeFileSync13 } from "node:fs";
29148
+ import { existsSync as existsSync21, mkdirSync as mkdirSync14, readdirSync as readdirSync3, readFileSync as readFileSync20, writeFileSync as writeFileSync13 } from "node:fs";
28431
29149
  import { join as join19 } from "node:path";
29150
+ var AUTHORING_GUIDE_FILE = "AGENTS.md";
28432
29151
  var STRUCTURAL_FRONTMATTER_KEYS = [
28433
29152
  "inputSchema",
28434
29153
  "outputSchema",
@@ -28444,11 +29163,11 @@ function listToolFiles(devRootDir, serverId) {
28444
29163
  const dir = serverToolsDir(devRootDir, serverId);
28445
29164
  if (!existsSync21(dir))
28446
29165
  return [];
28447
- return readdirSync3(dir).filter((entry) => entry.endsWith(".md")).map((entry) => entry.slice(0, -3)).sort();
29166
+ return readdirSync3(dir).filter((entry) => entry.endsWith(".md")).filter((entry) => entry !== AUTHORING_GUIDE_FILE).map((entry) => entry.slice(0, -3)).sort();
28448
29167
  }
28449
29168
  function readToolFile(devRootDir, serverId, toolName) {
28450
29169
  const file = join19(serverToolsDir(devRootDir, serverId), `${toolName}.md`);
28451
- const raw = readFileSync18(file, "utf-8");
29170
+ const raw = readFileSync20(file, "utf-8");
28452
29171
  try {
28453
29172
  return { raw, view: parseToolMarkdown(raw) };
28454
29173
  } catch (err) {
@@ -28466,6 +29185,21 @@ function findStructuralEdit(raw) {
28466
29185
  }
28467
29186
  return null;
28468
29187
  }
29188
+ async function writeAuthoringGuide(args) {
29189
+ try {
29190
+ const response = await api.get("/api/v1/tool-authoring-guide");
29191
+ const markdown = response?.guide?.markdown;
29192
+ if (typeof markdown !== "string" || !markdown.trim())
29193
+ return null;
29194
+ const dir = serverToolsDir(args.devRootDir, args.serverId);
29195
+ mkdirSync14(dir, { recursive: true });
29196
+ const guidePath = join19(dir, AUTHORING_GUIDE_FILE);
29197
+ writeFileSync13(guidePath, markdown, "utf8");
29198
+ return guidePath;
29199
+ } catch {
29200
+ return null;
29201
+ }
29202
+ }
28469
29203
  async function pullToolTree(args) {
28470
29204
  const tools = await fetchToolsForServer({
28471
29205
  organizationId: args.organizationId,
@@ -28477,7 +29211,11 @@ async function pullToolTree(args) {
28477
29211
  serverId: args.serverId,
28478
29212
  tools
28479
29213
  });
28480
- return { ...result, tools };
29214
+ const guidePath = await writeAuthoringGuide({
29215
+ devRootDir: args.devRootDir,
29216
+ serverId: args.serverId
29217
+ });
29218
+ return { ...result, guidePath, tools };
28481
29219
  }
28482
29220
  function planPush(args) {
28483
29221
  const changes = [];
@@ -28549,7 +29287,7 @@ function listHandlerFiles(devRootDir) {
28549
29287
  return [];
28550
29288
  return readdirSync3(dir).filter((entry) => entry.endsWith(".ts") && !entry.endsWith(".definition.ts")).sort().map((entry) => ({
28551
29289
  slug: entry.slice(0, -3),
28552
- source: readFileSync18(join19(dir, entry), "utf-8")
29290
+ source: readFileSync20(join19(dir, entry), "utf-8")
28553
29291
  }));
28554
29292
  }
28555
29293
  function writeHandlerManifest(args) {
@@ -28577,7 +29315,7 @@ function recordHandlerPushed(args) {
28577
29315
  serverId: args.serverId,
28578
29316
  version: 1
28579
29317
  };
28580
- manifest.handlers[args.slug] = hashSource2(readFileSync18(file, "utf-8"));
29318
+ manifest.handlers[args.slug] = hashSource2(readFileSync20(file, "utf-8"));
28581
29319
  writeFileSync13(handlerManifestPath(args.devRootDir, args.serverId), JSON.stringify(manifest, null, 2), "utf-8");
28582
29320
  }
28583
29321
  function readHandlerManifest(devRootDir, serverId) {
@@ -28585,7 +29323,7 @@ function readHandlerManifest(devRootDir, serverId) {
28585
29323
  if (!existsSync21(file))
28586
29324
  return null;
28587
29325
  try {
28588
- const parsed = JSON.parse(readFileSync18(file, "utf-8"));
29326
+ const parsed = JSON.parse(readFileSync20(file, "utf-8"));
28589
29327
  return parsed.version === 1 && parsed.handlers ? parsed : null;
28590
29328
  } catch {
28591
29329
  return null;
@@ -28649,6 +29387,7 @@ function describeToolPush(toolName, result) {
28649
29387
  return {
28650
29388
  detail: `updated ${result.changedFields.join(", ") || "metadata"}`,
28651
29389
  ok: true,
29390
+ ...result.notices.length > 0 ? { notices: result.notices.map((notice) => notice.message) } : {},
28652
29391
  target: toolName
28653
29392
  };
28654
29393
  case "noop":
@@ -28797,6 +29536,7 @@ function registerTreeCommands(program2) {
28797
29536
  name: target.serverName,
28798
29537
  projectId: target.projectId
28799
29538
  },
29539
+ authoringGuide: tools.guidePath,
28800
29540
  toolFilesRemoved: tools.filesRemoved,
28801
29541
  toolFilesWritten: tools.filesWritten,
28802
29542
  treeDir: prepared.destDir
@@ -28809,6 +29549,9 @@ function registerTreeCommands(program2) {
28809
29549
  handlers: handlerCount,
28810
29550
  tree: prepared.destDir
28811
29551
  });
29552
+ if (tools.guidePath) {
29553
+ printInfo(`Editing rules for agents: ${tools.guidePath}`);
29554
+ }
28812
29555
  printInfo("Edit, then run `mcp push --dry-run`.");
28813
29556
  }));
28814
29557
  program2.command("push").description("Push local tool metadata and handler edits back to the cloud (diffed against your last pull)").option("--server <server>", "Server to push to (id or name)").option("--org <organizationId>", "Organization ID").option("--dry-run", "Print the change set and exit without writing").addHelpText("after", [
@@ -28881,6 +29624,9 @@ function registerTreeCommands(program2) {
28881
29624
  }
28882
29625
  for (const outcome of applied) {
28883
29626
  printSuccess(`${outcome.target}: ${outcome.detail}`);
29627
+ for (const notice of outcome.notices ?? []) {
29628
+ printWarn(`${outcome.target}: ${notice}`);
29629
+ }
28884
29630
  }
28885
29631
  for (const outcome of refused) {
28886
29632
  printError(`${outcome.target}: ${outcome.detail}`);
@@ -29553,7 +30299,7 @@ import { isAbsolute as isAbsolute4, relative as relative7, resolve as resolve9 }
29553
30299
  import {
29554
30300
  existsSync as existsSync22,
29555
30301
  mkdirSync as mkdirSync15,
29556
- readFileSync as readFileSync19,
30302
+ readFileSync as readFileSync21,
29557
30303
  readdirSync as readdirSync4,
29558
30304
  unlinkSync,
29559
30305
  writeFileSync as writeFileSync14
@@ -29597,7 +30343,7 @@ function listSessions() {
29597
30343
  continue;
29598
30344
  const path = join21(dir, entry);
29599
30345
  try {
29600
- const parsed = JSON.parse(readFileSync19(path, "utf-8"));
30346
+ const parsed = JSON.parse(readFileSync21(path, "utf-8"));
29601
30347
  if (typeof parsed.pid !== "number") {
29602
30348
  unlinkSync(path);
29603
30349
  continue;
@@ -29995,7 +30741,7 @@ async function runDevTail(opts) {
29995
30741
  emitLines(complete, opts.filter);
29996
30742
  }
29997
30743
  }
29998
- await sleep(intervalMs);
30744
+ await sleep2(intervalMs);
29999
30745
  }
30000
30746
  }
30001
30747
  function parseInterval(raw) {
@@ -30056,7 +30802,7 @@ function emitLines(text, filter) {
30056
30802
  `);
30057
30803
  }
30058
30804
  }
30059
- function sleep(ms) {
30805
+ function sleep2(ms) {
30060
30806
  return new Promise((resolve8) => setTimeout(resolve8, ms));
30061
30807
  }
30062
30808
 
@@ -30956,19 +31702,19 @@ import { homedir as homedir4 } from "node:os";
30956
31702
  import { join as join26 } from "node:path";
30957
31703
 
30958
31704
  // src/lib/dev/agent-connectors/json-config-utils.ts
30959
- import { existsSync as existsSync28, mkdirSync as mkdirSync16, readFileSync as readFileSync20, writeFileSync as writeFileSync15 } from "node:fs";
31705
+ import { existsSync as existsSync28, mkdirSync as mkdirSync16, readFileSync as readFileSync22, writeFileSync as writeFileSync15 } from "node:fs";
30960
31706
  import { dirname as dirname10, join as join25, basename } from "node:path";
30961
31707
  function readJsonFile(path) {
30962
31708
  if (!existsSync28(path))
30963
31709
  return { ok: true, value: {} };
30964
31710
  try {
30965
- const raw = readFileSync20(path, "utf-8");
31711
+ const raw = readFileSync22(path, "utf-8");
30966
31712
  if (!raw.trim())
30967
31713
  return { ok: true, value: {} };
30968
31714
  return { ok: true, value: JSON.parse(raw) };
30969
31715
  } catch {
30970
31716
  try {
30971
- return { ok: false, raw: readFileSync20(path, "utf-8") };
31717
+ return { ok: false, raw: readFileSync22(path, "utf-8") };
30972
31718
  } catch {
30973
31719
  return { ok: false };
30974
31720
  }
@@ -30990,7 +31736,7 @@ function backupConfig(args) {
30990
31736
  const filename = `${args.agentId}__${basename(args.configPath)}.bak`;
30991
31737
  const backupPath = join25(args.backupsDir, filename);
30992
31738
  if (!existsSync28(backupPath)) {
30993
- const raw = readFileSync20(args.configPath, "utf-8");
31739
+ const raw = readFileSync22(args.configPath, "utf-8");
30994
31740
  writeFileSync15(backupPath, raw, "utf-8");
30995
31741
  }
30996
31742
  return { backupPath, existed: true };
@@ -31001,7 +31747,7 @@ function restoreFromBackup(args) {
31001
31747
  if (!existsSync28(backupPath)) {
31002
31748
  return { restored: false };
31003
31749
  }
31004
- const raw = readFileSync20(backupPath, "utf-8");
31750
+ const raw = readFileSync22(backupPath, "utf-8");
31005
31751
  mkdirSync16(dirname10(args.configPath), { recursive: true });
31006
31752
  writeFileSync15(args.configPath, raw, "utf-8");
31007
31753
  return { restored: true };
@@ -31090,7 +31836,7 @@ var claudeCodeConnector = {
31090
31836
  import {
31091
31837
  existsSync as existsSync30,
31092
31838
  mkdirSync as mkdirSync17,
31093
- readFileSync as readFileSync21,
31839
+ readFileSync as readFileSync23,
31094
31840
  unlinkSync as unlinkSync3,
31095
31841
  writeFileSync as writeFileSync17
31096
31842
  } from "node:fs";
@@ -31149,7 +31895,7 @@ var codexConnector = {
31149
31895
  });
31150
31896
  let existing = "";
31151
31897
  if (existsSync30(path)) {
31152
- existing = readFileSync21(path, "utf-8");
31898
+ existing = readFileSync23(path, "utf-8");
31153
31899
  }
31154
31900
  const conflict = findSectionRange(existing, args.name) !== null;
31155
31901
  let next = existing;
@@ -31171,7 +31917,7 @@ var codexConnector = {
31171
31917
  async remove(args) {
31172
31918
  const path = configPath2();
31173
31919
  if (existsSync30(path)) {
31174
- const existing = readFileSync21(path, "utf-8");
31920
+ const existing = readFileSync23(path, "utf-8");
31175
31921
  const range = findSectionRange(existing, args.name);
31176
31922
  if (range) {
31177
31923
  const next = existing.slice(0, range.start) + existing.slice(range.end);
@@ -31184,7 +31930,7 @@ var codexConnector = {
31184
31930
  agentId: this.id
31185
31931
  });
31186
31932
  if (!restored.restored && existsSync30(path)) {
31187
- const after = readFileSync21(path, "utf-8");
31933
+ const after = readFileSync23(path, "utf-8");
31188
31934
  if (!after.trim()) {
31189
31935
  try {
31190
31936
  unlinkSync3(path);
@@ -32437,12 +33183,8 @@ function registerDeploymentCommands(program2) {
32437
33183
  deployments.command("list").description("List deployments in an organization").option("--org <organizationId>", "Organization ID").option("--status <status>", `Filter: ${DEPLOYMENT_STATUSES.join(" | ")}`, "active").option("--limit <n>", "Maximum results (default 25)", parsePositiveIntOption("limit"), "25").action(runAction(async (opts) => {
32438
33184
  const orgId = await resolveOrgId(opts.org);
32439
33185
  const status = validateChoice("status", opts.status, DEPLOYMENT_STATUSES);
32440
- const data = await api.get("/api/v1/deployments", {
32441
- organizationId: orgId,
32442
- status,
32443
- limit: opts.limit
32444
- });
32445
- printList(data.deployments.map((d) => ({
33186
+ const { rows: deploymentRows, payload } = await fetchAllPagesWithEnvelope("/api/v1/deployments", { organizationId: orgId, status }, "deployments", { max: parseRowCap(opts.limit) });
33187
+ printList(deploymentRows.map((d) => ({
32446
33188
  id: d.id,
32447
33189
  server: d.serverName,
32448
33190
  project: d.projectName,
@@ -32460,7 +33202,7 @@ function registerDeploymentCommands(program2) {
32460
33202
  { key: "status", label: "Status", width: 10 },
32461
33203
  { key: "version", label: "Version", width: 10 },
32462
33204
  { key: "deployed", label: "Deployed", width: 22 }
32463
- ], data);
33205
+ ], payload);
32464
33206
  }));
32465
33207
  deployments.command("get <deployment>").description("Show one deployment by id or selector (latest | active | previous, with --server)").option("--org <organizationId>", "Organization ID").option("--server <server>", SELECTOR_SERVER_HELP).addHelpText("after", SELECTOR_HELP).action(runAction(async (deploymentRef, opts) => {
32466
33208
  const orgId = await resolveOrgId(opts.org);
@@ -32666,12 +33408,12 @@ async function confirmRollback(deploymentId) {
32666
33408
  }
32667
33409
 
32668
33410
  // src/commands/doctor.ts
32669
- import { existsSync as existsSync36, statSync as statSync6, readFileSync as readFileSync23 } from "node:fs";
33411
+ import { existsSync as existsSync36, statSync as statSync6, readFileSync as readFileSync25 } from "node:fs";
32670
33412
  import { homedir as homedir9, platform as platform6 } from "node:os";
32671
33413
  import { join as join32, delimiter as delimiter3 } from "node:path";
32672
33414
 
32673
33415
  // src/lib/version-check.ts
32674
- import { existsSync as existsSync35, mkdirSync as mkdirSync18, readFileSync as readFileSync22, writeFileSync as writeFileSync21 } from "node:fs";
33416
+ import { existsSync as existsSync35, mkdirSync as mkdirSync18, readFileSync as readFileSync24, writeFileSync as writeFileSync21 } from "node:fs";
32675
33417
  import { join as join31 } from "node:path";
32676
33418
  var CACHE_TTL_MS = 24 * 60 * 60 * 1000;
32677
33419
  var FETCH_TIMEOUT_MS2 = 2000;
@@ -32686,7 +33428,7 @@ function readCache() {
32686
33428
  if (!existsSync35(cacheFile()))
32687
33429
  return null;
32688
33430
  try {
32689
- const raw = JSON.parse(readFileSync22(cacheFile(), "utf-8"));
33431
+ const raw = JSON.parse(readFileSync24(cacheFile(), "utf-8"));
32690
33432
  if (typeof raw.latest !== "string" || typeof raw.fetchedAt !== "number")
32691
33433
  return null;
32692
33434
  return { latest: raw.latest, fetchedAt: raw.fetchedAt };
@@ -32832,7 +33574,7 @@ function checkConfigFile() {
32832
33574
  } catch {}
32833
33575
  }
32834
33576
  try {
32835
- JSON.parse(readFileSync23(path, "utf-8"));
33577
+ JSON.parse(readFileSync25(path, "utf-8"));
32836
33578
  } catch (err) {
32837
33579
  return {
32838
33580
  name: "Config file",
@@ -33678,7 +34420,7 @@ function registerInstallationCommands(program2) {
33678
34420
  }
33679
34421
 
33680
34422
  // src/commands/invoke.ts
33681
- import { existsSync as existsSync37, readFileSync as readFileSync24 } from "node:fs";
34423
+ import { existsSync as existsSync37, readFileSync as readFileSync26 } from "node:fs";
33682
34424
  import { join as join33 } from "node:path";
33683
34425
 
33684
34426
  // src/lib/dev/local-invoke.ts
@@ -33771,9 +34513,9 @@ function selectCodeModeInvocation(args) {
33771
34513
  }
33772
34514
  function readCodeOption(raw) {
33773
34515
  if (raw === "@-")
33774
- return readFileSync24(0, "utf-8");
34516
+ return readFileSync26(0, "utf-8");
33775
34517
  if (raw.startsWith("@"))
33776
- return readFileSync24(raw.slice(1), "utf-8");
34518
+ return readFileSync26(raw.slice(1), "utf-8");
33777
34519
  return raw;
33778
34520
  }
33779
34521
  function parseTimeoutMs4(value, fallbackMs) {
@@ -34055,7 +34797,7 @@ async function runLocalInvoke(args) {
34055
34797
  throw new CliExitError(1);
34056
34798
  }
34057
34799
  const env = {
34058
- ...args.envFile ? parseEnvFile(readFileSync24(args.envFile, "utf-8")) : {},
34800
+ ...args.envFile ? parseEnvFile(readFileSync26(args.envFile, "utf-8")) : {},
34059
34801
  ...parseEnvPairs(args.envPairs)
34060
34802
  };
34061
34803
  const port = await findAvailablePort({ range: 40, start: 43117 });
@@ -34653,7 +35395,7 @@ function registerUsageCommands(program2) {
34653
35395
  }
34654
35396
 
34655
35397
  // src/commands/metrics.ts
34656
- function formatPercent(rate) {
35398
+ function formatPercent2(rate) {
34657
35399
  if (rate == null)
34658
35400
  return "—";
34659
35401
  return `${(rate * 100).toFixed(2)}%`;
@@ -34715,7 +35457,7 @@ function registerMetricsCommands(program2) {
34715
35457
  "rate-limited": m2.totals.rateLimitedCount,
34716
35458
  unauthorized: m2.totals.unauthorizedCount,
34717
35459
  failed: m2.totals.failedCount,
34718
- "error rate": formatPercent(errorRate),
35460
+ "error rate": formatPercent2(errorRate),
34719
35461
  "avg duration": formatMs(m2.averageDurationMs),
34720
35462
  "avg cpu": formatMs(m2.averageCpuTimeMs),
34721
35463
  "last event": m2.lastEventAt ? formatDate(m2.lastEventAt) : "—"
@@ -35047,7 +35789,7 @@ import {
35047
35789
  existsSync as existsSync38,
35048
35790
  mkdirSync as mkdirSync19,
35049
35791
  readdirSync as readdirSync5,
35050
- readFileSync as readFileSync25,
35792
+ readFileSync as readFileSync27,
35051
35793
  rmSync as rmSync3,
35052
35794
  statSync as statSync7
35053
35795
  } from "node:fs";
@@ -35067,7 +35809,7 @@ function readManifestFromPackageDir(packageDir) {
35067
35809
  return null;
35068
35810
  let pkg;
35069
35811
  try {
35070
- pkg = JSON.parse(readFileSync25(pkgPath, "utf-8"));
35812
+ pkg = JSON.parse(readFileSync27(pkgPath, "utf-8"));
35071
35813
  } catch {
35072
35814
  return null;
35073
35815
  }
@@ -35819,8 +36561,9 @@ var CLI_EXAMPLES = {
35819
36561
  "tools handlers list": ["mcp tools handlers list srv_abc"],
35820
36562
  "tools diff": ["mcp tools diff srv_abc query_users"],
35821
36563
  "tools enrich": [
35822
- "mcp tools enrich srv_abc",
35823
- "mcp tools enrich srv_abc --only query_users"
36564
+ "mcp tools enrich query_users",
36565
+ "mcp tools enrich --all --server srv_abc",
36566
+ "mcp tools enrich --all --only query_users,create_user"
35824
36567
  ],
35825
36568
  "tools pull": ["mcp tools pull srv_abc"],
35826
36569
  "tools pull-handler": ["mcp tools pull-handler srv_abc query_users"],
@@ -35861,7 +36604,7 @@ var PLAYBOOKS = [
35861
36604
  {
35862
36605
  description: "Re-write every tool description for agent comprehension.",
35863
36606
  verb: "tools enrich",
35864
- command: "mcp tools enrich srv_abc"
36607
+ command: "mcp tools enrich --all --server srv_abc"
35865
36608
  },
35866
36609
  {
35867
36610
  description: "Deploy to the proxy.",
@@ -36800,7 +37543,7 @@ function displayValueFor(field, value) {
36800
37543
  import {
36801
37544
  existsSync as existsSync39,
36802
37545
  mkdirSync as mkdirSync20,
36803
- readFileSync as readFileSync26,
37546
+ readFileSync as readFileSync28,
36804
37547
  writeFileSync as writeFileSync22
36805
37548
  } from "node:fs";
36806
37549
  import { join as join35 } from "node:path";
@@ -36882,7 +37625,7 @@ function readTuiState() {
36882
37625
  return {};
36883
37626
  let parsed;
36884
37627
  try {
36885
- parsed = JSON.parse(readFileSync26(path, "utf-8"));
37628
+ parsed = JSON.parse(readFileSync28(path, "utf-8"));
36886
37629
  } catch {
36887
37630
  return {};
36888
37631
  }