agentic-wallet-mcp 0.9.0 → 0.9.2

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
@@ -8,6 +8,37 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
8
8
  > Entries for 0.5.0 and earlier were reconstructed from commit history when this file was
9
9
  > introduced in 0.6.0, so they summarise each release rather than being exhaustive.
10
10
 
11
+ ## [0.9.2] — 3 September 2026
12
+
13
+ ### Fixed
14
+
15
+ - **`request_ai_birthcert_verification`'s sponsored-payment path no longer surfaces a facilitator
16
+ insufficient-funds rejection as an opaque, unhandled MCP tool error.** A `461407`
17
+ (`X402_INSUFFICIENT_FUNDS`) rejection from the facilitator's `/prepare` endpoint is now reshaped
18
+ into a clean `{ error }` result naming the asset and amount, instead of falling through every
19
+ error branch and throwing raw.
20
+ - **That message now renders amounts in human units, not raw base units.** A raw base-unit count
21
+ next to a token symbol (e.g. "requires 1,000,000 of JMYR") reads as a million *whole* tokens —
22
+ for a 6-decimal asset the actual requirement was 1 JMYR, a 1,000,000x misreading that could lead
23
+ to a drastically oversized top-up. Amounts are now resolved through the same symbol/decimals
24
+ formatter the rest of the wallet already uses.
25
+ - **The reported "current balance" is read from the facilitator's structured response field when
26
+ available**, falling back to parsing it out of the free-text error message only for an
27
+ older/unfixed facilitator — the free-text format was never a stable contract between the two
28
+ services.
29
+
30
+ ## [0.9.1] — 28 August 2026
31
+
32
+ ### Fixed
33
+
34
+ - **`request_ai_birthcert_verification` no longer blocks retrying an expired session.** If the
35
+ owner never completed MyDigital ID verification before a Verified AI Birthcert session's TTL
36
+ elapsed (`status: "expired"`), retrying previously threw an "unrecognized prior session status"
37
+ error and left the flow stuck — even though the settlement receipt was already safely persisted
38
+ locally and unconsumed. Any confirmed terminal session status other than `"issued"` (the only
39
+ status that consumes the receipt) is now treated the same as the existing 404/"gone" handling:
40
+ the receipt is replayed and a fresh verification session is opened, with no new payment made.
41
+
11
42
  ## [0.9.0] — 24 August 2026
12
43
 
13
44
  ### Added
@@ -12549,7 +12549,7 @@ var import_node_path6 = require("node:path");
12549
12549
  // package.json
