agentic-wallet-mcp 0.2.0 → 0.3.1

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/README.md CHANGED
@@ -8,14 +8,12 @@ through Wallet BE's HSM.
8
8
 
9
9
  - **x401** proof → [`x401-zetrix-client`](https://www.npmjs.com/package/x401-zetrix-client) (npm)
10
10
  - **x402** payment → [`x402-zetrix-client`](https://www.npmjs.com/package/x402-zetrix-client) (npm)
11
- - **VC presentation** (BBS+ VP derivation) → MBI RS (`/v1/vp/ext/create` + `/v1/vp/ext/submit`, `includeVp: true` — BT-2357)
11
+ - **VC presentation** (BBS+ VP derivation) → MBI RS (`/v1/vp/ext/create` + `/v1/vp/ext/submit`, `includeVp: true`)
12
12
  - **issuer key resolution** (for the OID4VP submit body) → the Zetrix ZID resolver (`https://zid-resolver[-sandbox].zetrix.com`)
13
13
  - **holder key custody + signing** → Wallet BE softHSM (`/wallet/hsm/*`)
14
14
  - **VC issuance** → MBI RS (`/v1/vc/pay/*`)
15
15
 
16
- [`docs/CONTRACT_RECONCILIATION.md`](docs/CONTRACT_RECONCILIATION.md) has the authoritative
17
- endpoint/contract map, [`docs/DEVELOPMENT_CHECKLIST.md`](docs/DEVELOPMENT_CHECKLIST.md) has status,
18
- and [`docs/USAGE_FLOW.md`](docs/USAGE_FLOW.md) has a full end-to-end prompt script (onboarding →
16
+ [`docs/USAGE_FLOW.md`](docs/USAGE_FLOW.md) has a full end-to-end prompt script (onboarding →
19
17
  VC issuance → identity proof → pay-per-use).
20
18
 
21
19
  ## Tools
@@ -51,8 +49,7 @@ VC issuance → identity proof → pay-per-use).
51
49
  > resolves the issuer's DID document via the Zetrix ZID resolver, and matches the BBS+
52
50
  > (`publicKeyMultibase`) and Ed25519 (`publicKeyHex`) verification methods referenced by the VC's
53
51
  > own proofs. `issuerKeys` is still accepted as a manual escape hatch if the resolver is ever
54
- > unreachable. See `docs/CONTRACT_RECONCILIATION.md §8` for the full trace through the verifier's
55
- > source that led to this.
52
+ > unreachable.
56
53
 
57
54
  ## Install
58
55
 
@@ -81,10 +78,10 @@ Node ≥ 18 required (built-in `fetch`).
81
78
  | `HOLDER_DID` | no | Holder DID. Omit and the MCP derives it automatically — see "Onboarding" below |
82
79
  | `WALLET_BE_URL` | no | Wallet BE base URL override (HSM `/wallet/hsm/sign-blob`) — auto-derived from `ZETRIX_NETWORK` when not set |
83
80
  | `MBI_BASE_URL` | no | MBI RS base URL override (`/v1/vc/pay/apply`) — auto-derived from `ZETRIX_NETWORK` when not set |
84
- | `OID4VP_BASE_URL` | no | OID4VP verifier base URL override — auto-derived from `ZETRIX_NETWORK` by the x401 SDK when not set (BT-2368) |
81
+ | `OID4VP_BASE_URL` | no | OID4VP verifier base URL override — auto-derived from `ZETRIX_NETWORK` by the x401 SDK when not set |
85
82
  | `ZETRIX_NODE_HOST` / `ZETRIX_NODE_PORT` | no | RPC node override (auto-derived from network) |
86
83
  | `ZID_RESOLVER_BASE_URL` | no | ZID resolver override (auto-derived from network: sandbox for testnet, prod for mainnet) |
87
- | `MAX_PAYMENT_AMOUNT` | no** | Per-asset x402 auto-pay cap — JSON `{ "<asset>": "<maxRawUnits>", "*": "<fallback>" }`, e.g. `{"ZTX":"1000000000","*":"0"}`. Unset = no cap enforced. |
84
+ | `MAX_PAYMENT_AMOUNT` | no** | Per-asset x402 auto-pay cap — JSON `{ "<asset>": "<maxRawUnits>", "*": "<fallback>" }`. `pay_and_fetch`/`subscribe_and_issue` are asset-agnostic: the resource server's 402 challenge may quote the native ZETRIX token (asset code `ZTX`) **or** a ZTP20 token (e.g. `JMYR`) — cap whichever assets you expect, e.g. `{"ZTX":"1000000000","JMYR":"5000000","*":"0"}`. Unset = no cap enforced. |
88
85
 
89
86
  \* sensitive — never logged.
90
87
 
@@ -133,7 +130,7 @@ default one — an explicit value always wins over the network default. The `*.m
133
130
  troubleshooting" below if any of them time out.
134
131
 
135
132
  That's the complete list — no VC-MCP subprocess, no BaaS gateway key, no manually-configured
136
- BBS+ key to set up (BT-2357 replaced that whole path — see `docs/CONTRACT_RECONCILIATION.md §8`).
133
+ BBS+ key to set up.
137
134
 
138
135
  ## Configuring in Claude Desktop / Claude Code
139
136
 
@@ -202,12 +199,12 @@ either way, restart the server afterward (env vars load once, at process start).
202
199
  `heldCredentials`; the response tells you whether the agent-identity credential you need is
203
200
  already there. Skip to Phase 3 if so.
204
201
 
205
- **Phase 2 — `subscribe_and_issue` — VC issuance (✅ live-verified).**
202
+ **Phase 2 — `subscribe_and_issue` — VC issuance.**
206
203
  `{ templateId, attributes }` → holder-signs the payload via Wallet BE → MBI's x402 `402` →
207
204
  self-pay → MBI settles **and** issues the VC in one call. **Hold onto the returned `vc`** — it's
208
205
  what you pass into every future `prove_identity` call.
209
206
 
210
- **Phase 3 — `prove_identity` — x401 identity proof (✅ live-verified, `VERIFIED`).**
207
+ **Phase 3 — `prove_identity` — x401 identity proof.**
211
208
  `{ proofRequest, vc }` (omit `revealAttribute`/`issuerKeys` — both now resolve automatically).
212
209
  Internally: fetch the OID4VP presentation definition → derive the BBS+ selective-disclosure VP
213
210
  via MBI (`/vp/ext/create` + `/vp/ext/submit`, `includeVp: true`) → resolve the issuer's
@@ -217,7 +214,7 @@ resource server happens outside this MCP, in whatever drove the conversation. Se
217
214
  `PROOF-REQUEST` header" section in [`docs/USAGE_FLOW.md`](docs/USAGE_FLOW.md) for the exact wire
218
215
  structure and field semantics.
219
216
 
220
- **Phase 4 — `pay_and_fetch` — pay-per-use (✅ live-verified).**
217
+ **Phase 4 — `pay_and_fetch` — pay-per-use.**
221
218
  `{ url, method?, headers?, body? }` → fetch → on `402`, self-pay → retry with `X-PAYMENT`.
222
219
  Independent of Phases 2/3 — no VC or identity proof involved, just a fresh payment per call.
223
220
 
@@ -230,10 +227,10 @@ observed so far, the code was correct and the network/edge state had changed.
230
227
  | Symptom | Cause | Fix / status |
231
228
  |---|---|---|
232
229
  | `Wallet BE /wallet/hsm/sign-blob request failed <- fetch failed <- UND_ERR_CONNECT_TIMEOUT` (or same for `mbi-vc.myegdev.com`) | `*.myegdev.com` hosts are internal — unreachable without VPN | Connect/reconnect your VPN, then retry. Verify first: `curl -I https://wallet-api.myegdev.com/server` |
233
- | `VP derivation failed <- ZID resolver HTTP 403 ... cf-mitigated: challenge` | ZID resolver (`zid-resolver-sandbox.zetrix.com`) was behind a Cloudflare **managed challenge** that blocked plain server-to-server `fetch` | **Fixed 2026-07-17** — DevOps allowlisted server-to-server access; the resolver now returns `200` directly (verified: `curl https://zid-resolver-sandbox.zetrix.com/1.0/identifiers/<did>` real DID document, keys byte-identical to a browser-fetched copy). If it ever regresses, `prove_identity`'s `issuerKeys` input is the fallback — fetch the DID document via a real browser (it clears the JS challenge) and pass its `verificationMethod` entries' `publicKeyMultibase` (BBS+) / `publicKeyHex` (Ed25519) directly. |
230
+ | `VP derivation failed <- ZID resolver HTTP 403 ... cf-mitigated: challenge` | ZID resolver (`zid-resolver-sandbox.zetrix.com`) sitting behind a Cloudflare **managed challenge** that blocks plain server-to-server `fetch` | Server-to-server access to the resolver must be allowlisted so it returns `200` directly. If the challenge is active, `prove_identity`'s `issuerKeys` input is the fallback — fetch the DID document via a real browser (it clears the JS challenge) and pass its `verificationMethod` entries' `publicKeyMultibase` (BBS+) / `publicKeyHex` (Ed25519) directly. |
234
231
  | `OID4VP backend returned a malformed presentation definition` | Historical SDK bug: the live sandbox's `GET /v1/presentation/{id}` response has no `expires_at` field, but the SDK guard required one | **Fixed** in `x401-zetrix-client` — `expiresAt` is now optional on `PresentationDefinition`. If you see this, you're on a stale cached `npx` install — clear it (`npx clear-npx-cache` or bump the version) to pick up the current published `agentic-wallet-mcp`. |
235
232
  | `SUBMIT_FAILED: OID4VP backend returned 401 ... Missing X-Wallet-Public-Key header` | Historical SDK gap: `POST /v1/presentation/submit` requires wallet-auth headers (`X-Wallet-Public-Key` / `X-Wallet-Signed-Data`, holder signs their own address) that the SDK didn't send | **Fixed** — `X401Wallet` now accepts an injected `submitAuth` provider and the wallet wires it automatically; nothing to configure. |
236
- | `MBI /vp/ext/submit did not return vp` | MBI's `includeVp` opt-in (BT-2357) not deployed on the target instance | Confirmed deployed on the sandbox (`mbi-vc.myegdev.com`). If you see this against a different MBI instance, that instance needs the same rollout. |
233
+ | `MBI /vp/ext/submit did not return vp` | MBI's `includeVp` opt-in not deployed on the target instance | Deployed on the sandbox (`mbi-vc.myegdev.com`). If you see this against a different MBI instance, that instance needs the same rollout. |
237
234
 
238
235
  ## Security notes
239
236
 
@@ -241,8 +238,7 @@ observed so far, the code was correct and the network/edge state had changed.
241
238
  Wallet BE's HSM (`/wallet/hsm/*`); `walletCfg.privateKey` is always `''`.
242
239
  - **`MAX_PAYMENT_AMOUNT` is the real control against unbounded auto-spend** — see Environment
243
240
  above. Without it, `pay_and_fetch`/`subscribe_and_issue` will pay whatever a server's `402`
244
- challenge demands, up to the HSM account's balance. This was raised in code review (finding
245
- AWL-M01) specifically because an agent-side "confirm before paying" step is not a real security
246
- boundary: the same prompt injection or bad instruction that drove the call in the first place
247
- could just as easily drive the confirmation.
241
+ challenge demands, up to the HSM account's balance. An agent-side "confirm before paying" step
242
+ is not a real security boundary: the same prompt injection or bad instruction that drove the
243
+ call in the first place could just as easily drive the confirmation.
248
244
 
@@ -12541,6 +12541,54 @@ __export(index_exports, {
12541
12541
  });
12542
12542
  module.exports = __toCommonJS(index_exports);
12543
12543
 
12544
+ // package.json
12545
+ var package_default = {
12546
+ name: "agentic-wallet-mcp",
12547
+ version: "0.3.1",
12548
+ description: "Agent-facing MCP wallet for Zetrix \u2014 orchestrates x401 identity proof, x402 payment, and MBI VC issuance",
12549
+ keywords: ["mcp", "model-context-protocol", "zetrix", "wallet", "x401", "x402", "blockchain"],
12550
+ license: "MIT",
12551
+ author: "MyEG Services Berhad",
12552
+ homepage: "https://github.com/Zetrix-Chain/zetrix-agentic-wallet",
12553
+ repository: {
12554
+ type: "git",
12555
+ url: "https://github.com/Zetrix-Chain/zetrix-agentic-wallet.git"
12556
+ },
12557
+ bugs: {
12558
+ url: "https://github.com/Zetrix-Chain/zetrix-agentic-wallet/issues"
12559
+ },
12560
+ type: "module",
12561
+ engines: {
12562
+ node: ">=18"
12563
+ },
12564
+ bin: {
12565
+ "agentic-wallet-mcp": "dist/server-bundle.cjs"
12566
+ },
12567
+ files: [
12568
+ "dist/server-bundle.cjs",
12569
+ "README.md",
12570
+ "LICENSE"
12571
+ ],
12572
+ scripts: {
12573
+ build: "tsc --noEmit && esbuild src/index.ts --bundle --platform=node --target=node18 --format=cjs --external:zetrix-sdk-nodejs --outfile=dist/server-bundle.cjs",
12574
+ test: "vitest run",
12575
+ "test:watch": "vitest",
12576
+ typecheck: "tsc --noEmit"
12577
+ },
12578
+ dependencies: {
12579
+ "@modelcontextprotocol/sdk": "^1.0.0",
12580
+ "x401-zetrix-client": "^0.2.1",
12581
+ "x402-zetrix-client": "^0.2.2",
12582
+ "zetrix-sdk-nodejs": "^1.0.3"
12583
+ },
12584
+ devDependencies: {
12585
+ "@types/node": "^20.0.0",
12586
+ esbuild: "^0.24.0",
12587
+ typescript: "^5.9.0",
12588
+ vitest: "^1.6.0"
12589
+ }
12590
+ };
12591
+
12544
12592
  // node_modules/zod/v4/core/core.js
12545
12593
  var _a;
12546
12594
  // @__NO_SIDE_EFFECTS__
@@ -21426,6 +21474,9 @@ var X401Wallet = class {
21426
21474
  }
21427
21475
  };
