@agentwonderland/mcp 0.1.15 → 0.1.16
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/config.d.ts +4 -0
- package/dist/core/config.js +6 -0
- package/dist/tools/wallet.js +75 -4
- package/package.json +3 -1
- package/src/core/config.ts +7 -0
- package/src/tools/wallet.ts +86 -4
package/dist/core/config.d.ts
CHANGED
|
@@ -68,6 +68,10 @@ export declare function removeWallet(id: string): void;
|
|
|
68
68
|
* Get card configuration.
|
|
69
69
|
*/
|
|
70
70
|
export declare function getCardConfig(): CardConfig | null;
|
|
71
|
+
/**
|
|
72
|
+
* Save card configuration after setup.
|
|
73
|
+
*/
|
|
74
|
+
export declare function setCardConfig(card: CardConfig | null): void;
|
|
71
75
|
/**
|
|
72
76
|
* Resolve a payment method string to a wallet + chain.
|
|
73
77
|
* Accepts: wallet ID, chain name, or "card".
|
package/dist/core/config.js
CHANGED
|
@@ -259,6 +259,12 @@ export function removeWallet(id) {
|
|
|
259
259
|
export function getCardConfig() {
|
|
260
260
|
return getConfig().card;
|
|
261
261
|
}
|
|
262
|
+
/**
|
|
263
|
+
* Save card configuration after setup.
|
|
264
|
+
*/
|
|
265
|
+
export function setCardConfig(card) {
|
|
266
|
+
saveConfig({ card });
|
|
267
|
+
}
|
|
262
268
|
/**
|
|
263
269
|
* Resolve a payment method string to a wallet + chain.
|
|
264
270
|
* Accepts: wallet ID, chain name, or "card".
|
package/dist/tools/wallet.js
CHANGED
|
@@ -1,10 +1,15 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
|
-
import
|
|
2
|
+
import QRCode from "qrcode";
|
|
3
|
+
import { getWallets, getCardConfig, setCardConfig, addWallet } from "../core/config.js";
|
|
4
|
+
import { getApiUrl } from "../core/config.js";
|
|
3
5
|
import { getWalletAddress } from "../core/payments.js";
|
|
6
|
+
import { apiPost, apiGet } from "../core/api-client.js";
|
|
4
7
|
import { isOwsAvailable, createOwsWallet, importKeyToOws, listOwsWallets, } from "../core/ows-adapter.js";
|
|
5
8
|
function text(t) {
|
|
6
9
|
return { content: [{ type: "text", text: t }] };
|
|
7
10
|
}
|
|
11
|
+
// Pending card setup — stored between the QR display call and the confirmation poll
|
|
12
|
+
let pendingCardSetup = null;
|
|
8
13
|
export function registerWalletTools(server) {
|
|
9
14
|
// ── wallet_status (extracted from check_wallet) ─────────────────
|
|
10
15
|
server.tool("wallet_status", "Check payment readiness. Shows all configured wallets, their chains, addresses, and card status.", {}, async () => {
|
|
@@ -26,10 +31,10 @@ export function registerWalletTools(server) {
|
|
|
26
31
|
return text(lines.join("\n"));
|
|
27
32
|
});
|
|
28
33
|
// ── wallet_setup (NEW) ──────────────────────────────────────────
|
|
29
|
-
server.tool("wallet_setup", "
|
|
34
|
+
server.tool("wallet_setup", "Set up a payment method for running agents. Options: 'create' a crypto wallet, 'import' an existing key, or 'add-card' to connect a credit/debit card via QR code. Card setup shows a scannable QR code — call again after the user enters their card to confirm.", {
|
|
30
35
|
action: z
|
|
31
|
-
.enum(["create", "import"])
|
|
32
|
-
.describe("'create' a new wallet
|
|
36
|
+
.enum(["create", "import", "add-card"])
|
|
37
|
+
.describe("'create' a new crypto wallet, 'import' an existing private key, or 'add-card' to connect a credit/debit card"),
|
|
33
38
|
name: z
|
|
34
39
|
.string()
|
|
35
40
|
.optional()
|
|
@@ -41,6 +46,72 @@ export function registerWalletTools(server) {
|
|
|
41
46
|
chain: z.enum(["tempo", "base", "solana"]).optional()
|
|
42
47
|
.describe("Primary chain (default: tempo). Solana support is via Stripe deposit mode."),
|
|
43
48
|
}, async ({ action, name, key, chain }) => {
|
|
49
|
+
// ── Card setup flow ──────────────────────────────────────
|
|
50
|
+
if (action === "add-card") {
|
|
51
|
+
const existing = getCardConfig();
|
|
52
|
+
if (existing) {
|
|
53
|
+
return text(`Card already connected: ${existing.brand} ****${existing.last4}\n\nTo replace it, remove the current card first.`);
|
|
54
|
+
}
|
|
55
|
+
// Check if there's a pending setup to complete
|
|
56
|
+
if (pendingCardSetup) {
|
|
57
|
+
const pendingToken = pendingCardSetup.token;
|
|
58
|
+
// Poll for completion (up to 2 minutes)
|
|
59
|
+
const deadline = Date.now() + 120_000;
|
|
60
|
+
while (Date.now() < deadline) {
|
|
61
|
+
await new Promise((r) => setTimeout(r, 3000));
|
|
62
|
+
try {
|
|
63
|
+
const status = await apiGet(`/card/status?token=${pendingToken}`);
|
|
64
|
+
if (status.status === "complete" && status.consumer_token) {
|
|
65
|
+
setCardConfig({
|
|
66
|
+
consumerToken: status.consumer_token,
|
|
67
|
+
last4: status.card_last4 ?? "????",
|
|
68
|
+
brand: status.card_brand ?? "card",
|
|
69
|
+
});
|
|
70
|
+
pendingCardSetup = null;
|
|
71
|
+
return text(`Connected! ${status.card_brand ?? "Card"} ****${status.card_last4} is ready for payments.`);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
catch {
|
|
75
|
+
// Keep polling
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
pendingCardSetup = null;
|
|
79
|
+
return text("Card setup timed out. Run wallet_setup({ action: \"add-card\" }) to try again.");
|
|
80
|
+
}
|
|
81
|
+
// Create new card setup session
|
|
82
|
+
let setupResult;
|
|
83
|
+
try {
|
|
84
|
+
setupResult = await apiPost("/card/setup", {});
|
|
85
|
+
}
|
|
86
|
+
catch {
|
|
87
|
+
return text("Error: Could not create card setup session. Try again later.");
|
|
88
|
+
}
|
|
89
|
+
// Store for the follow-up poll call
|
|
90
|
+
pendingCardSetup = { token: setupResult.token };
|
|
91
|
+
// Build a short link URL for a compact QR code
|
|
92
|
+
const apiUrl = getApiUrl();
|
|
93
|
+
const shortUrl = `${apiUrl}/card/link/${setupResult.token}`;
|
|
94
|
+
// Generate QR code
|
|
95
|
+
let qr;
|
|
96
|
+
try {
|
|
97
|
+
qr = await QRCode.toString(shortUrl, {
|
|
98
|
+
type: "utf8",
|
|
99
|
+
errorCorrectionLevel: "L",
|
|
100
|
+
margin: 2,
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
catch {
|
|
104
|
+
qr = "";
|
|
105
|
+
}
|
|
106
|
+
return text([
|
|
107
|
+
"Scan to connect a payment card:\n",
|
|
108
|
+
qr,
|
|
109
|
+
`Or open: ${shortUrl}`,
|
|
110
|
+
"",
|
|
111
|
+
"After entering your card, tell me and I'll confirm the connection.",
|
|
112
|
+
].join("\n"));
|
|
113
|
+
}
|
|
114
|
+
// ── Crypto wallet setup ──────────────────────────────────
|
|
44
115
|
if (action === "import" && !key) {
|
|
45
116
|
return text("Error: 'key' parameter is required when action is 'import'.");
|
|
46
117
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@agentwonderland/mcp",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.16",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "MCP server for the Agent Wonderland AI agent marketplace",
|
|
6
6
|
"bin": {
|
|
@@ -24,6 +24,7 @@
|
|
|
24
24
|
"dependencies": {
|
|
25
25
|
"@modelcontextprotocol/sdk": "^1.12.1",
|
|
26
26
|
"mppx": "^0.4.9",
|
|
27
|
+
"qrcode": "^1.5.4",
|
|
27
28
|
"viem": "^2.47.6",
|
|
28
29
|
"zod": "^3.24.0"
|
|
29
30
|
},
|
|
@@ -36,6 +37,7 @@
|
|
|
36
37
|
}
|
|
37
38
|
},
|
|
38
39
|
"devDependencies": {
|
|
40
|
+
"@types/qrcode": "^1.5.6",
|
|
39
41
|
"tsx": "^4.0.0",
|
|
40
42
|
"typescript": "^5.7.0"
|
|
41
43
|
},
|
package/src/core/config.ts
CHANGED
|
@@ -346,6 +346,13 @@ export function getCardConfig(): CardConfig | null {
|
|
|
346
346
|
return getConfig().card;
|
|
347
347
|
}
|
|
348
348
|
|
|
349
|
+
/**
|
|
350
|
+
* Save card configuration after setup.
|
|
351
|
+
*/
|
|
352
|
+
export function setCardConfig(card: CardConfig | null): void {
|
|
353
|
+
saveConfig({ card });
|
|
354
|
+
}
|
|
355
|
+
|
|
349
356
|
/**
|
|
350
357
|
* Resolve a payment method string to a wallet + chain.
|
|
351
358
|
* Accepts: wallet ID, chain name, or "card".
|
package/src/tools/wallet.ts
CHANGED
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
2
2
|
import { z } from "zod";
|
|
3
|
-
import
|
|
3
|
+
import QRCode from "qrcode";
|
|
4
|
+
import { getWallets, getCardConfig, setCardConfig, addWallet } from "../core/config.js";
|
|
5
|
+
import { getApiUrl } from "../core/config.js";
|
|
4
6
|
import { getWalletAddress } from "../core/payments.js";
|
|
7
|
+
import { apiPost, apiGet } from "../core/api-client.js";
|
|
5
8
|
import {
|
|
6
9
|
isOwsAvailable,
|
|
7
10
|
createOwsWallet,
|
|
@@ -13,6 +16,9 @@ function text(t: string) {
|
|
|
13
16
|
return { content: [{ type: "text" as const, text: t }] };
|
|
14
17
|
}
|
|
15
18
|
|
|
19
|
+
// Pending card setup — stored between the QR display call and the confirmation poll
|
|
20
|
+
let pendingCardSetup: { token: string } | null = null;
|
|
21
|
+
|
|
16
22
|
export function registerWalletTools(server: McpServer): void {
|
|
17
23
|
// ── wallet_status (extracted from check_wallet) ─────────────────
|
|
18
24
|
server.tool(
|
|
@@ -52,11 +58,11 @@ export function registerWalletTools(server: McpServer): void {
|
|
|
52
58
|
// ── wallet_setup (NEW) ──────────────────────────────────────────
|
|
53
59
|
server.tool(
|
|
54
60
|
"wallet_setup",
|
|
55
|
-
"
|
|
61
|
+
"Set up a payment method for running agents. Options: 'create' a crypto wallet, 'import' an existing key, or 'add-card' to connect a credit/debit card via QR code. Card setup shows a scannable QR code — call again after the user enters their card to confirm.",
|
|
56
62
|
{
|
|
57
63
|
action: z
|
|
58
|
-
.enum(["create", "import"])
|
|
59
|
-
.describe("'create' a new wallet
|
|
64
|
+
.enum(["create", "import", "add-card"])
|
|
65
|
+
.describe("'create' a new crypto wallet, 'import' an existing private key, or 'add-card' to connect a credit/debit card"),
|
|
60
66
|
name: z
|
|
61
67
|
.string()
|
|
62
68
|
.optional()
|
|
@@ -71,6 +77,82 @@ export function registerWalletTools(server: McpServer): void {
|
|
|
71
77
|
.describe("Primary chain (default: tempo). Solana support is via Stripe deposit mode."),
|
|
72
78
|
},
|
|
73
79
|
async ({ action, name, key, chain }) => {
|
|
80
|
+
// ── Card setup flow ──────────────────────────────────────
|
|
81
|
+
if (action === "add-card") {
|
|
82
|
+
const existing = getCardConfig();
|
|
83
|
+
if (existing) {
|
|
84
|
+
return text(`Card already connected: ${existing.brand} ****${existing.last4}\n\nTo replace it, remove the current card first.`);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// Check if there's a pending setup to complete
|
|
88
|
+
if (pendingCardSetup) {
|
|
89
|
+
const pendingToken = pendingCardSetup.token;
|
|
90
|
+
// Poll for completion (up to 2 minutes)
|
|
91
|
+
const deadline = Date.now() + 120_000;
|
|
92
|
+
while (Date.now() < deadline) {
|
|
93
|
+
await new Promise((r) => setTimeout(r, 3000));
|
|
94
|
+
try {
|
|
95
|
+
const status = await apiGet<{
|
|
96
|
+
status: string;
|
|
97
|
+
card_last4?: string;
|
|
98
|
+
card_brand?: string;
|
|
99
|
+
consumer_token?: string;
|
|
100
|
+
}>(`/card/status?token=${pendingToken}`);
|
|
101
|
+
|
|
102
|
+
if (status.status === "complete" && status.consumer_token) {
|
|
103
|
+
setCardConfig({
|
|
104
|
+
consumerToken: status.consumer_token,
|
|
105
|
+
last4: status.card_last4 ?? "????",
|
|
106
|
+
brand: status.card_brand ?? "card",
|
|
107
|
+
});
|
|
108
|
+
pendingCardSetup = null;
|
|
109
|
+
return text(`Connected! ${status.card_brand ?? "Card"} ****${status.card_last4} is ready for payments.`);
|
|
110
|
+
}
|
|
111
|
+
} catch {
|
|
112
|
+
// Keep polling
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
pendingCardSetup = null;
|
|
116
|
+
return text("Card setup timed out. Run wallet_setup({ action: \"add-card\" }) to try again.");
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
// Create new card setup session
|
|
120
|
+
let setupResult: { url: string; token: string };
|
|
121
|
+
try {
|
|
122
|
+
setupResult = await apiPost<{ url: string; token: string }>("/card/setup", {});
|
|
123
|
+
} catch {
|
|
124
|
+
return text("Error: Could not create card setup session. Try again later.");
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
// Store for the follow-up poll call
|
|
128
|
+
pendingCardSetup = { token: setupResult.token };
|
|
129
|
+
|
|
130
|
+
// Build a short link URL for a compact QR code
|
|
131
|
+
const apiUrl = getApiUrl();
|
|
132
|
+
const shortUrl = `${apiUrl}/card/link/${setupResult.token}`;
|
|
133
|
+
|
|
134
|
+
// Generate QR code
|
|
135
|
+
let qr: string;
|
|
136
|
+
try {
|
|
137
|
+
qr = await QRCode.toString(shortUrl, {
|
|
138
|
+
type: "utf8",
|
|
139
|
+
errorCorrectionLevel: "L",
|
|
140
|
+
margin: 2,
|
|
141
|
+
});
|
|
142
|
+
} catch {
|
|
143
|
+
qr = "";
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
return text([
|
|
147
|
+
"Scan to connect a payment card:\n",
|
|
148
|
+
qr,
|
|
149
|
+
`Or open: ${shortUrl}`,
|
|
150
|
+
"",
|
|
151
|
+
"After entering your card, tell me and I'll confirm the connection.",
|
|
152
|
+
].join("\n"));
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
// ── Crypto wallet setup ──────────────────────────────────
|
|
74
156
|
if (action === "import" && !key) {
|
|
75
157
|
return text(
|
|
76
158
|
"Error: 'key' parameter is required when action is 'import'.",
|