@muhaven/mcp 0.1.0 → 0.1.3

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
@@ -7,7 +7,138 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
- ## [0.1.0] — 2026-05-10
10
+ ## [0.1.3] — 2026-05-16
11
+
12
+ Q2 fix bundle from the post-§4 queue closing four findings from §3e⁶
13
+ (broker-session-key-required-for-reads, broker-env-divergence,
14
+ mcp-serverinfo-version-stale) and unblocking the openclaw-skill ClawScan
15
+ fix (the `noExternal: ['@muhaven/mcp']` inline bundle requires this
16
+ version on npm before the skill can be republished).
17
+
18
+ ### Added
19
+
20
+ - **Read-only daemon posture**: the broker daemon now boots WITHOUT
21
+ `MUHAVEN_BROKER_SESSION_KEY`. In that mode the daemon still serves
22
+ `hello` + the JWT verbs (so `muhaven.read.*` tools work end-to-end via
23
+ the standalone `@muhaven/mcp` install), but any `sign_hash` request
24
+ returns the new `session_key_unavailable` broker error so write paths
25
+ fail with a clear remediation message instead of the daemon dying at
26
+ startup. Closes §3e⁶ F-broker-session-key-required-for-reads.
27
+ - **`muhaven-broker login --from-daemon` flag**: resolves backend +
28
+ dashboard URLs from the running daemon's `hello.effectiveConfig`
29
+ rather than the login CLI's env. Solves the daemon-vs-CLI env-divergence
30
+ problem when the two processes inherit different shell environments
31
+ (e.g. the daemon was launched by systemd/launchd, the CLI by ssh).
32
+ Mutually exclusive with explicit `--backend-base-url` /
33
+ `--dashboard-base-url`. Closes §3e⁶ F-broker-env-divergence.
34
+ - **`muhaven-broker doctor` surfaces the daemon's effective config**
35
+ and read-only-posture status — the operator can verify which backend
36
+ URL is actually in play before driving a login.
37
+
38
+ ### Changed
39
+
40
+ - **Broker protocol bumped 0.2.0 → 0.3.0** (additive — pre-0.3.0 clients
41
+ remain compatible):
42
+ - `hello.hasSessionKey` (optional `boolean`) — absence implies `true`
43
+ for back-compat.
44
+ - `hello.effectiveConfig` (optional `{ backendBaseUrl, dashboardBaseUrl }`).
45
+ - New `session_key_unavailable` broker error code.
46
+ - **`serverInfo.version`** in the MCP server's `initialize` response is
47
+ now build-time injected from `package.json#version` (tsup `define` on
48
+ `__SERVER_VERSION__`) rather than the previously hardcoded `'0.1.0'`
49
+ string in `src/server.ts`. Closes §3e⁶ F-mcp-serverinfo-version-stale.
50
+
51
+ ### Tests
52
+
53
+ - 134 vitest pass (up from 101 in 0.1.2). Net +33 cases:
54
+ - **+6** `config.test.ts` — `loadBrokerConfig` lazy-validation
55
+ (no key, empty string, valid key, malformed key) + env-driven backend
56
+ + dashboard URL surface.
57
+ - **+5** `daemon-handler.test.ts` — 0.3.0 protocol: `hello` surfaces
58
+ `hasSessionKey` + `effectiveConfig` from options, defaults `true`
59
+ when omitted, reflects `false` when set; `sign_hash` with
60
+ `NullSigner` returns `session_key_unavailable`; re-throws non-Missing
61
+ errors verbatim.
62
+ - **+9** `cli-parse-login-flags.test.ts` — flag parser unit cases
63
+ incl. `--from-daemon` mutual-exclusion guard.
64
+ - **+8** `session-key-required.test.ts` — `signEnvelope` probe of
65
+ `hello.hasSessionKey`; short-circuit returns `SESSION_KEY_REQUIRED`
66
+ for buy + claim with mint-URL pointing at `dashboardBaseUrl`;
67
+ safety-net mapping of inner `session_key_unavailable`;
68
+ probe-cache reuse; concurrent-call coalescing (one hello round-trip
69
+ for N callers); retry-after-rejection (eager cache clear); trailing-slash
70
+ mintUrl strip.
71
+ - **+2** `server-version.test.ts` — runtime fallback returns
72
+ `package.json#version`; matches `manifest.json#version`.
73
+ - **+2** `build-artifacts.test.ts` — hostname-migration guard + new
74
+ `__SERVER_VERSION__` literal grep in bundled dist.
75
+ - **+1** `daemon-lifecycle.test.ts` — read-only-posture boot test
76
+ replaces the prior "exits on missing key" assertion; added
77
+ "exits on a malformed session key" as the second negative-path test.
78
+
79
+ ## [0.1.2] — 2026-05-11
80
+
81
+ Re-roll of the `0.1.1` workflow-validation cut. `0.1.1` never reached npm:
82
+ the tag pointed at the version-bump commit but the workflow at that SHA
83
+ lacked two fixes that landed on `agenticwave` after the tag was first cut.
84
+ Bumping to `0.1.2` lets the tag reference the latest `agenticwave` HEAD
85
+ which contains both fixes; subsequent releases follow the normal flow.
86
+
87
+ ### Fixed
88
+
89
+ - **NODE_AUTH_TOKEN was overriding the OIDC trusted-publisher exchange in
90
+ `.github/workflows/mcp-publish.yml`** (commit `e373e36`). The
91
+ `actions/setup-node@v4` `registry-url` parameter writes an `.npmrc`
92
+ with `_authToken=${NODE_AUTH_TOKEN}` placeholder; the GitHub Actions
93
+ runner's inherited env had `NODE_AUTH_TOKEN` populated (visible in the
94
+ failing workflow logs as `XXXXX-XXXXX-XXXXX-XXXXX`), so npm tried
95
+ token-based publish first and 404'd because that token has no
96
+ permission on `@muhaven/mcp`. Fix: explicit `env: NODE_AUTH_TOKEN: ''`
97
+ on the publish step forces the `--provenance`-driven OIDC exchange as
98
+ the sole auth method.
99
+
100
+ - **OIDC claims diagnostic step added pre-publish** (commit `e373e36`).
101
+ Prints `github.repository_owner` / `github.repository` /
102
+ `github.workflow_ref` / `github.event_name` / `github.ref` so that any
103
+ future Trusted Publisher binding mismatch can be diff'd
104
+ character-by-character against the npm-side configuration. Surfaced
105
+ the case-sensitivity gotcha around `repository_owner` that `0.1.1`'s
106
+ three failed attempts triggered.
107
+
108
+ ### Distribution
109
+
110
+ - Identical bundle bytes to the `0.1.1` artifact except for the embedded
111
+ `0.1.2` version strings in `package.json` + `manifest.json`. No code
112
+ changes to the MCP server or broker daemon. Same `dist/` shape, same
113
+ 16 files in the tarball, same `bin/` entry-points.
114
+
115
+ ## [0.1.1] — 2026-05-11
116
+
117
+ Workflow-validation cut. `0.1.0` shipped via a one-time manual `npm publish
118
+ --no-provenance` because npm Trusted Publisher could not be configured against
119
+ a non-existent package; this release exercises the `mcp-publish.yml` workflow
120
+ end-to-end on the muhaven.app hosts so subsequent releases carry full Sigstore
121
+ provenance attestations and `npm view dist.signatures` populates.
122
+
123
+ ### Fixed
124
+
125
+ - Re-runs the publish path through `.github/workflows/mcp-publish.yml`
126
+ (Workstream D) on the now-configured Trusted Publisher binding for
127
+ `@muhaven/mcp`. Validates the full OIDC → cosign sign → `npm publish
128
+ --provenance` → post-publish shasum verify chain that `0.1.0` skipped.
129
+ - No code change relative to `0.1.0`. Bundle bytes identical except for the
130
+ embedded `0.1.1` version string in `package.json` + `manifest.json`. The
131
+ `0.1.0` "Provenance" badge gap (visible on the npmjs.com sidebar) closes
132
+ with this release.
133
+
134
+ ### Distribution
135
+
136
+ - First release where `npm view @muhaven/mcp@0.1.1 dist.signatures` returns a
137
+ populated array, `dist.attestations.url` resolves to a GitHub-hosted
138
+ attestation, and the npmjs.com sidebar shows the "Provenance" badge linked
139
+ to the workflow run.
140
+
141
+
11
142
 
