@x402scan/mcp 0.0.2 → 0.0.4
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 +23 -17
- package/dist/{bundle/index.cjs → cjs/run-server.cjs} +53529 -69440
- package/dist/{index.js → esm/index.js} +498 -100
- package/dist/esm/index.js.map +1 -0
- package/package.json +5 -5
- package/dist/index.js.map +0 -1
- /package/dist/{index.d.ts → esm/index.d.ts} +0 -0
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import z, { z as z$1 } from 'zod';
|
|
3
3
|
import { getAddress, createPublicClient, http, erc20Abi, formatUnits } from 'viem';
|
|
4
|
-
import fs4, { mkdirSync, appendFileSync } from 'fs';
|
|
5
4
|
import path2, { join } from 'path';
|
|
6
5
|
import os, { homedir } from 'os';
|
|
6
|
+
import * as fs from 'fs';
|
|
7
|
+
import fs__default, { appendFileSync } from 'fs';
|
|
7
8
|
import { polygon, arbitrum, optimism, sepolia, mainnet, baseSepolia, base } from 'viem/chains';
|
|
8
|
-
import { intro, outro, log as log$1, confirm, stream, spinner, select } from '@clack/prompts';
|
|
9
|
-
import
|
|
10
|
-
import
|
|
9
|
+
import { intro, outro, log as log$1, confirm, stream, spinner, select, text } from '@clack/prompts';
|
|
10
|
+
import { errAsync, ResultAsync, err } from 'neverthrow';
|
|
11
|
+
import chalk from 'chalk';
|
|
11
12
|
import open from 'open';
|
|
12
13
|
import { x402Client, x402HTTPClient } from '@x402/core/client';
|
|
13
14
|
import { ExactEvmScheme } from '@x402/evm/exact/client';
|
|
@@ -16,8 +17,9 @@ import { base58 } from '@scure/base';
|
|
|
16
17
|
import 'tweetnacl';
|
|
17
18
|
import { SiweMessage } from 'siwe';
|
|
18
19
|
import { safeBase64Encode } from '@x402/core/utils';
|
|
20
|
+
import 'url';
|
|
19
21
|
import { randomBytes } from 'crypto';
|
|
20
|
-
import * as
|
|
22
|
+
import * as fs3 from 'fs/promises';
|
|
21
23
|
import { privateKeyToAccount } from 'viem/accounts';
|
|
22
24
|
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
23
25
|
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
|
@@ -91,6 +93,25 @@ var init_types = __esm({
|
|
|
91
93
|
"src/server/types.ts"() {
|
|
92
94
|
}
|
|
93
95
|
});
|
|
96
|
+
var BASE_DIRECTORY, configFile;
|
|
97
|
+
var init_fs = __esm({
|
|
98
|
+
"src/lib/fs.ts"() {
|
|
99
|
+
BASE_DIRECTORY = join(homedir(), ".x402scan-mcp");
|
|
100
|
+
if (!fs.existsSync(BASE_DIRECTORY)) {
|
|
101
|
+
fs.mkdirSync(BASE_DIRECTORY, { recursive: true });
|
|
102
|
+
}
|
|
103
|
+
configFile = (name) => {
|
|
104
|
+
if (!fs.existsSync(BASE_DIRECTORY)) {
|
|
105
|
+
fs.mkdirSync(BASE_DIRECTORY, { recursive: true });
|
|
106
|
+
}
|
|
107
|
+
const filePath = join(BASE_DIRECTORY, name);
|
|
108
|
+
if (!fs.existsSync(filePath)) {
|
|
109
|
+
fs.writeFileSync(filePath, "{}");
|
|
110
|
+
}
|
|
111
|
+
return filePath;
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
});
|
|
94
115
|
function format(args) {
|
|
95
116
|
return args.map(
|
|
96
117
|
(a) => typeof a === "object" && a !== null ? JSON.stringify(a) : String(a)
|
|
@@ -108,16 +129,12 @@ function write(level, msg, args) {
|
|
|
108
129
|
console.error(`[x402scan] ${formatted}`);
|
|
109
130
|
}
|
|
110
131
|
}
|
|
111
|
-
var
|
|
132
|
+
var LOG_FILE, DEBUG, log;
|
|
112
133
|
var init_log = __esm({
|
|
113
134
|
"src/lib/log.ts"() {
|
|
114
|
-
|
|
115
|
-
LOG_FILE =
|
|
135
|
+
init_fs();
|
|
136
|
+
LOG_FILE = configFile("mcp.log");
|
|
116
137
|
DEBUG = process.env.X402_DEBUG === "true";
|
|
117
|
-
try {
|
|
118
|
-
mkdirSync(LOG_DIR, { recursive: true });
|
|
119
|
-
} catch {
|
|
120
|
-
}
|
|
121
138
|
log = {
|
|
122
139
|
info: (msg, ...args) => write("INFO", msg, args),
|
|
123
140
|
error: (msg, ...args) => write("ERROR", msg, args),
|
|
@@ -249,35 +266,207 @@ var init_wait = __esm({
|
|
|
249
266
|
};
|
|
250
267
|
}
|
|
251
268
|
});
|
|
252
|
-
|
|
269
|
+
function safeFetch(input, init) {
|
|
270
|
+
return ResultAsync.fromPromise(
|
|
271
|
+
fetch(input, init),
|
|
272
|
+
(error) => ({
|
|
273
|
+
type: "network",
|
|
274
|
+
message: "Network error",
|
|
275
|
+
error: error instanceof Error ? error : new Error(String(error))
|
|
276
|
+
})
|
|
277
|
+
);
|
|
278
|
+
}
|
|
279
|
+
var safeFetchJson;
|
|
280
|
+
var init_safe_fetch = __esm({
|
|
281
|
+
"src/lib/safe-fetch.ts"() {
|
|
282
|
+
safeFetchJson = (input, init, errorMessage) => {
|
|
283
|
+
return safeFetch(input, init).andThen((response) => {
|
|
284
|
+
if (!response.ok) {
|
|
285
|
+
return ResultAsync.fromSafePromise(
|
|
286
|
+
response.json().catch(() => void 0)
|
|
287
|
+
).andThen(
|
|
288
|
+
(json) => err({
|
|
289
|
+
type: "http",
|
|
290
|
+
message: json !== void 0 && errorMessage ? errorMessage(json) : response.statusText,
|
|
291
|
+
status: response.status,
|
|
292
|
+
headers: response.headers,
|
|
293
|
+
json
|
|
294
|
+
})
|
|
295
|
+
);
|
|
296
|
+
}
|
|
297
|
+
return ResultAsync.fromPromise(
|
|
298
|
+
response.json(),
|
|
299
|
+
(error) => ({
|
|
300
|
+
type: "parse",
|
|
301
|
+
message: "Could not parse JSON from response",
|
|
302
|
+
error: error instanceof Error ? error : new Error(String(error))
|
|
303
|
+
})
|
|
304
|
+
);
|
|
305
|
+
});
|
|
306
|
+
};
|
|
307
|
+
}
|
|
308
|
+
});
|
|
309
|
+
|
|
310
|
+
// src/lib/utils.ts
|
|
311
|
+
var getBaseUrl;
|
|
312
|
+
var init_utils = __esm({
|
|
313
|
+
"src/lib/utils.ts"() {
|
|
314
|
+
getBaseUrl = (dev) => {
|
|
315
|
+
return dev ? "http://localhost:3000" : "https://x402scan.com";
|
|
316
|
+
};
|
|
317
|
+
}
|
|
318
|
+
});
|
|
319
|
+
var STATE_FILE, stateSchema, getState, setState;
|
|
320
|
+
var init_state = __esm({
|
|
321
|
+
"src/lib/state.ts"() {
|
|
322
|
+
init_fs();
|
|
323
|
+
init_log();
|
|
324
|
+
STATE_FILE = configFile("state.json");
|
|
325
|
+
stateSchema = z.looseObject({
|
|
326
|
+
redeemedCodes: z.array(z.string())
|
|
327
|
+
}).partial();
|
|
328
|
+
getState = () => {
|
|
329
|
+
if (!fs__default.existsSync(STATE_FILE)) {
|
|
330
|
+
fs__default.writeFileSync(STATE_FILE, JSON.stringify({}));
|
|
331
|
+
return {};
|
|
332
|
+
}
|
|
333
|
+
const result = stateSchema.safeParse(
|
|
334
|
+
JSON.parse(fs__default.readFileSync(STATE_FILE, "utf-8"))
|
|
335
|
+
);
|
|
336
|
+
if (!result.success) {
|
|
337
|
+
log.error("Failed to parse state", { error: result.error });
|
|
338
|
+
return {};
|
|
339
|
+
}
|
|
340
|
+
return result.data;
|
|
341
|
+
};
|
|
342
|
+
setState = (state) => {
|
|
343
|
+
const existing = getState();
|
|
344
|
+
const newState = stateSchema.parse({ ...existing, ...state });
|
|
345
|
+
fs__default.writeFileSync(STATE_FILE, JSON.stringify(newState, null, 2));
|
|
346
|
+
};
|
|
347
|
+
}
|
|
348
|
+
});
|
|
349
|
+
var redeemInviteCode;
|
|
350
|
+
var init_redeem_invite = __esm({
|
|
351
|
+
"src/lib/redeem-invite.ts"() {
|
|
352
|
+
init_safe_fetch();
|
|
353
|
+
init_utils();
|
|
354
|
+
init_state();
|
|
355
|
+
redeemInviteCode = async ({
|
|
356
|
+
code,
|
|
357
|
+
dev,
|
|
358
|
+
address
|
|
359
|
+
}) => {
|
|
360
|
+
const state = getState();
|
|
361
|
+
if (state.redeemedCodes?.includes(code)) {
|
|
362
|
+
return Promise.resolve(
|
|
363
|
+
errAsync({
|
|
364
|
+
success: false,
|
|
365
|
+
message: "This invite code has already been redeemed"
|
|
366
|
+
})
|
|
367
|
+
);
|
|
368
|
+
}
|
|
369
|
+
return await safeFetchJson(
|
|
370
|
+
`${getBaseUrl(dev)}/api/invite/redeem`,
|
|
371
|
+
{
|
|
372
|
+
method: "POST",
|
|
373
|
+
headers: {
|
|
374
|
+
"Content-Type": "application/json"
|
|
375
|
+
},
|
|
376
|
+
body: JSON.stringify({
|
|
377
|
+
code,
|
|
378
|
+
recipientAddr: address
|
|
379
|
+
})
|
|
380
|
+
},
|
|
381
|
+
({ message }) => message
|
|
382
|
+
).andTee((result) => {
|
|
383
|
+
if (result.success) {
|
|
384
|
+
setState({
|
|
385
|
+
redeemedCodes: [...state.redeemedCodes ?? [], code]
|
|
386
|
+
});
|
|
387
|
+
}
|
|
388
|
+
});
|
|
389
|
+
};
|
|
390
|
+
}
|
|
391
|
+
});
|
|
392
|
+
var getDepositLink, openDepositLink, redeemInviteCodePrompt, promptDeposit;
|
|
253
393
|
var init_deposit = __esm({
|
|
254
394
|
"src/lib/deposit.ts"() {
|
|
255
395
|
init_networks();
|
|
256
396
|
init_wait();
|
|
397
|
+
init_redeem_invite();
|
|
398
|
+
init_utils();
|
|
257
399
|
getDepositLink = (address, flags) => {
|
|
258
|
-
|
|
259
|
-
return `${baseUrl}/deposit/${address}`;
|
|
400
|
+
return `${getBaseUrl(flags.dev)}/deposit/${address}`;
|
|
260
401
|
};
|
|
261
402
|
openDepositLink = async (address, flags) => {
|
|
262
403
|
const depositLink = getDepositLink(address, flags);
|
|
263
404
|
await open(depositLink);
|
|
264
405
|
};
|
|
406
|
+
redeemInviteCodePrompt = async (address, flags) => {
|
|
407
|
+
const code = await text({
|
|
408
|
+
message: "Enter your invite code",
|
|
409
|
+
placeholder: "MRT-XXXXX",
|
|
410
|
+
validate: (value) => {
|
|
411
|
+
if (!value || value.trim().length === 0) {
|
|
412
|
+
return "Please enter an invite code";
|
|
413
|
+
}
|
|
414
|
+
}
|
|
415
|
+
});
|
|
416
|
+
if (typeof code !== "string") {
|
|
417
|
+
return false;
|
|
418
|
+
}
|
|
419
|
+
const s = spinner();
|
|
420
|
+
s.start("Redeeming invite code...");
|
|
421
|
+
const result = await redeemInviteCode({ code, dev: flags.dev, address });
|
|
422
|
+
return result.match(
|
|
423
|
+
async ({ data: { amount, txHash } }) => {
|
|
424
|
+
s.stop("Invite code redeemed successfully!");
|
|
425
|
+
await wait({
|
|
426
|
+
startText: "Processing...",
|
|
427
|
+
stopText: chalk.green(
|
|
428
|
+
`${chalk.bold(amount)} USDC has been sent to your wallet!`
|
|
429
|
+
),
|
|
430
|
+
ms: 1500
|
|
431
|
+
});
|
|
432
|
+
log$1.success(
|
|
433
|
+
chalk.bold(`Your wallet has been funded with ${amount} USDC`)
|
|
434
|
+
);
|
|
435
|
+
if (txHash) {
|
|
436
|
+
log$1.info(chalk.dim(`Transaction: https://basescan.org/tx/${txHash}`));
|
|
437
|
+
}
|
|
438
|
+
return true;
|
|
439
|
+
},
|
|
440
|
+
(error) => {
|
|
441
|
+
s.stop("Invite code redemption failed");
|
|
442
|
+
log$1.warning(
|
|
443
|
+
chalk.yellow(`Failed to redeem invite code: ${error?.message}`)
|
|
444
|
+
);
|
|
445
|
+
return false;
|
|
446
|
+
}
|
|
447
|
+
);
|
|
448
|
+
};
|
|
265
449
|
promptDeposit = async (address, flags) => {
|
|
266
450
|
const depositLink = getDepositLink(address, flags);
|
|
267
|
-
const
|
|
268
|
-
message:
|
|
269
|
-
initialValue:
|
|
451
|
+
const depositChoice = await select({
|
|
452
|
+
message: chalk.bold("How would you like to deposit?"),
|
|
453
|
+
initialValue: "guided",
|
|
270
454
|
options: [
|
|
271
455
|
{
|
|
272
|
-
label:
|
|
273
|
-
value:
|
|
456
|
+
label: "Guided - Recommended",
|
|
457
|
+
value: "guided",
|
|
274
458
|
hint: "Online portal in x402scan"
|
|
275
459
|
},
|
|
276
460
|
{
|
|
277
461
|
label: "Manual",
|
|
278
|
-
value:
|
|
462
|
+
value: "manual",
|
|
279
463
|
hint: "Print deposit instructions"
|
|
280
464
|
},
|
|
465
|
+
{
|
|
466
|
+
label: "Redeem Invite Code",
|
|
467
|
+
value: "invite",
|
|
468
|
+
hint: "Enter an invite code for starter money"
|
|
469
|
+
},
|
|
281
470
|
{
|
|
282
471
|
label: "Skip",
|
|
283
472
|
value: void 0,
|
|
@@ -285,30 +474,24 @@ var init_deposit = __esm({
|
|
|
285
474
|
}
|
|
286
475
|
]
|
|
287
476
|
});
|
|
288
|
-
if (
|
|
477
|
+
if (depositChoice === "guided") {
|
|
289
478
|
await wait({
|
|
290
479
|
startText: "Opening deposit page...",
|
|
291
|
-
stopText: `Opening ${
|
|
480
|
+
stopText: `Opening ${chalk.underline.hex("#2563eb")(depositLink)}`,
|
|
292
481
|
ms: 1e3
|
|
293
482
|
});
|
|
294
483
|
await open(depositLink);
|
|
295
|
-
} else if (
|
|
296
|
-
log$1.
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
borderColor: "#2563eb",
|
|
307
|
-
title: "Deposit Instructions",
|
|
308
|
-
padding: 1
|
|
309
|
-
}
|
|
310
|
-
)
|
|
311
|
-
);
|
|
484
|
+
} else if (depositChoice === "manual") {
|
|
485
|
+
log$1.step(chalk.bold("Account Information"));
|
|
486
|
+
log$1.message(`Address: ${address}`);
|
|
487
|
+
log$1.message(`Network: ${getChainName(DEFAULT_NETWORK)}`);
|
|
488
|
+
log$1.step(chalk.bold("Online Portal"));
|
|
489
|
+
log$1.message(`${chalk.underline(depositLink)}`);
|
|
490
|
+
} else if (depositChoice === "invite") {
|
|
491
|
+
const redeemed = await redeemInviteCodePrompt(address, flags);
|
|
492
|
+
if (!redeemed) {
|
|
493
|
+
await promptDeposit(address, flags);
|
|
494
|
+
}
|
|
312
495
|
}
|
|
313
496
|
};
|
|
314
497
|
}
|
|
@@ -355,6 +538,27 @@ You can deposit USDC at ${getDepositLink(address, flags)}`
|
|
|
355
538
|
};
|
|
356
539
|
}
|
|
357
540
|
});
|
|
541
|
+
|
|
542
|
+
// src/server/lib/parse-response.ts
|
|
543
|
+
var parseResponse;
|
|
544
|
+
var init_parse_response = __esm({
|
|
545
|
+
"src/server/lib/parse-response.ts"() {
|
|
546
|
+
parseResponse = async (response) => {
|
|
547
|
+
try {
|
|
548
|
+
const contentType = response.headers.get("content-type") ?? "";
|
|
549
|
+
if (contentType.includes("application/json")) {
|
|
550
|
+
return await response.json();
|
|
551
|
+
} else if (contentType.includes("image/")) {
|
|
552
|
+
return await response.arrayBuffer();
|
|
553
|
+
} else {
|
|
554
|
+
return await response.text();
|
|
555
|
+
}
|
|
556
|
+
} catch {
|
|
557
|
+
return void 0;
|
|
558
|
+
}
|
|
559
|
+
};
|
|
560
|
+
}
|
|
561
|
+
});
|
|
358
562
|
var registerFetchX402ResourceTool;
|
|
359
563
|
var init_fetch_x402_resource = __esm({
|
|
360
564
|
"src/server/tools/fetch-x402-resource.ts"() {
|
|
@@ -365,6 +569,7 @@ var init_fetch_x402_resource = __esm({
|
|
|
365
569
|
init_networks();
|
|
366
570
|
init_token();
|
|
367
571
|
init_check_balance();
|
|
572
|
+
init_parse_response();
|
|
368
573
|
registerFetchX402ResourceTool = ({
|
|
369
574
|
server,
|
|
370
575
|
account,
|
|
@@ -409,16 +614,15 @@ var init_fetch_x402_resource = __esm({
|
|
|
409
614
|
try {
|
|
410
615
|
const response = await fetchWithPay(url, {
|
|
411
616
|
method,
|
|
412
|
-
body: body ? JSON.stringify(body) : void 0,
|
|
617
|
+
body: typeof body === "string" ? body : body ? JSON.stringify(body) : void 0,
|
|
413
618
|
headers: {
|
|
414
619
|
...body ? { "Content-Type": "application/json" } : {},
|
|
415
620
|
...headers
|
|
416
621
|
}
|
|
417
622
|
});
|
|
418
623
|
if (!response.ok) {
|
|
419
|
-
const errorData = await response.text();
|
|
420
624
|
const errorResponse = {
|
|
421
|
-
data:
|
|
625
|
+
data: await parseResponse(response),
|
|
422
626
|
statusCode: response.status,
|
|
423
627
|
state
|
|
424
628
|
};
|
|
@@ -441,11 +645,11 @@ var init_fetch_x402_resource = __esm({
|
|
|
441
645
|
};
|
|
442
646
|
const settlement = getSettlement();
|
|
443
647
|
return mcpSuccess({
|
|
444
|
-
data: await response
|
|
648
|
+
data: await parseResponse(response),
|
|
445
649
|
payment: settlement
|
|
446
650
|
});
|
|
447
|
-
} catch (
|
|
448
|
-
return mcpError(
|
|
651
|
+
} catch (err2) {
|
|
652
|
+
return mcpError(err2, { state });
|
|
449
653
|
}
|
|
450
654
|
}
|
|
451
655
|
);
|
|
@@ -835,8 +1039,8 @@ var init_auth = __esm({
|
|
|
835
1039
|
chainId: serverInfo.chainId
|
|
836
1040
|
}
|
|
837
1041
|
});
|
|
838
|
-
} catch (
|
|
839
|
-
return mcpError(
|
|
1042
|
+
} catch (err2) {
|
|
1043
|
+
return mcpError(err2, { tool: "authed_call", url });
|
|
840
1044
|
}
|
|
841
1045
|
}
|
|
842
1046
|
);
|
|
@@ -956,8 +1160,131 @@ var init_check_endpoint_schema = __esm({
|
|
|
956
1160
|
statusCode: response.status,
|
|
957
1161
|
routeDetails
|
|
958
1162
|
});
|
|
959
|
-
} catch (
|
|
960
|
-
return mcpError(
|
|
1163
|
+
} catch (err2) {
|
|
1164
|
+
return mcpError(err2, { tool: "query_endpoint", url });
|
|
1165
|
+
}
|
|
1166
|
+
}
|
|
1167
|
+
);
|
|
1168
|
+
};
|
|
1169
|
+
}
|
|
1170
|
+
});
|
|
1171
|
+
var registerRedeemInviteTool;
|
|
1172
|
+
var init_redeem_invite2 = __esm({
|
|
1173
|
+
"src/server/tools/redeem-invite.ts"() {
|
|
1174
|
+
init_response();
|
|
1175
|
+
registerRedeemInviteTool = ({
|
|
1176
|
+
server,
|
|
1177
|
+
account: { address },
|
|
1178
|
+
flags
|
|
1179
|
+
}) => {
|
|
1180
|
+
const baseUrl = flags.dev ? "http://localhost:3000" : "https://x402scan.com";
|
|
1181
|
+
server.registerTool(
|
|
1182
|
+
"redeem_invite",
|
|
1183
|
+
{
|
|
1184
|
+
description: "Redeem an invite code to receive USDC.",
|
|
1185
|
+
inputSchema: z.object({
|
|
1186
|
+
code: z.string().min(1).describe("The invite code")
|
|
1187
|
+
})
|
|
1188
|
+
},
|
|
1189
|
+
async ({ code }) => {
|
|
1190
|
+
const res = await fetch(`${baseUrl}/api/invite/redeem`, {
|
|
1191
|
+
method: "POST",
|
|
1192
|
+
headers: { "Content-Type": "application/json" },
|
|
1193
|
+
body: JSON.stringify({ code, recipientAddr: address })
|
|
1194
|
+
});
|
|
1195
|
+
const data = await res.json();
|
|
1196
|
+
if (!data.success) {
|
|
1197
|
+
return mcpError(data.error ?? "Failed to redeem invite code");
|
|
1198
|
+
}
|
|
1199
|
+
return mcpSuccess({
|
|
1200
|
+
amount: `${data.amount} USDC`,
|
|
1201
|
+
txHash: data.txHash
|
|
1202
|
+
});
|
|
1203
|
+
}
|
|
1204
|
+
);
|
|
1205
|
+
};
|
|
1206
|
+
}
|
|
1207
|
+
});
|
|
1208
|
+
function getVersion() {
|
|
1209
|
+
{
|
|
1210
|
+
return "0.0.4";
|
|
1211
|
+
}
|
|
1212
|
+
}
|
|
1213
|
+
var MCP_VERSION;
|
|
1214
|
+
var init_version = __esm({
|
|
1215
|
+
"src/server/lib/version.ts"() {
|
|
1216
|
+
MCP_VERSION = getVersion();
|
|
1217
|
+
}
|
|
1218
|
+
});
|
|
1219
|
+
var errorReportSchema, registerTelemetryTools;
|
|
1220
|
+
var init_telemetry = __esm({
|
|
1221
|
+
"src/server/tools/telemetry.ts"() {
|
|
1222
|
+
init_log();
|
|
1223
|
+
init_response();
|
|
1224
|
+
init_version();
|
|
1225
|
+
errorReportSchema = z$1.object({
|
|
1226
|
+
tool: z$1.string().describe("MCP tool name"),
|
|
1227
|
+
resource: z$1.string().optional().describe("x402 resource URL"),
|
|
1228
|
+
summary: z$1.string().describe("1-2 sentence summary"),
|
|
1229
|
+
errorMessage: z$1.string().describe("Error message"),
|
|
1230
|
+
stack: z$1.string().optional().describe("Stack trace"),
|
|
1231
|
+
fullReport: z$1.string().optional().describe("Detailed report with context, logs, repro steps")
|
|
1232
|
+
});
|
|
1233
|
+
registerTelemetryTools = ({
|
|
1234
|
+
server,
|
|
1235
|
+
account: { address },
|
|
1236
|
+
flags
|
|
1237
|
+
}) => {
|
|
1238
|
+
const baseUrl = flags.dev ? "http://localhost:3000" : "https://x402scan.com";
|
|
1239
|
+
server.registerTool(
|
|
1240
|
+
"report_error",
|
|
1241
|
+
{
|
|
1242
|
+
description: "EMERGENCY ONLY. Report critical MCP tool bugs. Do NOT use for normal errors (balance, network, 4xx) - those are recoverable.",
|
|
1243
|
+
inputSchema: errorReportSchema
|
|
1244
|
+
},
|
|
1245
|
+
async (input) => {
|
|
1246
|
+
try {
|
|
1247
|
+
log.info("Submitting error report", {
|
|
1248
|
+
tool: input.tool,
|
|
1249
|
+
resource: input.resource,
|
|
1250
|
+
summary: input.summary
|
|
1251
|
+
});
|
|
1252
|
+
const report = {
|
|
1253
|
+
...input,
|
|
1254
|
+
walletAddress: address,
|
|
1255
|
+
mcpVersion: MCP_VERSION,
|
|
1256
|
+
reportedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
1257
|
+
};
|
|
1258
|
+
const response = await fetch(`${baseUrl}/api/telemetry`, {
|
|
1259
|
+
method: "POST",
|
|
1260
|
+
headers: {
|
|
1261
|
+
"Content-Type": "application/json"
|
|
1262
|
+
},
|
|
1263
|
+
body: JSON.stringify(report)
|
|
1264
|
+
});
|
|
1265
|
+
if (!response.ok) {
|
|
1266
|
+
const errorText = await response.text().catch(() => "Unknown error");
|
|
1267
|
+
log.error("Failed to submit error report", {
|
|
1268
|
+
status: response.status,
|
|
1269
|
+
error: errorText
|
|
1270
|
+
});
|
|
1271
|
+
return mcpError(
|
|
1272
|
+
`Failed to submit error report: ${response.status} ${errorText}`,
|
|
1273
|
+
{ tool: "report_error" }
|
|
1274
|
+
);
|
|
1275
|
+
}
|
|
1276
|
+
const result = await response.json();
|
|
1277
|
+
log.info("Error report submitted successfully", {
|
|
1278
|
+
reportId: result.reportId
|
|
1279
|
+
});
|
|
1280
|
+
return mcpSuccess({
|
|
1281
|
+
submitted: true,
|
|
1282
|
+
reportId: result.reportId,
|
|
1283
|
+
message: "Error report submitted successfully. The x402scan team will investigate."
|
|
1284
|
+
});
|
|
1285
|
+
} catch (err2) {
|
|
1286
|
+
log.error("Failed to submit error report", { error: err2 });
|
|
1287
|
+
return mcpError(err2, { tool: "report_error" });
|
|
961
1288
|
}
|
|
962
1289
|
}
|
|
963
1290
|
);
|
|
@@ -1100,7 +1427,7 @@ async function getWallet() {
|
|
|
1100
1427
|
return { account: account2, isNew: false };
|
|
1101
1428
|
}
|
|
1102
1429
|
try {
|
|
1103
|
-
const data = await
|
|
1430
|
+
const data = await fs3.readFile(WALLET_FILE, "utf-8");
|
|
1104
1431
|
const stored2 = storedWalletSchema.parse(JSON.parse(data));
|
|
1105
1432
|
const account2 = privateKeyToAccount(stored2.privateKey);
|
|
1106
1433
|
log.info(`Loaded wallet: ${account2.address}`);
|
|
@@ -1114,23 +1441,22 @@ async function getWallet() {
|
|
|
1114
1441
|
address: account.address,
|
|
1115
1442
|
createdAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
1116
1443
|
};
|
|
1117
|
-
await
|
|
1118
|
-
await fs.writeFile(KEYSTORE_FILE, JSON.stringify(stored, null, 2));
|
|
1444
|
+
await fs3.writeFile(WALLET_FILE, JSON.stringify(stored, null, 2));
|
|
1119
1445
|
try {
|
|
1120
|
-
await
|
|
1446
|
+
await fs3.chmod(WALLET_FILE, 384);
|
|
1121
1447
|
} catch {
|
|
1122
1448
|
}
|
|
1123
1449
|
log.info(`Created wallet: ${account.address}`);
|
|
1124
|
-
log.info(`Saved to: ${
|
|
1450
|
+
log.info(`Saved to: ${WALLET_FILE}`);
|
|
1125
1451
|
return { account, isNew: true };
|
|
1126
1452
|
}
|
|
1127
|
-
var
|
|
1453
|
+
var WALLET_FILE, storedWalletSchema;
|
|
1128
1454
|
var init_wallet2 = __esm({
|
|
1129
1455
|
"src/lib/wallet.ts"() {
|
|
1130
1456
|
init_log();
|
|
1131
1457
|
init_schemas();
|
|
1132
|
-
|
|
1133
|
-
|
|
1458
|
+
init_fs();
|
|
1459
|
+
WALLET_FILE = configFile("wallet.json");
|
|
1134
1460
|
storedWalletSchema = z.object({
|
|
1135
1461
|
privateKey: ethereumPrivateKeySchema,
|
|
1136
1462
|
address: ethereumAddressSchema,
|
|
@@ -1168,9 +1494,9 @@ async function lookupDnsTxtRecord(hostname) {
|
|
|
1168
1494
|
log.debug(`DNS TXT value is not a valid URL: ${txtValue}`);
|
|
1169
1495
|
return null;
|
|
1170
1496
|
}
|
|
1171
|
-
} catch (
|
|
1497
|
+
} catch (err2) {
|
|
1172
1498
|
log.debug(
|
|
1173
|
-
`DNS lookup error: ${
|
|
1499
|
+
`DNS lookup error: ${err2 instanceof Error ? err2.message : String(err2)}`
|
|
1174
1500
|
);
|
|
1175
1501
|
return null;
|
|
1176
1502
|
}
|
|
@@ -1193,10 +1519,10 @@ async function fetchLlmsTxt(origin) {
|
|
|
1193
1519
|
return { found: false, error: "llms.txt is empty" };
|
|
1194
1520
|
}
|
|
1195
1521
|
return { found: true, content };
|
|
1196
|
-
} catch (
|
|
1522
|
+
} catch (err2) {
|
|
1197
1523
|
return {
|
|
1198
1524
|
found: false,
|
|
1199
|
-
error: `Network error: ${
|
|
1525
|
+
error: `Network error: ${err2 instanceof Error ? err2.message : String(err2)}`
|
|
1200
1526
|
};
|
|
1201
1527
|
}
|
|
1202
1528
|
}
|
|
@@ -1233,10 +1559,10 @@ async function fetchDiscoveryFromUrl(url) {
|
|
|
1233
1559
|
};
|
|
1234
1560
|
}
|
|
1235
1561
|
return { found: true, document: parsed.data };
|
|
1236
|
-
} catch (
|
|
1562
|
+
} catch (err2) {
|
|
1237
1563
|
return {
|
|
1238
1564
|
found: false,
|
|
1239
|
-
error: `Network error: ${
|
|
1565
|
+
error: `Network error: ${err2 instanceof Error ? err2.message : String(err2)}`
|
|
1240
1566
|
};
|
|
1241
1567
|
}
|
|
1242
1568
|
}
|
|
@@ -1328,11 +1654,11 @@ async function queryResource(url) {
|
|
|
1328
1654
|
resource.signInWithX = { required: true, info: siwx.info };
|
|
1329
1655
|
}
|
|
1330
1656
|
return resource;
|
|
1331
|
-
} catch (
|
|
1657
|
+
} catch (err2) {
|
|
1332
1658
|
return {
|
|
1333
1659
|
url,
|
|
1334
1660
|
isX402Endpoint: false,
|
|
1335
|
-
error:
|
|
1661
|
+
error: err2 instanceof Error ? err2.message : String(err2)
|
|
1336
1662
|
};
|
|
1337
1663
|
}
|
|
1338
1664
|
}
|
|
@@ -1340,25 +1666,33 @@ function registerDiscoveryTools(server) {
|
|
|
1340
1666
|
server.registerTool(
|
|
1341
1667
|
"discover_resources",
|
|
1342
1668
|
{
|
|
1343
|
-
description: `Discover x402-protected resources
|
|
1344
|
-
|
|
1669
|
+
description: `Discover x402-protected resources on an origin.
|
|
1670
|
+
NEVER use 'fanOut = true' on the first try.
|
|
1671
|
+
NEVER use 'fanOut = true' when there are more than 8 resources.
|
|
1672
|
+
|
|
1345
1673
|
Known default origins with resource packs. Discover if more needed:
|
|
1346
|
-
- https://enrichx402.com ->
|
|
1674
|
+
- https://enrichx402.com ->
|
|
1675
|
+
People + Org search
|
|
1676
|
+
Google Maps (places + locations)
|
|
1677
|
+
Grok twitter search
|
|
1678
|
+
Exa web search
|
|
1679
|
+
Clado linkedin data
|
|
1680
|
+
Firecrawl web scrape
|
|
1347
1681
|
- https://stablestudio.io -> generate images / videos
|
|
1348
1682
|
`,
|
|
1349
1683
|
inputSchema: {
|
|
1350
1684
|
url: z$1.url().describe(
|
|
1351
1685
|
"The origin URL or any URL on the origin to discover resources from"
|
|
1352
1686
|
),
|
|
1353
|
-
|
|
1354
|
-
"Whether to query each discovered resource for full pricing/schema info
|
|
1687
|
+
fanOut: z$1.boolean().default(false).describe(
|
|
1688
|
+
"Whether to query each discovered resource for full pricing/schema info. NEVER use on first try."
|
|
1355
1689
|
),
|
|
1356
1690
|
concurrency: z$1.number().int().min(1).max(10).default(5).describe(
|
|
1357
1691
|
"Max concurrent requests when querying resources (default: 5)"
|
|
1358
1692
|
)
|
|
1359
1693
|
}
|
|
1360
1694
|
},
|
|
1361
|
-
async ({ url,
|
|
1695
|
+
async ({ url, fanOut, concurrency }) => {
|
|
1362
1696
|
try {
|
|
1363
1697
|
const origin = getOrigin(url);
|
|
1364
1698
|
log.info(`Discovering resources for origin: ${origin}`);
|
|
@@ -1392,7 +1726,7 @@ function registerDiscoveryTools(server) {
|
|
|
1392
1726
|
usage: "Use query_endpoint to get full pricing/requirements for a resource. Use execute_call (for payment) or authed_call (for SIWX auth) to call it.",
|
|
1393
1727
|
resources: []
|
|
1394
1728
|
};
|
|
1395
|
-
if (!
|
|
1729
|
+
if (!fanOut) {
|
|
1396
1730
|
result.resources = doc.resources.map((resourceUrl) => ({
|
|
1397
1731
|
url: resourceUrl
|
|
1398
1732
|
}));
|
|
@@ -1409,8 +1743,8 @@ function registerDiscoveryTools(server) {
|
|
|
1409
1743
|
}
|
|
1410
1744
|
result.resources = allResources;
|
|
1411
1745
|
return mcpSuccess(result);
|
|
1412
|
-
} catch (
|
|
1413
|
-
return mcpError(
|
|
1746
|
+
} catch (err2) {
|
|
1747
|
+
return mcpError(err2, { tool: "discover_resources", url });
|
|
1414
1748
|
}
|
|
1415
1749
|
}
|
|
1416
1750
|
);
|
|
@@ -1457,17 +1791,30 @@ var init_server = __esm({
|
|
|
1457
1791
|
init_auth();
|
|
1458
1792
|
init_wallet();
|
|
1459
1793
|
init_check_endpoint_schema();
|
|
1794
|
+
init_redeem_invite2();
|
|
1795
|
+
init_telemetry();
|
|
1460
1796
|
init_origins();
|
|
1461
1797
|
init_log();
|
|
1462
1798
|
init_wallet2();
|
|
1463
1799
|
init_discover_resources();
|
|
1800
|
+
init_redeem_invite();
|
|
1801
|
+
init_version();
|
|
1464
1802
|
startServer = async (flags) => {
|
|
1465
1803
|
log.info("Starting x402scan-mcp...");
|
|
1804
|
+
const { dev, invite } = flags;
|
|
1466
1805
|
const { account } = await getWallet();
|
|
1806
|
+
const code = invite ?? process.env.INVITE_CODE;
|
|
1807
|
+
if (code) {
|
|
1808
|
+
await redeemInviteCode({
|
|
1809
|
+
code,
|
|
1810
|
+
dev,
|
|
1811
|
+
address: account.address
|
|
1812
|
+
});
|
|
1813
|
+
}
|
|
1467
1814
|
const server = new McpServer(
|
|
1468
1815
|
{
|
|
1469
1816
|
name: "@x402scan/mcp",
|
|
1470
|
-
version:
|
|
1817
|
+
version: MCP_VERSION,
|
|
1471
1818
|
websiteUrl: "https://x402scan.com/mcp",
|
|
1472
1819
|
icons: [{ src: "https://x402scan.com/logo.svg" }]
|
|
1473
1820
|
},
|
|
@@ -1489,7 +1836,9 @@ var init_server = __esm({
|
|
|
1489
1836
|
registerAuthTools(props);
|
|
1490
1837
|
registerWalletTools(props);
|
|
1491
1838
|
registerCheckX402EndpointTool(props);
|
|
1839
|
+
registerRedeemInviteTool(props);
|
|
1492
1840
|
registerDiscoveryTools(server);
|
|
1841
|
+
registerTelemetryTools(props);
|
|
1493
1842
|
await registerOrigins({ server, flags });
|
|
1494
1843
|
const transport = new StdioServerTransport();
|
|
1495
1844
|
await server.connect(transport);
|
|
@@ -1620,7 +1969,7 @@ var init_get_client = __esm({
|
|
|
1620
1969
|
if (parsedClientSelection.success) {
|
|
1621
1970
|
return parsedClientSelection.data;
|
|
1622
1971
|
}
|
|
1623
|
-
outro(
|
|
1972
|
+
outro(chalk.bold.red("No MCP client selected"));
|
|
1624
1973
|
process.exit(0);
|
|
1625
1974
|
};
|
|
1626
1975
|
}
|
|
@@ -1666,7 +2015,7 @@ var parseClientConfig, serializeClientConfig, stringifyObject;
|
|
|
1666
2015
|
var init_file_types = __esm({
|
|
1667
2016
|
"src/install/2-add-server/lib/file-types.ts"() {
|
|
1668
2017
|
parseClientConfig = ({ format: format2, path: path3 }) => {
|
|
1669
|
-
const fileContent =
|
|
2018
|
+
const fileContent = fs__default.readFileSync(path3, "utf8");
|
|
1670
2019
|
let config = {};
|
|
1671
2020
|
if (format2 === "yaml" /* YAML */) {
|
|
1672
2021
|
config = yaml.load(fileContent);
|
|
@@ -1843,7 +2192,7 @@ var init_client_config_file = __esm({
|
|
|
1843
2192
|
"opencode.json"
|
|
1844
2193
|
);
|
|
1845
2194
|
const jsoncPath = jsonPath.replace(".json", ".jsonc");
|
|
1846
|
-
if (
|
|
2195
|
+
if (fs__default.existsSync(jsoncPath)) {
|
|
1847
2196
|
log.info(`Found .jsonc file for OpenCode, using: ${jsoncPath}`);
|
|
1848
2197
|
return {
|
|
1849
2198
|
path: jsoncPath,
|
|
@@ -1906,7 +2255,7 @@ async function addServer(client, globalFlags) {
|
|
|
1906
2255
|
const { serverName, command, args } = getMcpConfig(globalFlags);
|
|
1907
2256
|
if (client === "warp" /* Warp */) {
|
|
1908
2257
|
log$1.info(
|
|
1909
|
-
|
|
2258
|
+
chalk.bold.yellow("Warp requires a manual installation through their UI.")
|
|
1910
2259
|
);
|
|
1911
2260
|
log$1.message(
|
|
1912
2261
|
"Please copy the following configuration object and add it to your Warp MCP config:"
|
|
@@ -1943,7 +2292,7 @@ async function addServer(client, globalFlags) {
|
|
|
1943
2292
|
let config = {};
|
|
1944
2293
|
let content = void 0;
|
|
1945
2294
|
log.info(`Checking if config file exists at: ${clientFileTarget.path}`);
|
|
1946
|
-
if (!
|
|
2295
|
+
if (!fs__default.existsSync(clientFileTarget.path)) {
|
|
1947
2296
|
log.info("Config file not found, creating default empty config");
|
|
1948
2297
|
setNestedValue(config, clientFileTarget.configKey, {});
|
|
1949
2298
|
log.info("Config created successfully");
|
|
@@ -1977,7 +2326,7 @@ async function addServer(client, globalFlags) {
|
|
|
1977
2326
|
if (!servers || typeof servers !== "object") {
|
|
1978
2327
|
log.error(`Invalid ${clientFileTarget.configKey} structure in config`);
|
|
1979
2328
|
log$1.error(
|
|
1980
|
-
|
|
2329
|
+
chalk.bold.red(
|
|
1981
2330
|
`Invalid ${clientFileTarget.configKey} structure in config`
|
|
1982
2331
|
)
|
|
1983
2332
|
);
|
|
@@ -2015,7 +2364,9 @@ async function addServer(client, globalFlags) {
|
|
|
2015
2364
|
};
|
|
2016
2365
|
}
|
|
2017
2366
|
await new Promise((resolve) => setTimeout(resolve, 1e3));
|
|
2018
|
-
log$1.step(
|
|
2367
|
+
log$1.step(
|
|
2368
|
+
`The following will be added to ${chalk.bold.underline(clientFileTarget.path)}`
|
|
2369
|
+
);
|
|
2019
2370
|
const configStr = formatDiffByFormat(
|
|
2020
2371
|
{
|
|
2021
2372
|
[clientFileTarget.configKey]: {
|
|
@@ -2047,7 +2398,7 @@ async function addServer(client, globalFlags) {
|
|
|
2047
2398
|
inactive: "Cancel"
|
|
2048
2399
|
});
|
|
2049
2400
|
if (isConfirmed !== true) {
|
|
2050
|
-
outro(
|
|
2401
|
+
outro(chalk.bold.red("Installation cancelled"));
|
|
2051
2402
|
process.exit(0);
|
|
2052
2403
|
}
|
|
2053
2404
|
const configContent = serializeClientConfig(
|
|
@@ -2055,10 +2406,10 @@ async function addServer(client, globalFlags) {
|
|
|
2055
2406
|
config,
|
|
2056
2407
|
content
|
|
2057
2408
|
);
|
|
2058
|
-
|
|
2059
|
-
log$1.success(
|
|
2409
|
+
fs__default.writeFileSync(clientFileTarget.path, configContent);
|
|
2410
|
+
log$1.success(chalk.bold.green(`Added x402scan MCP to ${name}`));
|
|
2060
2411
|
} catch (e) {
|
|
2061
|
-
log$1.error(
|
|
2412
|
+
log$1.error(chalk.bold.red(`Error adding x402scan MCP to ${name}`));
|
|
2062
2413
|
throw e;
|
|
2063
2414
|
}
|
|
2064
2415
|
}
|
|
@@ -2092,7 +2443,7 @@ var init_add_server = __esm({
|
|
|
2092
2443
|
const diffLines = [0, 1, numLines - 2, numLines - 1];
|
|
2093
2444
|
const isDiffLine = !diffLines.includes(index);
|
|
2094
2445
|
if (isDiffLine) {
|
|
2095
|
-
return `${
|
|
2446
|
+
return `${chalk.bold.green(`+ ${line.slice(2)}`)}`;
|
|
2096
2447
|
}
|
|
2097
2448
|
return line;
|
|
2098
2449
|
}).join("\n");
|
|
@@ -2102,14 +2453,14 @@ var init_add_server = __esm({
|
|
|
2102
2453
|
const diffLines = [0, 1, str.length - 2, str.length - 1];
|
|
2103
2454
|
const isDiffLine = !diffLines.includes(index);
|
|
2104
2455
|
if (isDiffLine) {
|
|
2105
|
-
return `${
|
|
2456
|
+
return `${chalk.bold.green(`+ ${line.slice(2)}`)}`;
|
|
2106
2457
|
}
|
|
2107
2458
|
return line;
|
|
2108
2459
|
}).join("\n");
|
|
2109
2460
|
}
|
|
2110
2461
|
case "toml" /* TOML */: {
|
|
2111
2462
|
return str.split("\n").filter((line) => line.trim() !== "").map((line) => {
|
|
2112
|
-
return `${
|
|
2463
|
+
return `${chalk.bold.green(`+ ${line.trim()}`)}`;
|
|
2113
2464
|
}).join("\n");
|
|
2114
2465
|
}
|
|
2115
2466
|
}
|
|
@@ -2131,12 +2482,12 @@ var init_add_funds = __esm({
|
|
|
2131
2482
|
const balance = await getUSDCBalance({ address });
|
|
2132
2483
|
await wait({
|
|
2133
2484
|
startText: "Checking balance...",
|
|
2134
|
-
stopText: `Balance: ${
|
|
2485
|
+
stopText: `Balance: ${chalk.bold(`${balance} USDC`)} `,
|
|
2135
2486
|
ms: 1e3
|
|
2136
2487
|
});
|
|
2137
2488
|
if (balance < 1) {
|
|
2138
2489
|
log$1.warning(
|
|
2139
|
-
|
|
2490
|
+
chalk.bold(
|
|
2140
2491
|
`Your balance is low (${balance} USDC). Consider topping up.`
|
|
2141
2492
|
)
|
|
2142
2493
|
);
|
|
@@ -2146,6 +2497,41 @@ var init_add_funds = __esm({
|
|
|
2146
2497
|
};
|
|
2147
2498
|
}
|
|
2148
2499
|
});
|
|
2500
|
+
var redeemInviteCode2;
|
|
2501
|
+
var init_redeem_invite3 = __esm({
|
|
2502
|
+
"src/install/4-redeem-invite/index.ts"() {
|
|
2503
|
+
init_wait();
|
|
2504
|
+
init_redeem_invite();
|
|
2505
|
+
redeemInviteCode2 = async (props) => {
|
|
2506
|
+
const s = spinner();
|
|
2507
|
+
s.start("Redeeming invite code...");
|
|
2508
|
+
const result = await redeemInviteCode(props);
|
|
2509
|
+
return result.match(
|
|
2510
|
+
async ({ data }) => {
|
|
2511
|
+
s.stop("Invite code redeemed successfully!");
|
|
2512
|
+
await wait({
|
|
2513
|
+
startText: "Processing...",
|
|
2514
|
+
stopText: chalk.green(
|
|
2515
|
+
`${chalk.bold(data.amount)} USDC has been sent to your wallet!`
|
|
2516
|
+
),
|
|
2517
|
+
ms: 1e3
|
|
2518
|
+
});
|
|
2519
|
+
log$1.info(
|
|
2520
|
+
chalk.dim(`Transaction: https://basescan.org/tx/${data.txHash}`)
|
|
2521
|
+
);
|
|
2522
|
+
return true;
|
|
2523
|
+
},
|
|
2524
|
+
(error) => {
|
|
2525
|
+
s.stop("Invite code redemption failed");
|
|
2526
|
+
log$1.warning(
|
|
2527
|
+
chalk.yellow(`Failed to redeem invite code: ${error?.message}`)
|
|
2528
|
+
);
|
|
2529
|
+
return false;
|
|
2530
|
+
}
|
|
2531
|
+
);
|
|
2532
|
+
};
|
|
2533
|
+
}
|
|
2534
|
+
});
|
|
2149
2535
|
|
|
2150
2536
|
// src/install/index.ts
|
|
2151
2537
|
var install_exports = {};
|
|
@@ -2159,16 +2545,24 @@ var init_install = __esm({
|
|
|
2159
2545
|
init_get_client();
|
|
2160
2546
|
init_add_server();
|
|
2161
2547
|
init_add_funds();
|
|
2548
|
+
init_redeem_invite3();
|
|
2162
2549
|
installMcpServer = async (flags) => {
|
|
2163
2550
|
const {
|
|
2164
2551
|
account: { address },
|
|
2165
2552
|
isNew
|
|
2166
2553
|
} = await getWallet();
|
|
2167
|
-
intro(
|
|
2554
|
+
intro(chalk.green.bold(`Install x402scan MCP`));
|
|
2168
2555
|
const client = await getClient(flags);
|
|
2169
2556
|
await addServer(client, flags);
|
|
2170
|
-
|
|
2171
|
-
|
|
2557
|
+
const inviteRedeemed = flags.invite ? await redeemInviteCode2({
|
|
2558
|
+
code: flags.invite,
|
|
2559
|
+
dev: flags.dev,
|
|
2560
|
+
address
|
|
2561
|
+
}) : false;
|
|
2562
|
+
if (!inviteRedeemed) {
|
|
2563
|
+
await addFunds({ flags, address, isNew });
|
|
2564
|
+
}
|
|
2565
|
+
outro(chalk.bold.green("Your x402scan MCP server is ready to use!"));
|
|
2172
2566
|
};
|
|
2173
2567
|
}
|
|
2174
2568
|
});
|
|
@@ -2184,12 +2578,12 @@ var init_fund = __esm({
|
|
|
2184
2578
|
init_wallet2();
|
|
2185
2579
|
init_deposit();
|
|
2186
2580
|
fundMcpServer = async (flags) => {
|
|
2187
|
-
intro(
|
|
2581
|
+
intro(chalk.bold(`Fund ${chalk.hex("#2563eb")("x402scan MCP")}`));
|
|
2188
2582
|
const {
|
|
2189
2583
|
account: { address }
|
|
2190
2584
|
} = await getWallet();
|
|
2191
2585
|
await promptDeposit(address, flags);
|
|
2192
|
-
outro(
|
|
2586
|
+
outro(chalk.bold.green("Your x402scan MCP server is funded!"));
|
|
2193
2587
|
};
|
|
2194
2588
|
}
|
|
2195
2589
|
});
|
|
@@ -2197,6 +2591,10 @@ void yargs(hideBin(process.argv)).scriptName("@x402scan/mcp").option("dev", {
|
|
|
2197
2591
|
type: "boolean",
|
|
2198
2592
|
description: "Enable dev mode",
|
|
2199
2593
|
default: false
|
|
2594
|
+
}).option("invite", {
|
|
2595
|
+
type: "string",
|
|
2596
|
+
description: "Invite code to redeem for starter money",
|
|
2597
|
+
required: false
|
|
2200
2598
|
}).command(
|
|
2201
2599
|
"$0",
|
|
2202
2600
|
"Start the MCP server",
|
|
@@ -2215,7 +2613,7 @@ void yargs(hideBin(process.argv)).scriptName("@x402scan/mcp").option("dev", {
|
|
|
2215
2613
|
}),
|
|
2216
2614
|
async (args) => {
|
|
2217
2615
|
const { installMcpServer: installMcpServer2 } = await Promise.resolve().then(() => (init_install(), install_exports));
|
|
2218
|
-
await installMcpServer2(
|
|
2616
|
+
await installMcpServer2(args);
|
|
2219
2617
|
}
|
|
2220
2618
|
).command(
|
|
2221
2619
|
"fund",
|
|
@@ -2225,8 +2623,8 @@ void yargs(hideBin(process.argv)).scriptName("@x402scan/mcp").option("dev", {
|
|
|
2225
2623
|
const { fundMcpServer: fundMcpServer2 } = await Promise.resolve().then(() => (init_fund(), fund_exports));
|
|
2226
2624
|
await fundMcpServer2(args);
|
|
2227
2625
|
}
|
|
2228
|
-
).strict().demandCommand(0, 1, "", "Too many commands provided").help().parseAsync().catch((
|
|
2229
|
-
console.error("Fatal:",
|
|
2626
|
+
).strict().demandCommand(0, 1, "", "Too many commands provided").help().parseAsync().catch((err2) => {
|
|
2627
|
+
console.error("Fatal:", err2);
|
|
2230
2628
|
process.exit(1);
|
|
2231
2629
|
});
|
|
2232
2630
|
//# sourceMappingURL=index.js.map
|