@agentwonderland/mcp 0.1.41 → 0.1.42

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.
@@ -46,7 +46,7 @@ describe("api-client headers", () => {
46
46
  "X-AW-Consumer-Principal": "did:pkh:solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp:42W2HfLfveSm1T5et9WTLp2CZ2QXdF2EYCUvyJ2gPpxF",
47
47
  "X-AW-Rebate-Principal": "did:pkh:eip155:8453:0xbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb",
48
48
  "X-AW-Surface": "mcp",
49
- "X-AW-MCP-Version": "0.1.41",
49
+ "X-AW-MCP-Version": "0.1.42",
50
50
  "X-AW-MCP-Tool": "run_agent",
51
51
  "X-AW-MCP-Action": "execute",
52
52
  }),
@@ -12,7 +12,7 @@ export class ApiError extends Error {
12
12
  this.name = "ApiError";
13
13
  }
14
14
  }
15
- const MCP_VERSION = "0.1.41";
15
+ const MCP_VERSION = "0.1.42";
16
16
  function inferToolHeaders(path, method) {
17
17
  if (path === "/solve") {
18
18
  return { "X-AW-MCP-Tool": "solve", "X-AW-MCP-Action": method === "POST" ? "execute" : "view" };
@@ -7,6 +7,9 @@
7
7
  * The OWS SDK (`@open-wallet-standard/core`) is a NAPI native module.
8
8
  * ALL imports are dynamic so the MCP server works without OWS installed.
9
9
  */
10
+ import { createHmac } from "node:crypto";
11
+ import { mnemonicToSeedSync, validateMnemonic } from "@scure/bip39";
12
+ import { wordlist } from "@scure/bip39/wordlists/english";
10
13
  // ── Helpers ──────────────────────────────────────────────────────
11
14
  const OWS_INSTALL_HINT = "OWS is not installed. Install with: npm install -g @open-wallet-standard/core";
12
15
  async function loadOws() {
@@ -58,6 +61,51 @@ function keypairFromEd25519Hex(privateKeyHex, KeypairCtor) {
58
61
  }
59
62
  throw new Error(`Unsupported ed25519 key length: ${bytes.length} bytes.`);
60
63
  }
64
+ function parseExportedSecret(exported) {
65
+ const secret = exported.trim();
66
+ try {
67
+ const parsed = JSON.parse(secret);
68
+ if (parsed.secp256k1 || parsed.ed25519 || parsed.mnemonic)
69
+ return parsed;
70
+ }
71
+ catch {
72
+ // OWS-created wallets export a BIP-39 mnemonic, not a JSON key object.
73
+ }
74
+ const hex = secret.startsWith("0x") ? secret.slice(2) : secret;
75
+ if (/^[0-9a-fA-F]+$/.test(hex)) {
76
+ if (hex.length === 64)
77
+ return { secp256k1: hex, ed25519: hex };
78
+ if (hex.length === 128)
79
+ return { ed25519: hex };
80
+ }
81
+ if (validateMnemonic(secret, wordlist)) {
82
+ return { mnemonic: secret };
83
+ }
84
+ return {};
85
+ }
86
+ function deriveSolanaSeedFromMnemonic(mnemonic, path = "m/44'/501'/0'/0'") {
87
+ const seed = mnemonicToSeedSync(mnemonic);
88
+ let digest = createHmac("sha512", "ed25519 seed").update(seed).digest();
89
+ let key = digest.subarray(0, 32);
90
+ let chainCode = digest.subarray(32);
91
+ for (const part of path.split("/").slice(1)) {
92
+ if (!part.endsWith("'")) {
93
+ throw new Error(`Unsupported non-hardened ed25519 path segment: ${part}`);
94
+ }
95
+ const index = Number(part.slice(0, -1));
96
+ if (!Number.isInteger(index) || index < 0) {
97
+ throw new Error(`Unsupported ed25519 path segment: ${part}`);
98
+ }
99
+ const data = Buffer.alloc(37);
100
+ data[0] = 0;
101
+ Buffer.from(key).copy(data, 1);
102
+ data.writeUInt32BE(index + 0x80000000, 33);
103
+ digest = createHmac("sha512", chainCode).update(data).digest();
104
+ key = digest.subarray(0, 32);
105
+ chainCode = digest.subarray(32);
106
+ }
107
+ return Uint8Array.from(key);
108
+ }
61
109
  // ── Public API ───────────────────────────────────────────────────
62
110
  /**
63
111
  * Check whether the OWS native module can be loaded.
@@ -160,7 +208,11 @@ export async function owsAccountFromWalletId(walletId, _chain) {
160
208
  // (EIP-5806 delegate calls) which OWS's native signing can't serialize.
161
209
  // OWS provides encrypted storage at rest; viem handles signing in memory.
162
210
  const exported = ows.exportWallet(walletId);
163
- const keys = JSON.parse(exported);
211
+ const keys = parseExportedSecret(exported);
212
+ if (keys.mnemonic) {
213
+ const { mnemonicToAccount } = await import("viem/accounts");
214
+ return mnemonicToAccount(keys.mnemonic);
215
+ }
164
216
  if (!keys.secp256k1) {
165
217
  throw new Error(`Wallet "${wallet.name}" has no secp256k1 key for EVM signing.`);
166
218
  }
@@ -172,11 +224,14 @@ export async function owsSolanaKeypairFromWalletId(walletId) {
172
224
  const wallet = ows.getWallet(walletId);
173
225
  findSolanaAccount(wallet);
174
226
  const exported = ows.exportWallet(walletId);
175
- const keys = JSON.parse(exported);
227
+ const keys = parseExportedSecret(exported);
228
+ const { Keypair } = await import("@solana/web3.js");
229
+ if (keys.mnemonic) {
230
+ return Keypair.fromSeed(deriveSolanaSeedFromMnemonic(keys.mnemonic));
231
+ }
176
232
  if (!keys.ed25519) {
177
233
  throw new Error(`Wallet "${wallet.name}" has no ed25519 key for Solana signing.`);
178
234
  }
179
- const { Keypair } = await import("@solana/web3.js");
180
235
  return keypairFromEd25519Hex(keys.ed25519, Keypair);
181
236
  }
182
237
  export async function getOwsWalletAddress(walletId, chain = "evm") {
@@ -53,52 +53,42 @@ function clearStaleCardCache(activeKey) {
53
53
  }
54
54
  // ── Per-protocol initializers ───────────────────────────────────
55
55
  async function initEvmMppForChain(wallet, chain) {
56
- try {
57
- const { Mppx } = await import("./mpp-client.js");
58
- let account;
59
- if (wallet.keyType === "ows" && wallet.owsWalletId) {
60
- const { owsAccountFromWalletId } = await import("./ows-adapter.js");
61
- account = await owsAccountFromWalletId(wallet.owsWalletId);
62
- }
63
- else if (wallet.key) {
64
- const { privateKeyToAccount } = await import("viem/accounts");
65
- account = privateKeyToAccount(normalizeKey(wallet.key));
66
- }
67
- else {
68
- return null;
69
- }
70
- const methods = [];
71
- if (chain === "tempo") {
72
- const { tempoChargeClient } = await import("./tempo-charge.js");
73
- methods.push(tempoChargeClient({ account }));
74
- }
75
- else {
76
- const { baseChargeClient } = await import("./base-charge.js");
77
- methods.push(baseChargeClient({ account }));
78
- }
79
- const mppx = Mppx.create({ methods: methods, polyfill: false });
80
- return mppx.fetch.bind(mppx);
56
+ const { Mppx } = await import("./mpp-client.js");
57
+ let account;
58
+ if (wallet.keyType === "ows" && wallet.owsWalletId) {
59
+ const { owsAccountFromWalletId } = await import("./ows-adapter.js");
60
+ account = await owsAccountFromWalletId(wallet.owsWalletId);
81
61
  }
82
- catch {
62
+ else if (wallet.key) {
63
+ const { privateKeyToAccount } = await import("viem/accounts");
64
+ account = privateKeyToAccount(normalizeKey(wallet.key));
65
+ }
66
+ else {
83
67
  return null;
84
68
  }
69
+ const methods = [];
70
+ if (chain === "tempo") {
71
+ const { tempoChargeClient } = await import("./tempo-charge.js");
72
+ methods.push(tempoChargeClient({ account }));
73
+ }
74
+ else {
75
+ const { baseChargeClient } = await import("./base-charge.js");
76
+ methods.push(baseChargeClient({ account }));
77
+ }
78
+ const mppx = Mppx.create({ methods: methods, polyfill: false });
79
+ return mppx.fetch.bind(mppx);
85
80
  }
86
81
  async function initSolanaMpp(wallet) {
87
- try {
88
- if (wallet.keyType !== "ows" && !wallet.key) {
89
- return null;
90
- }
91
- const { Mppx } = await import("./mpp-client.js");
92
- const { solanaChargeClient } = await import("./solana-charge.js");
93
- const mppx = Mppx.create({
94
- methods: [solanaChargeClient({ wallet })],
95
- polyfill: false,
96
- });
97
- return mppx.fetch.bind(mppx);
98
- }
99
- catch {
82
+ if (wallet.keyType !== "ows" && !wallet.key) {
100
83
  return null;
101
84
  }
85
+ const { Mppx } = await import("./mpp-client.js");
86
+ const { solanaChargeClient } = await import("./solana-charge.js");
87
+ const mppx = Mppx.create({
88
+ methods: [solanaChargeClient({ wallet })],
89
+ polyfill: false,
90
+ });
91
+ return mppx.fetch.bind(mppx);
102
92
  }
103
93
  async function initCard() {
104
94
  const cardConfig = getCardConfig();
@@ -149,6 +139,10 @@ async function initForChain(wallet, chain) {
149
139
  }
150
140
  return null;
151
141
  }
142
+ function initFailureMessage(method, wallet, chain, err) {
143
+ const reason = err instanceof Error ? err.message : String(err);
144
+ return `Payment method "${method}" is configured as ${chain} on wallet "${wallet.id}", but the signer could not initialize: ${reason}`;
145
+ }
152
146
  // ── Public API ──────────────────────────────────────────────────
153
147
  /**
154
148
  * Returns a payment-aware fetch for a specific method, or the best
@@ -185,7 +179,13 @@ export async function getPaymentFetch(method) {
185
179
  const ck = cacheKey(resolved.wallet.id, resolved.chain);
186
180
  if (fetchCache.has(ck))
187
181
  return fetchCache.get(ck);
188
- const pf = await initForChain(resolved.wallet, resolved.chain);
182
+ let pf;
183
+ try {
184
+ pf = await initForChain(resolved.wallet, resolved.chain);
185
+ }
186
+ catch (err) {
187
+ throw new Error(initFailureMessage(method, resolved.wallet, resolved.chain, err));
188
+ }
189
189
  if (pf) {
190
190
  fetchCache.set(ck, pf);
191
191
  return pf;
@@ -234,7 +234,18 @@ export async function getPaymentFetch(method) {
234
234
  const ck = cacheKey(resolved.wallet.id, resolved.chain);
235
235
  if (fetchCache.has(ck))
236
236
  return fetchCache.get(ck);
237
- const pf = await initForChain(resolved.wallet, resolved.chain);
237
+ let pf;
238
+ try {
239
+ pf = await initForChain(resolved.wallet, resolved.chain);
240
+ }
241
+ catch (err) {
242
+ if (m === defaultMethod) {
243
+ const others = configured.filter((x) => x !== m);
244
+ const altText = others.length > 0 ? ` Alternatives: ${others.join(", ")}` : "";
245
+ throw new Error(`${initFailureMessage(m, resolved.wallet, resolved.chain, err)}.${altText}`);
246
+ }
247
+ continue;
248
+ }
238
249
  if (pf) {
239
250
  fetchCache.set(ck, pf);
240
251
  return pf;
package/dist/index.js CHANGED
@@ -22,7 +22,7 @@ import { registerJobResources } from "./resources/jobs.js";
22
22
  // ── Prompts ──────────────────────────────────────────────────────
23
23
  import { registerPrompts } from "./prompts/index.js";
24
24
  import { runSetupCli } from "./setup.js";
25
- const PACKAGE_VERSION = "0.1.41";
25
+ const PACKAGE_VERSION = "0.1.42";
26
26
  export async function startMcpServer() {
27
27
  const server = new McpServer({
28
28
  name: "agentwonderland",
@@ -213,6 +213,8 @@ export function registerWalletTools(server) {
213
213
  "",
214
214
  chainStatus,
215
215
  "",
216
+ "No MCP restart is required for wallet changes.",
217
+ "",
216
218
  `Fund this address with USDC on ${defaultCh === "solana" ? "Solana" : "Tempo"} to start using agents.`,
217
219
  ].join("\n"));
218
220
  }
@@ -244,6 +246,8 @@ export function registerWalletTools(server) {
244
246
  ` Chains: solana`,
245
247
  ` Consumer principal: ${principal}`,
246
248
  "",
249
+ "No MCP restart is required for wallet changes.",
250
+ "",
247
251
  "Fund this address with USDC on Solana to start using agents.",
248
252
  ].join("\n") + owsNudge);
249
253
  }
@@ -269,6 +273,8 @@ export function registerWalletTools(server) {
269
273
  ` Chains: tempo, base`,
270
274
  ` Consumer principal: ${principal}`,
271
275
  "",
276
+ "No MCP restart is required for wallet changes.",
277
+ "",
272
278
  `Fund this address with USDC on Tempo or Base to start using agents.`,
273
279
  ].join("\n") + owsNudge);
274
280
  }
@@ -293,6 +299,8 @@ export function registerWalletTools(server) {
293
299
  ` Storage: ~/.ows/ (AES-256-GCM encrypted)`,
294
300
  ` Consumer principal: ${principal}`,
295
301
  "",
302
+ "No MCP restart is required for wallet changes.",
303
+ "",
296
304
  `Fund this address with USDC on ${defaultCh === "solana" ? "Solana" : "Tempo"} to start using agents.`,
297
305
  "For testnet: npx mppx account fund",
298
306
  ].join("\n"));
@@ -317,6 +325,8 @@ export function registerWalletTools(server) {
317
325
  ` Name: ${walletName}`,
318
326
  ` Chains: ${selectedChains.join(", ")}`,
319
327
  ` Consumer principal: ${principal}`,
328
+ "",
329
+ "No MCP restart is required for wallet changes.",
320
330
  ].join("\n"));
321
331
  }
322
332
  if (defaultCh === "solana") {
@@ -345,6 +355,8 @@ export function registerWalletTools(server) {
345
355
  ` Name: ${walletName}`,
346
356
  ` Chains: solana`,
347
357
  ` Consumer principal: ${principal}`,
358
+ "",
359
+ "No MCP restart is required for wallet changes.",
348
360
  ].join("\n") + owsNudge);
349
361
  }
350
362
  catch (err) {
@@ -376,6 +388,8 @@ export function registerWalletTools(server) {
376
388
  ` Name: ${walletName}`,
377
389
  ` Chains: ${selectedChains.join(", ")}`,
378
390
  ` Consumer principal: ${principal}`,
391
+ "",
392
+ "No MCP restart is required for wallet changes.",
379
393
  ].join("\n") + owsNudge);
380
394
  }
381
395
  catch {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agentwonderland/mcp",
3
- "version": "0.1.41",
3
+ "version": "0.1.42",
4
4
  "type": "module",
5
5
  "description": "MCP server for the Agent Wonderland AI agent marketplace",
6
6
  "bin": {
@@ -23,6 +23,7 @@
23
23
  },
24
24
  "dependencies": {
25
25
  "@modelcontextprotocol/sdk": "^1.12.1",
26
+ "@scure/bip39": "^1.6.0",
26
27
  "@solana/spl-token": "^0.4.14",
27
28
  "@solana/web3.js": "1.95.8",
28
29
  "qrcode": "^1.5.4",
@@ -72,7 +72,7 @@ describe("api-client headers", () => {
72
72
  "X-AW-Rebate-Principal":
73
73
  "did:pkh:eip155:8453:0xbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb",
74
74
  "X-AW-Surface": "mcp",
75
- "X-AW-MCP-Version": "0.1.41",
75
+ "X-AW-MCP-Version": "0.1.42",
76
76
  "X-AW-MCP-Tool": "run_agent",
77
77
  "X-AW-MCP-Action": "execute",
78
78
  }),
@@ -29,7 +29,7 @@ interface RequestOptions {
29
29
  extraHeaders?: Record<string, string>;
30
30
  }
31
31
 
32
- const MCP_VERSION = "0.1.41";
32
+ const MCP_VERSION = "0.1.42";
33
33
 
34
34
  function inferToolHeaders(path: string, method: string): Record<string, string> {
35
35
  if (path === "/solve") {
@@ -11,6 +11,9 @@
11
11
  import type { LocalAccount } from "viem/accounts";
12
12
  import type { Hex } from "viem";
13
13
  import type { Keypair } from "@solana/web3.js";
14
+ import { createHmac } from "node:crypto";
15
+ import { mnemonicToSeedSync, validateMnemonic } from "@scure/bip39";
16
+ import { wordlist } from "@scure/bip39/wordlists/english";
14
17
 
15
18
  // Note: OWS provides encrypted key storage at rest (~/.ows/, AES-256-GCM).
16
19
  // For EVM signing, we export the secp256k1 key and use viem's native
@@ -155,6 +158,56 @@ function keypairFromEd25519Hex(privateKeyHex: string, KeypairCtor: typeof import
155
158
  throw new Error(`Unsupported ed25519 key length: ${bytes.length} bytes.`);
156
159
  }
157
160
 
161
+ function parseExportedSecret(exported: string): { secp256k1?: string; ed25519?: string; mnemonic?: string } {
162
+ const secret = exported.trim();
163
+ try {
164
+ const parsed = JSON.parse(secret) as { secp256k1?: string; ed25519?: string; mnemonic?: string };
165
+ if (parsed.secp256k1 || parsed.ed25519 || parsed.mnemonic) return parsed;
166
+ } catch {
167
+ // OWS-created wallets export a BIP-39 mnemonic, not a JSON key object.
168
+ }
169
+
170
+ const hex = secret.startsWith("0x") ? secret.slice(2) : secret;
171
+ if (/^[0-9a-fA-F]+$/.test(hex)) {
172
+ if (hex.length === 64) return { secp256k1: hex, ed25519: hex };
173
+ if (hex.length === 128) return { ed25519: hex };
174
+ }
175
+
176
+ if (validateMnemonic(secret, wordlist)) {
177
+ return { mnemonic: secret };
178
+ }
179
+
180
+ return {};
181
+ }
182
+
183
+ function deriveSolanaSeedFromMnemonic(mnemonic: string, path = "m/44'/501'/0'/0'"): Uint8Array {
184
+ const seed = mnemonicToSeedSync(mnemonic);
185
+ let digest = createHmac("sha512", "ed25519 seed").update(seed).digest();
186
+ let key = digest.subarray(0, 32);
187
+ let chainCode = digest.subarray(32);
188
+
189
+ for (const part of path.split("/").slice(1)) {
190
+ if (!part.endsWith("'")) {
191
+ throw new Error(`Unsupported non-hardened ed25519 path segment: ${part}`);
192
+ }
193
+ const index = Number(part.slice(0, -1));
194
+ if (!Number.isInteger(index) || index < 0) {
195
+ throw new Error(`Unsupported ed25519 path segment: ${part}`);
196
+ }
197
+
198
+ const data = Buffer.alloc(37);
199
+ data[0] = 0;
200
+ Buffer.from(key).copy(data, 1);
201
+ data.writeUInt32BE(index + 0x80000000, 33);
202
+
203
+ digest = createHmac("sha512", chainCode).update(data).digest();
204
+ key = digest.subarray(0, 32);
205
+ chainCode = digest.subarray(32);
206
+ }
207
+
208
+ return Uint8Array.from(key);
209
+ }
210
+
158
211
  // ── Public API ───────────────────────────────────────────────────
159
212
 
160
213
  /**
@@ -278,7 +331,13 @@ export async function owsAccountFromWalletId(
278
331
  // (EIP-5806 delegate calls) which OWS's native signing can't serialize.
279
332
  // OWS provides encrypted storage at rest; viem handles signing in memory.
280
333
  const exported = ows.exportWallet(walletId);
281
- const keys = JSON.parse(exported) as { secp256k1?: string; ed25519?: string };
334
+ const keys = parseExportedSecret(exported);
335
+
336
+ if (keys.mnemonic) {
337
+ const { mnemonicToAccount } = await import("viem/accounts");
338
+ return mnemonicToAccount(keys.mnemonic);
339
+ }
340
+
282
341
  if (!keys.secp256k1) {
283
342
  throw new Error(`Wallet "${wallet.name}" has no secp256k1 key for EVM signing.`);
284
343
  }
@@ -295,12 +354,17 @@ export async function owsSolanaKeypairFromWalletId(
295
354
  findSolanaAccount(wallet);
296
355
 
297
356
  const exported = ows.exportWallet(walletId);
298
- const keys = JSON.parse(exported) as { secp256k1?: string; ed25519?: string };
357
+ const keys = parseExportedSecret(exported);
358
+ const { Keypair } = await import("@solana/web3.js");
359
+
360
+ if (keys.mnemonic) {
361
+ return Keypair.fromSeed(deriveSolanaSeedFromMnemonic(keys.mnemonic));
362
+ }
363
+
299
364
  if (!keys.ed25519) {
300
365
  throw new Error(`Wallet "${wallet.name}" has no ed25519 key for Solana signing.`);
301
366
  }
302
367
 
303
- const { Keypair } = await import("@solana/web3.js");
304
368
  return keypairFromEd25519Hex(keys.ed25519, Keypair);
305
369
  }
306
370
 
@@ -76,52 +76,44 @@ async function initEvmMppForChain(
76
76
  wallet: WalletEntry,
77
77
  chain: "tempo" | "base",
78
78
  ): Promise<typeof fetch | null> {
79
- try {
80
- const { Mppx } = await import("./mpp-client.js");
81
- let account;
82
-
83
- if (wallet.keyType === "ows" && wallet.owsWalletId) {
84
- const { owsAccountFromWalletId } = await import("./ows-adapter.js");
85
- account = await owsAccountFromWalletId(wallet.owsWalletId);
86
- } else if (wallet.key) {
87
- const { privateKeyToAccount } = await import("viem/accounts");
88
- account = privateKeyToAccount(normalizeKey(wallet.key));
89
- } else {
90
- return null;
91
- }
92
-
93
- const methods = [];
94
- if (chain === "tempo") {
95
- const { tempoChargeClient } = await import("./tempo-charge.js");
96
- methods.push(tempoChargeClient({ account }));
97
- } else {
98
- const { baseChargeClient } = await import("./base-charge.js");
99
- methods.push(baseChargeClient({ account }));
100
- }
79
+ const { Mppx } = await import("./mpp-client.js");
80
+ let account;
101
81
 
102
- const mppx = Mppx.create({ methods: methods as any, polyfill: false });
103
- return mppx.fetch.bind(mppx) as typeof fetch;
104
- } catch {
82
+ if (wallet.keyType === "ows" && wallet.owsWalletId) {
83
+ const { owsAccountFromWalletId } = await import("./ows-adapter.js");
84
+ account = await owsAccountFromWalletId(wallet.owsWalletId);
85
+ } else if (wallet.key) {
86
+ const { privateKeyToAccount } = await import("viem/accounts");
87
+ account = privateKeyToAccount(normalizeKey(wallet.key));
88
+ } else {
105
89
  return null;
106
90
  }
91
+
92
+ const methods = [];
93
+ if (chain === "tempo") {
94
+ const { tempoChargeClient } = await import("./tempo-charge.js");
95
+ methods.push(tempoChargeClient({ account }));
96
+ } else {
97
+ const { baseChargeClient } = await import("./base-charge.js");
98
+ methods.push(baseChargeClient({ account }));
99
+ }
100
+
101
+ const mppx = Mppx.create({ methods: methods as any, polyfill: false });
102
+ return mppx.fetch.bind(mppx) as typeof fetch;
107
103
  }
108
104
 
109
105
  async function initSolanaMpp(wallet: WalletEntry): Promise<typeof fetch | null> {
110
- try {
111
- if (wallet.keyType !== "ows" && !wallet.key) {
112
- return null;
113
- }
114
-
115
- const { Mppx } = await import("./mpp-client.js");
116
- const { solanaChargeClient } = await import("./solana-charge.js");
117
- const mppx = Mppx.create({
118
- methods: [solanaChargeClient({ wallet })] as any,
119
- polyfill: false,
120
- });
121
- return mppx.fetch.bind(mppx) as typeof fetch;
122
- } catch {
106
+ if (wallet.keyType !== "ows" && !wallet.key) {
123
107
  return null;
124
108
  }
109
+
110
+ const { Mppx } = await import("./mpp-client.js");
111
+ const { solanaChargeClient } = await import("./solana-charge.js");
112
+ const mppx = Mppx.create({
113
+ methods: [solanaChargeClient({ wallet })] as any,
114
+ polyfill: false,
115
+ });
116
+ return mppx.fetch.bind(mppx) as typeof fetch;
125
117
  }
126
118
 
127
119
  async function initCard(): Promise<typeof fetch | null> {
@@ -178,6 +170,11 @@ async function initForChain(wallet: WalletEntry, chain: string): Promise<typeof
178
170
  return null;
179
171
  }
180
172
 
173
+ function initFailureMessage(method: string, wallet: WalletEntry, chain: string, err: unknown): string {
174
+ const reason = err instanceof Error ? err.message : String(err);
175
+ return `Payment method "${method}" is configured as ${chain} on wallet "${wallet.id}", but the signer could not initialize: ${reason}`;
176
+ }
177
+
181
178
  // ── Public API ──────────────────────────────────────────────────
182
179
 
183
180
  /**
@@ -214,7 +211,12 @@ export async function getPaymentFetch(method?: string): Promise<typeof fetch> {
214
211
  }
215
212
  const ck = cacheKey(resolved.wallet.id, resolved.chain);
216
213
  if (fetchCache.has(ck)) return fetchCache.get(ck)!;
217
- const pf = await initForChain(resolved.wallet, resolved.chain);
214
+ let pf: typeof fetch | null;
215
+ try {
216
+ pf = await initForChain(resolved.wallet, resolved.chain);
217
+ } catch (err) {
218
+ throw new Error(initFailureMessage(method, resolved.wallet, resolved.chain, err));
219
+ }
218
220
  if (pf) {
219
221
  fetchCache.set(ck, pf);
220
222
  return pf;
@@ -264,7 +266,17 @@ export async function getPaymentFetch(method?: string): Promise<typeof fetch> {
264
266
  }
265
267
  const ck = cacheKey(resolved.wallet.id, resolved.chain);
266
268
  if (fetchCache.has(ck)) return fetchCache.get(ck)!;
267
- const pf = await initForChain(resolved.wallet, resolved.chain);
269
+ let pf: typeof fetch | null;
270
+ try {
271
+ pf = await initForChain(resolved.wallet, resolved.chain);
272
+ } catch (err) {
273
+ if (m === defaultMethod) {
274
+ const others = configured.filter((x) => x !== m);
275
+ const altText = others.length > 0 ? ` Alternatives: ${others.join(", ")}` : "";
276
+ throw new Error(`${initFailureMessage(m, resolved.wallet, resolved.chain, err)}.${altText}`);
277
+ }
278
+ continue;
279
+ }
268
280
  if (pf) {
269
281
  fetchCache.set(ck, pf);
270
282
  return pf;
package/src/index.ts CHANGED
@@ -27,7 +27,7 @@ import { registerJobResources } from "./resources/jobs.js";
27
27
  import { registerPrompts } from "./prompts/index.js";
28
28
  import { runSetupCli } from "./setup.js";
29
29
 
30
- const PACKAGE_VERSION = "0.1.41";
30
+ const PACKAGE_VERSION = "0.1.42";
31
31
 
32
32
  export async function startMcpServer(): Promise<void> {
33
33
  const server = new McpServer(
@@ -280,6 +280,8 @@ export function registerWalletTools(server: McpServer): void {
280
280
  "",
281
281
  chainStatus,
282
282
  "",
283
+ "No MCP restart is required for wallet changes.",
284
+ "",
283
285
  `Fund this address with USDC on ${defaultCh === "solana" ? "Solana" : "Tempo"} to start using agents.`,
284
286
  ].join("\n"));
285
287
  }
@@ -313,6 +315,8 @@ export function registerWalletTools(server: McpServer): void {
313
315
  ` Chains: solana`,
314
316
  ` Consumer principal: ${principal}`,
315
317
  "",
318
+ "No MCP restart is required for wallet changes.",
319
+ "",
316
320
  "Fund this address with USDC on Solana to start using agents.",
317
321
  ].join("\n") + owsNudge,
318
322
  );
@@ -340,6 +344,8 @@ export function registerWalletTools(server: McpServer): void {
340
344
  ` Chains: tempo, base`,
341
345
  ` Consumer principal: ${principal}`,
342
346
  "",
347
+ "No MCP restart is required for wallet changes.",
348
+ "",
343
349
  `Fund this address with USDC on Tempo or Base to start using agents.`,
344
350
  ].join("\n") + owsNudge,
345
351
  );
@@ -369,6 +375,8 @@ export function registerWalletTools(server: McpServer): void {
369
375
  ` Storage: ~/.ows/ (AES-256-GCM encrypted)`,
370
376
  ` Consumer principal: ${principal}`,
371
377
  "",
378
+ "No MCP restart is required for wallet changes.",
379
+ "",
372
380
  `Fund this address with USDC on ${defaultCh === "solana" ? "Solana" : "Tempo"} to start using agents.`,
373
381
  "For testnet: npx mppx account fund",
374
382
  ].join("\n"),
@@ -395,11 +403,13 @@ export function registerWalletTools(server: McpServer): void {
395
403
  `Key imported to OWS [encrypted]:`,
396
404
  ` ID: ${result.walletId}`,
397
405
  ` Address: ${result.address}`,
398
- ` Name: ${walletName}`,
399
- ` Chains: ${selectedChains.join(", ")}`,
400
- ` Consumer principal: ${principal}`,
401
- ].join("\n"),
402
- );
406
+ ` Name: ${walletName}`,
407
+ ` Chains: ${selectedChains.join(", ")}`,
408
+ ` Consumer principal: ${principal}`,
409
+ "",
410
+ "No MCP restart is required for wallet changes.",
411
+ ].join("\n"),
412
+ );
403
413
  }
404
414
 
405
415
  if (defaultCh === "solana") {
@@ -429,6 +439,8 @@ export function registerWalletTools(server: McpServer): void {
429
439
  ` Name: ${walletName}`,
430
440
  ` Chains: solana`,
431
441
  ` Consumer principal: ${principal}`,
442
+ "",
443
+ "No MCP restart is required for wallet changes.",
432
444
  ].join("\n") + owsNudge,
433
445
  );
434
446
  } catch (err) {
@@ -468,6 +480,8 @@ export function registerWalletTools(server: McpServer): void {
468
480
  ` Name: ${walletName}`,
469
481
  ` Chains: ${selectedChains.join(", ")}`,
470
482
  ` Consumer principal: ${principal}`,
483
+ "",
484
+ "No MCP restart is required for wallet changes.",
471
485
  ].join("\n") + owsNudge,
472
486
  );
473
487
  } catch {