@agentwonderland/mcp 0.1.22 → 0.1.24

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.
Files changed (74) hide show
  1. package/dist/core/__tests__/card-setup.test.d.ts +1 -0
  2. package/dist/core/__tests__/card-setup.test.js +99 -0
  3. package/dist/core/__tests__/formatters.test.d.ts +1 -0
  4. package/dist/core/__tests__/formatters.test.js +15 -0
  5. package/dist/core/__tests__/passes.test.d.ts +1 -0
  6. package/dist/core/__tests__/passes.test.js +82 -0
  7. package/dist/core/__tests__/payments.test.d.ts +1 -0
  8. package/dist/core/__tests__/payments.test.js +52 -0
  9. package/dist/core/__tests__/principal.test.d.ts +1 -0
  10. package/dist/core/__tests__/principal.test.js +67 -0
  11. package/dist/core/api-client.d.ts +9 -4
  12. package/dist/core/api-client.js +52 -22
  13. package/dist/core/card-setup.d.ts +20 -13
  14. package/dist/core/card-setup.js +87 -30
  15. package/dist/core/config.d.ts +4 -0
  16. package/dist/core/config.js +28 -1
  17. package/dist/core/formatters.d.ts +2 -0
  18. package/dist/core/formatters.js +5 -1
  19. package/dist/core/index.d.ts +2 -0
  20. package/dist/core/index.js +2 -0
  21. package/dist/core/ows-adapter.d.ts +10 -2
  22. package/dist/core/ows-adapter.js +54 -10
  23. package/dist/core/passes.d.ts +40 -0
  24. package/dist/core/passes.js +32 -0
  25. package/dist/core/payments.d.ts +8 -0
  26. package/dist/core/payments.js +121 -16
  27. package/dist/core/principal.d.ts +2 -0
  28. package/dist/core/principal.js +109 -0
  29. package/dist/core/solana-charge.d.ts +9 -0
  30. package/dist/core/solana-charge.js +95 -0
  31. package/dist/core/types.d.ts +10 -0
  32. package/dist/index.js +13 -4
  33. package/dist/prompts/index.js +1 -1
  34. package/dist/resources/wallet.js +8 -1
  35. package/dist/tools/__tests__/_payment-confirmation.test.d.ts +1 -0
  36. package/dist/tools/__tests__/_payment-confirmation.test.js +30 -0
  37. package/dist/tools/_payment-confirmation.d.ts +6 -0
  38. package/dist/tools/_payment-confirmation.js +28 -0
  39. package/dist/tools/agent-info.js +14 -0
  40. package/dist/tools/index.d.ts +1 -0
  41. package/dist/tools/index.js +1 -0
  42. package/dist/tools/passes.d.ts +2 -0
  43. package/dist/tools/passes.js +157 -0
  44. package/dist/tools/run.js +116 -49
  45. package/dist/tools/solve.js +102 -44
  46. package/dist/tools/wallet.js +85 -50
  47. package/package.json +3 -1
  48. package/src/core/__tests__/card-setup.test.ts +118 -0
  49. package/src/core/__tests__/formatters.test.ts +17 -0
  50. package/src/core/__tests__/passes.test.ts +94 -0
  51. package/src/core/__tests__/payments.test.ts +60 -0
  52. package/src/core/__tests__/principal.test.ts +87 -0
  53. package/src/core/api-client.ts +70 -23
  54. package/src/core/card-setup.ts +112 -35
  55. package/src/core/config.ts +33 -2
  56. package/src/core/formatters.ts +7 -1
  57. package/src/core/index.ts +2 -0
  58. package/src/core/ows-adapter.ts +74 -8
  59. package/src/core/passes.ts +74 -0
  60. package/src/core/payments.ts +140 -15
  61. package/src/core/principal.ts +128 -0
  62. package/src/core/solana-charge.ts +149 -0
  63. package/src/core/types.ts +10 -0
  64. package/src/index.ts +13 -4
  65. package/src/prompts/index.ts +1 -1
  66. package/src/resources/wallet.ts +8 -1
  67. package/src/tools/__tests__/_payment-confirmation.test.ts +45 -0
  68. package/src/tools/_payment-confirmation.ts +52 -0
  69. package/src/tools/agent-info.ts +23 -0
  70. package/src/tools/index.ts +1 -0
  71. package/src/tools/passes.ts +234 -0
  72. package/src/tools/run.ts +174 -53
  73. package/src/tools/solve.ts +149 -56
  74. package/src/tools/wallet.ts +102 -52
