@yawlabs/mcph 0.47.8 → 0.49.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 (2) hide show
  1. package/dist/index.js +88 -25
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -1006,6 +1006,8 @@ var flushTimer = null;
1006
1006
  var apiUrl = "";
1007
1007
  var token = "";
1008
1008
  var lastFailure = null;
1009
+ var lastLoggedConnectStatus = null;
1010
+ var lastLoggedDispatchStatus = null;
1009
1011
  function getLastAnalyticsFailure() {
1010
1012
  return lastFailure;
1011
1013
  }
@@ -1041,12 +1043,19 @@ async function flush() {
1041
1043
  bodyTimeout: 1e4
1042
1044
  });
1043
1045
  if (res.statusCode >= 400) {
1044
- const room = MAX_BUFFER - buffer.length;
1045
- if (room > 0) buffer.push(...events.slice(0, room));
1046
- log("warn", "Analytics flush failed", { status: res.statusCode });
1046
+ const retryable = res.statusCode >= 500 || res.statusCode === 408 || res.statusCode === 429;
1047
+ if (retryable) {
1048
+ const room = MAX_BUFFER - buffer.length;
1049
+ if (room > 0) buffer.push(...events.slice(0, room));
1050
+ }
1051
+ if (lastLoggedConnectStatus !== res.statusCode) {
1052
+ log("warn", "Analytics flush failed", { status: res.statusCode, retried: retryable });
1053
+ lastLoggedConnectStatus = res.statusCode;
1054
+ }
1047
1055
  lastFailure = { statusCode: res.statusCode, url, at: Date.now() };
1048
1056
  } else {
1049
1057
  lastFailure = null;
1058
+ lastLoggedConnectStatus = null;
1050
1059
  }
1051
1060
  await res.body.text().catch(() => {
1052
1061
  });
@@ -1072,12 +1081,19 @@ async function flushDispatch() {
1072
1081
  bodyTimeout: 1e4
1073
1082
  });
1074
1083
  if (res.statusCode >= 400 && res.statusCode !== 204) {
1075
- const room = MAX_BUFFER - dispatchBuffer.length;
1076
- if (room > 0) dispatchBuffer.push(...events.slice(0, room));
1077
- log("warn", "Dispatch-events flush failed", { status: res.statusCode });
1084
+ const retryable = res.statusCode >= 500 || res.statusCode === 408 || res.statusCode === 429;
1085
+ if (retryable) {
1086
+ const room = MAX_BUFFER - dispatchBuffer.length;
1087
+ if (room > 0) dispatchBuffer.push(...events.slice(0, room));
1088
+ }
1089
+ if (lastLoggedDispatchStatus !== res.statusCode) {
1090
+ log("warn", "Dispatch-events flush failed", { status: res.statusCode, retried: retryable });
1091
+ lastLoggedDispatchStatus = res.statusCode;
1092
+ }
1078
1093
  lastFailure = { statusCode: res.statusCode, url, at: Date.now() };
1079
1094
  } else if (res.statusCode < 400) {
1080
1095
  lastFailure = null;
1096
+ lastLoggedDispatchStatus = null;
1081
1097
  }
1082
1098
  await res.body.text().catch(() => {
1083
1099
  });
