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 +14 -18
- package/dist/server-bundle.cjs +178 -11
- package/package.json +6 -5
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`
|
|
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/
|
|
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.
|
|
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
|
|
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>" }
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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`)
|
|
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
|
|
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.
|
|
245
|
-
|
|
246
|
-
|
|
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
|
|
package/dist/server-bundle.cjs
CHANGED
|
@@ -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
|
|
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
|
-
|
|
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
|
-
|
|
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: {
|
|
21972
|
-
|
|
21973
|
-
|
|
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
|
|
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:
|
|
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.
|
|
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://
|
|
8
|
+
"homepage": "https://github.com/Zetrix-Chain/zetrix-agentic-wallet",
|
|
9
9
|
"repository": {
|
|
10
10
|
"type": "git",
|
|
11
|
-
"url": "https://
|
|
11
|
+
"url": "https://github.com/Zetrix-Chain/zetrix-agentic-wallet.git"
|
|
12
12
|
},
|
|
13
13
|
"bugs": {
|
|
14
|
-
"url": "https://
|
|
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",
|