12
143
  First publishable cut. All publish-readiness security must-fixes (H-1 / H-2 /
13
144
  H-3 from `MCP_PUBLISH_READINESS.md` §2) and package-hygiene work landed on
@@ -119,5 +250,8 @@ Workstream H)
119
250
  muhaven-mcp-0.1.0.tgz
120
251
  ```
121
252
 
122
- [Unreleased]: https://github.com/hasToDev/muhaven/compare/mcp-v0.1.0...HEAD
253
+ [Unreleased]: https://github.com/hasToDev/muhaven/compare/mcp-v0.1.3...HEAD
254
+ [0.1.3]: https://github.com/hasToDev/muhaven/releases/tag/mcp-v0.1.3
255
+ [0.1.2]: https://github.com/hasToDev/muhaven/releases/tag/mcp-v0.1.2
256
+ [0.1.1]: https://github.com/hasToDev/muhaven/releases/tag/mcp-v0.1.1
123
257
  [0.1.0]: https://github.com/hasToDev/muhaven/releases/tag/mcp-v0.1.0
package/README.md CHANGED
@@ -1,125 +1,125 @@
1
- # `@muhaven/mcp` — MCP server for MuHaven RWA portfolios
2
-
3
- Confidential RWA portfolio management on Fhenix CoFHE, exposed as a Model
4
- Context Protocol server installable in Claude Desktop / Cursor / Claude Code.
5
-
6
- ## What it does
7
-
8
- 22 tools across five groups (P3 + P7 + P11):
9
-
10
- | Group | Tools | Description |
11
- |---|---|---|
12
- | `muhaven.read.*` | `portfolio` · `yields` · `distribution` · `tokens` · `audit` · `protection_coverage` · `kyc_attestation` | Read your encrypted-balance portfolio, yield history, audit log, and P11 governance/KYC state |
13
- | `muhaven.position.*` | `buy` · `sell` · `claim` · `rebalance` | **Propose** trades — returns unsigned UserOps + broker signature; never auto-submits |
14
- | `muhaven.policy.*` | `set_tier` · `pause` · `audit_export` · `session_key_status` | Manage the tiered-autonomy state machine |
15
- | `muhaven.issuer.*` | `distribute_yield` · `kyc_add` · `kyc_remove` · `unpause_token` · `audit_query` | Issuer-side: distribute yield, manage KYC whitelist, NAV-set+unpause, query own audit trail |
16
- | `muhaven.governance.*` | `propose` · `cast_vote` | P11 encrypted-governance ceremony (cast-vote frontend runner deferred to Wave 5) |
17
-
18
- `MUHAVEN_READ_ONLY=true` exposes only the 7 `muhaven.read.*` tools.
19
-
20
- ## Architecture (one paragraph)
21
-
22
- The MCP server runs as an MCPB STDIO subprocess of the host LLM (Claude
23
- Desktop, Cursor, Claude Code). It speaks HTTPS to the MuHaven backend at
24
- `https://api.muhaven.app` and IPC to a long-running sibling daemon
25
- called `muhaven-broker`. The broker holds two secrets — your ZeroDev
26
- session-key private half (for signing UserOps) and your scoped JWT (for
27
- authenticating to the backend) — both in your OS keychain. The broker
28
- NEVER speaks TCP and NEVER reaches out to the network. It exposes one
29
- signing primitive over a Unix socket (POSIX) or named pipe (Windows).
30
- This split — network-facing MCP server / signing-only broker — is the
31
- **lethal-trifecta** mitigation: an attacker who compromises the LLM
32
- process cannot exfiltrate your key without also compromising a separate
33
- process running under your user.
34
-
35
- The `muhaven-broker login` ceremony uses the OAuth 2.0 Device
36
- Authorization Grant (RFC 8628) — same shape as `gh auth login --web`,
37
- `wrangler login`, `gcloud auth login`. You never paste a JWT.
38
-
39
- ## Install (development)
40
-
41
- ```bash
42
- # In the muhaven monorepo, from repo root
43
- pnpm install
44
- pnpm --filter @muhaven/mcp build
45
- ```
46
-
47
- The `bin/` shims will be invokable as `muhaven-mcp` and `muhaven-broker`
48
- once the package is linked.
49
-
50
- ## Setup (end-user, post-MCPB-publish)
51
-
52
- 1. **Install the MCPB package** in your host (Claude Desktop / Cursor / Claude Code).
53
- 2. **Provision a session key.** This is the private half the broker holds for signing UserOps. The dashboard-side mint UI is a Wave 5 deliverable — until then, generate one yourself:
54
- ```bash
55
- node -e "console.log('0x' + require('crypto').randomBytes(32).toString('hex'))"
56
- ```
57
- The corresponding kernel session key install on-chain runs through the dashboard `/agent/policy/transition` flow (one-time per tier). For read-only smokes you can skip the install — the broker only needs the private half to start.
58
- 3. **Start the broker daemon.** Set `MUHAVEN_BROKER_SESSION_KEY=0x…` and run:
59
- ```bash
60
- muhaven-broker
61
- ```
62
- Recipes for systemd / launchd / Windows Service in `docs/runbook.md` (TODO).
63
- 4. **Authenticate via device-code flow:**
64
- ```bash
65
- muhaven-broker login
66
- ```
67
- The broker prints a URL like `https://muhaven.app/link?code=ABCD-1234` and (when not run with `--no-launch-browser`) opens it. Sign in with your passkey on the dashboard, verify the device fingerprint shown on the `/link` page, click **Authorize**. The CLI exits with success when the JWT lands in your keystore.
68
- 5. **Use any MCP tool** from your host LLM. First call may take a moment as the broker fetches the JWT from the keystore.
69
-
70
- > **Windows / WSL2 / devcontainer / SSH-remote operators:** export `MUHAVEN_KEYRING=file` to skip the OS-keychain probe and use the file-backed keystore at `~/.muhaven/jwt` (mode 0600, parent dir mode 0700). The keychain backend depends on `@napi-rs/keyring` which needs platform-specific build prerequisites; the file fallback works everywhere.
71
-
72
- ## Hardening invariants (`THREAT_MODEL_P0.md` aligned)
73
-
74
- - **Transport is STDIO + Unix-socket only.** The MCP server's `StdioServerTransport` is the only transport mounted; the broker's IPC is a Unix socket on POSIX (parent dir mode `0700`, socket file mode `0600`) or a per-user named pipe on Windows. **Never bind TCP.**
75
- - **`mcp-remote` is banned.** CVE-2025-6514 disclosed an arbitrary-command-execution path through that proxy. Do not use it; do not set `MUHAVEN_BACKEND_URL` to anything that wraps it.
76
- - **`CLAUDE_CODE_SUBPROCESS_ENV_SCRUB=1`** is recommended in your shell rc when running Claude Code locally — it prevents inherited env vars from leaking into the MCP subprocess. The MCP package's `MUHAVEN_*` env vars are read at boot, but adopting the scrub habit limits collateral exposure.
77
- - **Tool descriptions are pinned** at build time in `tool-hashes.json`. The server exits with code 70 (`EX_CONFIG`) on startup if the live descriptors don't match the pinned hashes — defends against tool-description-poisoning patches per the mcp-context-protector pattern (post-MCPoison, March 2026).
78
- - **Position tools never auto-submit.** They return an unsigned UserOp envelope plus a broker signature. The host LLM is expected to present this to the user for explicit confirmation before bundler submission. The MCP server does not speak to any bundler.
79
-
80
- ## Environment variables
81
-
82
- | Var | Required | Default | Purpose |
83
- |---|---|---|---|
84
- | `MUHAVEN_BACKEND_URL` | no | `https://api.muhaven.app` | Backend host. Use staging URL for development. |
85
- | `MUHAVEN_DASHBOARD_URL` | no | `https://muhaven.app` | Dashboard origin used for the `/link` URL. |
86
- | `MUHAVEN_BROKER_ENDPOINT` | no | `~/.muhaven/broker.sock` (POSIX) / `\\.\pipe\muhaven-broker-<user>` (Windows) | IPC path. Set if running multiple isolated brokers. |
87
- | `MUHAVEN_BROKER_SESSION_KEY` | **yes** (broker) | — | 0x-prefixed 32-byte hex; the session-key private half. |
88
- | `MUHAVEN_READ_ONLY` | no | `false` | When `true`, only `muhaven.read.*` tools are registered. |
89
- | `MUHAVEN_KEYRING` | no | auto | Set to `file` to force the file-backed keystore (required on WSL2 / devcontainer / SSH-remote). |
90
- | `MUHAVEN_REQUEST_TIMEOUT_MS` | no | `15000` | Backend HTTP timeout. |
91
- | `MUHAVEN_BROKER_TIMEOUT_MS` | no | `5000` | Broker IPC timeout. |
92
- | `MUHAVEN_JWT_CACHE_TTL_SEC` | no | `30` | In-process JWT cache TTL. |
93
- | `MUHAVEN_BROKER_MAX_BYTES` | no | `65536` | Per-request payload cap on the broker IPC. |
94
-
95
- The MCPB `manifest.json` declares the user-facing subset (`backend_url`, `dashboard_url`, `broker_endpoint`, `read_only`); the host's secret manager handles the values.
96
-
97
- ## CLI subcommands (`muhaven-broker`)
98
-
99
- | Command | Effect |
100
- |---|---|
101
- | (none) | Run the daemon (production mode). |
102
- | `muhaven-broker login [--no-launch-browser]` | Run the device-code ceremony; on success store the JWT in the keystore. |
103
- | `muhaven-broker logout` | Clear the JWT from the keystore. |
104
- | `muhaven-broker doctor` | Print environment + keystore + reachability report. |
105
-
106
- ## Threat model in 30 seconds
107
-
108
- Per `development/DEV_WAVE_4/THREAT_MODEL_P0.md`:
109
-
110
- | Risk | Control |
111
- |---|---|
112
- | **R-1** Prompt injection escalating into a tx | Position tools return *unsigned* UserOps; host MUST present to user for explicit passkey confirmation. |
113
- | **R-2** Hallucinated tool call | Strict-enum tool registry + `additionalProperties: false` Zod schemas. |
114
- | **R-3** Replay of confirmation tokens | Single-use server-side nonced tokens via existing P1 confirm-token-service. |
115
- | **R-6** ZeroDev session-key escape | Session key lives in broker keystore (OS keychain) — never in the LLM-process env. |
116
- | **R-7** MCP env-block exfiltration | MCPB `sensitive: true` for secrets → OS keychain; broker isolation; no plaintext disk. |
117
- | **R-8** FHE ACL bypass | Backend enforces every read; MCP server never decrypts FHE handles. |
118
-
119
- ## License
120
-
121
- MIT
122
-
123
- ## Status: `0.1.0` — first publish-ready cut
124
-
125
- Wave 4 Phase P3 deliverable per `development/DEV_WAVE_4/PROGRESS.md`. Workstreams A–D of the npm-publish ceremony (security must-fixes, `package.json` hygiene, `LICENSE` + `CHANGELOG`, GitHub Actions workflows) are landed on `agenticwave`; the actual `npm publish` is operator-driven via the tag-push of `mcp-v0.1.0` against the `npm-publish` GitHub Environment (2-reviewer gate · OIDC trusted-publishing · Sigstore provenance). See `development/DEV_WAVE_4/MCP_PUBLISH_READINESS.md` §6 for the operator runbook.
1
+ # `@muhaven/mcp` — MCP server for MuHaven RWA portfolios
2
+
3
+ Confidential RWA portfolio management on Fhenix CoFHE, exposed as a Model
4
+ Context Protocol server installable in Claude Desktop / Cursor / Claude Code.
5
+
6
+ ## What it does
7
+
8
+ 22 tools across five groups (P3 + P7 + P11):
9
+
10
+ | Group | Tools | Description |
11
+ |---|---|---|
12
+ | `muhaven.read.*` | `portfolio` · `yields` · `distribution` · `tokens` · `audit` · `protection_coverage` · `kyc_attestation` | Read your encrypted-balance portfolio, yield history, audit log, and P11 governance/KYC state |
13
+ | `muhaven.position.*` | `buy` · `sell` · `claim` · `rebalance` | **Propose** trades — returns unsigned UserOps + broker signature; never auto-submits |
14
+ | `muhaven.policy.*` | `set_tier` · `pause` · `audit_export` · `session_key_status` | Manage the tiered-autonomy state machine |
15
+ | `muhaven.issuer.*` | `distribute_yield` · `kyc_add` · `kyc_remove` · `unpause_token` · `audit_query` | Issuer-side: distribute yield, manage KYC whitelist, NAV-set+unpause, query own audit trail |
16
+ | `muhaven.governance.*` | `propose` · `cast_vote` | P11 encrypted-governance ceremony (cast-vote frontend runner deferred to Wave 5) |
17
+
18
+ `MUHAVEN_READ_ONLY=true` exposes only the 7 `muhaven.read.*` tools.
19
+
20
+ ## Architecture (one paragraph)
21
+
22
+ The MCP server runs as an MCPB STDIO subprocess of the host LLM (Claude
23
+ Desktop, Cursor, Claude Code). It speaks HTTPS to the MuHaven backend at
24
+ `https://api.muhaven.app` and IPC to a long-running sibling daemon
25
+ called `muhaven-broker`. The broker holds two secrets — your ZeroDev
26
+ session-key private half (for signing UserOps) and your scoped JWT (for
27
+ authenticating to the backend) — both in your OS keychain. The broker
28
+ NEVER speaks TCP and NEVER reaches out to the network. It exposes one
29
+ signing primitive over a Unix socket (POSIX) or named pipe (Windows).
30
+ This split — network-facing MCP server / signing-only broker — is the
31
+ **lethal-trifecta** mitigation: an attacker who compromises the LLM
32
+ process cannot exfiltrate your key without also compromising a separate
33
+ process running under your user.
34
+
35
+ The `muhaven-broker login` ceremony uses the OAuth 2.0 Device
36
+ Authorization Grant (RFC 8628) — same shape as `gh auth login --web`,
37
+ `wrangler login`, `gcloud auth login`. You never paste a JWT.
38
+
39
+ ## Install (development)
40
+
41
+ ```bash
42
+ # In the muhaven monorepo, from repo root
43
+ pnpm install
44
+ pnpm --filter @muhaven/mcp build
45
+ ```
46
+
47
+ The `bin/` shims will be invokable as `muhaven-mcp` and `muhaven-broker`
48
+ once the package is linked.
49
+
50
+ ## Setup (end-user, post-MCPB-publish)
51
+
52
+ 1. **Install the MCPB package** in your host (Claude Desktop / Cursor / Claude Code).
53
+ 2. **Provision a session key.** This is the private half the broker holds for signing UserOps. The dashboard-side mint UI is a Wave 5 deliverable — until then, generate one yourself:
54
+ ```bash
55
+ node -e "console.log('0x' + require('crypto').randomBytes(32).toString('hex'))"
56
+ ```
57
+ The corresponding kernel session key install on-chain runs through the dashboard `/agent/policy/transition` flow (one-time per tier). For read-only smokes you can skip the install — the broker only needs the private half to start.
58
+ 3. **Start the broker daemon.** Set `MUHAVEN_BROKER_SESSION_KEY=0x…` and run:
59
+ ```bash
60
+ muhaven-broker
61
+ ```
62
+ Recipes for systemd / launchd / Windows Service in `docs/runbook.md` (TODO).
63
+ 4. **Authenticate via device-code flow:**
64
+ ```bash
65
+ muhaven-broker login
66
+ ```
67
+ The broker prints a URL like `https://muhaven.app/link?code=ABCD-1234` and (when not run with `--no-launch-browser`) opens it. Sign in with your passkey on the dashboard, verify the device fingerprint shown on the `/link` page, click **Authorize**. The CLI exits with success when the JWT lands in your keystore.
68
+ 5. **Use any MCP tool** from your host LLM. First call may take a moment as the broker fetches the JWT from the keystore.
69
+
70
+ > **Windows / WSL2 / devcontainer / SSH-remote operators:** export `MUHAVEN_KEYRING=file` to skip the OS-keychain probe and use the file-backed keystore at `~/.muhaven/jwt` (mode 0600, parent dir mode 0700). The keychain backend depends on `@napi-rs/keyring` which needs platform-specific build prerequisites; the file fallback works everywhere.
71
+
72
+ ## Hardening invariants (`THREAT_MODEL_P0.md` aligned)
73
+
74
+ - **Transport is STDIO + Unix-socket only.** The MCP server's `StdioServerTransport` is the only transport mounted; the broker's IPC is a Unix socket on POSIX (parent dir mode `0700`, socket file mode `0600`) or a per-user named pipe on Windows. **Never bind TCP.**
75
+ - **`mcp-remote` is banned.** CVE-2025-6514 disclosed an arbitrary-command-execution path through that proxy. Do not use it; do not set `MUHAVEN_BACKEND_URL` to anything that wraps it.
76
+ - **`CLAUDE_CODE_SUBPROCESS_ENV_SCRUB=1`** is recommended in your shell rc when running Claude Code locally — it prevents inherited env vars from leaking into the MCP subprocess. The MCP package's `MUHAVEN_*` env vars are read at boot, but adopting the scrub habit limits collateral exposure.
77
+ - **Tool descriptions are pinned** at build time in `tool-hashes.json`. The server exits with code 70 (`EX_CONFIG`) on startup if the live descriptors don't match the pinned hashes — defends against tool-description-poisoning patches per the mcp-context-protector pattern (post-MCPoison, March 2026).
78
+ - **Position tools never auto-submit.** They return an unsigned UserOp envelope plus a broker signature. The host LLM is expected to present this to the user for explicit confirmation before bundler submission. The MCP server does not speak to any bundler.
79
+
80
+ ## Environment variables
81
+
82
+ | Var | Required | Default | Purpose |
83
+ |---|---|---|---|
84
+ | `MUHAVEN_BACKEND_URL` | no | `https://api.muhaven.app` | Backend host. Use staging URL for development. |
85
+ | `MUHAVEN_DASHBOARD_URL` | no | `https://muhaven.app` | Dashboard origin used for the `/link` URL. |
86
+ | `MUHAVEN_BROKER_ENDPOINT` | no | `~/.muhaven/broker.sock` (POSIX) / `\\.\pipe\muhaven-broker-<user>` (Windows) | IPC path. Set if running multiple isolated brokers. |
87
+ | `MUHAVEN_BROKER_SESSION_KEY` | **yes** (broker) | — | 0x-prefixed 32-byte hex; the session-key private half. |
88
+ | `MUHAVEN_READ_ONLY` | no | `false` | When `true`, only `muhaven.read.*` tools are registered. |
89
+ | `MUHAVEN_KEYRING` | no | auto | Set to `file` to force the file-backed keystore (required on WSL2 / devcontainer / SSH-remote). |
90
+ | `MUHAVEN_REQUEST_TIMEOUT_MS` | no | `15000` | Backend HTTP timeout. |
91
+ | `MUHAVEN_BROKER_TIMEOUT_MS` | no | `5000` | Broker IPC timeout. |
92
+ | `MUHAVEN_JWT_CACHE_TTL_SEC` | no | `30` | In-process JWT cache TTL. |
93
+ | `MUHAVEN_BROKER_MAX_BYTES` | no | `65536` | Per-request payload cap on the broker IPC. |
94
+
95
+ The MCPB `manifest.json` declares the user-facing subset (`backend_url`, `dashboard_url`, `broker_endpoint`, `read_only`); the host's secret manager handles the values.
96
+
97
+ ## CLI subcommands (`muhaven-broker`)
98
+
99
+ | Command | Effect |
100
+ |---|---|
101
+ | (none) | Run the daemon (production mode). |
102
+ | `muhaven-broker login [--no-launch-browser]` | Run the device-code ceremony; on success store the JWT in the keystore. |
103
+ | `muhaven-broker logout` | Clear the JWT from the keystore. |
104
+ | `muhaven-broker doctor` | Print environment + keystore + reachability report. |
105
+
106
+ ## Threat model in 30 seconds
107
+
108
+ Per `development/DEV_WAVE_4/THREAT_MODEL_P0.md`:
109
+
110
+ | Risk | Control |
111
+ |---|---|
112
+ | **R-1** Prompt injection escalating into a tx | Position tools return *unsigned* UserOps; host MUST present to user for explicit passkey confirmation. |
113
+ | **R-2** Hallucinated tool call | Strict-enum tool registry + `additionalProperties: false` Zod schemas. |
114
+ | **R-3** Replay of confirmation tokens | Single-use server-side nonced tokens via existing P1 confirm-token-service. |
115
+ | **R-6** ZeroDev session-key escape | Session key lives in broker keystore (OS keychain) — never in the LLM-process env. |
116
+ | **R-7** MCP env-block exfiltration | MCPB `sensitive: true` for secrets → OS keychain; broker isolation; no plaintext disk. |
117
+ | **R-8** FHE ACL bypass | Backend enforces every read; MCP server never decrypts FHE handles. |
118
+
119
+ ## License
120
+
121
+ MIT
122
+
123
+ ## Status: `0.1.0` — first publish-ready cut
124
+
125
+ Wave 4 Phase P3 deliverable per `development/DEV_WAVE_4/PROGRESS.md`. Workstreams A–D of the npm-publish ceremony (security must-fixes, `package.json` hygiene, `LICENSE` + `CHANGELOG`, GitHub Actions workflows) are landed on `agenticwave`; the actual `npm publish` is operator-driven via the tag-push of `mcp-v0.1.0` against the `npm-publish` GitHub Environment (2-reviewer gate · OIDC trusted-publishing · Sigstore provenance). See `development/DEV_WAVE_4/MCP_PUBLISH_READINESS.md` §6 for the operator runbook.
@@ -1,11 +1,11 @@
1
- #!/usr/bin/env node
2
- /* eslint-disable */
3
- const { runCli } = require('../dist/broker.cjs');
4
-
5
- runCli(process.argv.slice(2)).then(
6
- (code) => process.exit(code ?? 0),
7
- (err) => {
8
- process.stderr.write(`fatal: ${err && err.stack ? err.stack : String(err)}\n`);
9
- process.exit(1);
10
- },
11
- );
1
+ #!/usr/bin/env node
2
+ /* eslint-disable */
3
+ const { runCli } = require('../dist/broker.cjs');
4
+
5
+ runCli(process.argv.slice(2)).then(
6
+ (code) => process.exit(code ?? 0),
7
+ (err) => {
8
+ process.stderr.write(`fatal: ${err && err.stack ? err.stack : String(err)}\n`);
9
+ process.exit(1);
10
+ },
11
+ );
@@ -1,11 +1,11 @@
1
- #!/usr/bin/env node
2
- /* eslint-disable */
3
- const { runMcpStdioCli } = require('../dist/index.cjs');
4
-
5
- runMcpStdioCli().then(
6
- () => process.exit(0),
7
- (err) => {
8
- process.stderr.write(`fatal: ${err && err.stack ? err.stack : String(err)}\n`);
9
- process.exit(1);
10
- },
11
- );
1
+ #!/usr/bin/env node
2
+ /* eslint-disable */
3
+ const { runMcpStdioCli } = require('../dist/index.cjs');
4
+
5
+ runMcpStdioCli().then(
6
+ () => process.exit(0),
7
+ (err) => {
8
+ process.stderr.write(`fatal: ${err && err.stack ? err.stack : String(err)}\n`);
9
+ process.exit(1);
10
+ },
11
+ );