@x402scan/mcp 0.0.7-beta.4 → 0.0.7
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/cjs/run-server.cjs +7156 -6859
- package/dist/esm/index.js +2657 -11
- package/dist/esm/index.js.map +1 -1
- package/package.json +10 -5
- package/dist/esm/chunk-2UP5W5MC.js +0 -47
- package/dist/esm/chunk-2UP5W5MC.js.map +0 -1
- package/dist/esm/chunk-JXXC6FYE.js +0 -970
- package/dist/esm/chunk-JXXC6FYE.js.map +0 -1
- package/dist/esm/chunk-Q2QVXJFE.js +0 -90
- package/dist/esm/chunk-Q2QVXJFE.js.map +0 -1
- package/dist/esm/chunk-RZYTNVC6.js +0 -112
- package/dist/esm/chunk-RZYTNVC6.js.map +0 -1
- package/dist/esm/fund-ANZCZU5C.js +0 -30
- package/dist/esm/fund-ANZCZU5C.js.map +0 -1
- package/dist/esm/install-BBOI4D6I.js +0 -701
- package/dist/esm/install-BBOI4D6I.js.map +0 -1
- package/dist/esm/server-IOVNYPTB.js +0 -976
- package/dist/esm/server-IOVNYPTB.js.map +0 -1
|
@@ -1,976 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
MCP_VERSION,
|
|
3
|
-
getBalance
|
|
4
|
-
} from "./chunk-2UP5W5MC.js";
|
|
5
|
-
import {
|
|
6
|
-
DEFAULT_NETWORK,
|
|
7
|
-
err,
|
|
8
|
-
fetchHttpErr,
|
|
9
|
-
getBaseUrl,
|
|
10
|
-
getChainName,
|
|
11
|
-
getDepositLink,
|
|
12
|
-
getWallet,
|
|
13
|
-
isFetchError,
|
|
14
|
-
log,
|
|
15
|
-
ok,
|
|
16
|
-
openDepositLink,
|
|
17
|
-
redeemInviteCode,
|
|
18
|
-
resultFromPromise,
|
|
19
|
-
resultFromThrowable,
|
|
20
|
-
safeFetch,
|
|
21
|
-
safeFetchJson,
|
|
22
|
-
safeParseResponse,
|
|
23
|
-
safeStringifyJson
|
|
24
|
-
} from "./chunk-JXXC6FYE.js";
|
|
25
|
-
|
|
26
|
-
// src/server/index.ts
|
|
27
|
-
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
28
|
-
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
29
|
-
|
|
30
|
-
// src/server/tools/x402-fetch.ts
|
|
31
|
-
import { x402Client, x402HTTPClient } from "@x402/core/client";
|
|
32
|
-
import { ExactEvmScheme } from "@x402/evm/exact/client";
|
|
33
|
-
|
|
34
|
-
// src/server/tools/response/lib.ts
|
|
35
|
-
var parsedResponseToToolContentPart = (data) => {
|
|
36
|
-
switch (data.type) {
|
|
37
|
-
case "json":
|
|
38
|
-
return {
|
|
39
|
-
type: "text",
|
|
40
|
-
text: JSON.stringify(data.data, null, 2)
|
|
41
|
-
};
|
|
42
|
-
case "image":
|
|
43
|
-
return {
|
|
44
|
-
type: "image",
|
|
45
|
-
mimeType: data.mimeType,
|
|
46
|
-
data: Buffer.from(data.data).toString("base64")
|
|
47
|
-
};
|
|
48
|
-
case "audio":
|
|
49
|
-
return {
|
|
50
|
-
type: "audio",
|
|
51
|
-
mimeType: data.mimeType,
|
|
52
|
-
data: Buffer.from(data.data).toString("base64")
|
|
53
|
-
};
|
|
54
|
-
case "text":
|
|
55
|
-
return { type: "text", text: data.data };
|
|
56
|
-
default:
|
|
57
|
-
return {
|
|
58
|
-
type: "text",
|
|
59
|
-
text: `Unsupported response type: ${data.type}`
|
|
60
|
-
};
|
|
61
|
-
}
|
|
62
|
-
};
|
|
63
|
-
|
|
64
|
-
// src/server/tools/response/error.ts
|
|
65
|
-
var buildMcpError = (content) => {
|
|
66
|
-
return {
|
|
67
|
-
content,
|
|
68
|
-
isError: true
|
|
69
|
-
};
|
|
70
|
-
};
|
|
71
|
-
var mcpErrorJson = (error) => {
|
|
72
|
-
return safeStringifyJson("mcp-error-json", error).match(
|
|
73
|
-
(success) => buildMcpError([{ type: "text", text: success }]),
|
|
74
|
-
(error2) => buildMcpError([
|
|
75
|
-
{ type: "text", text: JSON.stringify(error2, null, 2) }
|
|
76
|
-
])
|
|
77
|
-
);
|
|
78
|
-
};
|
|
79
|
-
var mcpError = async (err2) => {
|
|
80
|
-
const { error } = err2;
|
|
81
|
-
if (isFetchError(error)) {
|
|
82
|
-
switch (error.cause) {
|
|
83
|
-
case "network":
|
|
84
|
-
case "parse":
|
|
85
|
-
return mcpErrorJson({ ...error });
|
|
86
|
-
case "http":
|
|
87
|
-
const { response, ...rest } = error;
|
|
88
|
-
const parseResponseResult = await safeParseResponse(
|
|
89
|
-
"mcp-error-fetch-parse-response",
|
|
90
|
-
response
|
|
91
|
-
);
|
|
92
|
-
return buildMcpError([
|
|
93
|
-
{ type: "text", text: JSON.stringify(rest, null, 2) },
|
|
94
|
-
...parseResponseResult.match(
|
|
95
|
-
(success) => [parsedResponseToToolContentPart(success)],
|
|
96
|
-
() => []
|
|
97
|
-
)
|
|
98
|
-
]);
|
|
99
|
-
}
|
|
100
|
-
}
|
|
101
|
-
return mcpErrorJson({ ...error });
|
|
102
|
-
};
|
|
103
|
-
var mcpErrorFetch = async (surface2, response) => {
|
|
104
|
-
return mcpError(fetchHttpErr(surface2, response));
|
|
105
|
-
};
|
|
106
|
-
|
|
107
|
-
// src/server/tools/response/success.ts
|
|
108
|
-
var buildMcpSuccess = (content) => {
|
|
109
|
-
return {
|
|
110
|
-
content
|
|
111
|
-
};
|
|
112
|
-
};
|
|
113
|
-
var mcpSuccessJson = (data) => {
|
|
114
|
-
return safeStringifyJson("mcp-success-text", data).match(
|
|
115
|
-
(success) => buildMcpSuccess([{ type: "text", text: success }]),
|
|
116
|
-
(error) => mcpErrorJson(error)
|
|
117
|
-
);
|
|
118
|
-
};
|
|
119
|
-
var mcpSuccessResponse = (data, extra) => {
|
|
120
|
-
const parsedExtra = extra ? safeStringifyJson("mcp-success-extra", extra).match(
|
|
121
|
-
(success) => success,
|
|
122
|
-
() => void 0
|
|
123
|
-
) : void 0;
|
|
124
|
-
return buildMcpSuccess([
|
|
125
|
-
parsedResponseToToolContentPart(data),
|
|
126
|
-
...parsedExtra ? [{ type: "text", text: parsedExtra }] : []
|
|
127
|
-
]);
|
|
128
|
-
};
|
|
129
|
-
|
|
130
|
-
// src/server/tools/lib/request.ts
|
|
131
|
-
import z from "zod";
|
|
132
|
-
var requestSchema = z.object({
|
|
133
|
-
url: z.url().describe("The endpoint URL"),
|
|
134
|
-
method: z.enum(["GET", "POST", "PUT", "DELETE", "PATCH"]).default("GET").describe("HTTP method"),
|
|
135
|
-
body: z.unknown().optional().describe("Request body for POST/PUT/PATCH methods"),
|
|
136
|
-
headers: z.record(z.string(), z.string()).optional().describe("Additional headers to include").default({})
|
|
137
|
-
});
|
|
138
|
-
var buildRequest = (input) => {
|
|
139
|
-
return new Request(input.url, {
|
|
140
|
-
method: input.method,
|
|
141
|
-
body: input.body ? typeof input.body === "string" ? input.body : JSON.stringify(input.body) : void 0,
|
|
142
|
-
headers: {
|
|
143
|
-
...input.body ? { "Content-Type": "application/json" } : {},
|
|
144
|
-
...input.headers
|
|
145
|
-
}
|
|
146
|
-
});
|
|
147
|
-
};
|
|
148
|
-
|
|
149
|
-
// src/server/tools/lib/check-balance.ts
|
|
150
|
-
var checkBalance = async ({
|
|
151
|
-
server,
|
|
152
|
-
address,
|
|
153
|
-
amountNeeded,
|
|
154
|
-
message,
|
|
155
|
-
flags,
|
|
156
|
-
surface: surface2
|
|
157
|
-
}) => {
|
|
158
|
-
const balanceResult = await getBalance({ address, flags, surface: surface2 });
|
|
159
|
-
if (balanceResult.isErr()) {
|
|
160
|
-
log.error(JSON.stringify(balanceResult.error, null, 2));
|
|
161
|
-
return;
|
|
162
|
-
}
|
|
163
|
-
const balance = balanceResult.value;
|
|
164
|
-
if (balance.balance < amountNeeded) {
|
|
165
|
-
const capabilities = server.server.getClientCapabilities();
|
|
166
|
-
if (!capabilities?.elicitation) {
|
|
167
|
-
throw new Error(
|
|
168
|
-
`${message(balance.balance)}
|
|
169
|
-
|
|
170
|
-
You can deposit USDC at ${getDepositLink(address, flags)}`
|
|
171
|
-
);
|
|
172
|
-
}
|
|
173
|
-
const result = await server.server.elicitInput({
|
|
174
|
-
mode: "form",
|
|
175
|
-
message: message(balance.balance),
|
|
176
|
-
requestedSchema: {
|
|
177
|
-
type: "object",
|
|
178
|
-
properties: {}
|
|
179
|
-
}
|
|
180
|
-
});
|
|
181
|
-
if (result.action === "accept") {
|
|
182
|
-
await openDepositLink(address, flags);
|
|
183
|
-
}
|
|
184
|
-
}
|
|
185
|
-
return balance.balance;
|
|
186
|
-
};
|
|
187
|
-
|
|
188
|
-
// src/shared/token.ts
|
|
189
|
-
import { formatUnits } from "viem";
|
|
190
|
-
var tokenStringToNumber = (amount, decimals = 6) => {
|
|
191
|
-
return Number(formatUnits(BigInt(amount), decimals));
|
|
192
|
-
};
|
|
193
|
-
|
|
194
|
-
// src/shared/neverthrow/x402/index.ts
|
|
195
|
-
import { createSIWxPayload } from "@x402scan/siwx";
|
|
196
|
-
var errorType = "x402";
|
|
197
|
-
var x402Err = (cause, error) => err(errorType, cause, error);
|
|
198
|
-
var x402ResultFromPromise = (surface2, promise, error) => resultFromPromise(errorType, surface2, promise, error);
|
|
199
|
-
var x402ResultFromThrowable = (surface2, fn, error) => resultFromThrowable(errorType, surface2, fn, error);
|
|
200
|
-
var safeGetPaymentRequired = (surface2, client, response) => {
|
|
201
|
-
return x402ResultFromPromise(
|
|
202
|
-
surface2,
|
|
203
|
-
response.json().then(
|
|
204
|
-
(json) => client.getPaymentRequiredResponse(
|
|
205
|
-
(name) => response.headers.get(name),
|
|
206
|
-
json
|
|
207
|
-
),
|
|
208
|
-
() => client.getPaymentRequiredResponse((name) => response.headers.get(name))
|
|
209
|
-
),
|
|
210
|
-
(error) => ({
|
|
211
|
-
cause: "parse_payment_required",
|
|
212
|
-
message: error instanceof Error ? error.message : "Failed to parse payment required"
|
|
213
|
-
})
|
|
214
|
-
);
|
|
215
|
-
};
|
|
216
|
-
var safeCreatePaymentPayload = (surface2, client, paymentRequired) => {
|
|
217
|
-
return x402ResultFromPromise(
|
|
218
|
-
surface2,
|
|
219
|
-
client.createPaymentPayload(paymentRequired),
|
|
220
|
-
(error) => ({
|
|
221
|
-
cause: "create_payment_payload",
|
|
222
|
-
message: error instanceof Error ? error.message : "Failed to create payment payload"
|
|
223
|
-
})
|
|
224
|
-
);
|
|
225
|
-
};
|
|
226
|
-
var safeGetPaymentSettlement = (surface2, client, response) => {
|
|
227
|
-
return x402ResultFromThrowable(
|
|
228
|
-
surface2,
|
|
229
|
-
() => client.getPaymentSettleResponse((name) => response.headers.get(name)),
|
|
230
|
-
(error) => ({
|
|
231
|
-
cause: "get_payment_settlement",
|
|
232
|
-
message: error instanceof Error ? error.message : "Failed to get payment settlement"
|
|
233
|
-
})
|
|
234
|
-
);
|
|
235
|
-
};
|
|
236
|
-
var safeCreateSIWxPayload = (surface2, serverInfo, signer) => {
|
|
237
|
-
return x402ResultFromPromise(
|
|
238
|
-
surface2,
|
|
239
|
-
createSIWxPayload(serverInfo, signer),
|
|
240
|
-
(error) => ({
|
|
241
|
-
cause: "create_siwx_payload",
|
|
242
|
-
message: error instanceof Error ? error.message : "Failed to create SIWX payload"
|
|
243
|
-
})
|
|
244
|
-
);
|
|
245
|
-
};
|
|
246
|
-
|
|
247
|
-
// src/server/tools/x402-fetch.ts
|
|
248
|
-
var toolName = "fetch";
|
|
249
|
-
var registerFetchX402ResourceTool = ({
|
|
250
|
-
server,
|
|
251
|
-
account,
|
|
252
|
-
flags
|
|
253
|
-
}) => {
|
|
254
|
-
server.registerTool(
|
|
255
|
-
toolName,
|
|
256
|
-
{
|
|
257
|
-
description: "Makes an http fetch request. If the request is to an x402-protected resource, it will handle payment automatically.",
|
|
258
|
-
inputSchema: requestSchema
|
|
259
|
-
},
|
|
260
|
-
async (input) => {
|
|
261
|
-
const coreClient = x402Client.fromConfig({
|
|
262
|
-
schemes: [
|
|
263
|
-
{ network: DEFAULT_NETWORK, client: new ExactEvmScheme(account) }
|
|
264
|
-
]
|
|
265
|
-
});
|
|
266
|
-
coreClient.onBeforePaymentCreation(async ({ selectedRequirements }) => {
|
|
267
|
-
const amount = tokenStringToNumber(selectedRequirements.amount);
|
|
268
|
-
await checkBalance({
|
|
269
|
-
surface: toolName,
|
|
270
|
-
server,
|
|
271
|
-
address: account.address,
|
|
272
|
-
amountNeeded: amount,
|
|
273
|
-
message: (balance) => `This request costs ${amount} USDC. Your current balance is ${balance} USDC.`,
|
|
274
|
-
flags
|
|
275
|
-
});
|
|
276
|
-
});
|
|
277
|
-
const client = new x402HTTPClient(coreClient);
|
|
278
|
-
const fetchWithPay = safeWrapFetchWithPayment(client);
|
|
279
|
-
const fetchResult = await fetchWithPay(buildRequest(input));
|
|
280
|
-
if (fetchResult.isErr()) {
|
|
281
|
-
return mcpError(fetchResult);
|
|
282
|
-
}
|
|
283
|
-
const response = fetchResult.value;
|
|
284
|
-
if (!response.ok) {
|
|
285
|
-
return mcpErrorFetch(toolName, response);
|
|
286
|
-
}
|
|
287
|
-
const parseResponseResult = await safeParseResponse(toolName, response);
|
|
288
|
-
if (parseResponseResult.isErr()) {
|
|
289
|
-
return mcpError(parseResponseResult);
|
|
290
|
-
}
|
|
291
|
-
const settlementResult = safeGetPaymentSettlement(
|
|
292
|
-
toolName,
|
|
293
|
-
client,
|
|
294
|
-
response
|
|
295
|
-
);
|
|
296
|
-
return mcpSuccessResponse(
|
|
297
|
-
parseResponseResult.value,
|
|
298
|
-
settlementResult.isOk() ? { payment: settlementResult.value } : void 0
|
|
299
|
-
);
|
|
300
|
-
}
|
|
301
|
-
);
|
|
302
|
-
};
|
|
303
|
-
function safeWrapFetchWithPayment(client) {
|
|
304
|
-
return async (input, init) => {
|
|
305
|
-
const request = new Request(input, init);
|
|
306
|
-
const clonedRequest = request.clone();
|
|
307
|
-
const probeResult = await safeFetch(toolName, request);
|
|
308
|
-
if (probeResult.isErr()) {
|
|
309
|
-
return probeResult;
|
|
310
|
-
}
|
|
311
|
-
if (probeResult.value.status !== 402) {
|
|
312
|
-
return probeResult;
|
|
313
|
-
}
|
|
314
|
-
const response = probeResult.value;
|
|
315
|
-
const paymentRequiredResult = await safeGetPaymentRequired(
|
|
316
|
-
toolName,
|
|
317
|
-
client,
|
|
318
|
-
response
|
|
319
|
-
);
|
|
320
|
-
if (paymentRequiredResult.isErr()) {
|
|
321
|
-
return paymentRequiredResult;
|
|
322
|
-
}
|
|
323
|
-
const paymentRequired = paymentRequiredResult.value;
|
|
324
|
-
const paymentPayloadResult = await safeCreatePaymentPayload(
|
|
325
|
-
toolName,
|
|
326
|
-
client,
|
|
327
|
-
paymentRequired
|
|
328
|
-
);
|
|
329
|
-
if (paymentPayloadResult.isErr()) {
|
|
330
|
-
return paymentPayloadResult;
|
|
331
|
-
}
|
|
332
|
-
const paymentPayload = paymentPayloadResult.value;
|
|
333
|
-
const paymentHeaders = client.encodePaymentSignatureHeader(paymentPayload);
|
|
334
|
-
if (clonedRequest.headers.has("PAYMENT-SIGNATURE") || clonedRequest.headers.has("X-PAYMENT")) {
|
|
335
|
-
return x402Err(toolName, {
|
|
336
|
-
cause: "payment_already_attempted",
|
|
337
|
-
message: "Payment already attempted"
|
|
338
|
-
});
|
|
339
|
-
}
|
|
340
|
-
for (const [key, value] of Object.entries(paymentHeaders)) {
|
|
341
|
-
clonedRequest.headers.set(key, value);
|
|
342
|
-
}
|
|
343
|
-
clonedRequest.headers.set(
|
|
344
|
-
"Access-Control-Expose-Headers",
|
|
345
|
-
"PAYMENT-RESPONSE,X-PAYMENT-RESPONSE"
|
|
346
|
-
);
|
|
347
|
-
return await safeFetch(toolName, clonedRequest);
|
|
348
|
-
};
|
|
349
|
-
}
|
|
350
|
-
|
|
351
|
-
// src/server/tools/auth-fetch.ts
|
|
352
|
-
import { x402Client as x402Client2, x402HTTPClient as x402HTTPClient2 } from "@x402/core/client";
|
|
353
|
-
import { encodeSIWxHeader } from "@x402scan/siwx";
|
|
354
|
-
|
|
355
|
-
// src/server/lib/x402-extensions.ts
|
|
356
|
-
var getBazaarExtension = (extensions) => {
|
|
357
|
-
const { bazaar } = extensions ?? {};
|
|
358
|
-
if (!bazaar) {
|
|
359
|
-
return void 0;
|
|
360
|
-
}
|
|
361
|
-
return bazaar;
|
|
362
|
-
};
|
|
363
|
-
var getInputSchema = (extensions) => getBazaarExtension(extensions)?.schema.properties.input;
|
|
364
|
-
var getSiwxExtension = (extensions) => {
|
|
365
|
-
const siwx = extensions?.["sign-in-with-x"];
|
|
366
|
-
if (!siwx?.info) {
|
|
367
|
-
return void 0;
|
|
368
|
-
}
|
|
369
|
-
return siwx.info;
|
|
370
|
-
};
|
|
371
|
-
|
|
372
|
-
// src/server/tools/auth-fetch.ts
|
|
373
|
-
var toolName2 = "fetchWithAuth";
|
|
374
|
-
var registerAuthTools = ({ server, account }) => {
|
|
375
|
-
server.registerTool(
|
|
376
|
-
toolName2,
|
|
377
|
-
{
|
|
378
|
-
description: "Make a request to a SIWX-protected endpoint. Handles auth flow automatically: detects SIWX requirement from 402 response, signs proof with server-provided challenge, retries.",
|
|
379
|
-
inputSchema: requestSchema
|
|
380
|
-
},
|
|
381
|
-
async (input) => {
|
|
382
|
-
const httpClient = new x402HTTPClient2(new x402Client2());
|
|
383
|
-
const firstResult = await safeFetch(toolName2, buildRequest(input));
|
|
384
|
-
if (firstResult.isErr()) {
|
|
385
|
-
return mcpError(firstResult);
|
|
386
|
-
}
|
|
387
|
-
const firstResponse = firstResult.value;
|
|
388
|
-
if (firstResponse.status !== 402) {
|
|
389
|
-
if (!firstResponse.ok) {
|
|
390
|
-
return mcpErrorFetch(toolName2, firstResponse);
|
|
391
|
-
}
|
|
392
|
-
const parseResponseResult2 = await safeParseResponse(
|
|
393
|
-
toolName2,
|
|
394
|
-
firstResponse
|
|
395
|
-
);
|
|
396
|
-
if (parseResponseResult2.isErr()) {
|
|
397
|
-
return mcpError(parseResponseResult2);
|
|
398
|
-
}
|
|
399
|
-
return mcpSuccessResponse(parseResponseResult2.value);
|
|
400
|
-
}
|
|
401
|
-
const getPaymentRequiredResult = await safeGetPaymentRequired(
|
|
402
|
-
toolName2,
|
|
403
|
-
httpClient,
|
|
404
|
-
firstResponse
|
|
405
|
-
);
|
|
406
|
-
if (getPaymentRequiredResult.isErr()) {
|
|
407
|
-
return mcpError(getPaymentRequiredResult);
|
|
408
|
-
}
|
|
409
|
-
const paymentRequired = getPaymentRequiredResult.value;
|
|
410
|
-
const siwxExtension = getSiwxExtension(paymentRequired.extensions);
|
|
411
|
-
if (!siwxExtension) {
|
|
412
|
-
return mcpErrorJson({
|
|
413
|
-
message: "Endpoint returned 402 but no sign-in-with-x extension found",
|
|
414
|
-
statusCode: 402,
|
|
415
|
-
extensions: Object.keys(paymentRequired.extensions ?? {}),
|
|
416
|
-
hint: "This endpoint may require payment instead of authentication. Use execute_call for paid requests."
|
|
417
|
-
});
|
|
418
|
-
}
|
|
419
|
-
const serverInfo = siwxExtension;
|
|
420
|
-
const requiredFields = [
|
|
421
|
-
"domain",
|
|
422
|
-
"uri",
|
|
423
|
-
"version",
|
|
424
|
-
"chainId",
|
|
425
|
-
"nonce",
|
|
426
|
-
"issuedAt"
|
|
427
|
-
];
|
|
428
|
-
const missingFields = requiredFields.filter(
|
|
429
|
-
(f) => !serverInfo[f]
|
|
430
|
-
);
|
|
431
|
-
if (missingFields.length > 0) {
|
|
432
|
-
return mcpErrorJson({
|
|
433
|
-
message: "Invalid sign-in-with-x extension: missing required fields",
|
|
434
|
-
missingFields,
|
|
435
|
-
receivedInfo: { ...serverInfo }
|
|
436
|
-
});
|
|
437
|
-
}
|
|
438
|
-
if (serverInfo.chainId.startsWith("solana:")) {
|
|
439
|
-
return mcpErrorJson({
|
|
440
|
-
message: "Solana authentication not supported",
|
|
441
|
-
chainId: serverInfo.chainId,
|
|
442
|
-
hint: "This endpoint requires a Solana wallet. The MCP server currently only supports EVM wallets."
|
|
443
|
-
});
|
|
444
|
-
}
|
|
445
|
-
const payloadResult = await safeCreateSIWxPayload(
|
|
446
|
-
toolName2,
|
|
447
|
-
serverInfo,
|
|
448
|
-
account
|
|
449
|
-
);
|
|
450
|
-
if (payloadResult.isErr()) {
|
|
451
|
-
return mcpError(payloadResult);
|
|
452
|
-
}
|
|
453
|
-
const siwxHeader = encodeSIWxHeader(payloadResult.value);
|
|
454
|
-
const authedRequest = buildRequest(input);
|
|
455
|
-
authedRequest.headers.set("SIGN-IN-WITH-X", siwxHeader);
|
|
456
|
-
const authedResult = await safeFetch(toolName2, authedRequest);
|
|
457
|
-
if (authedResult.isErr()) {
|
|
458
|
-
return mcpError(authedResult);
|
|
459
|
-
}
|
|
460
|
-
const authedResponse = authedResult.value;
|
|
461
|
-
if (!authedResponse.ok) {
|
|
462
|
-
return mcpErrorFetch(toolName2, authedResponse);
|
|
463
|
-
}
|
|
464
|
-
const parseResponseResult = await safeParseResponse(
|
|
465
|
-
toolName2,
|
|
466
|
-
authedResponse
|
|
467
|
-
);
|
|
468
|
-
if (parseResponseResult.isErr()) {
|
|
469
|
-
return mcpError(parseResponseResult);
|
|
470
|
-
}
|
|
471
|
-
return mcpSuccessResponse(parseResponseResult.value, {
|
|
472
|
-
authentication: {
|
|
473
|
-
address: account.address,
|
|
474
|
-
domain: serverInfo.domain,
|
|
475
|
-
chainId: serverInfo.chainId
|
|
476
|
-
}
|
|
477
|
-
});
|
|
478
|
-
}
|
|
479
|
-
);
|
|
480
|
-
};
|
|
481
|
-
|
|
482
|
-
// src/server/tools/wallet.ts
|
|
483
|
-
var toolName3 = "getWalletInfo";
|
|
484
|
-
var registerWalletTools = ({
|
|
485
|
-
server,
|
|
486
|
-
account: { address },
|
|
487
|
-
flags
|
|
488
|
-
}) => {
|
|
489
|
-
server.registerTool(
|
|
490
|
-
toolName3,
|
|
491
|
-
{
|
|
492
|
-
description: "Check wallet address and USDC balance. Creates wallet if needed."
|
|
493
|
-
},
|
|
494
|
-
async () => {
|
|
495
|
-
const balanceResult = await getBalance({
|
|
496
|
-
address,
|
|
497
|
-
flags,
|
|
498
|
-
surface: toolName3
|
|
499
|
-
});
|
|
500
|
-
if (balanceResult.isErr()) {
|
|
501
|
-
return mcpError(balanceResult);
|
|
502
|
-
}
|
|
503
|
-
const { balance } = balanceResult.value;
|
|
504
|
-
return mcpSuccessJson({
|
|
505
|
-
address,
|
|
506
|
-
network: DEFAULT_NETWORK,
|
|
507
|
-
networkName: getChainName(DEFAULT_NETWORK),
|
|
508
|
-
usdcBalance: balance,
|
|
509
|
-
isNewWallet: balance === 0,
|
|
510
|
-
depositLink: getDepositLink(address, flags),
|
|
511
|
-
...balance < 2.5 ? {
|
|
512
|
-
message: `Your balance is low. Consider topping it up`
|
|
513
|
-
} : {}
|
|
514
|
-
});
|
|
515
|
-
}
|
|
516
|
-
);
|
|
517
|
-
};
|
|
518
|
-
|
|
519
|
-
// src/server/tools/check-endpoint.ts
|
|
520
|
-
import { x402Client as x402Client3, x402HTTPClient as x402HTTPClient3 } from "@x402/core/client";
|
|
521
|
-
var toolName4 = "checkEndpointSchema";
|
|
522
|
-
var registerCheckX402EndpointTool = ({ server }) => {
|
|
523
|
-
server.registerTool(
|
|
524
|
-
toolName4,
|
|
525
|
-
{
|
|
526
|
-
description: "Check if an endpoint is x402-protected and get pricing options, schema, and auth requirements (if applicable).",
|
|
527
|
-
inputSchema: requestSchema
|
|
528
|
-
},
|
|
529
|
-
async (input) => {
|
|
530
|
-
log.info("Querying endpoint", input);
|
|
531
|
-
const responseResult = await safeFetch(toolName4, buildRequest(input));
|
|
532
|
-
if (responseResult.isErr()) {
|
|
533
|
-
return mcpError(responseResult);
|
|
534
|
-
}
|
|
535
|
-
const response = responseResult.value;
|
|
536
|
-
if (response.status !== 402) {
|
|
537
|
-
if (!response.ok) {
|
|
538
|
-
return mcpErrorFetch(toolName4, response);
|
|
539
|
-
}
|
|
540
|
-
const parseResponseResult = await safeParseResponse(toolName4, response);
|
|
541
|
-
if (parseResponseResult.isErr()) {
|
|
542
|
-
return mcpError(parseResponseResult);
|
|
543
|
-
}
|
|
544
|
-
return mcpSuccessResponse(parseResponseResult.value, {
|
|
545
|
-
requiresPayment: false
|
|
546
|
-
});
|
|
547
|
-
}
|
|
548
|
-
const client = new x402HTTPClient3(new x402Client3());
|
|
549
|
-
const paymentRequiredResult = await safeGetPaymentRequired(
|
|
550
|
-
toolName4,
|
|
551
|
-
client,
|
|
552
|
-
response
|
|
553
|
-
);
|
|
554
|
-
if (paymentRequiredResult.isErr()) {
|
|
555
|
-
return mcpError(paymentRequiredResult);
|
|
556
|
-
}
|
|
557
|
-
const { resource, extensions, accepts } = paymentRequiredResult.value;
|
|
558
|
-
return mcpSuccessJson({
|
|
559
|
-
requiresPayment: true,
|
|
560
|
-
statusCode: response.status,
|
|
561
|
-
routeDetails: {
|
|
562
|
-
...resource,
|
|
563
|
-
schema: getInputSchema(extensions),
|
|
564
|
-
paymentMethods: accepts.map((accept) => ({
|
|
565
|
-
price: tokenStringToNumber(accept.amount),
|
|
566
|
-
network: accept.network,
|
|
567
|
-
asset: accept.asset
|
|
568
|
-
}))
|
|
569
|
-
}
|
|
570
|
-
});
|
|
571
|
-
}
|
|
572
|
-
);
|
|
573
|
-
};
|
|
574
|
-
|
|
575
|
-
// src/server/tools/redeem-invite.ts
|
|
576
|
-
import z2 from "zod";
|
|
577
|
-
var toolName5 = "redeemInvite";
|
|
578
|
-
var registerRedeemInviteTool = ({
|
|
579
|
-
server,
|
|
580
|
-
account: { address },
|
|
581
|
-
flags
|
|
582
|
-
}) => {
|
|
583
|
-
server.registerTool(
|
|
584
|
-
toolName5,
|
|
585
|
-
{
|
|
586
|
-
description: "Redeem an invite code to receive USDC.",
|
|
587
|
-
inputSchema: z2.object({
|
|
588
|
-
code: z2.string().min(1).describe("The invite code")
|
|
589
|
-
})
|
|
590
|
-
},
|
|
591
|
-
async ({ code }) => {
|
|
592
|
-
const result = await redeemInviteCode({
|
|
593
|
-
code,
|
|
594
|
-
dev: flags.dev,
|
|
595
|
-
address,
|
|
596
|
-
surface: toolName5
|
|
597
|
-
});
|
|
598
|
-
if (result.isErr()) {
|
|
599
|
-
return mcpError(result);
|
|
600
|
-
}
|
|
601
|
-
const { amount, txHash } = result.value;
|
|
602
|
-
return mcpSuccessJson({
|
|
603
|
-
redeemed: true,
|
|
604
|
-
amount: `${amount} USDC`,
|
|
605
|
-
txHash
|
|
606
|
-
});
|
|
607
|
-
}
|
|
608
|
-
);
|
|
609
|
-
};
|
|
610
|
-
|
|
611
|
-
// src/server/tools/telemetry.ts
|
|
612
|
-
import z3 from "zod";
|
|
613
|
-
var toolName6 = "reportError";
|
|
614
|
-
var registerTelemetryTools = ({
|
|
615
|
-
server,
|
|
616
|
-
account: { address },
|
|
617
|
-
flags
|
|
618
|
-
}) => {
|
|
619
|
-
server.registerTool(
|
|
620
|
-
toolName6,
|
|
621
|
-
{
|
|
622
|
-
description: "EMERGENCY ONLY. Report critical MCP tool bugs. Do NOT use for normal errors (balance, network, 4xx) - those are recoverable.",
|
|
623
|
-
inputSchema: z3.object({
|
|
624
|
-
tool: z3.string().describe("MCP tool name"),
|
|
625
|
-
resource: z3.string().optional().describe("x402 resource URL"),
|
|
626
|
-
summary: z3.string().describe("1-2 sentence summary"),
|
|
627
|
-
errorMessage: z3.string().describe("Error message"),
|
|
628
|
-
stack: z3.string().optional().describe("Stack trace"),
|
|
629
|
-
fullReport: z3.string().optional().describe("Detailed report with context, logs, repro steps")
|
|
630
|
-
})
|
|
631
|
-
},
|
|
632
|
-
async (input) => {
|
|
633
|
-
log.info("Submitting error report", {
|
|
634
|
-
tool: input.tool,
|
|
635
|
-
resource: input.resource,
|
|
636
|
-
summary: input.summary
|
|
637
|
-
});
|
|
638
|
-
const telemetryResult = await safeFetchJson(
|
|
639
|
-
toolName6,
|
|
640
|
-
new Request(`${getBaseUrl(flags.dev)}/api/telemetry`, {
|
|
641
|
-
method: "POST",
|
|
642
|
-
headers: {
|
|
643
|
-
"Content-Type": "application/json"
|
|
644
|
-
},
|
|
645
|
-
body: JSON.stringify({
|
|
646
|
-
...input,
|
|
647
|
-
walletAddress: address,
|
|
648
|
-
mcpVersion: MCP_VERSION,
|
|
649
|
-
reportedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
650
|
-
})
|
|
651
|
-
})
|
|
652
|
-
);
|
|
653
|
-
if (telemetryResult.isErr()) {
|
|
654
|
-
log.error("Failed to submit error report", telemetryResult.error);
|
|
655
|
-
return mcpError(telemetryResult);
|
|
656
|
-
}
|
|
657
|
-
const { reportId } = telemetryResult.value;
|
|
658
|
-
log.info("Error report submitted successfully", {
|
|
659
|
-
reportId
|
|
660
|
-
});
|
|
661
|
-
return mcpSuccessJson({
|
|
662
|
-
submitted: true,
|
|
663
|
-
reportId,
|
|
664
|
-
message: "Error report submitted successfully. The x402scan team will investigate."
|
|
665
|
-
});
|
|
666
|
-
}
|
|
667
|
-
);
|
|
668
|
-
};
|
|
669
|
-
|
|
670
|
-
// src/server/tools/discover-resources.ts
|
|
671
|
-
import { z as z4 } from "zod";
|
|
672
|
-
var toolName7 = "discoverResources";
|
|
673
|
-
var discoveryDocumentSchema = z4.object({
|
|
674
|
-
version: z4.number().refine((v) => v === 1, { message: "version must be 1" }),
|
|
675
|
-
resources: z4.array(z4.url()),
|
|
676
|
-
ownershipProofs: z4.array(z4.string()).optional(),
|
|
677
|
-
instructions: z4.string().optional()
|
|
678
|
-
});
|
|
679
|
-
function registerDiscoveryTools(server) {
|
|
680
|
-
server.registerTool(
|
|
681
|
-
"discover_resources",
|
|
682
|
-
{
|
|
683
|
-
description: `Discover x402-protected resources on an origin. Returns a list of resource URLs.
|
|
684
|
-
Use check_x402_endpoint separately to get detailed pricing/schema info for specific resources.
|
|
685
|
-
|
|
686
|
-
Known default origins with resource packs. Discover if more needed:
|
|
687
|
-
- https://enrichx402.com ->
|
|
688
|
-
People + Org search
|
|
689
|
-
Google Maps (places + locations)
|
|
690
|
-
Grok twitter search
|
|
691
|
-
Exa web search
|
|
692
|
-
Clado linkedin data
|
|
693
|
-
Firecrawl web scrape
|
|
694
|
-
- https://stablestudio.io -> generate images / videos
|
|
695
|
-
`,
|
|
696
|
-
inputSchema: {
|
|
697
|
-
url: z4.url().describe(
|
|
698
|
-
"The origin URL or any URL on the origin to discover resources from"
|
|
699
|
-
)
|
|
700
|
-
}
|
|
701
|
-
},
|
|
702
|
-
async ({ url }) => {
|
|
703
|
-
const origin = URL.canParse(url) ? new URL(url).origin : url;
|
|
704
|
-
const hostname = URL.canParse(origin) ? new URL(origin).hostname : origin;
|
|
705
|
-
log.info(`Discovering resources for origin: ${origin}`);
|
|
706
|
-
const wellKnownUrl = `${origin}/.well-known/x402`;
|
|
707
|
-
log.debug(`Fetching discovery document from: ${wellKnownUrl}`);
|
|
708
|
-
const wellKnownResult = await safeFetchJson(
|
|
709
|
-
toolName7,
|
|
710
|
-
new Request(wellKnownUrl, { headers: { Accept: "application/json" } })
|
|
711
|
-
);
|
|
712
|
-
if (wellKnownResult.isOk()) {
|
|
713
|
-
const parsed = discoveryDocumentSchema.safeParse(wellKnownResult.value);
|
|
714
|
-
if (parsed.success) {
|
|
715
|
-
return mcpSuccessJson({
|
|
716
|
-
found: true,
|
|
717
|
-
origin,
|
|
718
|
-
source: "well-known",
|
|
719
|
-
data: parsed.data
|
|
720
|
-
});
|
|
721
|
-
}
|
|
722
|
-
} else {
|
|
723
|
-
log.info(
|
|
724
|
-
`No well-known x402 discovery document found at ${wellKnownUrl}`
|
|
725
|
-
);
|
|
726
|
-
}
|
|
727
|
-
const dnsQuery = `_x402.${hostname}`;
|
|
728
|
-
log.debug(`Looking up DNS TXT record: ${dnsQuery}`);
|
|
729
|
-
const dnsResult = await safeFetchJson(
|
|
730
|
-
toolName7,
|
|
731
|
-
new Request(
|
|
732
|
-
`https://cloudflare-dns.com/dns-query?name=${encodeURIComponent(dnsQuery)}&type=TXT`,
|
|
733
|
-
{ headers: { Accept: "application/dns-json" } }
|
|
734
|
-
)
|
|
735
|
-
);
|
|
736
|
-
if (dnsResult.isOk() && dnsResult.value.Answer && dnsResult.value.Answer.length > 0) {
|
|
737
|
-
const dnsUrl = dnsResult.value.Answer[0].data.replace(/^"|"$/g, "");
|
|
738
|
-
if (URL.canParse(dnsUrl)) {
|
|
739
|
-
const dnsDocResult = await safeFetchJson(
|
|
740
|
-
toolName7,
|
|
741
|
-
new Request(dnsUrl, { headers: { Accept: "application/json" } })
|
|
742
|
-
);
|
|
743
|
-
if (dnsDocResult.isOk()) {
|
|
744
|
-
const parsed = discoveryDocumentSchema.safeParse(
|
|
745
|
-
dnsDocResult.value
|
|
746
|
-
);
|
|
747
|
-
if (parsed.success) {
|
|
748
|
-
return mcpSuccessJson({
|
|
749
|
-
found: true,
|
|
750
|
-
origin,
|
|
751
|
-
source: "dns-txt",
|
|
752
|
-
data: parsed.data
|
|
753
|
-
});
|
|
754
|
-
}
|
|
755
|
-
}
|
|
756
|
-
} else {
|
|
757
|
-
log.debug(`DNS TXT value is not a valid URL: ${dnsUrl}`);
|
|
758
|
-
}
|
|
759
|
-
} else {
|
|
760
|
-
log.info(`No DNS TXT record found for ${dnsQuery}`);
|
|
761
|
-
}
|
|
762
|
-
const llmsTxtUrl = `${origin}/llms.txt`;
|
|
763
|
-
log.debug(`Fetching llms.txt from: ${llmsTxtUrl}`);
|
|
764
|
-
const llmsResult = await safeFetch(
|
|
765
|
-
toolName7,
|
|
766
|
-
new Request(llmsTxtUrl, { headers: { Accept: "text/plain" } })
|
|
767
|
-
);
|
|
768
|
-
if (llmsResult.isOk()) {
|
|
769
|
-
const parseResult = await safeParseResponse(toolName7, llmsResult.value);
|
|
770
|
-
if (parseResult.isOk() && parseResult.value.type === "text") {
|
|
771
|
-
return mcpSuccessJson({
|
|
772
|
-
found: true,
|
|
773
|
-
origin,
|
|
774
|
-
source: "llms-txt",
|
|
775
|
-
usage: "Found llms.txt but no structured x402 discovery document. The content below may contain information about x402 resources. Parse it to find relevant endpoints.",
|
|
776
|
-
data: parseResult.value
|
|
777
|
-
});
|
|
778
|
-
}
|
|
779
|
-
}
|
|
780
|
-
return mcpErrorJson({
|
|
781
|
-
found: false,
|
|
782
|
-
origin,
|
|
783
|
-
error: "No discovery document found. Tried: .well-known/x402, DNS TXT record, llms.txt"
|
|
784
|
-
});
|
|
785
|
-
}
|
|
786
|
-
);
|
|
787
|
-
}
|
|
788
|
-
|
|
789
|
-
// src/server/resources/origins.ts
|
|
790
|
-
import { x402HTTPClient as x402HTTPClient4 } from "@x402/core/client";
|
|
791
|
-
import { x402Client as x402Client4 } from "@x402/core/client";
|
|
792
|
-
|
|
793
|
-
// src/server/resources/_lib.ts
|
|
794
|
-
var surface = "getWebPageMetadata";
|
|
795
|
-
var getWebPageMetadata = (url) => {
|
|
796
|
-
return safeFetch(surface, new Request(url)).andThen((response) => safeParseResponse(surface, response)).andThen((parsedResponse) => {
|
|
797
|
-
if (parsedResponse.type === "text") {
|
|
798
|
-
return ok(parseMetadataFromResponse(parsedResponse.data));
|
|
799
|
-
}
|
|
800
|
-
return err("user", surface, {
|
|
801
|
-
cause: "invalid_response_type",
|
|
802
|
-
message: "Invalid response type"
|
|
803
|
-
});
|
|
804
|
-
});
|
|
805
|
-
};
|
|
806
|
-
var parseMetadataFromResponse = (html) => {
|
|
807
|
-
const titleMatch = /<title[^>]*>([\s\S]*?)<\/title>/i.exec(html);
|
|
808
|
-
const title = titleMatch ? titleMatch[1].trim().replace(/\s+/g, " ") : null;
|
|
809
|
-
let descriptionMatch = /<meta\s+name=["']description["']\s+content=["']([^"']*)["']/i.exec(html);
|
|
810
|
-
descriptionMatch ??= /<meta\s+property=["']og:description["']\s+content=["']([^"']*)["']/i.exec(
|
|
811
|
-
html
|
|
812
|
-
);
|
|
813
|
-
descriptionMatch ??= /<meta\s+content=["']([^"']*)["']\s+name=["']description["']/i.exec(html);
|
|
814
|
-
descriptionMatch ??= /<meta\s+content=["']([^"']*)["']\s+property=["']og:description["']/i.exec(
|
|
815
|
-
html
|
|
816
|
-
);
|
|
817
|
-
const description = descriptionMatch ? descriptionMatch[1].trim().replace(/\s+/g, " ") : null;
|
|
818
|
-
return {
|
|
819
|
-
title,
|
|
820
|
-
description
|
|
821
|
-
};
|
|
822
|
-
};
|
|
823
|
-
|
|
824
|
-
// src/server/resources/origins.ts
|
|
825
|
-
var origins = ["enrichx402.com"];
|
|
826
|
-
var registerOrigins = async ({ server }) => {
|
|
827
|
-
await Promise.all(
|
|
828
|
-
origins.map(async (origin) => {
|
|
829
|
-
const metadataResult = await getWebPageMetadata(`https://${origin}`);
|
|
830
|
-
const metadata = metadataResult.isOk() ? metadataResult.value : null;
|
|
831
|
-
server.registerResource(
|
|
832
|
-
origin,
|
|
833
|
-
`api://${origin}`,
|
|
834
|
-
{
|
|
835
|
-
title: metadata?.title ?? origin,
|
|
836
|
-
description: metadata?.description ?? "",
|
|
837
|
-
mimeType: "application/json"
|
|
838
|
-
},
|
|
839
|
-
async (uri) => {
|
|
840
|
-
const response = await fetch(
|
|
841
|
-
`${uri.toString().replace("api://", "https://")}/.well-known/x402`
|
|
842
|
-
).then((response2) => response2.json());
|
|
843
|
-
const resources = await Promise.all(
|
|
844
|
-
response.resources.map(async (resource) => {
|
|
845
|
-
const resourceResponse = await getResourceResponse(
|
|
846
|
-
resource,
|
|
847
|
-
await fetch(resource, {
|
|
848
|
-
method: "POST",
|
|
849
|
-
headers: {
|
|
850
|
-
"Content-Type": "application/json"
|
|
851
|
-
}
|
|
852
|
-
})
|
|
853
|
-
);
|
|
854
|
-
if (resourceResponse) {
|
|
855
|
-
return resourceResponse;
|
|
856
|
-
}
|
|
857
|
-
const getResponse = await getResourceResponse(
|
|
858
|
-
resource,
|
|
859
|
-
await fetch(resource, {
|
|
860
|
-
method: "GET"
|
|
861
|
-
})
|
|
862
|
-
);
|
|
863
|
-
if (getResponse) {
|
|
864
|
-
return getResponse;
|
|
865
|
-
}
|
|
866
|
-
console.error(`Failed to get resource response for ${resource}`);
|
|
867
|
-
return null;
|
|
868
|
-
})
|
|
869
|
-
);
|
|
870
|
-
return {
|
|
871
|
-
contents: [
|
|
872
|
-
{
|
|
873
|
-
uri: origin,
|
|
874
|
-
text: JSON.stringify({
|
|
875
|
-
server: origin,
|
|
876
|
-
name: metadata?.title,
|
|
877
|
-
description: metadata?.description,
|
|
878
|
-
resources: resources.filter(Boolean).map((resource) => {
|
|
879
|
-
if (!resource) return null;
|
|
880
|
-
const schema = getInputSchema(
|
|
881
|
-
resource.paymentRequired?.extensions
|
|
882
|
-
);
|
|
883
|
-
return {
|
|
884
|
-
url: resource.resource,
|
|
885
|
-
schema,
|
|
886
|
-
mimeType: resource.paymentRequired.resource.mimeType
|
|
887
|
-
};
|
|
888
|
-
})
|
|
889
|
-
}),
|
|
890
|
-
mimeType: "application/json"
|
|
891
|
-
}
|
|
892
|
-
]
|
|
893
|
-
};
|
|
894
|
-
}
|
|
895
|
-
);
|
|
896
|
-
})
|
|
897
|
-
);
|
|
898
|
-
};
|
|
899
|
-
var getResourceResponse = async (resource, response) => {
|
|
900
|
-
const client = new x402HTTPClient4(new x402Client4());
|
|
901
|
-
if (response.status === 402) {
|
|
902
|
-
const paymentRequired = client.getPaymentRequiredResponse(
|
|
903
|
-
(name) => response.headers.get(name),
|
|
904
|
-
JSON.parse(await response.text())
|
|
905
|
-
);
|
|
906
|
-
return {
|
|
907
|
-
paymentRequired,
|
|
908
|
-
resource
|
|
909
|
-
};
|
|
910
|
-
}
|
|
911
|
-
return null;
|
|
912
|
-
};
|
|
913
|
-
|
|
914
|
-
// src/server/index.ts
|
|
915
|
-
var startServer = async (flags) => {
|
|
916
|
-
log.info("Starting x402scan-mcp...");
|
|
917
|
-
const { dev, invite } = flags;
|
|
918
|
-
const walletResult = await getWallet();
|
|
919
|
-
if (walletResult.isErr()) {
|
|
920
|
-
log.error(JSON.stringify(walletResult.error, null, 2));
|
|
921
|
-
console.error(walletResult.error);
|
|
922
|
-
process.exit(1);
|
|
923
|
-
}
|
|
924
|
-
const { account } = walletResult.value;
|
|
925
|
-
const code = invite ?? process.env.INVITE_CODE;
|
|
926
|
-
if (code) {
|
|
927
|
-
await redeemInviteCode({
|
|
928
|
-
code,
|
|
929
|
-
dev,
|
|
930
|
-
address: account.address,
|
|
931
|
-
surface: "startServer"
|
|
932
|
-
});
|
|
933
|
-
}
|
|
934
|
-
const server = new McpServer(
|
|
935
|
-
{
|
|
936
|
-
name: "@x402scan/mcp",
|
|
937
|
-
version: MCP_VERSION,
|
|
938
|
-
websiteUrl: "https://x402scan.com/mcp",
|
|
939
|
-
icons: [{ src: "https://x402scan.com/logo.svg" }]
|
|
940
|
-
},
|
|
941
|
-
{
|
|
942
|
-
capabilities: {
|
|
943
|
-
resources: {
|
|
944
|
-
subscribe: true,
|
|
945
|
-
listChanged: true
|
|
946
|
-
}
|
|
947
|
-
}
|
|
948
|
-
}
|
|
949
|
-
);
|
|
950
|
-
const props = {
|
|
951
|
-
server,
|
|
952
|
-
account,
|
|
953
|
-
flags
|
|
954
|
-
};
|
|
955
|
-
registerFetchX402ResourceTool(props);
|
|
956
|
-
registerAuthTools(props);
|
|
957
|
-
registerWalletTools(props);
|
|
958
|
-
registerCheckX402EndpointTool(props);
|
|
959
|
-
registerRedeemInviteTool(props);
|
|
960
|
-
registerDiscoveryTools(server);
|
|
961
|
-
registerTelemetryTools(props);
|
|
962
|
-
await registerOrigins({ server, flags });
|
|
963
|
-
const transport = new StdioServerTransport();
|
|
964
|
-
await server.connect(transport);
|
|
965
|
-
const shutdown = async () => {
|
|
966
|
-
log.info("Shutting down...");
|
|
967
|
-
await server.close();
|
|
968
|
-
process.exit(0);
|
|
969
|
-
};
|
|
970
|
-
process.on("SIGINT", () => void shutdown());
|
|
971
|
-
process.on("SIGTERM", () => void shutdown());
|
|
972
|
-
};
|
|
973
|
-
export {
|
|
974
|
-
startServer
|
|
975
|
-
};
|
|
976
|
-
//# sourceMappingURL=server-IOVNYPTB.js.map
|