@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.
- package/dist/core/__tests__/card-setup.test.d.ts +1 -0
- package/dist/core/__tests__/card-setup.test.js +99 -0
- package/dist/core/__tests__/formatters.test.d.ts +1 -0
- package/dist/core/__tests__/formatters.test.js +15 -0
- package/dist/core/__tests__/passes.test.d.ts +1 -0
- package/dist/core/__tests__/passes.test.js +82 -0
- package/dist/core/__tests__/payments.test.d.ts +1 -0
- package/dist/core/__tests__/payments.test.js +52 -0
- package/dist/core/__tests__/principal.test.d.ts +1 -0
- package/dist/core/__tests__/principal.test.js +67 -0
- package/dist/core/api-client.d.ts +9 -4
- package/dist/core/api-client.js +52 -22
- package/dist/core/card-setup.d.ts +20 -13
- package/dist/core/card-setup.js +87 -30
- package/dist/core/config.d.ts +4 -0
- package/dist/core/config.js +28 -1
- package/dist/core/formatters.d.ts +2 -0
- package/dist/core/formatters.js +5 -1
- package/dist/core/index.d.ts +2 -0
- package/dist/core/index.js +2 -0
- package/dist/core/ows-adapter.d.ts +10 -2
- package/dist/core/ows-adapter.js +54 -10
- package/dist/core/passes.d.ts +40 -0
- package/dist/core/passes.js +32 -0
- package/dist/core/payments.d.ts +8 -0
- package/dist/core/payments.js +121 -16
- package/dist/core/principal.d.ts +2 -0
- package/dist/core/principal.js +109 -0
- package/dist/core/solana-charge.d.ts +9 -0
- package/dist/core/solana-charge.js +95 -0
- package/dist/core/types.d.ts +10 -0
- package/dist/index.js +13 -4
- package/dist/prompts/index.js +1 -1
- package/dist/resources/wallet.js +8 -1
- package/dist/tools/__tests__/_payment-confirmation.test.d.ts +1 -0
- package/dist/tools/__tests__/_payment-confirmation.test.js +30 -0
- package/dist/tools/_payment-confirmation.d.ts +6 -0
- package/dist/tools/_payment-confirmation.js +28 -0
- package/dist/tools/agent-info.js +14 -0
- package/dist/tools/index.d.ts +1 -0
- package/dist/tools/index.js +1 -0
- package/dist/tools/passes.d.ts +2 -0
- package/dist/tools/passes.js +157 -0
- package/dist/tools/run.js +116 -49
- package/dist/tools/solve.js +102 -44
- package/dist/tools/wallet.js +85 -50
- package/package.json +3 -1
- package/src/core/__tests__/card-setup.test.ts +118 -0
- package/src/core/__tests__/formatters.test.ts +17 -0
- package/src/core/__tests__/passes.test.ts +94 -0
- package/src/core/__tests__/payments.test.ts +60 -0
- package/src/core/__tests__/principal.test.ts +87 -0
- package/src/core/api-client.ts +70 -23
- package/src/core/card-setup.ts +112 -35
- package/src/core/config.ts +33 -2
- package/src/core/formatters.ts +7 -1
- package/src/core/index.ts +2 -0
- package/src/core/ows-adapter.ts +74 -8
- package/src/core/passes.ts +74 -0
- package/src/core/payments.ts +140 -15
- package/src/core/principal.ts +128 -0
- package/src/core/solana-charge.ts +149 -0
- package/src/core/types.ts +10 -0
- package/src/index.ts +13 -4
- package/src/prompts/index.ts +1 -1
- package/src/resources/wallet.ts +8 -1
- package/src/tools/__tests__/_payment-confirmation.test.ts +45 -0
- package/src/tools/_payment-confirmation.ts +52 -0
- package/src/tools/agent-info.ts +23 -0
- package/src/tools/index.ts +1 -0
- package/src/tools/passes.ts +234 -0
- package/src/tools/run.ts +174 -53
- package/src/tools/solve.ts +149 -56
- package/src/tools/wallet.ts +102 -52
package/src/tools/wallet.ts
CHANGED
|
@@ -1,22 +1,32 @@
|
|
|
1
1
|
import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
2
2
|
import { z } from "zod";
|
|
3
|
-
import {
|
|
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 {
|
|
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}: ${
|
|
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
|
|
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 (
|
|
87
|
-
const
|
|
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
|
-
|
|
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
|
-
|
|
98
|
-
|
|
99
|
-
|
|
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
|
-
|
|
119
|
-
|
|
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 =
|
|
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
|
-
|
|
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
|
-
|
|
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"),
|