@@ -1090,6 +1106,8 @@ async function flushDispatch() {
1090
1106
  function initAnalytics(url, tok) {
1091
1107
  apiUrl = url;
1092
1108
  token = tok;
1109
+ lastLoggedConnectStatus = null;
1110
+ lastLoggedDispatchStatus = null;
1093
1111
  flushTimer = setInterval(() => {
1094
1112
  flush().catch(() => {
1095
1113
  });
@@ -1650,7 +1668,7 @@ function selectFlakyNamespaces(entries, limit) {
1650
1668
  }
1651
1669
 
1652
1670
  // src/doctor-cmd.ts
1653
- var VERSION = true ? "0.47.8" : "dev";
1671
+ var VERSION = true ? "0.49.0" : "dev";
1654
1672
  async function runDoctor(opts = {}) {
1655
1673
  if (opts.json) return runDoctorJson(opts);
1656
1674
  const lines = [];
@@ -3091,7 +3109,7 @@ Or re-run with --run to upgrade in place.`);
3091
3109
  return { exitCode: 3, lines };
3092
3110
  }
3093
3111
  function readCurrentVersion() {
3094
- return true ? "0.47.8" : "dev";
3112
+ return true ? "0.49.0" : "dev";
3095
3113
  }
3096
3114
 
3097
3115
  // src/auto-upgrade.ts
@@ -3125,7 +3143,11 @@ function defaultSpawn2(cmd, args) {
3125
3143
  if (code === 0) {
3126
3144
  log("info", "mcph self-upgrade complete; the next client restart will run the new version");
3127
3145
  } else {
3128
- log("warn", "mcph self-upgrade: npm exited non-zero", { code });
3146
+ log(
3147
+ "warn",
3148
+ "mcph self-upgrade: npm exited non-zero (often EACCES on a sudo-installed global). Run `npm install -g @yawlabs/mcph@latest` with the right permissions, or set MCPH_AUTO_UPGRADE=0 to silence this.",
3149
+ { code }
3150
+ );
3129
3151
  }
3130
3152
  });
3131
3153
  child.on("error", (err) => {
@@ -3133,7 +3155,9 @@ function defaultSpawn2(cmd, args) {
3133
3155
  });
3134
3156
  }
3135
3157
  async function maybeAutoUpgrade(deps = {}) {
3136
- const current = deps.currentVersion ?? (true ? "0.47.8" : "dev");
3158
+ const optOut = process.env.MCPH_AUTO_UPGRADE;
3159
+ if (optOut === "0" || optOut?.toLowerCase() === "false") return;
3160
+ const current = deps.currentVersion ?? (true ? "0.49.0" : "dev");
3137
3161
  if (current === "dev") return;
3138
3162
  const method = detectInstallMethod(deps.argvPath ?? process.argv[1]);
3139
3163
  const latest = await (deps.fetchLatestImpl ?? fetchLatestVersion2)();
@@ -3588,9 +3612,13 @@ import { request as request5 } from "undici";
3588
3612
  var HEARTBEAT_PATH = "/api/connect/heartbeat";
3589
3613
  var apiUrl3 = "";
3590
3614
  var token3 = "";
3615
+ var lastLoggedFailureStatus = null;
3616
+ var lastLoggedErrorMessage = null;
3591
3617
  function initHeartbeat(url, tok) {
3592
3618
  apiUrl3 = url;
3593
3619
  token3 = tok;
3620
+ lastLoggedFailureStatus = null;
3621
+ lastLoggedErrorMessage = null;
3594
3622
  }
3595
3623
  async function reportHeartbeat(clientName, clientVersion, isRefresh = false) {
3596
3624
  if (!apiUrl3 || !token3) return;
@@ -3615,15 +3643,26 @@ async function reportHeartbeat(clientName, clientVersion, isRefresh = false) {
3615
3643
  await res.body.text().catch(() => {
3616
3644
  });
3617
3645
  if (res.statusCode >= 400 && res.statusCode !== 404) {
3618
- log("warn", "Heartbeat failed", { status: res.statusCode, isRefresh });
3619
- } else if (!isRefresh) {
3620
- log("info", "Reported AI client connect to mcp.hosting", {
3621
- clientName: clientName ?? null,
3622
- clientVersion: clientVersion ?? null
3623
- });
3646
+ if (lastLoggedFailureStatus !== res.statusCode) {
3647
+ log("warn", "Heartbeat failed", { status: res.statusCode, isRefresh });
3648
+ lastLoggedFailureStatus = res.statusCode;
3649
+ }
3650
+ } else {
3651
+ lastLoggedFailureStatus = null;
3652
+ lastLoggedErrorMessage = null;
3653
+ if (!isRefresh) {
3654
+ log("info", "Reported AI client connect to mcp.hosting", {
3655
+ clientName: clientName ?? null,
3656
+ clientVersion: clientVersion ?? null
3657
+ });
3658
+ }
3624
3659
  }
3625
3660
  } catch (err) {
3626
- log("warn", "Heartbeat error", { error: err?.message, isRefresh });
3661
+ const errMsg = err?.message ?? "unknown error";
3662
+ if (lastLoggedErrorMessage !== errMsg) {
3663
+ log("warn", "Heartbeat error", { error: errMsg, isRefresh });
3664
+ lastLoggedErrorMessage = errMsg;
3665
+ }
3627
3666
  }
3628
3667
  }
3629
3668
 
@@ -5262,7 +5301,7 @@ function categorizeSpawnError(err) {
5262
5301
  }
5263
5302
  async function connectToUpstream(config, onDisconnect, onListChanged) {
5264
5303
  const client = new Client(
5265
- { name: "mcph", version: true ? "0.47.8" : "dev" },
5304
+ { name: "mcph", version: true ? "0.49.0" : "dev" },
5266
5305
  { capabilities: {} }
5267
5306
  );
5268
5307
  let transport;
@@ -5570,7 +5609,7 @@ var ConnectServer = class _ConnectServer {
5570
5609
  this.apiUrl = apiUrl6;
5571
5610
  this.token = token6;
5572
5611
  this.server = new Server(
5573
- { name: "mcph", version: true ? "0.47.8" : "dev" },
5612
+ { name: "mcph", version: true ? "0.49.0" : "dev" },
5574
5613
  {
5575
5614
  capabilities: {
5576
5615
  tools: { listChanged: true },
@@ -5882,15 +5921,33 @@ var ConnectServer = class _ConnectServer {
5882
5921
  });
5883
5922
  if (candidates.length === 0) return;
5884
5923
  const top = candidates[0];
5924
+ const loaded = [];
5925
+ const refused = [];
5885
5926
  for (const namespace of top.namespaces) {
5886
- await this.activateOne(namespace).catch(
5887
- (err) => log("warn", "Auto-load activateOne failed", { namespace, error: err?.message })
5888
- );
5927
+ try {
5928
+ const result = await this.activateOne(namespace);
5929
+ if (result.ok) {
5930
+ loaded.push(namespace);
5931
+ } else {
5932
+ refused.push({ namespace, message: result.message });
5933
+ }
5934
+ } catch (err) {
5935
+ refused.push({ namespace, message: err?.message ?? "unknown error" });
5936
+ }
5889
5937
  }
5890
5938
  log("info", "Auto-loaded recurring pack", {
5891
- namespaces: top.namespaces,
5939
+ loaded,
5940
+ refusedCount: refused.length,
5892
5941
  frequency: top.frequency
5893
5942
  });
5943
+ if (refused.length > 0) {
5944
+ const message = loaded.length === 0 ? "Auto-load could not activate any namespace in the pack" : "Auto-load could not activate every namespace in the pack";
5945
+ log("warn", message, {
5946
+ serverCap: this.serverCap,
5947
+ loadedCount: loaded.length,
5948
+ refused
5949
+ });
5950
+ }
5894
5951
  }
5895
5952
  // Populate toolCache for any isActive-but-never-activated server so
5896
5953
  // Claude's tools/list shows the full toggled set on first run.
@@ -7912,10 +7969,16 @@ if (subcommand === "compliance") {
7912
7969
  MCPH_POLL_INTERVAL Dashboard polling interval, seconds (default 60).
7913
7970
  MCPH_SERVER_CAP Max concurrently active servers (default 6).
7914
7971
  MCPH_MIN_COMPLIANCE Minimum grade to auto-activate (A|B|C|D|F).
7915
- MCPH_AUTO_LOAD Load all servers at startup, ignoring SERVER_CAP.
7972
+ MCPH_AUTO_LOAD Auto-activate the namespaces of the highest-
7973
+ ranked recurring pack at startup, subject to
7974
+ SERVER_CAP (default: off).
7916
7975
  MCPH_AUTO_ACTIVATE Set to \`0\` to disable discover's auto-activate
7917
7976
  gate (default: a clearly-winning server is
7918
7977
  activated in the same call).
7978
+ MCPH_AUTO_UPGRADE Set to \`0\` to disable the background
7979
+ self-upgrade check at \`mcph serve\` startup
7980
+ (default: stale global-npm installs are
7981
+ upgraded in the background).
7919
7982
  MCPH_PRUNE_RESPONSES Set to \`0\` to disable response pruning.
7920
7983
  MCPH_DISABLE_PERSISTENCE Disable cross-session learning state.
7921
7984
 
@@ -7935,7 +7998,7 @@ if (subcommand === "compliance") {
7935
7998
  `);
7936
7999
  process.exit(0);
7937
8000
  } else if (subcommand === "--version" || subcommand === "-V") {
7938
- process.stdout.write(`mcph ${true ? "0.47.8" : "dev"}
8001
+ process.stdout.write(`mcph ${true ? "0.49.0" : "dev"}
7939
8002
  `);
7940
8003
  process.exit(0);
7941
8004
  } else if (subcommand && !subcommand.startsWith("-")) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@yawlabs/mcph",
3
- "version": "0.47.8",
3
+ "version": "0.49.0",
4
4
  "description": "mcp.hosting — one install, all your MCP servers, managed from the cloud",
5
5
  "license": "UNLICENSED",
6
6
  "author": "Yaw Labs <support@mcp.hosting> (https://mcp.hosting)",