@yawlabs/mcph 0.46.3 → 0.47.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 CHANGED
@@ -2,6 +2,16 @@
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.47.0 — 2026-04-18
6
+
7
+ - **Compliance grade surfaces on every `discover` output, not just when `MCPH_MIN_COMPLIANCE` is set** — Previously the `[A]`/`[B]`/… tag only appeared when the user had pre-configured a floor with `MCPH_MIN_COMPLIANCE`, which meant the trust signal was invisible by default. Forum feedback (r/cursor, 2026-04-18) called this out directly: "how do you manage trust … making sure MCPs do not contain malicious code?" The grade is the answer — but only if you can see it without opting in first. Now every scored server renders with its grade inline (`github — GitHub [ready] [A]`), so the model (and the human reading the output) factors trust into activation decisions unconditionally. The `mcp_connect_discover` tool description picks this up ("treat it as a trust signal and prefer higher-graded alternatives when otherwise equivalent"). Ungraded servers still render untagged (don't punish unknown on a catalog where many entries aren't scored yet). When the floor IS set and a server is below it, the tag is replaced by the existing `(grade D — below MCPH_MIN_COMPLIANCE=B, won't auto-activate)` refusal line. Paired test: `server.test.ts` flips the "omits `[grade]` when env unset" contract to "shows `[grade]` when env unset" and keeps the ungraded-leaves-line-clean invariant.
8
+ - **`Trust & security` section in `README.md`** — Explicit trust-model section addressing the three concerns raised in the same forum thread: (1) malicious code in MCPs, (2) prompt injection through tool output, (3) data siphoning to third parties. Takes the posture that mcph is a source of **visibility and a gate**, not a sandbox — compliance grades + `MCPH_MIN_COMPLIANCE` + `mcph compliance <target>` + `mcph servers` transparency + per-server encrypted credentials + response pruning + namespace isolation — and explicitly documents what mcph does **not** try to solve (outbound network firewalling, process sandboxing, source-hash pinning) so users know where to layer their own defenses (restricted OS user, containers, token rotation). Direct answer to the forum question rather than a hand-wave.
9
+
10
+ ## 0.46.4 — 2026-04-18
11
+
12
+ - **`mcph --help` Setup block rewritten for clarity** — The v0.46.3 rewrite used jargony wording ("Auto-edit an MCP client's config") and split the client list onto an ambiguous continuation line. Rewrote the three install rows to action-first prose: `install <client>` says "Configure one MCP client to launch mcph" and spells out the exact slugs (`claude-code, claude-desktop, cursor, vscode`) inline; `--list` says "List which MCP clients are installed on this machine"; `--all` says "Configure every installed MCP client in one go". Same three commands, but it now reads as plain English.
13
+ - **Help + doctor now list `MCPH_AUTO_ACTIVATE`** — The env var has controlled the discover auto-activate gate since the confidence-scoring work landed, but neither the help page nor `mcph doctor`'s ENVIRONMENT section mentioned it, so the only way to discover the toggle was to grep `server.ts`. Added to both: help describes what flipping to `0` does, doctor surfaces the current value with `default on` hint. Also tightens the config resolution table in help — tier 3 (`<project>/.mcph/config.json`, the project-shared file) now notes "never put a token here — apiBase only" so nobody accidentally commits a token to a shared repo.
14
+
5
15
  ## 0.46.3 — 2026-04-18
6
16
 
7
17
  - **`mcph --help` rewritten: quickstart, grouped subcommands, env vars, config precedence** — The old help listed ten subcommands in a flat table and spent most of its real estate on install flag details (already available via `mcph install --help`) and a three-line token-resolution note. Subcommands are now grouped by purpose (Setup, Inspection, Maintenance, Other), each with a multi-line description that explains what the command actually does — not just its name. A numbered Quickstart at the top points users at the token URL and shows the two commands needed to finish onboarding. An Environment variables section documents the eight `MCPH_*` overrides (`MCPH_URL`, `MCPH_POLL_INTERVAL`, `MCPH_SERVER_CAP`, `MCPH_MIN_COMPLIANCE`, `MCPH_AUTO_LOAD`, `MCPH_PRUNE_RESPONSES`, `MCPH_DISABLE_PERSISTENCE`) that were previously only discoverable by reading the doctor source. Config resolution is expanded from three lines to a proper four-tier precedence list (env → project.local → project → user-global). Trailing pointer to `mcph <subcommand> --help` for flag-level detail so the top-level stays scannable. `INSTALL_USAGE` import removed from `index.ts` since the install flag block no longer inlines into top-level help.