@@ -1,22 +1,32 @@
1
1
  import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
2
  import { z } from "zod";
3
- import { getWallets, getCardConfig, setCardConfig, addWallet } from "../core/config.js";
3
+ import {
4
+ getWallets,
5
+ getCardConfig,
6
+ setCardConfig,
7
+ addWallet,
8
+ getPendingCardSetupToken,
9
+ } from "../core/config.js";
4
10
  import { getWalletAddress } from "../core/payments.js";
5
- import { initiateCardSetup, pollCardSetup } from "../core/card-setup.js";
11
+ import {
12
+ getOrCreatePendingCardSetup,
13
+ formatCardSetupBlocks,
14
+ getCardCapabilities,
15
+ pollCardSetup,
16
+ } from "../core/card-setup.js";
6
17
  import {
7
18
  isOwsAvailable,
8
19
  createOwsWallet,
9
20
  importKeyToOws,
10
21
  listOwsWallets,
22
+ listOwsWalletsByChain,
11
23
  } from "../core/ows-adapter.js";
24
+ import { ensureConsumerPrincipal, getConsumerPrincipal } from "../core/principal.js";
12
25
 
13
26
  function text(t: string) {
14
27
  return { content: [{ type: "text" as const, text: t }] };
15
28
  }
16
29
 
