agentwallet-mcp 1.10.6 → 1.10.8
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 +26 -5
- package/build/index.js +4 -2
- package/build/ssrf-guard.d.ts +22 -2
- package/build/ssrf-guard.js +77 -4
- package/package.json +69 -69
package/README.md
CHANGED
|
@@ -76,7 +76,7 @@ Local signing uses [viem](https://viem.sh) for EVM and `@solana/web3.js` for Sol
|
|
|
76
76
|
- **31 MCP tools**: create wallets, send transactions, approve tokens, wrap ETH, transfer SPL tokens, pay and accept x402 payments, verify custody mode, and more
|
|
77
77
|
- **EVM + Solana**: Ethereum, Base, Polygon, BSC, Arbitrum, Optimism, Avalanche, Zora, PulseChain, Solana, and any other EVM-compatible chain
|
|
78
78
|
- **SOL + SPL tokens**: native SOL transfers and SPL token transfers (USDC, USDT, etc.) with automatic account creation
|
|
79
|
-
- **Built-in guards**: daily spending limits, gas price protection, emergency pause
|
|
79
|
+
- **Built-in guards**: in hosted mode, daily spending limits, gas price protection, emergency pause and rate limiting are enforced server-side by default. In local mode your protection is the per-transaction caps you set (`AGENTWALLET_MAX_TX_NATIVE`, `AGENTWALLET_MAX_TX_TOKEN`, `AGENTWALLET_MAX_TX_SOL`, `AGENTWALLET_MAX_AUTOPAY`). x402 replay protection and on-chain verification apply either way
|
|
80
80
|
- **x402 payments**: pay for x402-enabled APIs automatically, or accept x402 payments on your own endpoints (EVM and Solana)
|
|
81
81
|
- **Self-custody option**: run local mode and the key never leaves your machine. In hosted mode, keys are encrypted at rest, decrypted only during signing, and zeroed from memory immediately after. Either way you can export and walk away.
|
|
82
82
|
- **Permissionless**: No KYC. No KYT. No identity verification. No approval process. No compliance gatekeeping. Sign up, get an API key, and start transacting immediately.
|
|
@@ -274,7 +274,7 @@ On-chain verification ensures every payment is real. Replay protection prevents
|
|
|
274
274
|
| KYC Required | Yes | **No** |
|
|
275
275
|
| KYT / Transaction Monitoring | Yes | **No** |
|
|
276
276
|
| Can Block Your Wallet | Yes | **No** |
|
|
277
|
-
| Built-in Guards | Yes (requires setup) | **Yes (active by default)** |
|
|
277
|
+
| Built-in Guards | Yes (requires setup) | **Yes (hosted: active by default; local: env caps you set)** |
|
|
278
278
|
| Free Operations / Month | 5,000 | **6,000** |
|
|
279
279
|
| Cost Per Operation | $0.005 | **$0.00345** |
|
|
280
280
|
| x402 Verification Cost | $0.001 | **$0.0005** |
|
|
@@ -295,17 +295,30 @@ You can also pre-purchase x402 verification credits with USDC using the `buy_ver
|
|
|
295
295
|
|
|
296
296
|
## Built-in Guards
|
|
297
297
|
|
|
298
|
-
|
|
298
|
+
Which guards apply depends on who holds the key.
|
|
299
|
+
|
|
300
|
+
**Hosted mode** (the server holds the key): every guard below is active by default, no configuration required.
|
|
299
301
|
|
|
300
302
|
- **Encrypted at rest**: private keys encrypted before storage and never leave the server
|
|
301
303
|
- **Memory zeroing**: keys wiped from memory immediately after every signing operation
|
|
302
|
-
- **Daily spending limits**: set a per-wallet daily cap in USD, enforced
|
|
304
|
+
- **Daily spending limits**: set a per-wallet daily cap in USD, enforced by the server on every transaction
|
|
303
305
|
- **Gas price protection**: transactions blocked when gas prices spike above safe thresholds
|
|
304
306
|
- **Emergency pause**: instantly freeze any wallet or all wallets with one click
|
|
305
307
|
- **Rate limiting**: API requests capped per minute to prevent abuse and brute force attacks
|
|
308
|
+
|
|
309
|
+
**Local mode** (you hold the key): there is no server in the signing path, so the server-side limits and pause above cannot see or stop a locally signed transaction, and nobody (including us) can freeze a local wallet. Your protection is the per-transaction caps enforced inside your own process before anything is signed. Set them before you fund the wallet; an unset cap means no limit.
|
|
310
|
+
|
|
311
|
+
- `AGENTWALLET_MAX_TX_NATIVE`: ceiling per transaction in native units (ETH, MATIC, and so on)
|
|
312
|
+
- `AGENTWALLET_MAX_TX_TOKEN`: ceiling per ERC-20 transfer, in human units of the token
|
|
313
|
+
- `AGENTWALLET_MAX_TX_SOL`: ceiling per SOL or SPL transfer
|
|
314
|
+
- `AGENTWALLET_MAX_AUTOPAY`: ceiling per x402 auto-payment (default `1`)
|
|
315
|
+
|
|
316
|
+
**Either mode**, for x402 paywalls you run through the hosted API:
|
|
317
|
+
|
|
306
318
|
- **Replay protection**: every x402 payment verified on-chain with unique transaction tracking
|
|
307
319
|
- **On-chain verification**: x402 payments verified directly on the blockchain with finalized commitment
|
|
308
|
-
|
|
320
|
+
|
|
321
|
+
Bug bounty program: $50 to $500 for responsible disclosure ([details](https://hifriendbot.com/wallet)).
|
|
309
322
|
|
|
310
323
|
## Links
|
|
311
324
|
|
|
@@ -328,6 +341,14 @@ resolve public for the check and private for the connection. The hostname is
|
|
|
328
341
|
still used for the `Host` header and for TLS SNI and certificate validation, so
|
|
329
342
|
pinning is invisible to legitimate endpoints.
|
|
330
343
|
|
|
344
|
+
Credentials stay with the origin they were given to. If an endpoint redirects
|
|
345
|
+
`pay_x402` to a different origin, the caller-supplied `Authorization`, `Cookie`
|
|
346
|
+
and `X-PAYMENT` headers, and every other custom header, are dropped before the
|
|
347
|
+
next hop; only content-negotiation headers (`Accept`, `Accept-Language`,
|
|
348
|
+
`Accept-Encoding`, `User-Agent`, `Content-Type`) are carried. A redirect that
|
|
349
|
+
turns a POST into a GET also sheds the body headers. Same-origin redirects keep
|
|
350
|
+
everything, as a browser would.
|
|
351
|
+
|
|
331
352
|
Report security issues privately to security@hifriendbot.com.
|
|
332
353
|
|
|
333
354
|
## License
|
package/build/index.js
CHANGED
|
@@ -424,7 +424,7 @@ function resolveChainId(network) {
|
|
|
424
424
|
const AddressSchema = z.string().regex(/^(0x[a-fA-F0-9]{40}|[1-9A-HJ-NP-Za-km-z]{32,44})$/, 'Must be a 0x-prefixed 40-hex EVM address or a base58 Solana address');
|
|
425
425
|
const server = new McpServer({
|
|
426
426
|
name: 'agentwallet',
|
|
427
|
-
version: '1.10.
|
|
427
|
+
version: '1.10.8',
|
|
428
428
|
}, {
|
|
429
429
|
instructions: `AgentWallet gives AI agents their own blockchain wallets. Private keys are encrypted server-side and never exposed — agents sign and broadcast transactions without ever touching raw keys.
|
|
430
430
|
|
|
@@ -944,7 +944,9 @@ server.tool('pay_x402', 'Handle an x402 payment flow. Fetches a URL, and if the
|
|
|
944
944
|
url: z.string().url().describe('The URL to access (will handle 402 payment if required)'),
|
|
945
945
|
wallet_id: z.number().int().describe('Wallet ID to pay from'),
|
|
946
946
|
method: z.string().default('GET').describe('HTTP method (GET, POST, PUT, DELETE)'),
|
|
947
|
-
headers: z.string().optional().describe('Optional JSON string of additional request headers'
|
|
947
|
+
headers: z.string().optional().describe('Optional JSON string of additional request headers. Credentials placed here ' +
|
|
948
|
+
'(Authorization, Cookie, API keys) are sent only to the origin in `url`; if the ' +
|
|
949
|
+
'endpoint redirects to a different origin they are dropped, not forwarded.'),
|
|
948
950
|
body: z.string().optional().describe('Optional request body for POST/PUT requests'),
|
|
949
951
|
max_payment: z.string().optional().describe('Maximum payment in human-readable format (e.g. "1.00" for 1 USDC). ' +
|
|
950
952
|
'Rejects payments above this amount. If omitted, a default cap of ' +
|
package/build/ssrf-guard.d.ts
CHANGED
|
@@ -21,8 +21,14 @@
|
|
|
21
21
|
* still used for the Host header and for TLS SNI and certificate validation,
|
|
22
22
|
* so pinning is invisible to legitimate endpoints.
|
|
23
23
|
*
|
|
24
|
-
*
|
|
25
|
-
*
|
|
24
|
+
* Redirects are followed by hand, and a redirect to a different origin drops
|
|
25
|
+
* every caller-supplied header except a short content-negotiation list. A
|
|
26
|
+
* bearer token meant for api.example.com must not be replayed to whatever
|
|
27
|
+
* host api.example.com chooses to redirect to.
|
|
28
|
+
*
|
|
29
|
+
* Reported privately by ARC Security Research, 2026-07-31 (spelling bypasses),
|
|
30
|
+
* by an anonymous researcher, 2026-08-02 (the DNS rebinding race), and by
|
|
31
|
+
* Arthur Kijkrittaya, 2026-09-08 (credentials surviving cross-origin redirects).
|
|
26
32
|
*/
|
|
27
33
|
/**
|
|
28
34
|
* Reduce a host to the IP address it actually denotes.
|
|
@@ -64,6 +70,17 @@ type LookupCallback = (err: NodeJS.ErrnoException | null, addressOrList?: string
|
|
|
64
70
|
* second query cannot reach the socket.
|
|
65
71
|
*/
|
|
66
72
|
export declare function createPinnedLookup(addresses: ValidatedAddress[]): (_hostname: string, options: unknown, callback?: LookupCallback) => void;
|
|
73
|
+
/** True when two URLs share scheme, host and port (the web origin). */
|
|
74
|
+
export declare function sameOrigin(a: string, b: string): boolean;
|
|
75
|
+
/**
|
|
76
|
+
* Decide which request headers follow a redirect from `from` to `to`.
|
|
77
|
+
*
|
|
78
|
+
* Same origin: everything is kept, as a browser would. Different origin: only
|
|
79
|
+
* CROSS_ORIGIN_SAFE_HEADERS survive. When the redirect also turned the request
|
|
80
|
+
* into a body-less GET (`bodyDropped`), the entity headers go too, on either
|
|
81
|
+
* kind of hop.
|
|
82
|
+
*/
|
|
83
|
+
export declare function headersForRedirect(headers: HeadersInit | undefined, from: string, to: string, bodyDropped: boolean): Record<string, string>;
|
|
67
84
|
/**
|
|
68
85
|
* fetch() that validates the target, and every redirect hop, against
|
|
69
86
|
* resolvePublicUrl, and connects only to the addresses that validation
|
|
@@ -71,6 +88,9 @@ export declare function createPinnedLookup(addresses: ValidatedAddress[]): (_hos
|
|
|
71
88
|
* would happily land on a private address after a public first hop, and
|
|
72
89
|
* because each hop needs its own resolve-then-pin cycle.
|
|
73
90
|
*
|
|
91
|
+
* Headers are re-derived on every redirect (see headersForRedirect): a hop to
|
|
92
|
+
* another origin carries no credential the caller attached for the first one.
|
|
93
|
+
*
|
|
74
94
|
* The body is buffered so the pinned connection can be torn down before the
|
|
75
95
|
* response is handed back.
|
|
76
96
|
*/
|
package/build/ssrf-guard.js
CHANGED
|
@@ -21,8 +21,14 @@
|
|
|
21
21
|
* still used for the Host header and for TLS SNI and certificate validation,
|
|
22
22
|
* so pinning is invisible to legitimate endpoints.
|
|
23
23
|
*
|
|
24
|
-
*
|
|
25
|
-
*
|
|
24
|
+
* Redirects are followed by hand, and a redirect to a different origin drops
|
|
25
|
+
* every caller-supplied header except a short content-negotiation list. A
|
|
26
|
+
* bearer token meant for api.example.com must not be replayed to whatever
|
|
27
|
+
* host api.example.com chooses to redirect to.
|
|
28
|
+
*
|
|
29
|
+
* Reported privately by ARC Security Research, 2026-07-31 (spelling bypasses),
|
|
30
|
+
* by an anonymous researcher, 2026-08-02 (the DNS rebinding race), and by
|
|
31
|
+
* Arthur Kijkrittaya, 2026-09-08 (credentials surviving cross-origin redirects).
|
|
26
32
|
*/
|
|
27
33
|
import { isIP } from 'node:net';
|
|
28
34
|
import { lookup as dnsLookup } from 'node:dns/promises';
|
|
@@ -212,6 +218,66 @@ export function createPinnedLookup(addresses) {
|
|
|
212
218
|
}
|
|
213
219
|
/** Statuses whose Response must be constructed with a null body. */
|
|
214
220
|
const NULL_BODY_STATUS = new Set([101, 103, 204, 205, 304]);
|
|
221
|
+
/**
|
|
222
|
+
* The only request headers that may travel to a different origin on a
|
|
223
|
+
* redirect. Everything else the caller supplied (Authorization, Cookie,
|
|
224
|
+
* X-PAYMENT, API keys under any custom name) is bound to the origin the caller
|
|
225
|
+
* addressed and is dropped. An allow list is used rather than a deny list so a
|
|
226
|
+
* secret under an unanticipated header name cannot slip through.
|
|
227
|
+
*/
|
|
228
|
+
const CROSS_ORIGIN_SAFE_HEADERS = new Set([
|
|
229
|
+
'accept',
|
|
230
|
+
'accept-language',
|
|
231
|
+
'accept-encoding',
|
|
232
|
+
'user-agent',
|
|
233
|
+
'content-type',
|
|
234
|
+
]);
|
|
235
|
+
/** Headers that describe a request body and are wrong once the body is gone. */
|
|
236
|
+
const ENTITY_HEADERS = new Set(['content-type', 'content-length', 'content-encoding', 'transfer-encoding']);
|
|
237
|
+
/** True when two URLs share scheme, host and port (the web origin). */
|
|
238
|
+
export function sameOrigin(a, b) {
|
|
239
|
+
const ua = new URL(a);
|
|
240
|
+
const ub = new URL(b);
|
|
241
|
+
return ua.protocol === ub.protocol && ua.host === ub.host;
|
|
242
|
+
}
|
|
243
|
+
function headersToRecord(headers) {
|
|
244
|
+
const out = {};
|
|
245
|
+
if (!headers)
|
|
246
|
+
return out;
|
|
247
|
+
if (typeof headers.forEach === 'function' && !Array.isArray(headers)) {
|
|
248
|
+
headers.forEach((v, k) => { out[k] = v; });
|
|
249
|
+
return out;
|
|
250
|
+
}
|
|
251
|
+
if (Array.isArray(headers)) {
|
|
252
|
+
for (const [k, v] of headers)
|
|
253
|
+
out[k] = v;
|
|
254
|
+
return out;
|
|
255
|
+
}
|
|
256
|
+
for (const [k, v] of Object.entries(headers))
|
|
257
|
+
out[k] = v;
|
|
258
|
+
return out;
|
|
259
|
+
}
|
|
260
|
+
/**
|
|
261
|
+
* Decide which request headers follow a redirect from `from` to `to`.
|
|
262
|
+
*
|
|
263
|
+
* Same origin: everything is kept, as a browser would. Different origin: only
|
|
264
|
+
* CROSS_ORIGIN_SAFE_HEADERS survive. When the redirect also turned the request
|
|
265
|
+
* into a body-less GET (`bodyDropped`), the entity headers go too, on either
|
|
266
|
+
* kind of hop.
|
|
267
|
+
*/
|
|
268
|
+
export function headersForRedirect(headers, from, to, bodyDropped) {
|
|
269
|
+
const crossOrigin = !sameOrigin(from, to);
|
|
270
|
+
const out = {};
|
|
271
|
+
for (const [k, v] of Object.entries(headersToRecord(headers))) {
|
|
272
|
+
const name = k.toLowerCase();
|
|
273
|
+
if (bodyDropped && ENTITY_HEADERS.has(name))
|
|
274
|
+
continue;
|
|
275
|
+
if (crossOrigin && !CROSS_ORIGIN_SAFE_HEADERS.has(name))
|
|
276
|
+
continue;
|
|
277
|
+
out[k] = v;
|
|
278
|
+
}
|
|
279
|
+
return out;
|
|
280
|
+
}
|
|
215
281
|
/**
|
|
216
282
|
* fetch() that validates the target, and every redirect hop, against
|
|
217
283
|
* resolvePublicUrl, and connects only to the addresses that validation
|
|
@@ -219,6 +285,9 @@ const NULL_BODY_STATUS = new Set([101, 103, 204, 205, 304]);
|
|
|
219
285
|
* would happily land on a private address after a public first hop, and
|
|
220
286
|
* because each hop needs its own resolve-then-pin cycle.
|
|
221
287
|
*
|
|
288
|
+
* Headers are re-derived on every redirect (see headersForRedirect): a hop to
|
|
289
|
+
* another origin carries no credential the caller attached for the first one.
|
|
290
|
+
*
|
|
222
291
|
* The body is buffered so the pinned connection can be torn down before the
|
|
223
292
|
* response is handed back.
|
|
224
293
|
*/
|
|
@@ -262,8 +331,12 @@ export async function safeFetch(url, options = {}, maxHops = 3) {
|
|
|
262
331
|
if (!isRedirect)
|
|
263
332
|
return out;
|
|
264
333
|
const next = new URL(out.headers.get('location'), current).toString();
|
|
265
|
-
// A redirected request must not replay the body or method blindly
|
|
266
|
-
|
|
334
|
+
// A redirected request must not replay the body or method blindly, and it
|
|
335
|
+
// must not replay the caller's credentials to a different origin at all.
|
|
336
|
+
const bodyDropped = status === 303
|
|
337
|
+
|| ((status === 301 || status === 302) && !!opts.method && opts.method !== 'GET');
|
|
338
|
+
opts = { ...opts, headers: headersForRedirect(opts.headers, current, next, bodyDropped) };
|
|
339
|
+
if (bodyDropped) {
|
|
267
340
|
opts = { ...opts, method: 'GET', body: undefined };
|
|
268
341
|
}
|
|
269
342
|
current = next;
|
package/package.json
CHANGED
|
@@ -1,69 +1,69 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "agentwallet-mcp",
|
|
3
|
-
"mcpName": "io.github.hifriendbot/agentwallet",
|
|
4
|
-
"version": "1.10.
|
|
5
|
-
"description": "MCP server for AgentWallet: self-custody local signing on EVM and Solana, or hosted wallets. Sign, broadcast, pay x402 invoices, and accept x402 payments.",
|
|
6
|
-
"type": "module",
|
|
7
|
-
"main": "build/index.js",
|
|
8
|
-
"bin": {
|
|
9
|
-
"agentwallet-mcp": "build/index.js"
|
|
10
|
-
},
|
|
11
|
-
"files": [
|
|
12
|
-
"build",
|
|
13
|
-
"README.md",
|
|
14
|
-
"LICENSE"
|
|
15
|
-
],
|
|
16
|
-
"scripts": {
|
|
17
|
-
"build": "tsc",
|
|
18
|
-
"start": "node build/index.js",
|
|
19
|
-
"test": "node test/x402-payment.test.mjs && node test/token-cap.test.mjs && node test/spl-cap.test.mjs && node test/unknown-decimals-cap.test.mjs && node test/local-mode.test.mjs && node test/ssrf-guard.test.mjs",
|
|
20
|
-
"prepublishOnly": "npm run build"
|
|
21
|
-
},
|
|
22
|
-
"keywords": [
|
|
23
|
-
"mcp",
|
|
24
|
-
"model-context-protocol",
|
|
25
|
-
"wallet",
|
|
26
|
-
"ai-agent",
|
|
27
|
-
"blockchain",
|
|
28
|
-
"evm",
|
|
29
|
-
"ethereum",
|
|
30
|
-
"base",
|
|
31
|
-
"arbitrum",
|
|
32
|
-
"optimism",
|
|
33
|
-
"polygon",
|
|
34
|
-
"avalanche",
|
|
35
|
-
"bsc",
|
|
36
|
-
"zora",
|
|
37
|
-
"pulsechain",
|
|
38
|
-
"solana",
|
|
39
|
-
"spl-token",
|
|
40
|
-
"erc20",
|
|
41
|
-
"token-transfer",
|
|
42
|
-
"transaction-signing",
|
|
43
|
-
"x402",
|
|
44
|
-
"http-402",
|
|
45
|
-
"agent-payments",
|
|
46
|
-
"agentwallet",
|
|
47
|
-
"self-custody",
|
|
48
|
-
"non-custodial",
|
|
49
|
-
"local-signing"
|
|
50
|
-
],
|
|
51
|
-
"author": "HiFriendbot (https://hifriendbot.com)",
|
|
52
|
-
"license": "MIT",
|
|
53
|
-
"homepage": "https://hifriendbot.com/wallet/",
|
|
54
|
-
"engines": {
|
|
55
|
-
"node": ">=18.0.0"
|
|
56
|
-
},
|
|
57
|
-
"dependencies": {
|
|
58
|
-
"@modelcontextprotocol/sdk": "^1.11.4",
|
|
59
|
-
"@solana/web3.js": "^1.98.4",
|
|
60
|
-
"bs58": "^6.0.0",
|
|
61
|
-
"undici": "^8.9.0",
|
|
62
|
-
"viem": "^2.55.10",
|
|
63
|
-
"zod": "^3.24.0"
|
|
64
|
-
},
|
|
65
|
-
"devDependencies": {
|
|
66
|
-
"@types/node": "^20.0.0",
|
|
67
|
-
"typescript": "^5.3.0"
|
|
68
|
-
}
|
|
69
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "agentwallet-mcp",
|
|
3
|
+
"mcpName": "io.github.hifriendbot/agentwallet",
|
|
4
|
+
"version": "1.10.8",
|
|
5
|
+
"description": "MCP server for AgentWallet: self-custody local signing on EVM and Solana, or hosted wallets. Sign, broadcast, pay x402 invoices, and accept x402 payments.",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"main": "build/index.js",
|
|
8
|
+
"bin": {
|
|
9
|
+
"agentwallet-mcp": "build/index.js"
|
|
10
|
+
},
|
|
11
|
+
"files": [
|
|
12
|
+
"build",
|
|
13
|
+
"README.md",
|
|
14
|
+
"LICENSE"
|
|
15
|
+
],
|
|
16
|
+
"scripts": {
|
|
17
|
+
"build": "tsc",
|
|
18
|
+
"start": "node build/index.js",
|
|
19
|
+
"test": "node test/x402-payment.test.mjs && node test/token-cap.test.mjs && node test/spl-cap.test.mjs && node test/unknown-decimals-cap.test.mjs && node test/local-mode.test.mjs && node test/ssrf-guard.test.mjs",
|
|
20
|
+
"prepublishOnly": "npm run build"
|
|
21
|
+
},
|
|
22
|
+
"keywords": [
|
|
23
|
+
"mcp",
|
|
24
|
+
"model-context-protocol",
|
|
25
|
+
"wallet",
|
|
26
|
+
"ai-agent",
|
|
27
|
+
"blockchain",
|
|
28
|
+
"evm",
|
|
29
|
+
"ethereum",
|
|
30
|
+
"base",
|
|
31
|
+
"arbitrum",
|
|
32
|
+
"optimism",
|
|
33
|
+
"polygon",
|
|
34
|
+
"avalanche",
|
|
35
|
+
"bsc",
|
|
36
|
+
"zora",
|
|
37
|
+
"pulsechain",
|
|
38
|
+
"solana",
|
|
39
|
+
"spl-token",
|
|
40
|
+
"erc20",
|
|
41
|
+
"token-transfer",
|
|
42
|
+
"transaction-signing",
|
|
43
|
+
"x402",
|
|
44
|
+
"http-402",
|
|
45
|
+
"agent-payments",
|
|
46
|
+
"agentwallet",
|
|
47
|
+
"self-custody",
|
|
48
|
+
"non-custodial",
|
|
49
|
+
"local-signing"
|
|
50
|
+
],
|
|
51
|
+
"author": "HiFriendbot (https://hifriendbot.com)",
|
|
52
|
+
"license": "MIT",
|
|
53
|
+
"homepage": "https://hifriendbot.com/wallet/",
|
|
54
|
+
"engines": {
|
|
55
|
+
"node": ">=18.0.0"
|
|
56
|
+
},
|
|
57
|
+
"dependencies": {
|
|
58
|
+
"@modelcontextprotocol/sdk": "^1.11.4",
|
|
59
|
+
"@solana/web3.js": "^1.98.4",
|
|
60
|
+
"bs58": "^6.0.0",
|
|
61
|
+
"undici": "^8.9.0",
|
|
62
|
+
"viem": "^2.55.10",
|
|
63
|
+
"zod": "^3.24.0"
|
|
64
|
+
},
|
|
65
|
+
"devDependencies": {
|
|
66
|
+
"@types/node": "^20.0.0",
|
|
67
|
+
"typescript": "^5.3.0"
|
|
68
|
+
}
|
|
69
|
+
}
|