@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 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
@@ -2783,7 +2783,7 @@ function printUsage() {
2783
2783
  }
2784
2784
  function getBrokerPackageVersion() {
2785
2785
  {
2786
- return "0.2.6";
2786
+ return "0.2.7";
2787
2787
  }
2788
2788
  }
2789
2789
  function printVersion() {
package/dist/broker.js CHANGED
@@ -2785,7 +2785,7 @@ function printUsage() {
2785
2785
  }
2786
2786
  function getBrokerPackageVersion() {
2787
2787
  {
2788
- return "0.2.6";
2788
+ return "0.2.7";
2789
2789
  }
2790
2790
  }
2791
2791
  function printVersion() {
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: `pm_sponsorUserOperation rejected${detail}: ${safeMsg}`
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.6";
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: `pm_sponsorUserOperation rejected${detail}: ${safeMsg}`
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.6";
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",
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.6",
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": {