@muhaven/mcp 0.1.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 ADDED
@@ -0,0 +1,123 @@
1
+ # Changelog
2
+
3
+ All notable changes to `@muhaven/mcp` will be documented in this file.
4
+
5
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
+ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
+
8
+ ## [Unreleased]
9
+
10
+ ## [0.1.0] — 2026-05-10
11
+
12
+ First publishable cut. All publish-readiness security must-fixes (H-1 / H-2 /
13
+ H-3 from `MCP_PUBLISH_READINESS.md` §2) and package-hygiene work landed on
14
+ `agenticwave` ahead of the npm publish ceremony. The actual `npm publish` is
15
+ gated on the operator-side `AGENTIC_TEST_PLAN.md` walkthroughs completing.
16
+
17
+ ### Added — Tools (22)
18
+
19
+ - `muhaven.read.*` (7): `portfolio` · `yields` · `distribution` · `tokens` ·
20
+ `audit` · `protection_coverage` · `kyc_attestation`
21
+ - `muhaven.position.*` (4): `buy` · `sell` · `claim` · `rebalance`
22
+ - `muhaven.policy.*` (4): `set_tier` · `pause` · `audit_export` ·
23
+ `session_key_status`
24
+ - `muhaven.issuer.*` (5): `distribute_yield` · `kyc_add` · `kyc_remove` ·
25
+ `unpause_token` · `audit_query`
26
+ - `muhaven.governance.*` (2): `propose` · `cast_vote` (frontend runner
27
+ deferred to Wave 5)
28
+
29
+ ### Added — Infrastructure
30
+
31
+ - MCPB-format `manifest.json` (manifest_version 0.2) declaring four
32
+ `user_config` entries (`backend_url`, `dashboard_url`, `broker_endpoint`,
33
+ `read_only`) so MCPB hosts (Claude Desktop, Cursor, future MCPB store) can
34
+ render install dialogs without the operator hand-editing config files.
35
+ - Companion `muhaven-broker` daemon over Unix socket (POSIX) / named pipe
36
+ (Windows). Holds the session-key private half; the MCP server never sees
37
+ the key, only signed UserOps it relays back to the LLM host.
38
+ - OAuth 2.0 Device Authorization Grant flow with scoped JWTs
39
+ (`mcp.read.*` + `mcp.propose.*`). Replaces paste-JWT UX; mitigates the
40
+ R-7 lethal-trifecta concern (env-block credential storage).
41
+ - Tool-description SHA-256 hash pinning (`tool-hashes.json` + the
42
+ `verify-tool-hashes` script). Server startup re-verifies and exits with
43
+ code `70` (`EX_CONFIG`) on drift; CI gate via the same script with
44
+ `--check`.
45
+ - `@napi-rs/keyring` integration for the broker's JWT keystore (Windows
46
+ DPAPI / macOS Security framework / Linux Secret Service via D-Bus) with
47
+ file-backed fallback (`MUHAVEN_KEYRING=file`) for WSL2 / devcontainer /
48
+ SSH-remote where Secret Service is absent.
49
+
50
+ ### Security
51
+
52
+ - Broker isolation: no TCP transport; POSIX socket created at mode `0700`
53
+ with file mode `0600`; Windows named-pipe ACL inherits user.
54
+ - STDIO-only MCP transport; `mcp-remote` (CVE-2025-6514) banned in README.
55
+ - Position / policy / issuer / governance tools return unsigned UserOps +
56
+ broker signatures; **never** auto-submit to a bundler.
57
+ - Tool-description hash pinning makes MCPoison-style descriptor-tampering
58
+ attacks fail-closed (server exits before the LLM sees the drifted text).
59
+ - Workstream A security must-fixes (commit `44bd8b2`):
60
+ - **H-1**: sourcemaps stripped from publish bundle (`tsup.config.ts`
61
+ gates on `MUHAVEN_DEV_BUILD=1`). Removes `.js.map` / `.cjs.map` /
62
+ `.d.ts.map` containing absolute developer paths from npm tarballs.
63
+ - **H-2**: `package.json` declares `publishConfig.{access:public,
64
+ registry:https://registry.npmjs.org/, provenance:true}` so a manual
65
+ `npm publish` from a recovery laptop can't silently publish privately
66
+ or without provenance.
67
+ - **H-3**: keystore probe round-trip-parses the OS-keychain value via
68
+ `parseRecord`. Malformed JSON / wrong-shape JSON / Secret-Service-down
69
+ each fall back to `FileKeystore` with a discriminated `fallbackReason`.
70
+ `muhaven-broker doctor` performs a non-destructive sentinel round-trip.
71
+ - Workstream B publint hardening (commit `a01116e`): `exports` map fixed
72
+ to per-condition `import.types` + `require.types` so TypeScript
73
+ resolution is honest on both ESM and CJS consumers.
74
+
75
+ ### Tests
76
+
77
+ - 100 vitest cases (`__tests__/`):
78
+ - `protocol` (13) — IPC frame codec / JSON-RPC envelope shape
79
+ - `backend-client` (5) — REST-call shape + error mapping
80
+ - `descriptions` (7) — descriptor surface drift detection
81
+ - `jwt-source` (5) — broker-cached JWT lifecycle
82
+ - `daemon-handler` (7) — IPC method dispatch
83
+ - `registry` (8) — tool registration invariants
84
+ - `mcp-redteam` (46) — adversarial inputs against `buildMcpServer` +
85
+ `InMemoryTransport`
86
+ - `daemon-lifecycle` (3) — bin shim survives past `runMcpStdioCli`
87
+ resolution (regression guard against the 2026-05-10 ship-blocker
88
+ bugs in `bin/*.cjs`)
89
+ - `keystore` (5) — H-3 OS-keychain probe regression coverage
90
+ - `build-artifacts` (1) — H-1 publish-bundle map-free assertion
91
+ - Three-way subset gate (`scripts/verify-tool-hashes.ts`) enforces
92
+ consistency between `src/index.ts` registry, `manifest.json#tools`,
93
+ and `tool-hashes.json`.
94
+
95
+ ### Known limitations (documented residuals — see SECURITY.md to land in
96
+ Workstream H)
97
+
98
+ - The MCP package is published WITHOUT a domain-bound icon — manifest's
99
+ `icon` field was deliberately removed in Workstream B because no asset
100
+ ships yet. MCPB host install dialogs render the default placeholder.
101
+ Real amber-gradient icon ships in a Wave 5 follow-up.
102
+ - Listed JSON schemas don't reflect per-tool field hints (L-1 backlog).
103
+ - `BackendClient` errors echo URL pathnames (L-2; recommend host-side
104
+ scrubbing).
105
+
106
+ ### Distribution
107
+
108
+ - Published via npm OIDC + Sigstore provenance attestations from the
109
+ `.github/workflows/mcp-publish.yml` workflow (tag-driven on
110
+ `mcp-v*`; manual `workflow_dispatch` available for recovery).
111
+ - Tarball + `.sigstore` bundle uploaded as workflow artifacts and as
112
+ files on the `mcp-v0.1.0` GitHub Release.
113
+ - Verify locally with:
114
+ ```
115
+ cosign verify-blob \
116
+ --bundle muhaven-mcp-0.1.0.tgz.sigstore \
117
+ --certificate-identity-regexp "^https://github\.com/hasToDev/muhaven/" \
118
+ --certificate-oidc-issuer "https://token.actions.githubusercontent.com" \
119
+ muhaven-mcp-0.1.0.tgz
120
+ ```
121
+
122
+ [Unreleased]: https://github.com/hasToDev/muhaven/compare/mcp-v0.1.0...HEAD
123
+ [0.1.0]: https://github.com/hasToDev/muhaven/releases/tag/mcp-v0.1.0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 hasToDev
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +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.
@@ -0,0 +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
+ );
@@ -0,0 +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
+ );