@muhaven/mcp 0.2.6 → 0.2.7
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 +34 -0
- package/dist/broker.cjs +1 -1
- package/dist/broker.js +1 -1
- package/dist/index.cjs +42 -2
- package/dist/index.js +42 -2
- package/manifest.json +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,40 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [0.2.7] — 2026-05-23
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
|
|
14
|
+
- **Startup banner (always on).** `runMcpStdioCli` writes one stderr
|
|
15
|
+
line at boot with the running version + verbose mode:
|
|
16
|
+
|
|
17
|
+
[muhaven-mcp] starting @muhaven/mcp@0.2.7 (verbose=off)
|
|
18
|
+
|
|
19
|
+
Multiple smoke iterations have been ambiguous about whether
|
|
20
|
+
`npm i -g @muhaven/mcp@<v>` actually updated the global binary
|
|
21
|
+
picked up by Claude Code (the subprocess only re-spawns on FULL
|
|
22
|
+
Claude Code restart, not `/mcp reconnect`). One stderr line at boot
|
|
23
|
+
makes the version mismatch impossible to miss.
|
|
24
|
+
|
|
25
|
+
- **Verbose paymaster/bundler logging (`MUHAVEN_MCP_VERBOSE=1`).**
|
|
26
|
+
Gated env var that emits two stderr lines per bundler RPC:
|
|
27
|
+
|
|
28
|
+
[muhaven-mcp] [bundler→] zd_sponsorUserOperation id=N body={...}
|
|
29
|
+
[muhaven-mcp] [bundler←] zd_sponsorUserOperation id=N resp={...}
|
|
30
|
+
|
|
31
|
+
Bodies truncated at 2KB; covers happy-path, http_error, timeout,
|
|
32
|
+
non-JSON, network failures. Add `"MUHAVEN_MCP_VERBOSE": "1"` to the
|
|
33
|
+
`.mcp.json` env block when triaging a `pathDFallbackReason` —
|
|
34
|
+
removes the need for curl repro entirely.
|
|
35
|
+
|
|
36
|
+
### Fixed
|
|
37
|
+
|
|
38
|
+
- **Stale `pm_sponsorUserOperation` label in the
|
|
39
|
+
`paymaster_rejected` fallback message** (0.2.4 leftover). The
|
|
40
|
+
actual method call has been `zd_sponsorUserOperation` since 0.2.4,
|
|
41
|
+
but the error message label still said `pm_*`. No functional
|
|
42
|
+
impact — just a confusing log string when the gate fires.
|
|
43
|
+
|
|
10
44
|
## [0.2.6] — 2026-05-23
|
|
11
45
|
|
|
12
46
|
### Fixed
|
package/dist/broker.cjs
CHANGED
package/dist/broker.js
CHANGED
package/dist/index.cjs
CHANGED
|
@@ -1211,6 +1211,14 @@ var BundlerClient = class {
|
|
|
1211
1211
|
async rpc(method, params) {
|
|
1212
1212
|
const id = this.nextRpcId++;
|
|
1213
1213
|
const body = JSON.stringify({ jsonrpc: "2.0", id, method, params });
|
|
1214
|
+
const verbose = process.env.MUHAVEN_MCP_VERBOSE === "1";
|
|
1215
|
+
if (verbose) {
|
|
1216
|
+
const bodyDump = body.length > 2048 ? body.slice(0, 2048) + "\u2026(truncated)" : body;
|
|
1217
|
+
process.stderr.write(
|
|
1218
|
+
`[muhaven-mcp] [bundler\u2192] ${method} id=${id} body=${bodyDump}
|
|
1219
|
+
`
|
|
1220
|
+
);
|
|
1221
|
+
}
|
|
1214
1222
|
const ctrl = new AbortController();
|
|
1215
1223
|
const timer = setTimeout(() => ctrl.abort(), this.options.requestTimeoutMs);
|
|
1216
1224
|
let res;
|
|
@@ -1231,8 +1239,18 @@ var BundlerClient = class {
|
|
|
1231
1239
|
} catch (err2) {
|
|
1232
1240
|
clearTimeout(timer);
|
|
1233
1241
|
if (err2.name === "AbortError") {
|
|
1242
|
+
if (verbose) {
|
|
1243
|
+
process.stderr.write(`[muhaven-mcp] [bundler\u2717] ${method} id=${id} timeout
|
|
1244
|
+
`);
|
|
1245
|
+
}
|
|
1234
1246
|
throw new BundlerClientError("timeout", `bundler ${method} timed out`);
|
|
1235
1247
|
}
|
|
1248
|
+
if (verbose) {
|
|
1249
|
+
process.stderr.write(
|
|
1250
|
+
`[muhaven-mcp] [bundler\u2717] ${method} id=${id} network err=${err2 instanceof Error ? err2.message : String(err2)}
|
|
1251
|
+
`
|
|
1252
|
+
);
|
|
1253
|
+
}
|
|
1236
1254
|
throw new BundlerClientError(
|
|
1237
1255
|
"network",
|
|
1238
1256
|
`bundler ${method} network error: ${err2 instanceof Error ? err2.message : String(err2)}`,
|
|
@@ -1247,6 +1265,12 @@ var BundlerClient = class {
|
|
|
1247
1265
|
text = (await res.text()).slice(0, 256);
|
|
1248
1266
|
} catch {
|
|
1249
1267
|
}
|
|
1268
|
+
if (verbose) {
|
|
1269
|
+
process.stderr.write(
|
|
1270
|
+
`[muhaven-mcp] [bundler\u2717] ${method} id=${id} HTTP ${res.status} body=${text}
|
|
1271
|
+
`
|
|
1272
|
+
);
|
|
1273
|
+
}
|
|
1250
1274
|
throw new BundlerClientError(
|
|
1251
1275
|
"http_error",
|
|
1252
1276
|
`bundler ${method} \u2192 HTTP ${res.status}: ${text}`
|
|
@@ -1256,11 +1280,23 @@ var BundlerClient = class {
|
|
|
1256
1280
|
try {
|
|
1257
1281
|
parsed = await res.json();
|
|
1258
1282
|
} catch (err2) {
|
|
1283
|
+
if (verbose) {
|
|
1284
|
+
process.stderr.write(
|
|
1285
|
+
`[muhaven-mcp] [bundler\u2717] ${method} id=${id} non-JSON err=${err2 instanceof Error ? err2.message : String(err2)}
|
|
1286
|
+
`
|
|
1287
|
+
);
|
|
1288
|
+
}
|
|
1259
1289
|
throw new BundlerClientError(
|
|
1260
1290
|
"invalid_response",
|
|
1261
1291
|
`bundler ${method} returned non-JSON: ${err2 instanceof Error ? err2.message : String(err2)}`
|
|
1262
1292
|
);
|
|
1263
1293
|
}
|
|
1294
|
+
if (verbose) {
|
|
1295
|
+
const respDump = JSON.stringify(parsed);
|
|
1296
|
+
const trunc = respDump.length > 2048 ? respDump.slice(0, 2048) + "\u2026(truncated)" : respDump;
|
|
1297
|
+
process.stderr.write(`[muhaven-mcp] [bundler\u2190] ${method} id=${id} resp=${trunc}
|
|
1298
|
+
`);
|
|
1299
|
+
}
|
|
1264
1300
|
if (typeof parsed !== "object" || parsed === null) {
|
|
1265
1301
|
throw new BundlerClientError(
|
|
1266
1302
|
"invalid_response",
|
|
@@ -2462,7 +2498,7 @@ async function attemptPathD(args, deps) {
|
|
|
2462
2498
|
return {
|
|
2463
2499
|
kind: "fallback",
|
|
2464
2500
|
reason: "paymaster_rejected",
|
|
2465
|
-
message: `
|
|
2501
|
+
message: `zd_sponsorUserOperation rejected${detail}: ${safeMsg}`
|
|
2466
2502
|
};
|
|
2467
2503
|
}
|
|
2468
2504
|
const userOpForHash = {
|
|
@@ -3057,7 +3093,7 @@ var SERVER_NAME = "@muhaven/mcp";
|
|
|
3057
3093
|
var SERVER_VERSION = resolveServerVersion();
|
|
3058
3094
|
function resolveServerVersion() {
|
|
3059
3095
|
{
|
|
3060
|
-
return "0.2.
|
|
3096
|
+
return "0.2.7";
|
|
3061
3097
|
}
|
|
3062
3098
|
}
|
|
3063
3099
|
function toJsonInputSchema(schema) {
|
|
@@ -3176,6 +3212,10 @@ function toolJsonResponse(payload) {
|
|
|
3176
3212
|
}
|
|
3177
3213
|
async function runMcpStdioCli(opts = {}) {
|
|
3178
3214
|
const config = loadMcpConfig();
|
|
3215
|
+
process.stderr.write(
|
|
3216
|
+
`[muhaven-mcp] starting @muhaven/mcp@${SERVER_VERSION} (verbose=${process.env.MUHAVEN_MCP_VERBOSE === "1" ? "on" : "off"})
|
|
3217
|
+
`
|
|
3218
|
+
);
|
|
3179
3219
|
const pinned = await loadPinnedToolHashes();
|
|
3180
3220
|
const verify = verifyToolHashes(pinned);
|
|
3181
3221
|
if (!verify.ok) {
|
package/dist/index.js
CHANGED
|
@@ -1207,6 +1207,14 @@ var BundlerClient = class {
|
|
|
1207
1207
|
async rpc(method, params) {
|
|
1208
1208
|
const id = this.nextRpcId++;
|
|
1209
1209
|
const body = JSON.stringify({ jsonrpc: "2.0", id, method, params });
|
|
1210
|
+
const verbose = process.env.MUHAVEN_MCP_VERBOSE === "1";
|
|
1211
|
+
if (verbose) {
|
|
1212
|
+
const bodyDump = body.length > 2048 ? body.slice(0, 2048) + "\u2026(truncated)" : body;
|
|
1213
|
+
process.stderr.write(
|
|
1214
|
+
`[muhaven-mcp] [bundler\u2192] ${method} id=${id} body=${bodyDump}
|
|
1215
|
+
`
|
|
1216
|
+
);
|
|
1217
|
+
}
|
|
1210
1218
|
const ctrl = new AbortController();
|
|
1211
1219
|
const timer = setTimeout(() => ctrl.abort(), this.options.requestTimeoutMs);
|
|
1212
1220
|
let res;
|
|
@@ -1227,8 +1235,18 @@ var BundlerClient = class {
|
|
|
1227
1235
|
} catch (err2) {
|
|
1228
1236
|
clearTimeout(timer);
|
|
1229
1237
|
if (err2.name === "AbortError") {
|
|
1238
|
+
if (verbose) {
|
|
1239
|
+
process.stderr.write(`[muhaven-mcp] [bundler\u2717] ${method} id=${id} timeout
|
|
1240
|
+
`);
|
|
1241
|
+
}
|
|
1230
1242
|
throw new BundlerClientError("timeout", `bundler ${method} timed out`);
|
|
1231
1243
|
}
|
|
1244
|
+
if (verbose) {
|
|
1245
|
+
process.stderr.write(
|
|
1246
|
+
`[muhaven-mcp] [bundler\u2717] ${method} id=${id} network err=${err2 instanceof Error ? err2.message : String(err2)}
|
|
1247
|
+
`
|
|
1248
|
+
);
|
|
1249
|
+
}
|
|
1232
1250
|
throw new BundlerClientError(
|
|
1233
1251
|
"network",
|
|
1234
1252
|
`bundler ${method} network error: ${err2 instanceof Error ? err2.message : String(err2)}`,
|
|
@@ -1243,6 +1261,12 @@ var BundlerClient = class {
|
|
|
1243
1261
|
text = (await res.text()).slice(0, 256);
|
|
1244
1262
|
} catch {
|
|
1245
1263
|
}
|
|
1264
|
+
if (verbose) {
|
|
1265
|
+
process.stderr.write(
|
|
1266
|
+
`[muhaven-mcp] [bundler\u2717] ${method} id=${id} HTTP ${res.status} body=${text}
|
|
1267
|
+
`
|
|
1268
|
+
);
|
|
1269
|
+
}
|
|
1246
1270
|
throw new BundlerClientError(
|
|
1247
1271
|
"http_error",
|
|
1248
1272
|
`bundler ${method} \u2192 HTTP ${res.status}: ${text}`
|
|
@@ -1252,11 +1276,23 @@ var BundlerClient = class {
|
|
|
1252
1276
|
try {
|
|
1253
1277
|
parsed = await res.json();
|
|
1254
1278
|
} catch (err2) {
|
|
1279
|
+
if (verbose) {
|
|
1280
|
+
process.stderr.write(
|
|
1281
|
+
`[muhaven-mcp] [bundler\u2717] ${method} id=${id} non-JSON err=${err2 instanceof Error ? err2.message : String(err2)}
|
|
1282
|
+
`
|
|
1283
|
+
);
|
|
1284
|
+
}
|
|
1255
1285
|
throw new BundlerClientError(
|
|
1256
1286
|
"invalid_response",
|
|
1257
1287
|
`bundler ${method} returned non-JSON: ${err2 instanceof Error ? err2.message : String(err2)}`
|
|
1258
1288
|
);
|
|
1259
1289
|
}
|
|
1290
|
+
if (verbose) {
|
|
1291
|
+
const respDump = JSON.stringify(parsed);
|
|
1292
|
+
const trunc = respDump.length > 2048 ? respDump.slice(0, 2048) + "\u2026(truncated)" : respDump;
|
|
1293
|
+
process.stderr.write(`[muhaven-mcp] [bundler\u2190] ${method} id=${id} resp=${trunc}
|
|
1294
|
+
`);
|
|
1295
|
+
}
|
|
1260
1296
|
if (typeof parsed !== "object" || parsed === null) {
|
|
1261
1297
|
throw new BundlerClientError(
|
|
1262
1298
|
"invalid_response",
|
|
@@ -2458,7 +2494,7 @@ async function attemptPathD(args, deps) {
|
|
|
2458
2494
|
return {
|
|
2459
2495
|
kind: "fallback",
|
|
2460
2496
|
reason: "paymaster_rejected",
|
|
2461
|
-
message: `
|
|
2497
|
+
message: `zd_sponsorUserOperation rejected${detail}: ${safeMsg}`
|
|
2462
2498
|
};
|
|
2463
2499
|
}
|
|
2464
2500
|
const userOpForHash = {
|
|
@@ -3053,7 +3089,7 @@ var SERVER_NAME = "@muhaven/mcp";
|
|
|
3053
3089
|
var SERVER_VERSION = resolveServerVersion();
|
|
3054
3090
|
function resolveServerVersion() {
|
|
3055
3091
|
{
|
|
3056
|
-
return "0.2.
|
|
3092
|
+
return "0.2.7";
|
|
3057
3093
|
}
|
|
3058
3094
|
}
|
|
3059
3095
|
function toJsonInputSchema(schema) {
|
|
@@ -3172,6 +3208,10 @@ function toolJsonResponse(payload) {
|
|
|
3172
3208
|
}
|
|
3173
3209
|
async function runMcpStdioCli(opts = {}) {
|
|
3174
3210
|
const config = loadMcpConfig();
|
|
3211
|
+
process.stderr.write(
|
|
3212
|
+
`[muhaven-mcp] starting @muhaven/mcp@${SERVER_VERSION} (verbose=${process.env.MUHAVEN_MCP_VERBOSE === "1" ? "on" : "off"})
|
|
3213
|
+
`
|
|
3214
|
+
);
|
|
3175
3215
|
const pinned = await loadPinnedToolHashes();
|
|
3176
3216
|
const verify = verifyToolHashes(pinned);
|
|
3177
3217
|
if (!verify.ok) {
|
package/manifest.json
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"manifest_version": "0.2",
|
|
4
4
|
"name": "muhaven-mcp",
|
|
5
5
|
"display_name": "MuHaven (RWA portfolio)",
|
|
6
|
-
"version": "0.2.
|
|
6
|
+
"version": "0.2.7",
|
|
7
7
|
"description": "Confidential RWA portfolio management on Fhenix CoFHE. Read your encrypted balances, propose yield claims and policy changes — all signing happens in a sibling broker daemon, the LLM never sees your private key.",
|
|
8
8
|
"long_description": "MuHaven MCP exposes 24 tools across read.* / position.* / policy.* / issuer.* / governance.* groups for managing real-world asset (RWA) tokens with FHE-encrypted balances. Authentication uses a one-time device-code ceremony (run `muhaven-broker login`); subsequent tool calls fetch the JWT from the broker over a Unix socket. Position / governance tools deep-link to the dashboard for passkey signing — they NEVER auto-submit to a bundler. The companion `muhaven-broker` daemon must be running before tools can be invoked. See README for setup.",
|
|
9
9
|
"author": {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@muhaven/mcp",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.7",
|
|
4
4
|
"description": "MuHaven MCP server — read/position/policy toolsets bridging Claude Desktop / Cursor / Claude Code to the MuHaven backend, with a sibling muhaven-broker daemon holding the session-key private half over a local IPC socket",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"repository": {
|