@yawlabs/mcph 0.47.4 → 0.47.6

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 +129 -67
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -292,11 +292,11 @@ async function readConfigAt(path5, scope, warnings) {
292
292
  `${path5}: schema version ${version} is newer than this mcph (${CURRENT_SCHEMA_VERSION}); upgrade with \`npm i -g @yawlabs/mcph@latest\`. Loading best-effort.`
293
293
  );
294
294
  }
295
- const token5 = typeof obj.token === "string" && obj.token.length > 0 ? obj.token : void 0;
295
+ const token6 = typeof obj.token === "string" && obj.token.length > 0 ? obj.token : void 0;
296
296
  const apiBase = typeof obj.apiBase === "string" && obj.apiBase.length > 0 ? obj.apiBase : void 0;
297
297
  const servers = Array.isArray(obj.servers) ? obj.servers.filter((v) => typeof v === "string") : void 0;
298
298
  const blocked = Array.isArray(obj.blocked) ? obj.blocked.filter((v) => typeof v === "string") : void 0;
299
- if (token5) {
299
+ if (token6) {
300
300
  if (scope === "project") {
301
301
  warnings.push(
302
302
  `${path5}: 'token' should not appear in a project-shared file. Move it to ${CONFIG_DIRNAME}/${LOCAL_CONFIG_FILENAME} (gitignored) or ~/${CONFIG_DIRNAME}/${CONFIG_FILENAME}.`
@@ -304,7 +304,7 @@ async function readConfigAt(path5, scope, warnings) {
304
304
  }
305
305
  await checkPermissions(path5, warnings);
306
306
  }
307
- return { path: path5, scope, version, token: token5, apiBase, servers, blocked };
307
+ return { path: path5, scope, version, token: token6, apiBase, servers, blocked };
308
308
  }
309
309
  async function checkPermissions(path5, warnings) {
310
310
  if (process.platform === "win32") return;
@@ -361,16 +361,16 @@ async function loadMcphConfig(opts = {}) {
361
361
  if (project) loadedFiles.push(project);
362
362
  const global = await readConfigAt(globalPath, "global", warnings);
363
363
  if (global) loadedFiles.push(global);
364
- let token5 = null;
364
+ let token6 = null;
365
365
  let tokenSource = "missing";
366
366
  if (typeof env.MCPH_TOKEN === "string" && env.MCPH_TOKEN.length > 0) {
367
- token5 = env.MCPH_TOKEN;
367
+ token6 = env.MCPH_TOKEN;
368
368
  tokenSource = "env";
369
369
  } else if (local?.token) {
370
- token5 = local.token;
370
+ token6 = local.token;
371
371
  tokenSource = "local";
372
372
  } else if (global?.token) {
373
- token5 = global.token;
373
+ token6 = global.token;
374
374
  tokenSource = "global";
375
375
  }
376
376
  let apiBase = DEFAULT_API_BASE;
@@ -389,7 +389,7 @@ async function loadMcphConfig(opts = {}) {
389
389
  apiBaseSource = "global";
390
390
  }
391
391
  return {
392
- token: token5,
392
+ token: token6,
393
393
  tokenSource,
394
394
  apiBase,
395
395
  apiBaseSource,
@@ -400,10 +400,10 @@ async function loadMcphConfig(opts = {}) {
400
400
  warnings
401
401
  };
402
402
  }
403
- function tokenFingerprint(token5) {
404
- if (!token5) return "(none)";
405
- if (token5.length <= 8) return `***${token5.slice(-2)}`;
406
- return `${token5.slice(0, 8)}\u2026${token5.slice(-4)}`;
403
+ function tokenFingerprint(token6) {
404
+ if (!token6) return "(none)";
405
+ if (token6.length <= 8) return `***${token6.slice(-2)}`;
406
+ return `${token6.slice(0, 8)}\u2026${token6.slice(-4)}`;
407
407
  }
408
408
  function toProfile(config) {
409
409
  if (config.servers === void 0 && config.blocked === void 0) return null;
@@ -442,10 +442,10 @@ function profileAllows(profile, namespace) {
442
442
 
443
443
  // src/config.ts
444
444
  import { request } from "undici";
445
- async function fetchConfig(apiUrl5, token5, currentVersion) {
446
- const url = `${apiUrl5.replace(/\/$/, "")}/api/connect/config`;
445
+ async function fetchConfig(apiUrl6, token6, currentVersion) {
446
+ const url = `${apiUrl6.replace(/\/$/, "")}/api/connect/config`;
447
447
  const headers = {
448
- Authorization: `Bearer ${token5}`,
448
+ Authorization: `Bearer ${token6}`,
449
449
  Accept: "application/json"
450
450
  };
451
451
  if (currentVersion) {
@@ -466,7 +466,7 @@ async function fetchConfig(apiUrl5, token5, currentVersion) {
466
466
  await res.body.text().catch(() => {
467
467
  });
468
468
  throw new ConfigError(
469
- `Token rejected (HTTP 401) \u2014 the token ${tokenFingerprint(token5)} is invalid or revoked.
469
+ `Token rejected (HTTP 401) \u2014 the token ${tokenFingerprint(token6)} is invalid or revoked.
470
470
  Generate a new token at https://mcp.hosting/dashboard/settings/tokens,
471
471
  then re-run \`mcph install <client> --token mcp_pat_...\` or set MCPH_TOKEN.`,
472
472
  true
@@ -476,7 +476,7 @@ async function fetchConfig(apiUrl5, token5, currentVersion) {
476
476
  await res.body.text().catch(() => {
477
477
  });
478
478
  throw new ConfigError(
479
- `Access denied (HTTP 403) \u2014 the token ${tokenFingerprint(token5)} was accepted but lacks permission to read this account's servers.
479
+ `Access denied (HTTP 403) \u2014 the token ${tokenFingerprint(token6)} was accepted but lacks permission to read this account's servers.
480
480
  The account may be suspended or the token scope reduced \u2014 check
481
481
  https://mcp.hosting/dashboard/settings/tokens, or reach support@mcp.hosting.`,
482
482
  true
@@ -900,12 +900,12 @@ async function runComplianceCommand(argv) {
900
900
  );
901
901
  return 1;
902
902
  }
903
- const apiUrl5 = process.env.MCPH_URL ?? "https://mcp.hosting";
903
+ const apiUrl6 = process.env.MCPH_URL ?? "https://mcp.hosting";
904
904
  const report = await runTest(args);
905
905
  if (!report) return 1;
906
906
  printSummary(report);
907
907
  if (publish) {
908
- const result = await publishReport(apiUrl5, report);
908
+ const result = await publishReport(apiUrl6, report);
909
909
  if (!result) return 1;
910
910
  process.stdout.write(`
911
911
  Published: ${result.reportUrl}
@@ -965,9 +965,9 @@ Target: ${url}
965
965
  `
966
966
  );
967
967
  }
968
- async function publishReport(apiUrl5, report) {
968
+ async function publishReport(apiUrl6, report) {
969
969
  try {
970
- const res = await request2(`${apiUrl5.replace(/\/$/, "")}/api/compliance/ext`, {
970
+ const res = await request2(`${apiUrl6.replace(/\/$/, "")}/api/compliance/ext`, {
971
971
  method: "POST",
972
972
  headers: { "Content-Type": "application/json" },
973
973
  body: JSON.stringify(report)
@@ -1650,7 +1650,7 @@ function selectFlakyNamespaces(entries, limit) {
1650
1650
  }
1651
1651
 
1652
1652
  // src/doctor-cmd.ts
1653
- var VERSION = true ? "0.47.4" : "dev";
1653
+ var VERSION = true ? "0.47.6" : "dev";
1654
1654
  async function runDoctor(opts = {}) {
1655
1655
  if (opts.json) return runDoctorJson(opts);
1656
1656
  const lines = [];
@@ -2348,12 +2348,12 @@ ${USAGE}`);
2348
2348
  }
2349
2349
  log2(`Target: ${target.label} (${scope})`);
2350
2350
  log2(`File: ${resolved.absolute}`);
2351
- let token5 = opts.token ?? null;
2352
- if (!token5) {
2351
+ let token6 = opts.token ?? null;
2352
+ if (!token6) {
2353
2353
  const cfg = await loadMcphConfig({ home: opts.home, cwd: process.cwd(), env: {} });
2354
- token5 = cfg.token;
2354
+ token6 = cfg.token;
2355
2355
  }
2356
- if (!token5) {
2356
+ if (!token6) {
2357
2357
  err(
2358
2358
  "\nmcph install: no token available.\n Pass one with --token mcp_pat_\u2026, or run `mcph install` with --token once to seed ~/.mcph/config.json,\n or create the token at https://mcp.hosting \u2192 Settings \u2192 API Tokens."
2359
2359
  );
@@ -2423,7 +2423,7 @@ ${USAGE}`);
2423
2423
  const writeMcphConfig = !opts.skipMcphConfig;
2424
2424
  const home = opts.home ?? homedir5();
2425
2425
  const mcphConfigPath = join5(home, CONFIG_DIRNAME, CONFIG_FILENAME);
2426
- const mcphConfigComposed = await composeMcphConfig(mcphConfigPath, token5);
2426
+ const mcphConfigComposed = await composeMcphConfig(mcphConfigPath, token6);
2427
2427
  if (mcphConfigComposed.backupPath) {
2428
2428
  log2(
2429
2429
  `mcph install: existing ${mcphConfigPath} was malformed; original bytes backed up to ${mcphConfigComposed.backupPath} before overwriting.`
@@ -2579,7 +2579,7 @@ function mergeClientConfig(existing, containerPath, entry) {
2579
2579
  parent[leafKey] = container;
2580
2580
  return out;
2581
2581
  }
2582
- async function composeMcphConfig(path5, token5) {
2582
+ async function composeMcphConfig(path5, token6) {
2583
2583
  let existing = {};
2584
2584
  let backupPath;
2585
2585
  if (existsSync2(path5)) {
@@ -2606,7 +2606,7 @@ async function composeMcphConfig(path5, token5) {
2606
2606
  }
2607
2607
  }
2608
2608
  const next = { version: CURRENT_SCHEMA_VERSION, ...existing };
2609
- next.token = token5;
2609
+ next.token = token6;
2610
2610
  if (typeof next.version !== "number") next.version = CURRENT_SCHEMA_VERSION;
2611
2611
  return { json: `${JSON.stringify(next, null, 2)}
2612
2612
  `, backupPath };
@@ -2903,7 +2903,7 @@ import {
2903
2903
  ListToolsRequestSchema,
2904
2904
  ReadResourceRequestSchema
2905
2905
  } from "@modelcontextprotocol/sdk/types.js";
2906
- import { request as request8 } from "undici";
2906
+ import { request as request9 } from "undici";
2907
2907
 
2908
2908
  // src/compliance.ts
2909
2909
  var GRADE_ORDER = {
@@ -3336,6 +3336,50 @@ function truncateForWarning(msg) {
3336
3336
  return clean.length > 120 ? `${clean.slice(0, 117)}...` : clean;
3337
3337
  }
3338
3338
 
3339
+ // src/heartbeat.ts
3340
+ import { request as request5 } from "undici";
3341
+ var HEARTBEAT_PATH = "/api/connect/heartbeat";
3342
+ var apiUrl3 = "";
3343
+ var token3 = "";
3344
+ function initHeartbeat(url, tok) {
3345
+ apiUrl3 = url;
3346
+ token3 = tok;
3347
+ }
3348
+ async function reportHeartbeat(clientName, clientVersion, isRefresh = false) {
3349
+ if (!apiUrl3 || !token3) return;
3350
+ try {
3351
+ const res = await request5(`${apiUrl3.replace(/\/$/, "")}${HEARTBEAT_PATH}`, {
3352
+ method: "POST",
3353
+ headers: {
3354
+ Authorization: `Bearer ${token3}`,
3355
+ "Content-Type": "application/json"
3356
+ },
3357
+ body: JSON.stringify({
3358
+ // Pass through whatever the AI client self-reported. Backend
3359
+ // normalizes (fallback to 'unknown', length caps) — keep this
3360
+ // side dumb so a backend tightening doesn't need a CLI roll.
3361
+ clientName: clientName ?? null,
3362
+ clientVersion: clientVersion ?? null,
3363
+ isRefresh
3364
+ }),
3365
+ headersTimeout: 1e4,
3366
+ bodyTimeout: 1e4
3367
+ });
3368
+ await res.body.text().catch(() => {
3369
+ });
3370
+ if (res.statusCode >= 400 && res.statusCode !== 404) {
3371
+ log("warn", "Heartbeat failed", { status: res.statusCode, isRefresh });
3372
+ } else if (!isRefresh) {
3373
+ log("info", "Reported AI client connect to mcp.hosting", {
3374
+ clientName: clientName ?? null,
3375
+ clientVersion: clientVersion ?? null
3376
+ });
3377
+ }
3378
+ } catch (err) {
3379
+ log("warn", "Heartbeat error", { error: err?.message, isRefresh });
3380
+ }
3381
+ }
3382
+
3339
3383
  // src/idle-ttl.ts
3340
3384
  var ADAPTIVE_WINDOW_MS = 5 * 60 * 1e3;
3341
3385
  var ADAPTIVE_LOOKBACK = 20;
@@ -3944,9 +3988,9 @@ var PackDetector = class {
3944
3988
 
3945
3989
  // src/progress.ts
3946
3990
  function createProgressReporter(extra) {
3947
- const token5 = extra?._meta?.progressToken;
3991
+ const token6 = extra?._meta?.progressToken;
3948
3992
  const send = extra?.sendNotification;
3949
- if (token5 === void 0 || token5 === null || !send) {
3993
+ if (token6 === void 0 || token6 === null || !send) {
3950
3994
  return () => {
3951
3995
  };
3952
3996
  }
@@ -3954,7 +3998,7 @@ function createProgressReporter(extra) {
3954
3998
  return (message, progress, total) => {
3955
3999
  step += 1;
3956
4000
  const params = {
3957
- progressToken: token5,
4001
+ progressToken: token6,
3958
4002
  progress: progress ?? step,
3959
4003
  message
3960
4004
  };
@@ -4408,26 +4452,26 @@ function rankServers(context, servers) {
4408
4452
  }
4409
4453
 
4410
4454
  // src/rerank.ts
4411
- import { request as request5 } from "undici";
4412
- var apiUrl3 = "";
4413
- var token3 = "";
4455
+ import { request as request6 } from "undici";
4456
+ var apiUrl4 = "";
4457
+ var token4 = "";
4414
4458
  var RERANK_TIMEOUT_MS = 2e3;
4415
4459
  function initRerank(url, tok) {
4416
- apiUrl3 = url;
4417
- token3 = tok;
4460
+ apiUrl4 = url;
4461
+ token4 = tok;
4418
4462
  }
4419
4463
  async function rerank(intent, candidateIds, limit) {
4420
- if (!apiUrl3 || !token3) return null;
4464
+ if (!apiUrl4 || !token4) return null;
4421
4465
  if (!intent?.trim()) return null;
4422
4466
  if (candidateIds !== void 0 && candidateIds.length === 0) return null;
4423
4467
  const payload = { intent: intent.trim() };
4424
4468
  if (candidateIds && candidateIds.length > 0) payload.candidateIds = candidateIds;
4425
4469
  if (typeof limit === "number" && limit > 0) payload.limit = limit;
4426
4470
  try {
4427
- const res = await request5(`${apiUrl3.replace(/\/$/, "")}/api/connect/rerank`, {
4471
+ const res = await request6(`${apiUrl4.replace(/\/$/, "")}/api/connect/rerank`, {
4428
4472
  method: "POST",
4429
4473
  headers: {
4430
- Authorization: `Bearer ${token3}`,
4474
+ Authorization: `Bearer ${token4}`,
4431
4475
  "Content-Type": "application/json"
4432
4476
  },
4433
4477
  body: JSON.stringify(payload),
@@ -4457,14 +4501,14 @@ async function rerank(intent, candidateIds, limit) {
4457
4501
 
4458
4502
  // src/runtime-detect.ts
4459
4503
  import { spawn as spawn2 } from "child_process";
4460
- import { request as request6 } from "undici";
4504
+ import { request as request7 } from "undici";
4461
4505
  var PROBE_TIMEOUT_MS = 3e3;
4462
4506
  var RUNTIME_REPORT_PATH = "/api/connect/runtimes";
4463
- var apiUrl4 = "";
4464
- var token4 = "";
4507
+ var apiUrl5 = "";
4508
+ var token5 = "";
4465
4509
  function initRuntimeDetect(url, tok) {
4466
- apiUrl4 = url;
4467
- token4 = tok;
4510
+ apiUrl5 = url;
4511
+ token5 = tok;
4468
4512
  }
4469
4513
  var PROBES = {
4470
4514
  node: {
@@ -4576,7 +4620,7 @@ async function detectRuntimes() {
4576
4620
  return out;
4577
4621
  }
4578
4622
  async function reportRuntimes() {
4579
- if (!apiUrl4 || !token4) return;
4623
+ if (!apiUrl5 || !token5) return;
4580
4624
  let runtimes;
4581
4625
  try {
4582
4626
  runtimes = await detectRuntimes();
@@ -4585,10 +4629,10 @@ async function reportRuntimes() {
4585
4629
  return;
4586
4630
  }
4587
4631
  try {
4588
- const res = await request6(`${apiUrl4.replace(/\/$/, "")}${RUNTIME_REPORT_PATH}`, {
4632
+ const res = await request7(`${apiUrl5.replace(/\/$/, "")}${RUNTIME_REPORT_PATH}`, {
4589
4633
  method: "POST",
4590
4634
  headers: {
4591
- Authorization: `Bearer ${token4}`,
4635
+ Authorization: `Bearer ${token5}`,
4592
4636
  "Content-Type": "application/json"
4593
4637
  },
4594
4638
  body: JSON.stringify({ runtimes }),
@@ -4745,7 +4789,7 @@ import { createWriteStream } from "fs";
4745
4789
  import fs from "fs/promises";
4746
4790
  import path4 from "path";
4747
4791
  import { pipeline } from "stream/promises";
4748
- import { request as request7 } from "undici";
4792
+ import { request as request8 } from "undici";
4749
4793
  var UV_VERSION = "0.11.7";
4750
4794
  var RELEASE_BASE = `https://github.com/astral-sh/uv/releases/download/${UV_VERSION}`;
4751
4795
  function uvTarget() {
@@ -4822,7 +4866,7 @@ async function onPath(cmd) {
4822
4866
  async function fetchWithRedirects(url, maxHops = 5) {
4823
4867
  let current = url;
4824
4868
  for (let i = 0; i < maxHops; i++) {
4825
- const res = await request7(current, { method: "GET" });
4869
+ const res = await request8(current, { method: "GET" });
4826
4870
  if (res.statusCode >= 300 && res.statusCode < 400) {
4827
4871
  const loc = res.headers.location;
4828
4872
  if (!loc) throw new Error(`Redirect without Location header from ${current}`);
@@ -4971,7 +5015,7 @@ function categorizeSpawnError(err) {
4971
5015
  }
4972
5016
  async function connectToUpstream(config, onDisconnect, onListChanged) {
4973
5017
  const client = new Client(
4974
- { name: "mcph", version: true ? "0.47.4" : "dev" },
5018
+ { name: "mcph", version: true ? "0.47.6" : "dev" },
4975
5019
  { capabilities: {} }
4976
5020
  );
4977
5021
  let transport;
@@ -5275,11 +5319,11 @@ function computeToolOverlaps(connections) {
5275
5319
  return overlaps;
5276
5320
  }
5277
5321
  var ConnectServer = class _ConnectServer {
5278
- constructor(apiUrl5, token5) {
5279
- this.apiUrl = apiUrl5;
5280
- this.token = token5;
5322
+ constructor(apiUrl6, token6) {
5323
+ this.apiUrl = apiUrl6;
5324
+ this.token = token6;
5281
5325
  this.server = new Server(
5282
- { name: "mcph", version: true ? "0.47.4" : "dev" },
5326
+ { name: "mcph", version: true ? "0.47.6" : "dev" },
5283
5327
  {
5284
5328
  capabilities: {
5285
5329
  tools: { listChanged: true },
@@ -5297,6 +5341,10 @@ var ConnectServer = class _ConnectServer {
5297
5341
  config = null;
5298
5342
  configVersion = null;
5299
5343
  pollTimer = null;
5344
+ // Flipped true once the first MCP `initialize` lands (see
5345
+ // this.server.oninitialized). Gates the per-poll heartbeat refresh so
5346
+ // we only ping liveness while a client is actually attached.
5347
+ aiClientAttached = false;
5300
5348
  toolRoutes = /* @__PURE__ */ new Map();
5301
5349
  resourceRoutes = /* @__PURE__ */ new Map();
5302
5350
  promptRoutes = /* @__PURE__ */ new Map();
@@ -5420,23 +5468,23 @@ var ConnectServer = class _ConnectServer {
5420
5468
  this.server.setRequestHandler(ListToolsRequestSchema, async () => ({
5421
5469
  tools: buildToolList(this.connections, this.getDeferredServers(), this.toolFilters)
5422
5470
  }));
5423
- this.server.setRequestHandler(CallToolRequestSchema, async (request9, extra) => {
5424
- const { name, arguments: args } = request9.params;
5471
+ this.server.setRequestHandler(CallToolRequestSchema, async (request10, extra) => {
5472
+ const { name, arguments: args } = request10.params;
5425
5473
  return this.handleToolCall(name, args ?? {}, extra);
5426
5474
  });
5427
5475
  this.server.setRequestHandler(ListResourcesRequestSchema, async () => ({
5428
5476
  resources: buildResourceList(this.connections, this.getBuiltinResources())
5429
5477
  }));
5430
- this.server.setRequestHandler(ReadResourceRequestSchema, async (request9) => {
5431
- return routeResourceRead(request9.params.uri, this.resourceRoutes, this.connections, this.getBuiltinResourceMap());
5478
+ this.server.setRequestHandler(ReadResourceRequestSchema, async (request10) => {
5479
+ return routeResourceRead(request10.params.uri, this.resourceRoutes, this.connections, this.getBuiltinResourceMap());
5432
5480
  });
5433
5481
  this.server.setRequestHandler(ListPromptsRequestSchema, async () => ({
5434
5482
  prompts: buildPromptList(this.connections)
5435
5483
  }));
5436
- this.server.setRequestHandler(GetPromptRequestSchema, async (request9) => {
5484
+ this.server.setRequestHandler(GetPromptRequestSchema, async (request10) => {
5437
5485
  return routePromptGet(
5438
- request9.params.name,
5439
- request9.params.arguments,
5486
+ request10.params.name,
5487
+ request10.params.arguments,
5440
5488
  this.promptRoutes,
5441
5489
  this.connections
5442
5490
  );
@@ -5541,10 +5589,18 @@ var ConnectServer = class _ConnectServer {
5541
5589
  initToolReport(this.apiUrl, this.token);
5542
5590
  initRerank(this.apiUrl, this.token);
5543
5591
  initRuntimeDetect(this.apiUrl, this.token);
5592
+ initHeartbeat(this.apiUrl, this.token);
5544
5593
  reportRuntimes().catch((err) => log("warn", "reportRuntimes failed", { error: err?.message }));
5545
5594
  if (this.config?.servers.some((s) => s.command === "uv" || s.command === "uvx")) {
5546
5595
  ensureUv().catch((err) => log("warn", "uv prewarm failed", { error: err?.message }));
5547
5596
  }
5597
+ this.server.oninitialized = () => {
5598
+ this.aiClientAttached = true;
5599
+ const info = this.server.getClientVersion();
5600
+ reportHeartbeat(info?.name, info?.version).catch(
5601
+ (err) => log("warn", "reportHeartbeat failed", { error: err?.message })
5602
+ );
5603
+ };
5548
5604
  const transport = new StdioServerTransport();
5549
5605
  await this.server.connect(transport);
5550
5606
  this.startPolling();
@@ -6708,6 +6764,12 @@ ${activeCount} loaded in this session, ${totalTools} tools in context${tokenSumm
6708
6764
  } catch (err) {
6709
6765
  log("warn", "Config poll failed", { error: err.message });
6710
6766
  }
6767
+ if (this.aiClientAttached) {
6768
+ const info = this.server.getClientVersion();
6769
+ reportHeartbeat(info?.name, info?.version, true).catch(
6770
+ (err) => log("warn", "reportHeartbeat refresh failed", { error: err?.message })
6771
+ );
6772
+ }
6711
6773
  this.pollTimer = setTimeout(poll, intervalMs);
6712
6774
  if (this.pollTimer.unref) this.pollTimer.unref();
6713
6775
  };
@@ -6781,7 +6843,7 @@ ${activeCount} loaded in this session, ${totalTools} tools in context${tokenSumm
6781
6843
  nsToKeys.set(s.namespace, existing);
6782
6844
  }
6783
6845
  const collisions = [...nsToKeys.entries()].filter(([, keys]) => keys.length > 1);
6784
- const res = await request8(`${this.apiUrl.replace(/\/$/, "")}/api/connect/import`, {
6846
+ const res = await request9(`${this.apiUrl.replace(/\/$/, "")}/api/connect/import`, {
6785
6847
  method: "POST",
6786
6848
  headers: {
6787
6849
  Authorization: `Bearer ${this.token}`,
@@ -6842,7 +6904,7 @@ Use mcp_connect_discover to see imported servers.`
6842
6904
  }
6843
6905
  const payload = built.payload;
6844
6906
  try {
6845
- const res = await request8(`${this.apiUrl.replace(/\/$/, "")}/api/connect/servers`, {
6907
+ const res = await request9(`${this.apiUrl.replace(/\/$/, "")}/api/connect/servers`, {
6846
6908
  method: "POST",
6847
6909
  headers: {
6848
6910
  Authorization: `Bearer ${this.token}`,
@@ -7640,7 +7702,7 @@ Or re-run with --run to upgrade in place.`);
7640
7702
  return { exitCode: 3, lines };
7641
7703
  }
7642
7704
  function readCurrentVersion() {
7643
- return true ? "0.47.4" : "dev";
7705
+ return true ? "0.47.6" : "dev";
7644
7706
  }
7645
7707
 
7646
7708
  // src/index.ts
@@ -7808,7 +7870,7 @@ if (subcommand === "compliance") {
7808
7870
  `);
7809
7871
  process.exit(0);
7810
7872
  } else if (subcommand === "--version" || subcommand === "-V") {
7811
- process.stdout.write(`mcph ${true ? "0.47.4" : "dev"}
7873
+ process.stdout.write(`mcph ${true ? "0.47.6" : "dev"}
7812
7874
  `);
7813
7875
  process.exit(0);
7814
7876
  } else if (subcommand && !subcommand.startsWith("-")) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@yawlabs/mcph",
3
- "version": "0.47.4",
3
+ "version": "0.47.6",
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)",