21428
21476
 
21477
+ // src/index.ts
21478
+ var import_zetrix_sdk_nodejs = __toESM(require("zetrix-sdk-nodejs"), 1);
21479
+
21429
21480
  // src/payment-guard.ts
21430
21481
  var PaymentCapError = class extends Error {
21431
21482
  constructor(message) {
@@ -21490,6 +21541,9 @@ function deriveWalletBeUrl(network) {
21490
21541
  function deriveMbiBaseUrl(network) {
21491
21542
  return network.includes("testnet") ? "https://mbi-vc.myegdev.com" : "https://mbi-vc.zetrix.com";
21492
21543
  }
21544
+ function deriveTemplateRegistryAddress(network) {
21545
+ return network.includes("testnet") ? "ZTX3JszqPgRUx743SAp7q7zURfjvkWuH2FMEz" : "ZTX3GqJM1U6ifMPonwD4fGvrgoTKJua7b2cKX";
21546
+ }
21493
21547
  function loadConfig(env) {
21494
21548
  const req = (key, hint) => {
21495
21549
  const v = env[key];
@@ -21515,11 +21569,67 @@ function loadConfig(env) {
21515
21569
  ),
21516
21570
  nodeHost: opt("ZETRIX_NODE_HOST") ?? deriveNodeHost(network),
21517
21571
  nodePort: opt("ZETRIX_NODE_PORT") ?? "",
21572
+ templateRegistryAddress: opt("ZETRIX_TEMPLATE_REGISTRY_ADDRESS") ?? deriveTemplateRegistryAddress(network),
21518
21573
  zidResolverBaseUrl: stripTrailingSlash(opt("ZID_RESOLVER_BASE_URL") ?? deriveZidResolverBaseUrl(network)),
21519
21574
  maxPaymentAmount: parsePaymentCaps(opt("MAX_PAYMENT_AMOUNT"))
21520
21575
  };
21521
21576
  }
21522
21577
 
21578
+ // src/clients/token-info-client.ts
21579
+ async function fetchTokenInfo(contractAddress, query) {
21580
+ let result;
21581
+ try {
21582
+ result = await query({
21583
+ contractAddress,
21584
+ input: JSON.stringify({ method: "contractInfo", params: {} }),
21585
+ optType: 2
21586
+ });
21587
+ } catch {
21588
+ return null;
21589
+ }
21590
+ if (result?.errorCode !== 0) return null;
21591
+ const raw = result.result?.query_rets?.[0]?.result?.value;
21592
+ if (!raw) return null;
21593
+ try {
21594
+ const parsed = JSON.parse(raw);
21595
+ const info = parsed.contractInfo ?? parsed;
21596
+ if (typeof info.symbol !== "string" || info.symbol === "") return null;
21597
+ const decimals = Number(info.decimals);
21598
+ return { symbol: info.symbol, decimals: Number.isFinite(decimals) ? decimals : 0 };
21599
+ } catch {
21600
+ return null;
21601
+ }
21602
+ }
21603
+ async function resolveAssetSymbol(asset, query) {
21604
+ if (asset === "" || asset === "ZTX") return asset;
21605
+ const info = await fetchTokenInfo(asset, query);
21606
+ return info?.symbol ?? asset;
21607
+ }
21608
+
21609
+ // src/clients/template-info-client.ts
21610
+ async function fetchTemplateRequiredFields(templateId, registryAddress, nodeBaseUrl, query) {
21611
+ const key = `template__${templateId}`;
21612
+ const url = `${nodeBaseUrl.replace(/\/+$/, "")}/getAccountMetaData?address=${encodeURIComponent(registryAddress)}&key=${encodeURIComponent(key)}`;
21613
+ let res;
21614
+ try {
21615
+ res = await query(url);
21616
+ } catch {
21617
+ return null;
21618
+ }
21619
+ if (res?.error_code !== 0) return null;
21620
+ const value = res.result?.[key]?.value;
21621
+ if (!value) return null;
21622
+ try {
21623
+ const parsed = JSON.parse(value);
21624
+ if (parsed.applyFormat === void 0 || parsed.applyFormat === null) return [];
21625
+ const format = typeof parsed.applyFormat === "string" ? JSON.parse(parsed.applyFormat) : parsed.applyFormat;
21626
+ if (!Array.isArray(format)) return null;
21627
+ return format.filter((e) => e && e.mandatory === 1 && typeof e.key === "string" && e.key !== "").map((e) => e.key);
21628
+ } catch {
21629
+ return null;
21630
+ }
21631
+ }
21632
+
21523
21633
  // src/clients/wallet-be-client.ts
21524
21634
  var WalletBeError = class extends Error {
21525
21635
  errorCode;
@@ -21717,7 +21827,7 @@ var MbiClient = class {
21717
21827
  if (!res.ok) throw await this.error(res, "vp/ext/create failed");
21718
21828
  return this.unwrap(res);
21719
21829
  }
21720
- /** POST /v1/vp/ext/submit — submit the signed VP blob; `includeVp: true` returns the finished VP too (BT-2357). */
21830
+ /** POST /v1/vp/ext/submit — submit the signed VP blob; `includeVp: true` returns the finished VP too. */
21721
21831
  async submitVp(body, auth) {
21722
21832
  const res = await this.fetch("POST", "/v1/vp/ext/submit", body, { signedData: auth.signedData, publicKey: auth.publicKey });
21723
21833
  if (!res.ok) throw await this.error(res, "vp/ext/submit failed");
@@ -21842,7 +21952,23 @@ function zetrixHexStringToBytes(s) {
21842
21952
 
21843
21953
  // src/orchestrator/subscribe.ts
21844
21954
  async function subscribeAndIssue(deps, opts) {
21845
- const data = JSON.stringify([{ templateId: opts.templateId, metadata: opts.attributes }]);
21955
+ if (!/^did:zid:/.test(opts.templateId)) {
21956
+ return { issued: false, reason: `templateId must be a did:zid:... credential-definition id, got "${opts.templateId}"` };
21957
+ }
21958
+ const { agentDid, ...rest } = opts.attributes ?? {};
21959
+ const attributes = agentDid ? opts.attributes : { agentDid: deps.holderDid, ...rest };
21960
+ const required2 = deps.resolveRequiredFields ? await deps.resolveRequiredFields(opts.templateId) : null;
21961
+ if (!opts.dryRun && required2) {
21962
+ const attrs = attributes;
21963
+ const missing = required2.filter((k) => attrs[k] === void 0 || attrs[k] === null || attrs[k] === "");
21964
+ if (missing.length > 0) {
21965
+ return {
21966
+ issued: false,
21967
+ reason: `template requires attribute(s) not supplied: ${missing.join(", ")} \u2014 no payment made`
21968
+ };
21969
+ }
21970
+ }
21971
+ const data = JSON.stringify([{ templateId: opts.templateId, metadata: attributes }]);
21846
21972
  const blob = zetrixHexStringToBytes(data).toString("hex");
21847
21973
  const { signBlob: signData, publicKey } = await deps.sign(blob);
21848
21974
  const body = { data, signData, publicKey };
@@ -21850,9 +21976,32 @@ async function subscribeAndIssue(deps, opts) {
21850
21976
  const challenge = await deps.mbi.applyChallenge(body);
21851
21977
  const accept = challenge.accepts[0];
21852
21978
  if (!accept) return { issued: false, reason: "MBI 402 returned no payment options" };
21979
+ if (opts.dryRun) {
21980
+ const quotedRaw = String(accept.asset ?? "");
21981
+ const quotedAsset = deps.resolveSymbol ? await deps.resolveSymbol(quotedRaw) : quotedRaw;
21982
+ return {
21983
+ issued: false,
21984
+ reason: "dry run \u2014 quoted only, no payment made",
21985
+ quote: {
21986
+ asset: quotedAsset,
21987
+ maxAmountRequired: accept.maxAmountRequired,
21988
+ payTo: accept.payTo,
21989
+ ...required2 ? { requiredAttributes: required2 } : {}
21990
+ }
21991
+ };
21992
+ }
21853
21993
  const xPayment = await deps.pay(accept);
21854
21994
  const issued = await deps.mbi.applySettle({ ...body, paymentId: challenge.paymentId }, xPayment);
21855
- return { issued: true, vcId: issued.vcId, vc: issued.verifiableCredential, txHash: issued.txHash };
21995
+ const rawAsset = String(accept.asset ?? "");
21996
+ const paidAsset = deps.resolveSymbol ? await deps.resolveSymbol(rawAsset) : rawAsset;
21997
+ return {
21998
+ issued: true,
21999
+ vcId: issued.vcId,
22000
+ vc: issued.verifiableCredential,
22001
+ txHash: issued.txHash,
22002
+ paidAsset,
22003
+ amountPaid: String(accept.maxAmountRequired ?? "")
22004
+ };
21856
22005
  }
21857
22006
 
21858
22007
  // src/orchestrator/onboard.ts
@@ -21915,6 +22064,7 @@ async function resolveHolder(deps, input) {
21915
22064
  }
21916
22065
 
21917
22066
  // src/index.ts
22067
+ var packageVersion = package_default.version;
21918
22068
  function buildToolList() {
21919
22069
  return [
21920
22070
  {
@@ -21950,7 +22100,7 @@ function buildToolList() {
21950
22100
  },
21951
22101
  {
21952
22102
  name: "pay_and_fetch",
21953
- description: "Fetch a URL, auto-paying with x402 (self-pay via Wallet BE) if the server returns 402.",
22103
+ description: "Fetch a URL, auto-paying with x402 (self-pay via Wallet BE) if the server returns 402. The asset charged is whatever the server's 402 challenge demands \u2014 the native ZETRIX token or a ZTP20 token (e.g. JMYR) \u2014 never assume it's ZETRIX; the result's `asset` field reports what was actually paid.",
21954
22104
  inputSchema: {
21955
22105
  type: "object",
21956
22106
  properties: {
@@ -21964,13 +22114,23 @@ function buildToolList() {
21964
22114
  },
21965
22115
  {
21966
22116
  name: "subscribe_and_issue",
21967
- description: "Obtain a VC from MBI: build the signed payload, pay x402, and return the issued credential.",
22117
+ description: "Obtain a VC from MBI: build the signed payload, pay x402, and return the issued credential. Payment is asset-agnostic \u2014 MBI's 402 challenge may quote the native ZETRIX token or a ZTP20 token (e.g. JMYR); pass dryRun:true first to see the quoted asset/amount for free before committing to pay.",
21968
22118
  inputSchema: {
21969
22119
  type: "object",
21970
22120
  properties: {
21971
- templateId: { type: "string" },
21972
- attributes: { type: "object" },
21973
- expirationDate: { type: "string" }
22121
+ templateId: {
22122
+ type: "string",
22123
+ description: `The MBI credential-definition id to issue, e.g. "did:zid:...". Take this from the x401 challenge's credential_requirements.query.credentials[].id \u2014 NOT from requirementsId (that's just a label for the requirement set, e.g. "agent-identity").`
22124
+ },
22125
+ attributes: {
22126
+ type: "object",
22127
+ description: `Claim values for the credential (schema varies by template \u2014 check what the issuer requires before guessing). "agentDid" does not need to be supplied: it is auto-filled with this wallet's own holder DID (the credential's self-referential subject) unless you explicitly override it.`
22128
+ },
22129
+ expirationDate: { type: "string" },
22130
+ dryRun: {
22131
+ type: "boolean",
22132
+ description: "Stop after MBI's free phase-1 quote and return { quote: { asset, maxAmountRequired, payTo, requiredAttributes? } } without paying or issuing \u2014 use this to check the payment requirement AND the template's required attributes (read from chain) before spending funds."
22133
+ }
21974
22134
  },
21975
22135
  required: ["templateId", "attributes"]
21976
22136
  }
@@ -22021,6 +22181,12 @@ async function main() {
22021
22181
  const walletBeSignerFn = (blob) => be.signBlob(blob, zetrixAddress, hsmPassword);
22022
22182
  const walletCfg = { privateKey: "", address: zetrixAddress, network: config2.network };
22023
22183
  const node = { host: config2.nodeHost, port: config2.nodePort };
22184
+ const sdk = new import_zetrix_sdk_nodejs.default({ host: config2.nodeHost, port: config2.nodePort });
22185
+ const contractQuery = (a) => sdk.contract.call(a);
22186
+ const resolveSymbol = (asset) => resolveAssetSymbol(asset, contractQuery);
22187
+ const nodeBaseUrl = `https://${config2.nodeHost}${config2.nodePort ? `:${config2.nodePort}` : ""}`;
22188
+ const nodeMetaQuery = (url) => fetch(url, { headers: { Accept: "application/json" } }).then((r) => r.json());
22189
+ const resolveRequiredFields = (templateId) => fetchTemplateRequiredFields(templateId, config2.templateRegistryAddress, nodeBaseUrl, nodeMetaQuery);
22024
22190
  const pay = (accept) => {
22025
22191
  assertWithinPaymentCap(accept, config2.maxPaymentAmount);
22026
22192
  return import_x402_zetrix_client.PaymentEngine.pay(asPayRequest(accept), walletCfg, node, {}, walletBeSignerFn);
@@ -22036,13 +22202,14 @@ async function main() {
22036
22202
  if (!accept) throw new Error("pay_and_fetch: 402 had no accepts[]");
22037
22203
  const xPayment = await pay(accept);
22038
22204
  const retry = await fetch(req.url, { ...init, headers: { ...req.headers ?? {}, "x-payment": xPayment } });
22205
+ const asset = await resolveSymbol(String(accept.asset ?? ""));
22039
22206
  return {
22040
22207
  status: retry.status,
22041
22208
  body: await retry.text(),
22042
22209
  paymentMade: true,
22043
22210
  amountPaid: String(accept.maxAmountRequired ?? ""),
22044
22211
  amountPaidHuman: "",
22045
- asset: String(accept.asset ?? "")
22212
+ asset
22046
22213
  };
22047
22214
  };
22048
22215
  const subscribeSign = (blob) => be.signBlob(blob, zetrixAddress, hsmPassword);
@@ -22062,11 +22229,11 @@ async function main() {
22062
22229
  config: { holderDid, zetrixAddress, network: config2.network },
22063
22230
  makeWallet,
22064
22231
  payer,
22065
- subscribeDeps: { mbi, sign: subscribeSign, pay },
22232
+ subscribeDeps: { mbi, sign: subscribeSign, pay, resolveSymbol, holderDid, resolveRequiredFields },
22066
22233
  createAccount: (password, label, purpose) => be.createAccount(password, label, purpose)
22067
22234
  };
22068
22235
  const tools = createTools(deps);
22069
- const server = new Server({ name: "agentic-wallet-mcp", version: "0.1.0" }, { capabilities: { tools: {} } });
22236
+ const server = new Server({ name: "agentic-wallet-mcp", version: packageVersion }, { capabilities: { tools: {} } });
22070
22237
  server.setRequestHandler(ListToolsRequestSchema, async () => ({ tools: buildToolList() }));
22071
22238
  server.setRequestHandler(CallToolRequestSchema, async (request) => {
22072
22239
  const { name, arguments: args } = request.params;
package/package.json CHANGED
@@ -1,17 +1,17 @@
1
1
  {
2
2
  "name": "agentic-wallet-mcp",
3
- "version": "0.2.0",
3
+ "version": "0.3.1",
4
4
  "description": "Agent-facing MCP wallet for Zetrix — orchestrates x401 identity proof, x402 payment, and MBI VC issuance",
5
5
  "keywords": ["mcp", "model-context-protocol", "zetrix", "wallet", "x401", "x402", "blockchain"],
6
6
  "license": "MIT",
7
7
  "author": "MyEG Services Berhad",
8
- "homepage": "https://git.myeg.com.my/genesis/zetrix-agentic-wallet",
8
+ "homepage": "https://github.com/Zetrix-Chain/zetrix-agentic-wallet",
9
9
  "repository": {
10
10
  "type": "git",
11
- "url": "https://git.myeg.com.my/genesis/zetrix-agentic-wallet.git"
11
+ "url": "https://github.com/Zetrix-Chain/zetrix-agentic-wallet.git"
12
12
  },
13
13
  "bugs": {
14
- "url": "https://git.myeg.com.my/genesis/zetrix-agentic-wallet/-/issues"
14
+ "url": "https://github.com/Zetrix-Chain/zetrix-agentic-wallet/issues"
15
15
  },
16
16
  "type": "module",
17
17
  "engines": {
@@ -34,7 +34,8 @@
34
34
  "dependencies": {
35
35
  "@modelcontextprotocol/sdk": "^1.0.0",
36
36
  "x401-zetrix-client": "^0.2.1",
37
- "x402-zetrix-client": "^0.2.2"
37
+ "x402-zetrix-client": "^0.2.2",
38
+ "zetrix-sdk-nodejs": "^1.0.3"
38
39
  },
39
40
  "devDependencies": {
40
41
  "@types/node": "^20.0.0",