12550
12550
  var package_default = {
12551
12551
  name: "agentic-wallet-mcp",
12552
- version: "0.9.0",
12552
+ version: "0.9.2",
12553
12553
  description: "Agent-facing MCP wallet for Zetrix \u2014 orchestrates x401 identity proof, x402 payment, and MBI VC issuance",
12554
12554
  keywords: [
12555
12555
  "mcp",
@@ -23406,13 +23406,14 @@ async function decidePriorSession(deps, agentName) {
23406
23406
  if (stored.agentName !== agentName) {
23407
23407
  const otherStatus = await getConfirmedStatus(deps, stored.sessionId);
23408
23408
  if (otherStatus === "gone") return { kind: "replay_receipt", receipt: stored.paymentReceipt };
23409
- if (otherStatus.status !== "issued") {
23409
+ if (otherStatus.status === "pending") {
23410
23410
  return {
23411
23411
  kind: "blocked",
23412
- message: `a verification session for a different agent ("${stored.agentName}") is still in progress (status: "${otherStatus.status}") and its payment has not been consumed yet \u2014 starting a new session for "${agentName}" would lose track of it. Call check_ai_birthcert_verification to resolve or confirm it first.`
23412
+ message: `a verification session for a different agent ("${stored.agentName}") is still in progress (status: "pending") and its payment has not been consumed yet \u2014 starting a new session for "${agentName}" would lose track of it. Call check_ai_birthcert_verification to resolve or confirm it first.`
23413
23413
  };
23414
23414
  }
23415
- return { kind: "pay_fresh" };
23415
+ if (otherStatus.status === "issued") return { kind: "pay_fresh" };
23416
+ return { kind: "replay_receipt", receipt: stored.paymentReceipt };
23416
23417
  }
23417
23418
  const status = await getConfirmedStatus(deps, stored.sessionId);
23418
23419
  if (status === "gone") return { kind: "replay_receipt", receipt: stored.paymentReceipt };
@@ -23423,9 +23424,7 @@ async function decidePriorSession(deps, agentName) {
23423
23424
  };
23424
23425
  }
23425
23426
  if (status.status === "issued") return { kind: "pay_fresh" };
23426
- throw new Error(
23427
- `requestAiBirthcertVerification: unrecognized prior session status "${status.status}" for session ${stored.sessionId} \u2014 refusing to guess whether its settlement receipt is safe to replay (see SPEC.md D8)`
23428
- );
23427
+ return { kind: "replay_receipt", receipt: stored.paymentReceipt };
23429
23428
  }
23430
23429
  var requestQueue = Promise.resolve();
23431
23430
  function withRequestLock(fn) {
@@ -23497,6 +23496,7 @@ var DEFINITIVE_PREPARE_REFUSALS = /* @__PURE__ */ new Set([
23497
23496
  461415
23498
23497
  // X402_UNSUPPORTED_ASSET — sponsorship is ZTP-20 only
23499
23498
  ]);
23499
+ var FACILITATOR_INSUFFICIENT_FUNDS_CODE = 461407;
23500
23500
  function facilitatorErrorCode(err) {
23501
23501
  const m = /"errorCode"\s*:\s*(\d{6})/.exec(err instanceof Error ? err.message : String(err));
23502
23502
  return m ? Number(m[1]) : void 0;
@@ -23516,6 +23516,41 @@ function isDefinitiveSponsorshipFailure(err) {
23516
23516
  if (code === void 0) return false;
23517
23517
  return DEFINITIVE_PREPARE_REFUSALS.has(code);
23518
23518
  }
23519
+ var FacilitatorInsufficientFundsError = class extends Error {
23520
+ constructor(requiredHuman, availableHuman, rawMessage) {
23521
+ super(
23522
+ `insufficient funds: the sponsored payment requires ${requiredHuman}` + (availableHuman !== void 0 ? ` \u2014 this wallet currently holds ${availableHuman}` : " and this wallet does not hold enough of it") + ` (facilitator: ${rawMessage})`
23523
+ );
23524
+ this.name = "FacilitatorInsufficientFundsError";
23525
+ }
23526
+ };
23527
+ function extractFacilitatorBalance(rawMessage) {
23528
+ const braceIdx = rawMessage.indexOf("{");
23529
+ if (braceIdx !== -1) {
23530
+ try {
23531
+ const body = JSON.parse(rawMessage.slice(braceIdx));
23532
+ const detail = body.messages?.[0]?.detail;
23533
+ if (Array.isArray(detail) && detail.length >= 3 && detail[2] !== null && detail[2] !== void 0) {
23534
+ return String(detail[2]);
23535
+ }
23536
+ } catch {
23537
+ }
23538
+ }
23539
+ const m = /insufficient_funds \[[^,]+,\s*[^,]+,\s*([^\]]+)\]/.exec(rawMessage);
23540
+ return m ? m[1].trim() : void 0;
23541
+ }
23542
+ async function toFacilitatorInsufficientFundsError(err, accept, formatAssetAmount) {
23543
+ if (!(err instanceof PrepareStageError)) return err;
23544
+ if (facilitatorErrorCode(err.cause) !== FACILITATOR_INSUFFICIENT_FUNDS_CODE) return err;
23545
+ const asset = accept.asset ?? "";
23546
+ const maxAmountRequired = accept.maxAmountRequired ?? "";
23547
+ if (!asset || !maxAmountRequired) return err;
23548
+ const rawMessage = err.cause instanceof Error ? err.cause.message : String(err.cause);
23549
+ const requiredHuman = formatAssetAmount ? await formatAssetAmount(asset, maxAmountRequired) : `${maxAmountRequired} of asset "${asset}"`;
23550
+ const availableRaw = extractFacilitatorBalance(rawMessage);
23551
+ const availableHuman = availableRaw !== void 0 && formatAssetAmount ? await formatAssetAmount(asset, availableRaw) : availableRaw;
23552
+ return new FacilitatorInsufficientFundsError(requiredHuman, availableHuman, rawMessage);
23553
+ }
23519
23554
  async function attemptCandidate(deps, accept, buildBody, onQueued) {
23520
23555
  let xPayment;
23521
23556
  try {
@@ -23535,8 +23570,9 @@ async function payAndCreateSession(deps, buildBody, onQueued) {
23535
23570
  return await attemptCandidate(deps, primary, buildBody, onQueued);
23536
23571
  } catch (err) {
23537
23572
  const fallback = candidates[1];
23538
- if (!fallback || !isSponsored(primary) || isSponsored(fallback)) throw err;
23539
- if (!isDefinitiveSponsorshipFailure(err)) throw err;
23573
+ if (!fallback || !isSponsored(primary) || isSponsored(fallback) || !isDefinitiveSponsorshipFailure(err)) {
23574
+ throw await toFacilitatorInsufficientFundsError(err, primary, deps.formatAssetAmount);
23575
+ }
23540
23576
  return await attemptCandidate(deps, fallback, buildBody, onQueued);
23541
23577
  }
23542
23578
  }
@@ -23606,6 +23642,7 @@ async function requestAiBirthcertVerificationLocked(deps, agentName, input) {
23606
23642
  if (err instanceof PaymentReadinessError) return { error: `insufficient funds: ${err.message}` };
23607
23643
  if (err instanceof PaymentCapError) return { error: err.message };
23608
23644
  if (err instanceof NoPaymentOptionsError) return { error: err.message };
23645
+ if (err instanceof FacilitatorInsufficientFundsError) return { error: err.message };
23609
23646
  if (err instanceof SettlementStillQueuedError) {
23610
23647
  try {
23611
23648
  await deps.sessionStore.set({
@@ -24016,7 +24053,8 @@ async function main() {
24016
24053
  cache: vcCache,
24017
24054
  quarantine: downloadQuarantine,
24018
24055
  gasPreference: config2.gasPreference,
24019
- maxSettlementAttempts: config2.maxSettlementAttempts
24056
+ maxSettlementAttempts: config2.maxSettlementAttempts,
24057
+ formatAssetAmount
24020
24058
  };
24021
24059
  return {
24022
24060
  request: (input) => requestAiBirthcertVerification(verifyAiBirthcertDeps, input),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agentic-wallet-mcp",
3
- "version": "0.9.0",
3
+ "version": "0.9.2",
4
4
  "description": "Agent-facing MCP wallet for Zetrix — orchestrates x401 identity proof, x402 payment, and MBI VC issuance",
5
5
  "keywords": [
6
6
  "mcp",