17
- // Pending card setup — stored between the QR display call and the confirmation poll
18
- let pendingCardSetup: { token: string } | null = null;
19
-
20
30
  export function registerWalletTools(server: McpServer): void {
21
31
  // ── wallet_status (extracted from check_wallet) ─────────────────
22
32
  server.tool(
@@ -26,8 +36,10 @@ export function registerWalletTools(server: McpServer): void {
26
36
  async () => {
27
37
  const wallets = getWallets();
28
38
  const card = getCardConfig();
39
+ const pendingCardSetupToken = getPendingCardSetupToken();
40
+ const consumerPrincipal = await getConsumerPrincipal();
29
41
 
30
- if (wallets.length === 0 && !card) {
42
+ if (wallets.length === 0 && !card && !pendingCardSetupToken) {
31
43
  return text(
32
44
  "No payment methods configured.\nUse wallet_setup to create or import a wallet.",
33
45
  );
@@ -36,17 +48,38 @@ export function registerWalletTools(server: McpServer): void {
36
48
  const lines = ["Payment methods:"];
37
49
 
38
50
  for (const w of wallets) {
39
- const addr = await getWalletAddress(w.id);
40
51
  const label = w.label ? ` (${w.label})` : "";
41
52
  const storage =
42
53
  w.keyType === "ows" ? " [encrypted]" : " [plaintext]";
54
+ const chainAddresses = await Promise.all(
55
+ w.chains.map(async (chainName) => {
56
+ const addr = await getWalletAddress(chainName);
57
+ return `${chainName}: ${addr ?? "unknown"}`;
58
+ }),
59
+ );
43
60
  lines.push(
44
- ` ${w.id}${label}${storage}: ${w.chains.join(", ")} \u2014 ${addr ?? "unknown"}`,
61
+ ` ${w.id}${label}${storage}: ${chainAddresses.join(" | ")}`,
45
62
  );
46
63
  }
47
64
 
48
65
  if (card) {
49
66
  lines.push(` Card: ${card.brand} ****${card.last4}`);
67
+ const capabilities = await getCardCapabilities();
68
+ if (capabilities.spt_status === "enabled") {
69
+ lines.push(" Card MPP: ready");
70
+ } else if (capabilities.spt_status === "unavailable") {
71
+ lines.push(` Card MPP: unavailable — ${capabilities.message ?? "Stripe Shared Payment Token access is not enabled."}`);
72
+ } else {
73
+ lines.push(` Card MPP: unknown — ${capabilities.message ?? "Could not determine card payment readiness."}`);
74
+ }
75
+ }
76
+
77
+ if (pendingCardSetupToken) {
78
+ lines.push(" Card setup: pending confirmation");
79
+ }
80
+
81
+ if (consumerPrincipal) {
82
+ lines.push("", `Consumer principal: ${consumerPrincipal}`);
50
83
  }
51
84
 
52
85
  return text(lines.join("\n"));
@@ -72,7 +105,7 @@ export function registerWalletTools(server: McpServer): void {
72
105
  "Private key hex string (required for 'import', ignored for 'create')",
73
106
  ),
74
107
  chain: z.enum(["tempo", "base", "solana"]).optional()
75
- .describe("Primary chain (default: tempo). Solana support is via Stripe deposit mode."),
108
+ .describe("Primary chain (default: tempo). Solana uses an OWS wallet plus Stripe deposit-mode USDC."),
76
109
  },
77
110
  async ({ action, name, key, chain }) => {
78
111
  // ── Card setup flow ──────────────────────────────────────
@@ -82,53 +115,37 @@ export function registerWalletTools(server: McpServer): void {
82
115
  return text(`Card already connected: ${existing.brand} ****${existing.last4}\n\nTo replace it, remove the current card first.`);
83
116
  }
84
117
 
118
+ const pendingToken = getPendingCardSetupToken();
119
+
85
120
  // Check if there's a pending setup to complete (user said they're done)
86
- if (pendingCardSetup) {
87
- const pendingToken = pendingCardSetup.token;
88
- const result = await pollCardSetup(pendingToken, 120_000);
89
- pendingCardSetup = null;
121
+ if (pendingToken) {
122
+ const result = await pollCardSetup(pendingToken, 250);
90
123
 
91
124
  if (result) {
92
- return text(`Connected! ${result.brand} ****${result.last4} is ready for payments.`);
125
+ const principal = await ensureConsumerPrincipal();
126
+ return text(
127
+ `Connected! ${result.brand} ****${result.last4} is ready for payments.\n\n` +
128
+ `Consumer principal: ${principal}`,
129
+ );
93
130
  }
94
- return text("Card setup timed out. Run wallet_setup({ action: \"add-card\" }) to try again.");
95
- }
96
131
 
97
- // Create new card setup session with QR code, then auto-poll
98
- try {
99
- const { qr, url, token } = await initiateCardSetup();
100
-
101
- // Auto-poll for up to 90 seconds — if the user enters their card
102
- // quickly, the tool returns success without a second call
103
- const result = await pollCardSetup(token, 90_000);
104
-
105
- if (result) {
132
+ try {
133
+ const { url } = await getOrCreatePendingCardSetup();
134
+ const blocks = formatCardSetupBlocks(url);
106
135
  return {
107
- content: [
108
- { type: "text" as const, text: "\n" + qr.trim() },
109
- { type: "text" as const, text: [
110
- `Open to connect a card: ${url}`,
111
- "",
112
- `Connected! ${result.brand} ****${result.last4} is ready for payments.`,
113
- ].join("\n") },
114
- ],
136
+ content: blocks.map((t) => ({ type: "text" as const, text: t })),
115
137
  };
138
+ } catch {
139
+ return text("Card setup timed out. Run wallet_setup({ action: \"add-card\" }) to try again.");
116
140
  }
141
+ }
117
142
 
118
- // Timed out save token for manual follow-up
119
- pendingCardSetup = { token };
143
+ // Create new card setup session and return immediately so clients
144
+ // don't appear hung while the user is still in the browser flow.
145
+ try {
146
+ const { url } = await getOrCreatePendingCardSetup();
120
147
  return {
121
- content: [
122
- { type: "text" as const, text: "\n" + qr.trim() },
123
- { type: "text" as const, text: [
124
- `IMPORTANT: Present this link to the user to connect a payment card:`,
125
- "",
126
- url,
127
- "",
128
- `Tell the user: "Scan the QR code above or open this link to connect your card. Let me know when you're done."`,
129
- `After they confirm, call wallet_setup({ action: "add-card" }) to complete setup.`,
130
- ].join("\n") },
131
- ],
148
+ content: formatCardSetupBlocks(url).map((t) => ({ type: "text" as const, text: t })),
132
149
  };
133
150
  } catch {
134
151
  return text("Error: Could not create card setup session. Try again later.");
@@ -155,18 +172,23 @@ export function registerWalletTools(server: McpServer): void {
155
172
 
156
173
  const selectedChains = chain === "solana" ? ["solana"] : ["tempo", "base"];
157
174
  const defaultCh = chain ?? "tempo";
175
+ const preferredOwsChain = defaultCh === "solana" ? "solana" : "evm";
158
176
 
159
177
  const owsReady = await isOwsAvailable();
160
178
 
161
179
  if (action === "create") {
162
180
  // Check for existing OWS wallets first
163
181
  if (owsReady) {
164
- const existing = await listOwsWallets();
182
+ const existing = preferredOwsChain === "solana"
183
+ ? await listOwsWalletsByChain("solana")
184
+ : await listOwsWallets();
165
185
  if (existing.length > 0) {
166
186
  const w = existing[0];
167
187
  // Check if already in config
168
188
  const wallets = getWallets();
169
- const alreadyLinked = wallets.find(wl => wl.owsWalletId === w.id);
189
+ const alreadyLinked = wallets.find((wl) => wl.owsWalletId === w.id);
190
+ let chainStatus = "Linked to Agent Wonderland.";
191
+
170
192
  if (!alreadyLinked) {
171
193
  addWallet({
172
194
  id: w.name,
@@ -176,15 +198,28 @@ export function registerWalletTools(server: McpServer): void {
176
198
  defaultChain: defaultCh,
177
199
  label: w.name,
178
200
  });
201
+ } else {
202
+ const mergedChains = [...new Set([...alreadyLinked.chains, ...selectedChains])];
203
+ if (mergedChains.length !== alreadyLinked.chains.length) {
204
+ addWallet({
205
+ ...alreadyLinked,
206
+ chains: mergedChains,
207
+ });
208
+ chainStatus = `Updated linked chains: ${mergedChains.join(", ")}.`;
209
+ } else {
210
+ chainStatus = "Already linked to Agent Wonderland.";
211
+ }
179
212
  }
213
+ const principal = await ensureConsumerPrincipal();
180
214
  return text([
181
215
  "Found existing OWS wallet:",
182
216
  ` Name: ${w.name}`,
183
217
  ` Address: ${w.address}`,
184
218
  ` Chains: ${selectedChains.join(", ")}`,
185
219
  ` Storage: ~/.ows/ (encrypted)`,
220
+ ` Consumer principal: ${principal}`,
186
221
  "",
187
- alreadyLinked ? "Already linked to Agent Wonderland." : "Linked to Agent Wonderland.",
222
+ chainStatus,
188
223
  "",
189
224
  `Fund this address with USDC on ${defaultCh === "solana" ? "Solana" : "Tempo"} to start using agents.`,
190
225
  ].join("\n"));
@@ -195,12 +230,14 @@ export function registerWalletTools(server: McpServer): void {
195
230
  return text(
196
231
  "Cannot create wallet: OWS (Open Wallet Standard) is not installed.\n" +
197
232
  "Install with: npm install -g @open-wallet-standard/core\n\n" +
198
- "Alternatively, use action 'import' with an existing private key.",
233
+ (defaultCh === "solana"
234
+ ? "Solana wallets currently require OWS-managed encrypted storage."
235
+ : "Alternatively, use action 'import' with an existing private key."),
199
236
  );
200
237
  }
201
238
 
202
239
  const walletName = name ?? `aw-${Date.now()}`;
203
- const result = await createOwsWallet(walletName);
240
+ const result = await createOwsWallet(walletName, preferredOwsChain);
204
241
 
205
242
  // Persist to config so payment flows can find it
206
243
  addWallet({
@@ -211,6 +248,7 @@ export function registerWalletTools(server: McpServer): void {
211
248
  defaultChain: defaultCh,
212
249
  label: walletName,
213
250
  });
251
+ const principal = await ensureConsumerPrincipal();
214
252
 
215
253
  return text(
216
254
  [
@@ -220,6 +258,7 @@ export function registerWalletTools(server: McpServer): void {
220
258
  ` Name: ${walletName}`,
221
259
  ` Chains: ${selectedChains.join(", ")}`,
222
260
  ` Storage: ~/.ows/ (AES-256-GCM encrypted)`,
261
+ ` Consumer principal: ${principal}`,
223
262
  "",
224
263
  `Fund this address with USDC on ${defaultCh === "solana" ? "Solana" : "Tempo"} to start using agents.`,
225
264
  "For testnet: npx mppx account fund",
@@ -230,7 +269,7 @@ export function registerWalletTools(server: McpServer): void {
230
269
  // action === "import"
231
270
  if (owsReady) {
232
271
  const walletName = name ?? `imported-${Date.now()}`;
233
- const result = await importKeyToOws(key!, walletName);
272
+ const result = await importKeyToOws(key!, walletName, preferredOwsChain);
234
273
 
235
274
  addWallet({
236
275
  id: walletName,
@@ -240,6 +279,7 @@ export function registerWalletTools(server: McpServer): void {
240
279
  defaultChain: defaultCh,
241
280
  label: walletName,
242
281
  });
282
+ const principal = await ensureConsumerPrincipal();
243
283
 
244
284
  return text(
245
285
  [
@@ -248,10 +288,18 @@ export function registerWalletTools(server: McpServer): void {
248
288
  ` Address: ${result.address}`,
249
289
  ` Name: ${walletName}`,
250
290
  ` Chains: ${selectedChains.join(", ")}`,
291
+ ` Consumer principal: ${principal}`,
251
292
  ].join("\n"),
252
293
  );
253
294
  }
254
295
 
296
+ if (defaultCh === "solana") {
297
+ return text(
298
+ "Solana key import currently requires OWS (Open Wallet Standard) so the ed25519 key can be stored safely.\n" +
299
+ "Install with: npm install -g @open-wallet-standard/core",
300
+ );
301
+ }
302
+
255
303
  // No OWS — store plaintext
256
304
  try {
257
305
  const { privateKeyToAccount } = await import("viem/accounts");
@@ -269,6 +317,7 @@ export function registerWalletTools(server: McpServer): void {
269
317
  defaultChain: defaultCh,
270
318
  label: walletName,
271
319
  });
320
+ const principal = await ensureConsumerPrincipal();
272
321
 
273
322
  return text(
274
323
  [
@@ -276,6 +325,7 @@ export function registerWalletTools(server: McpServer): void {
276
325
  ` Address: ${account.address}`,
277
326
  ` Name: ${walletName}`,
278
327
  ` Chains: ${selectedChains.join(", ")}`,
328
+ ` Consumer principal: ${principal}`,
279
329
  "",
280
330
  "Install OWS for encrypted storage: npm install -g @open-wallet-standard/core",
281
331
  ].join("\n"),