@yawlabs/mcph 0.38.0 → 0.39.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.
- package/CHANGELOG.md +4 -0
- package/dist/index.js +118 -4
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,10 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to `@yawlabs/mcph` are documented here. This project uses [semantic versioning](https://semver.org) and a CI-gated release flow: pushing a `vX.Y.Z` tag triggers `.github/workflows/release.yml`, which publishes to npm.
|
|
4
4
|
|
|
5
|
+
## 0.39.0 — 2026-04-18
|
|
6
|
+
|
|
7
|
+
- **`mcph servers` CLI subcommand** — Lists the servers currently configured for your account in the mcp.hosting dashboard, hitting the same `/api/connect/config` endpoint that `runServer` polls at startup. Fills a gap between `mcph doctor` (local state: config files, clients, state.json) and the web dashboard: users can sanity-check their dashboard edits from the terminal, support engineers can ask for `mcph servers --json` output in a ticket, and scripts can pick a namespace up-front before piping into `mcph compliance` or `mcph install`. Table view groups the relevant columns (namespace, name, type, enabled/disabled, compliance grade, cached tool count) and is sorted alphabetically by namespace for diffable re-runs; `--json` emits the raw backend response verbatim. Exit codes: 0 success, 1 no token, 2 fetch error.
|
|
8
|
+
|
|
5
9
|
## 0.38.0 — 2026-04-18
|
|
6
10
|
|
|
7
11
|
- **`mcph reset-learning` CLI subcommand** — Deletes `~/.mcph/state.json` so cross-session learning starts fresh; prints the entry counts that were cleared. Pairs with v0.37.0's doctor RELIABILITY section: once a namespace has been flagged flaky, the dispatch penalty branch (v0.36.0) keeps suppressing it until enough new successes pile up — but if the user has since fixed the underlying cause (rotated a token, swapped the upstream, re-authed), that history is stale and the penalty has overstayed its welcome. This gives them a direct CLI lever to clear it. Scope is all-or-nothing by design; a per-namespace flag is footgunny (user clears one, forgets the others, keeps getting silently mis-ranked). No-op with an explanatory message when `MCPH_DISABLE_PERSISTENCE` is set or the file doesn't exist, so `mcph reset-learning` never surprises. Exit 0 on success or no-op, exit 1 on I/O error (permissions, disk).
|
package/dist/index.js
CHANGED
|
@@ -1004,7 +1004,7 @@ function selectFlakyNamespaces(entries, limit) {
|
|
|
1004
1004
|
}
|
|
1005
1005
|
|
|
1006
1006
|
// src/doctor-cmd.ts
|
|
1007
|
-
var VERSION = true ? "0.
|
|
1007
|
+
var VERSION = true ? "0.39.0" : "dev";
|
|
1008
1008
|
async function runDoctor(opts = {}) {
|
|
1009
1009
|
const lines = [];
|
|
1010
1010
|
const write = opts.out ?? ((s) => process.stdout.write(s));
|
|
@@ -4065,7 +4065,7 @@ function categorizeSpawnError(err) {
|
|
|
4065
4065
|
}
|
|
4066
4066
|
async function connectToUpstream(config, onDisconnect, onListChanged) {
|
|
4067
4067
|
const client = new Client(
|
|
4068
|
-
{ name: "mcph", version: true ? "0.
|
|
4068
|
+
{ name: "mcph", version: true ? "0.39.0" : "dev" },
|
|
4069
4069
|
{ capabilities: {} }
|
|
4070
4070
|
);
|
|
4071
4071
|
let transport;
|
|
@@ -4546,7 +4546,7 @@ var ConnectServer = class _ConnectServer {
|
|
|
4546
4546
|
this.apiUrl = apiUrl6;
|
|
4547
4547
|
this.token = token6;
|
|
4548
4548
|
this.server = new Server(
|
|
4549
|
-
{ name: "mcph", version: true ? "0.
|
|
4549
|
+
{ name: "mcph", version: true ? "0.39.0" : "dev" },
|
|
4550
4550
|
{
|
|
4551
4551
|
capabilities: {
|
|
4552
4552
|
tools: { listChanged: true },
|
|
@@ -6598,12 +6598,117 @@ To load the top pack in one step, call \`mcp_connect_activate\` with namespaces=
|
|
|
6598
6598
|
}
|
|
6599
6599
|
};
|
|
6600
6600
|
|
|
6601
|
+
// src/servers-cmd.ts
|
|
6602
|
+
function parseServersArgs(argv) {
|
|
6603
|
+
let json = false;
|
|
6604
|
+
for (const a of argv) {
|
|
6605
|
+
if (a === "--json") {
|
|
6606
|
+
json = true;
|
|
6607
|
+
} else if (a === "--help" || a === "-h") {
|
|
6608
|
+
return { ok: false, error: SERVERS_USAGE };
|
|
6609
|
+
} else {
|
|
6610
|
+
return { ok: false, error: `mcph servers: unknown argument "${a}"
|
|
6611
|
+
|
|
6612
|
+
${SERVERS_USAGE}` };
|
|
6613
|
+
}
|
|
6614
|
+
}
|
|
6615
|
+
return { ok: true, options: { json } };
|
|
6616
|
+
}
|
|
6617
|
+
var SERVERS_USAGE = `Usage: mcph servers [--json]
|
|
6618
|
+
|
|
6619
|
+
List the servers configured in your mcp.hosting dashboard.
|
|
6620
|
+
|
|
6621
|
+
--json Emit machine-readable JSON instead of a table.`;
|
|
6622
|
+
async function runServersCommand(opts = {}) {
|
|
6623
|
+
const write = opts.out ?? ((s) => process.stdout.write(s));
|
|
6624
|
+
const writeErr = opts.err ?? ((s) => process.stderr.write(s));
|
|
6625
|
+
const lines = [];
|
|
6626
|
+
const print = (s = "") => {
|
|
6627
|
+
lines.push(s);
|
|
6628
|
+
write(`${s}
|
|
6629
|
+
`);
|
|
6630
|
+
};
|
|
6631
|
+
const printErr = (s) => {
|
|
6632
|
+
lines.push(s);
|
|
6633
|
+
writeErr(`${s}
|
|
6634
|
+
`);
|
|
6635
|
+
};
|
|
6636
|
+
const config = await loadMcphConfig({
|
|
6637
|
+
cwd: opts.cwd,
|
|
6638
|
+
home: opts.home,
|
|
6639
|
+
env: opts.env
|
|
6640
|
+
});
|
|
6641
|
+
if (!config.token) {
|
|
6642
|
+
printErr("mcph servers: no token resolved. Run `mcph install <client> --token mcp_pat_\u2026` or set MCPH_TOKEN.");
|
|
6643
|
+
return { exitCode: 1, lines };
|
|
6644
|
+
}
|
|
6645
|
+
const fetcher = opts.fetcher ?? fetchConfig;
|
|
6646
|
+
let backend;
|
|
6647
|
+
try {
|
|
6648
|
+
backend = await fetcher(config.apiBase, config.token);
|
|
6649
|
+
} catch (err) {
|
|
6650
|
+
const msg = err instanceof ConfigError || err instanceof Error ? err.message : String(err);
|
|
6651
|
+
printErr(`mcph servers: ${msg}`);
|
|
6652
|
+
return { exitCode: 2, lines };
|
|
6653
|
+
}
|
|
6654
|
+
if (!backend) {
|
|
6655
|
+
printErr("mcph servers: backend returned no data (unexpected 304).");
|
|
6656
|
+
return { exitCode: 2, lines };
|
|
6657
|
+
}
|
|
6658
|
+
if (opts.json) {
|
|
6659
|
+
print(JSON.stringify(backend, null, 2));
|
|
6660
|
+
return { exitCode: 0, lines };
|
|
6661
|
+
}
|
|
6662
|
+
renderTable(backend, print);
|
|
6663
|
+
return { exitCode: 0, lines };
|
|
6664
|
+
}
|
|
6665
|
+
function renderTable(cfg, print) {
|
|
6666
|
+
const servers = cfg.servers;
|
|
6667
|
+
if (servers.length === 0) {
|
|
6668
|
+
print("No servers configured yet. Visit https://mcp.hosting to add one.");
|
|
6669
|
+
return;
|
|
6670
|
+
}
|
|
6671
|
+
const version = cfg.configVersion ? ` (config ${truncateVersion(cfg.configVersion)})` : "";
|
|
6672
|
+
const active = servers.filter((s) => s.isActive).length;
|
|
6673
|
+
const disabled = servers.length - active;
|
|
6674
|
+
const summary = disabled === 0 ? `${servers.length} server${servers.length === 1 ? "" : "s"}` : `${servers.length} servers (${active} enabled, ${disabled} disabled)`;
|
|
6675
|
+
print(`${summary}${version}`);
|
|
6676
|
+
print("");
|
|
6677
|
+
const rows = servers.map((s) => ({
|
|
6678
|
+
namespace: s.namespace,
|
|
6679
|
+
name: s.name,
|
|
6680
|
+
type: s.type,
|
|
6681
|
+
status: s.isActive ? "enabled" : "disabled",
|
|
6682
|
+
grade: s.complianceGrade ?? "-",
|
|
6683
|
+
tools: s.toolCache ? String(s.toolCache.length) : "?"
|
|
6684
|
+
}));
|
|
6685
|
+
const widths = {
|
|
6686
|
+
namespace: Math.max("NAMESPACE".length, ...rows.map((r) => r.namespace.length)),
|
|
6687
|
+
name: Math.max("NAME".length, ...rows.map((r) => r.name.length)),
|
|
6688
|
+
type: Math.max("TYPE".length, ...rows.map((r) => r.type.length)),
|
|
6689
|
+
status: Math.max("STATUS".length, ...rows.map((r) => r.status.length)),
|
|
6690
|
+
grade: Math.max("GRADE".length, ...rows.map((r) => r.grade.length)),
|
|
6691
|
+
tools: Math.max("TOOLS".length, ...rows.map((r) => r.tools.length))
|
|
6692
|
+
};
|
|
6693
|
+
const header = ` ${"NAMESPACE".padEnd(widths.namespace)} ${"NAME".padEnd(widths.name)} ${"TYPE".padEnd(widths.type)} ${"STATUS".padEnd(widths.status)} ${"GRADE".padEnd(widths.grade)} ${"TOOLS".padStart(widths.tools)}`;
|
|
6694
|
+
print(header);
|
|
6695
|
+
const sorted = [...rows].sort((a, b) => a.namespace.localeCompare(b.namespace));
|
|
6696
|
+
for (const r of sorted) {
|
|
6697
|
+
const line = ` ${r.namespace.padEnd(widths.namespace)} ${r.name.padEnd(widths.name)} ${r.type.padEnd(widths.type)} ${r.status.padEnd(widths.status)} ${r.grade.padEnd(widths.grade)} ${r.tools.padStart(widths.tools)}`;
|
|
6698
|
+
print(line);
|
|
6699
|
+
}
|
|
6700
|
+
}
|
|
6701
|
+
function truncateVersion(v) {
|
|
6702
|
+
return v.length > 8 ? v.slice(0, 8) : v;
|
|
6703
|
+
}
|
|
6704
|
+
|
|
6601
6705
|
// src/index.ts
|
|
6602
6706
|
var KNOWN_SUBCOMMANDS = [
|
|
6603
6707
|
"compliance",
|
|
6604
6708
|
"install",
|
|
6605
6709
|
"doctor",
|
|
6606
6710
|
"reset-learning",
|
|
6711
|
+
"servers",
|
|
6607
6712
|
"help",
|
|
6608
6713
|
"--help",
|
|
6609
6714
|
"-h",
|
|
@@ -6625,6 +6730,14 @@ if (subcommand === "compliance") {
|
|
|
6625
6730
|
runDoctor().then((r) => process.exit(r.exitCode));
|
|
6626
6731
|
} else if (subcommand === "reset-learning") {
|
|
6627
6732
|
runResetLearning().then((r) => process.exit(r.exitCode));
|
|
6733
|
+
} else if (subcommand === "servers") {
|
|
6734
|
+
const parsed = parseServersArgs(process.argv.slice(3));
|
|
6735
|
+
if (!parsed.ok) {
|
|
6736
|
+
process.stderr.write(`${parsed.error}
|
|
6737
|
+
`);
|
|
6738
|
+
process.exit(2);
|
|
6739
|
+
}
|
|
6740
|
+
runServersCommand(parsed.options).then((r) => process.exit(r.exitCode));
|
|
6628
6741
|
} else if (subcommand === "--help" || subcommand === "-h" || subcommand === "help") {
|
|
6629
6742
|
const installBlock = ` ${INSTALL_USAGE.replace(/^Usage: /, "").replace(/\n/g, "\n ")}`;
|
|
6630
6743
|
process.stdout.write(
|
|
@@ -6635,6 +6748,7 @@ if (subcommand === "compliance") {
|
|
|
6635
6748
|
mcph Run as MCP server (requires a token)
|
|
6636
6749
|
mcph install <client> [flags] Auto-edit an MCP client's config to launch mcph
|
|
6637
6750
|
mcph doctor Print loaded config + detected clients (support diagnostic)
|
|
6751
|
+
mcph servers [--json] List servers configured in your mcp.hosting dashboard
|
|
6638
6752
|
mcph compliance <target> [flags] Run the compliance suite against an MCP server
|
|
6639
6753
|
mcph reset-learning Clear cross-session learning history (~/.mcph/state.json)
|
|
6640
6754
|
mcph --version Print version
|
|
@@ -6657,7 +6771,7 @@ ${installBlock}
|
|
|
6657
6771
|
);
|
|
6658
6772
|
process.exit(0);
|
|
6659
6773
|
} else if (subcommand === "--version" || subcommand === "-V") {
|
|
6660
|
-
process.stdout.write(`mcph ${true ? "0.
|
|
6774
|
+
process.stdout.write(`mcph ${true ? "0.39.0" : "dev"}
|
|
6661
6775
|
`);
|
|
6662
6776
|
process.exit(0);
|
|
6663
6777
|
} else if (subcommand && !subcommand.startsWith("-")) {
|
package/package.json
CHANGED