package/README.md CHANGED
@@ -342,6 +342,25 @@ The popular Python-based MCP servers (`fetch`, `sqlite`, `time`, `sentry`, etc.)
342
342
 
343
343
  `uvx ARGS` is always rewritten to `uv tool run ARGS` at spawn time — so only `uv` needs to be reachable, not `uvx` separately. Fixes Windows setups where one was on PATH and the other wasn't.
344
344
 
345
+ ## Trust & security
346
+
347
+ MCP servers are third-party code that you choose to run, and mcph launches them on your machine or calls them over the network. We don't sandbox arbitrary code and we're not an antivirus — that's your OS and network. What mcph gives you is **visibility and a gate**:
348
+
349
+ - **Compliance grades (A–F)** — the `@yawlabs/mcp-compliance` suite runs 88 behavioral tests against an MCP server and reports a grade. mcp.hosting publishes grades for catalog servers; `mcph servers` shows them, and `mcp_connect_discover` surfaces them inline on every listing (e.g., `github — GitHub [ready] [A]`). Set `MCPH_MIN_COMPLIANCE=B` (or any grade) and `mcp_connect_activate` will refuse to load anything below the floor — the refusal message spells out the grade and the env var to unset. Ungraded servers always pass (don't punish unknown), so audit unknowns yourself with `mcph compliance <target>` before you rely on them.
350
+ - **Source transparency** — `mcph servers` and the mcp.hosting dashboard show the exact `command`, `args`, and `url` each server launches with. Nothing is hidden or wrapped — if a server is `npx -y @example/foo` you see that, and you can trace it back to npm / GitHub / the remote endpoint before installing.
351
+ - **Credentials stay encrypted at rest on mcp.hosting** — API tokens and other secrets you paste into a server's `env` block are encrypted on the backend and injected at spawn time. They don't sit in a committed `.env` file or a client config JSON, and they are never logged. Revoke the mcp.hosting token (Settings → API Tokens) and every install loses access on the next poll.
352
+ - **Response pruning** — `MCPH_PRUNE_RESPONSES` (on by default) redacts large file-blob-shaped content before it reaches your LLM. This cuts the easiest form of cross-server prompt injection (stuffing a giant payload into a tool reply to swamp the model's context) and reduces accidental token burn. Set to `0` to disable.
353
+ - **Namespace isolation** — tools are namespace-prefixed (`gh_create_issue`, never bare `create_issue`), so a server can't impersonate tools from another server it has no business touching. `mcp_connect_read_tool` lets you inspect a tool's schema without loading its server, so you can decide before any code runs.
354
+
355
+ **What mcph does not try to solve.** mcph does not prevent a server you deliberately installed from doing harmful things inside its own process. It doesn't block outbound network traffic, firewall DNS, analyze source, or pin package hashes. A malicious server you chose to run can call any URL your machine can reach; cross-server prompt injection through tool output is a fundamentally model-layer problem that no orchestrator fully fixes. The defenses that matter for those threats live at the layer below mcph:
356
+
357
+ - Review the command (`npx -y @scope/pkg`, a remote URL, …) before adding a server. If you don't recognize it, run `mcph compliance <target>` against it first.
358
+ - Run mcph and its spawned servers under a restricted OS user or inside a container if you're handling sensitive data. mcph stays out of your sandbox's way — a restricted user will block egress just like it would for anything else.
359
+ - Keep the mcp.hosting token scoped to the devices that need it. Rotate with `mcph install <client> --token …`; every client picks up the new value.
360
+ - Prefer graded servers when the alternatives are otherwise equivalent. A server that can't pass the compliance suite on basic spec conformance is a worse choice than one that does.
361
+
362
+ If you find a security issue in mcph itself, email `support@mcp.hosting` — details in [`SECURITY.md`](./SECURITY.md).
363
+
345
364
  ## Requirements
346
365
 
347
366
  - Node.js 18+
package/dist/index.js CHANGED
@@ -1458,7 +1458,7 @@ function selectFlakyNamespaces(entries, limit) {
1458
1458
  }
1459
1459
 
1460
1460
  // src/doctor-cmd.ts
1461
- var VERSION = true ? "0.46.3" : "dev";
1461
+ var VERSION = true ? "0.47.0" : "dev";
1462
1462
  async function runDoctor(opts = {}) {
1463
1463
  if (opts.json) return runDoctorJson(opts);
1464
1464
  const lines = [];
@@ -1563,6 +1563,7 @@ async function runDoctorJson(opts) {
1563
1563
  "MCPH_SERVER_CAP",
1564
1564
  "MCPH_MIN_COMPLIANCE",
1565
1565
  "MCPH_AUTO_LOAD",
1566
+ "MCPH_AUTO_ACTIVATE",
1566
1567
  "MCPH_PRUNE_RESPONSES"
1567
1568
  ];
1568
1569
  const envOverrides = {};
@@ -1650,6 +1651,7 @@ function renderEnvSection(opts) {
1650
1651
  { name: "MCPH_SERVER_CAP", defaultHint: "default 6" },
1651
1652
  { name: "MCPH_MIN_COMPLIANCE", defaultHint: "filter inactive" },
1652
1653
  { name: "MCPH_AUTO_LOAD", defaultHint: "auto-load inactive" },
1654
+ { name: "MCPH_AUTO_ACTIVATE", defaultHint: "default on" },
1653
1655
  { name: "MCPH_PRUNE_RESPONSES", defaultHint: "pruning active" }
1654
1656
  ];
1655
1657
  const widest = vars.reduce((m, v) => Math.max(m, v.name.length), 0);
@@ -3252,7 +3254,7 @@ var LearningStore = class {
3252
3254
  var META_TOOLS = {
3253
3255
  discover: {
3254
3256
  name: "mcp_connect_discover",
3255
- description: 'List the MCP servers installed on the user\'s mcp.hosting account and ready to use. Call this when browsing what\'s available or when the task isn\'t specific yet. If the task is already clear ("file a github issue", "query postgres", "post to slack"), prefer `mcp_connect_dispatch` \u2014 it picks the right server and loads its tools in one call. Load only the servers the CURRENT task needs; each one adds tools to your context. Shows names, namespaces, tool counts, a token-cost estimate per server (e.g. "22 tools, ~2.8k tokens") so you can budget context before activating \u2014 tilde values are estimates based on cached tool metadata, unprefixed values reflect live tool schemas. Also surfaces whether each server is loaded, any local CLI it shadows (prefer the MCP tools over the CLI when a shadow is listed), and usage hints ("used Nx" or "often loaded with X") when the signals are present (counts persist across mcph restarts). Recurring packs that have been loaded together \u22652 times get their own block at the top with a ready-to-run `activate` call \u2014 skip the extra `mcp_connect_suggest` round-trip when the signal is already there. If a `mcph://guide` resource is listed, read it FIRST: it carries project/user-specific routing rules and credential conventions that override generic defaults.',
3257
+ description: 'List the MCP servers installed on the user\'s mcp.hosting account and ready to use. Call this when browsing what\'s available or when the task isn\'t specific yet. If the task is already clear ("file a github issue", "query postgres", "post to slack"), prefer `mcp_connect_dispatch` \u2014 it picks the right server and loads its tools in one call. Load only the servers the CURRENT task needs; each one adds tools to your context. Shows names, namespaces, tool counts, a token-cost estimate per server (e.g. "22 tools, ~2.8k tokens") so you can budget context before activating \u2014 tilde values are estimates based on cached tool metadata, unprefixed values reflect live tool schemas. Scored servers carry an inline `[A]`\u2013`[F]` compliance grade from the mcp.hosting test suite \u2014 treat it as a trust signal and prefer higher-graded alternatives when otherwise equivalent (ungraded servers are unmarked, not penalized). Also surfaces whether each server is loaded, any local CLI it shadows (prefer the MCP tools over the CLI when a shadow is listed), and usage hints ("used Nx" or "often loaded with X") when the signals are present (counts persist across mcph restarts). Recurring packs that have been loaded together \u22652 times get their own block at the top with a ready-to-run `activate` call \u2014 skip the extra `mcp_connect_suggest` round-trip when the signal is already there. If a `mcph://guide` resource is listed, read it FIRST: it carries project/user-specific routing rules and credential conventions that override generic defaults.',
3256
3258
  inputSchema: {
3257
3259
  type: "object",
3258
3260
  properties: {
@@ -4744,7 +4746,7 @@ function categorizeSpawnError(err) {
4744
4746
  }
4745
4747
  async function connectToUpstream(config, onDisconnect, onListChanged) {
4746
4748
  const client = new Client(
4747
- { name: "mcph", version: true ? "0.46.3" : "dev" },
4749
+ { name: "mcph", version: true ? "0.47.0" : "dev" },
4748
4750
  { capabilities: {} }
4749
4751
  );
4750
4752
  let transport;
@@ -5225,7 +5227,7 @@ var ConnectServer = class _ConnectServer {
5225
5227
  this.apiUrl = apiUrl6;
5226
5228
  this.token = token6;
5227
5229
  this.server = new Server(
5228
- { name: "mcph", version: true ? "0.46.3" : "dev" },
5230
+ { name: "mcph", version: true ? "0.47.0" : "dev" },
5229
5231
  {
5230
5232
  capabilities: {
5231
5233
  tools: { listChanged: true },
@@ -6086,11 +6088,11 @@ var ConnectServer = class _ConnectServer {
6086
6088
  }
6087
6089
  }
6088
6090
  let complianceLabel = "";
6089
- if (minCompliance !== null && server.complianceGrade) {
6090
- if (passesMinCompliance(server.complianceGrade, minCompliance)) {
6091
- complianceLabel = ` [${server.complianceGrade}]`;
6092
- } else {
6091
+ if (server.complianceGrade) {
6092
+ if (minCompliance !== null && !passesMinCompliance(server.complianceGrade, minCompliance)) {
6093
6093
  complianceLabel = ` (grade ${server.complianceGrade} \u2014 below MCPH_MIN_COMPLIANCE=${minCompliance}, won't auto-activate)`;
6094
+ } else {
6095
+ complianceLabel = ` [${server.complianceGrade}]`;
6094
6096
  }
6095
6097
  }
6096
6098
  lines.push(
@@ -7570,7 +7572,7 @@ async function runUpgrade(opts = {}) {
7570
7572
  return { exitCode: 3, lines };
7571
7573
  }
7572
7574
  function readCurrentVersion() {
7573
- return true ? "0.46.3" : "dev";
7575
+ return true ? "0.47.0" : "dev";
7574
7576
  }
7575
7577
 
7576
7578
  // src/index.ts
@@ -7660,10 +7662,12 @@ if (subcommand === "compliance") {
7660
7662
  3. Verify setup mcph doctor
7661
7663
 
7662
7664
  Setup:
7663
- install <client> Auto-edit an MCP client's config to launch mcph.
7664
- Clients: claude-code | claude-desktop | cursor | vscode.
7665
- install --list Detect MCP clients on this machine (read-only).
7666
- install --all Install into every detected client in one shot.
7665
+ install <client> Configure one MCP client to launch mcph.
7666
+ <client> is one of: claude-code, claude-desktop,
7667
+ cursor, vscode.
7668
+ install --list List which MCP clients are installed on this
7669
+ machine (read-only; no writes).
7670
+ install --all Configure every installed MCP client in one go.
7667
7671
 
7668
7672
  Inspection:
7669
7673
  doctor Diagnose setup: config, token, clients, learning,
@@ -7702,13 +7706,17 @@ if (subcommand === "compliance") {
7702
7706
  MCPH_SERVER_CAP Max concurrently active servers (default 6).
7703
7707
  MCPH_MIN_COMPLIANCE Minimum grade to auto-activate (A|B|C|D|F).
7704
7708
  MCPH_AUTO_LOAD Load all servers at startup, ignoring SERVER_CAP.
7709
+ MCPH_AUTO_ACTIVATE Set to \`0\` to disable discover's auto-activate
7710
+ gate (default: a clearly-winning server is
7711
+ activated in the same call).
7705
7712
  MCPH_PRUNE_RESPONSES Set to \`0\` to disable response pruning.
7706
7713
  MCPH_DISABLE_PERSISTENCE Disable cross-session learning state.
7707
7714
 
7708
7715
  Config resolution (highest precedence first):
7709
7716
  1. MCPH_TOKEN / MCPH_URL env vars
7710
7717
  2. <project>/.mcph/config.local.json machine-local overrides (gitignore)
7711
- 3. <project>/.mcph/config.json project-shared (checked in)
7718
+ 3. <project>/.mcph/config.json project-shared (checked in; never
7719
+ put a token here \u2014 apiBase only)
7712
7720
  4. ~/.mcph/config.json user-global default
7713
7721
 
7714
7722
  Token rotation: mcph reads config at startup. Restart the MCP client
@@ -7720,7 +7728,7 @@ if (subcommand === "compliance") {
7720
7728
  `);
7721
7729
  process.exit(0);
7722
7730
  } else if (subcommand === "--version" || subcommand === "-V") {
7723
- process.stdout.write(`mcph ${true ? "0.46.3" : "dev"}
7731
+ process.stdout.write(`mcph ${true ? "0.47.0" : "dev"}
7724
7732
  `);
7725
7733
  process.exit(0);
7726
7734
  } else if (subcommand && !subcommand.startsWith("-")) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@yawlabs/mcph",
3
- "version": "0.46.3",
3
+ "version": "0.47.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)",