@x402scan/mcp 0.0.1
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 +115 -0
- package/dist/bundle/index.cjs +110336 -0
- package/dist/chunk-FFXFOKKF.js +267 -0
- package/dist/chunk-KD3GRRAV.js +43 -0
- package/dist/fund-743A34XB.js +19 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +41 -0
- package/dist/install-QDUD2KOS.js +646 -0
- package/dist/server-CD4OSIVL.js +1109 -0
- package/package.json +78 -0
|
@@ -0,0 +1,646 @@
|
|
|
1
|
+
import {
|
|
2
|
+
getUSDCBalance
|
|
3
|
+
} from "./chunk-KD3GRRAV.js";
|
|
4
|
+
import {
|
|
5
|
+
getWallet,
|
|
6
|
+
log,
|
|
7
|
+
promptDeposit,
|
|
8
|
+
wait
|
|
9
|
+
} from "./chunk-FFXFOKKF.js";
|
|
10
|
+
|
|
11
|
+
// src/install/1-get-client/index.ts
|
|
12
|
+
import z from "zod";
|
|
13
|
+
import { select, log as log2, outro } from "@clack/prompts";
|
|
14
|
+
import chalk from "chalk";
|
|
15
|
+
|
|
16
|
+
// src/install/clients.ts
|
|
17
|
+
var Clients = /* @__PURE__ */ ((Clients2) => {
|
|
18
|
+
Clients2["ClaudeCode"] = "claude-code";
|
|
19
|
+
Clients2["Cursor"] = "cursor";
|
|
20
|
+
Clients2["Claude"] = "claude";
|
|
21
|
+
Clients2["Codex"] = "codex";
|
|
22
|
+
Clients2["Vscode"] = "vscode";
|
|
23
|
+
Clients2["Cline"] = "cline";
|
|
24
|
+
Clients2["RooCline"] = "roo-cline";
|
|
25
|
+
Clients2["Windsurf"] = "windsurf";
|
|
26
|
+
Clients2["Warp"] = "warp";
|
|
27
|
+
Clients2["GeminiCli"] = "gemini-cli";
|
|
28
|
+
Clients2["Goose"] = "goose";
|
|
29
|
+
Clients2["Zed"] = "zed";
|
|
30
|
+
Clients2["Opencode"] = "opencode";
|
|
31
|
+
return Clients2;
|
|
32
|
+
})(Clients || {});
|
|
33
|
+
var clientMetadata = {
|
|
34
|
+
["claude-code" /* ClaudeCode */]: {
|
|
35
|
+
name: "Claude Code",
|
|
36
|
+
description: "Claude Code is a code editor that uses the Claude API.",
|
|
37
|
+
website: "https://claude.com"
|
|
38
|
+
},
|
|
39
|
+
["cursor" /* Cursor */]: {
|
|
40
|
+
name: "Cursor",
|
|
41
|
+
description: "Cursor is a code editor that uses the Cursor API.",
|
|
42
|
+
website: "https://cursor.com"
|
|
43
|
+
},
|
|
44
|
+
["claude" /* Claude */]: {
|
|
45
|
+
name: "Claude",
|
|
46
|
+
description: "Claude is a code editor that uses the Claude API.",
|
|
47
|
+
website: "https://claude.com"
|
|
48
|
+
},
|
|
49
|
+
["codex" /* Codex */]: {
|
|
50
|
+
name: "Codex",
|
|
51
|
+
description: "Codex is a code editor that uses the Codex API.",
|
|
52
|
+
website: "https://codex.com"
|
|
53
|
+
},
|
|
54
|
+
["vscode" /* Vscode */]: {
|
|
55
|
+
name: "VSCode",
|
|
56
|
+
description: "VSCode is a code editor that uses the VSCode API.",
|
|
57
|
+
website: "https://vscode.com"
|
|
58
|
+
},
|
|
59
|
+
["cline" /* Cline */]: {
|
|
60
|
+
name: "Cline",
|
|
61
|
+
description: "Cline is a code editor that uses the Cline API.",
|
|
62
|
+
website: "https://cline.com"
|
|
63
|
+
},
|
|
64
|
+
["roo-cline" /* RooCline */]: {
|
|
65
|
+
name: "RooCline",
|
|
66
|
+
description: "RooCline is a code editor that uses the RooCline API.",
|
|
67
|
+
website: "https://roo-cline.com"
|
|
68
|
+
},
|
|
69
|
+
["windsurf" /* Windsurf */]: {
|
|
70
|
+
name: "Windsurf",
|
|
71
|
+
description: "Windsurf is a code editor that uses the Windsurf API.",
|
|
72
|
+
website: "https://windsurf.com"
|
|
73
|
+
},
|
|
74
|
+
["warp" /* Warp */]: {
|
|
75
|
+
name: "Warp",
|
|
76
|
+
description: "Warp is a code editor that uses the Warp API.",
|
|
77
|
+
website: "https://warp.com"
|
|
78
|
+
},
|
|
79
|
+
["gemini-cli" /* GeminiCli */]: {
|
|
80
|
+
name: "Gemini CLI",
|
|
81
|
+
description: "Gemini CLI is a code editor that uses the Gemini CLI API.",
|
|
82
|
+
website: "https://gemini-cli.com"
|
|
83
|
+
},
|
|
84
|
+
["goose" /* Goose */]: {
|
|
85
|
+
name: "Goose",
|
|
86
|
+
description: "Goose is a code editor that uses the Goose API.",
|
|
87
|
+
website: "https://goose.com"
|
|
88
|
+
},
|
|
89
|
+
["zed" /* Zed */]: {
|
|
90
|
+
name: "Zed",
|
|
91
|
+
description: "Zed is a code editor that uses the Zed API.",
|
|
92
|
+
website: "https://zed.com"
|
|
93
|
+
},
|
|
94
|
+
["opencode" /* Opencode */]: {
|
|
95
|
+
name: "Opencode",
|
|
96
|
+
description: "Opencode is a code editor that uses the Opencode API.",
|
|
97
|
+
website: "https://opencode.com"
|
|
98
|
+
}
|
|
99
|
+
};
|
|
100
|
+
|
|
101
|
+
// src/install/1-get-client/index.ts
|
|
102
|
+
var getClient = async ({ client: flagClient }) => {
|
|
103
|
+
const parsedClient = z.enum(Clients).safeParse(flagClient);
|
|
104
|
+
if (parsedClient.success) {
|
|
105
|
+
return parsedClient.data;
|
|
106
|
+
}
|
|
107
|
+
if (flagClient) {
|
|
108
|
+
log2.error(`${flagClient} is not a valid client. Please select a client`);
|
|
109
|
+
}
|
|
110
|
+
const client = await select({
|
|
111
|
+
message: "Where would you like to install the x402scan MCP server?",
|
|
112
|
+
options: Object.values(Clients).map((client2) => {
|
|
113
|
+
const metadata = clientMetadata[client2];
|
|
114
|
+
return {
|
|
115
|
+
label: metadata.name,
|
|
116
|
+
value: client2
|
|
117
|
+
};
|
|
118
|
+
}),
|
|
119
|
+
maxItems: 7
|
|
120
|
+
});
|
|
121
|
+
const parsedClientSelection = z.enum(Clients).safeParse(client);
|
|
122
|
+
if (parsedClientSelection.success) {
|
|
123
|
+
return parsedClientSelection.data;
|
|
124
|
+
}
|
|
125
|
+
outro(chalk.bold.red("No MCP client selected"));
|
|
126
|
+
process.exit(0);
|
|
127
|
+
};
|
|
128
|
+
|
|
129
|
+
// src/install/2-add-server/index.ts
|
|
130
|
+
import fs3 from "fs";
|
|
131
|
+
import chalk2 from "chalk";
|
|
132
|
+
import { log as clackLog, confirm, outro as outro2, stream } from "@clack/prompts";
|
|
133
|
+
|
|
134
|
+
// src/install/2-add-server/lib/client-config-file.ts
|
|
135
|
+
import os2 from "os";
|
|
136
|
+
import path2 from "path";
|
|
137
|
+
import process3 from "process";
|
|
138
|
+
import fs2 from "fs";
|
|
139
|
+
|
|
140
|
+
// src/install/2-add-server/lib/platforms.ts
|
|
141
|
+
import os from "os";
|
|
142
|
+
import path from "path";
|
|
143
|
+
import process2 from "process";
|
|
144
|
+
import z2 from "zod";
|
|
145
|
+
var Platforms = /* @__PURE__ */ ((Platforms2) => {
|
|
146
|
+
Platforms2["Windows"] = "win32";
|
|
147
|
+
Platforms2["MacOS"] = "darwin";
|
|
148
|
+
Platforms2["Linux"] = "linux";
|
|
149
|
+
return Platforms2;
|
|
150
|
+
})(Platforms || {});
|
|
151
|
+
var getPlatformPath = () => {
|
|
152
|
+
const platform = z2.enum(Platforms).safeParse(process2.platform);
|
|
153
|
+
if (!platform.success) {
|
|
154
|
+
throw new Error(`Invalid platform: ${process2.platform}`);
|
|
155
|
+
}
|
|
156
|
+
const homeDir = os.homedir();
|
|
157
|
+
switch (platform.data) {
|
|
158
|
+
case "win32" /* Windows */:
|
|
159
|
+
return {
|
|
160
|
+
baseDir: process2.env.APPDATA ?? path.join(homeDir, "AppData", "Roaming"),
|
|
161
|
+
vscodePath: path.join("Code", "User")
|
|
162
|
+
};
|
|
163
|
+
case "darwin" /* MacOS */:
|
|
164
|
+
return {
|
|
165
|
+
baseDir: path.join(homeDir, "Library", "Application Support"),
|
|
166
|
+
vscodePath: path.join("Code", "User")
|
|
167
|
+
};
|
|
168
|
+
case "linux" /* Linux */:
|
|
169
|
+
return {
|
|
170
|
+
baseDir: process2.env.XDG_CONFIG_HOME ?? path.join(homeDir, ".config"),
|
|
171
|
+
vscodePath: path.join("Code/User")
|
|
172
|
+
};
|
|
173
|
+
default:
|
|
174
|
+
throw new Error(`Invalid platform: ${process2.platform}`);
|
|
175
|
+
}
|
|
176
|
+
};
|
|
177
|
+
|
|
178
|
+
// src/install/2-add-server/lib/file-types.ts
|
|
179
|
+
import fs from "fs";
|
|
180
|
+
import * as TOML from "@iarna/toml";
|
|
181
|
+
import yaml from "js-yaml";
|
|
182
|
+
import * as jsonc from "jsonc-parser";
|
|
183
|
+
var parseClientConfig = ({ format, path: path3 }) => {
|
|
184
|
+
const fileContent = fs.readFileSync(path3, "utf8");
|
|
185
|
+
let config = {};
|
|
186
|
+
if (format === "yaml" /* YAML */) {
|
|
187
|
+
config = yaml.load(fileContent);
|
|
188
|
+
} else if (format === "toml" /* TOML */) {
|
|
189
|
+
config = TOML.parse(fileContent);
|
|
190
|
+
} else if (path3.endsWith(".jsonc")) {
|
|
191
|
+
config = jsonc.parse(fileContent);
|
|
192
|
+
} else {
|
|
193
|
+
config = JSON.parse(fileContent);
|
|
194
|
+
}
|
|
195
|
+
return {
|
|
196
|
+
config,
|
|
197
|
+
fileContent
|
|
198
|
+
};
|
|
199
|
+
};
|
|
200
|
+
var serializeClientConfig = ({ format, path: path3 }, config, originalContent) => {
|
|
201
|
+
if (format === "yaml" /* YAML */) {
|
|
202
|
+
return yaml.dump(config, {
|
|
203
|
+
indent: 2,
|
|
204
|
+
lineWidth: -1,
|
|
205
|
+
noRefs: true
|
|
206
|
+
});
|
|
207
|
+
}
|
|
208
|
+
if (format === "toml" /* TOML */) {
|
|
209
|
+
return TOML.stringify(config);
|
|
210
|
+
}
|
|
211
|
+
if (path3.endsWith(".jsonc") && originalContent) {
|
|
212
|
+
try {
|
|
213
|
+
const editedContent = originalContent;
|
|
214
|
+
const modifications = [];
|
|
215
|
+
for (const key of Object.keys(config)) {
|
|
216
|
+
const path4 = [key];
|
|
217
|
+
const edits = jsonc.modify(editedContent, path4, config[key], {
|
|
218
|
+
formattingOptions: { tabSize: 2, insertSpaces: true }
|
|
219
|
+
});
|
|
220
|
+
modifications.push(...edits);
|
|
221
|
+
}
|
|
222
|
+
return jsonc.applyEdits(originalContent, modifications);
|
|
223
|
+
} catch (error) {
|
|
224
|
+
console.log(
|
|
225
|
+
`Error applying JSONC edits: ${error instanceof Error ? error.message : String(error)}`
|
|
226
|
+
);
|
|
227
|
+
console.log("Falling back to JSON.stringify (comments will be lost)");
|
|
228
|
+
return JSON.stringify(config, null, 2);
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
return JSON.stringify(config, null, 2);
|
|
232
|
+
};
|
|
233
|
+
var stringifyObject = (config, format) => {
|
|
234
|
+
if (format === "yaml" /* YAML */) {
|
|
235
|
+
return yaml.dump(config, {
|
|
236
|
+
indent: 2,
|
|
237
|
+
lineWidth: -1,
|
|
238
|
+
noRefs: true
|
|
239
|
+
});
|
|
240
|
+
}
|
|
241
|
+
if (format === "toml" /* TOML */) {
|
|
242
|
+
return TOML.stringify(config);
|
|
243
|
+
}
|
|
244
|
+
return JSON.stringify(config, null, 2);
|
|
245
|
+
};
|
|
246
|
+
|
|
247
|
+
// src/install/2-add-server/lib/client-config-file.ts
|
|
248
|
+
var getClientConfigFile = (client) => {
|
|
249
|
+
const homeDir = os2.homedir();
|
|
250
|
+
const { baseDir, vscodePath } = getPlatformPath();
|
|
251
|
+
switch (client) {
|
|
252
|
+
case "claude" /* Claude */:
|
|
253
|
+
return {
|
|
254
|
+
path: path2.join(baseDir, "Claude", "claude_desktop_config.json"),
|
|
255
|
+
configKey: "mcpServers",
|
|
256
|
+
format: "json" /* JSON */
|
|
257
|
+
};
|
|
258
|
+
case "cline" /* Cline */:
|
|
259
|
+
return {
|
|
260
|
+
path: path2.join(
|
|
261
|
+
baseDir,
|
|
262
|
+
vscodePath,
|
|
263
|
+
"globalStorage",
|
|
264
|
+
"saoudrizwan.claude-dev",
|
|
265
|
+
"settings",
|
|
266
|
+
"cline_mcp_settings.json"
|
|
267
|
+
),
|
|
268
|
+
configKey: "mcpServers",
|
|
269
|
+
format: "json" /* JSON */
|
|
270
|
+
};
|
|
271
|
+
case "roo-cline" /* RooCline */:
|
|
272
|
+
return {
|
|
273
|
+
path: path2.join(
|
|
274
|
+
baseDir,
|
|
275
|
+
vscodePath,
|
|
276
|
+
"globalStorage",
|
|
277
|
+
"rooveterinaryinc.roo-cline",
|
|
278
|
+
"settings",
|
|
279
|
+
"mcp_settings.json"
|
|
280
|
+
),
|
|
281
|
+
configKey: "mcpServers",
|
|
282
|
+
format: "json" /* JSON */
|
|
283
|
+
};
|
|
284
|
+
case "windsurf" /* Windsurf */:
|
|
285
|
+
return {
|
|
286
|
+
path: path2.join(homeDir, ".codeium", "windsurf", "mcp_config.json"),
|
|
287
|
+
configKey: "mcpServers",
|
|
288
|
+
format: "json" /* JSON */
|
|
289
|
+
};
|
|
290
|
+
case "cursor" /* Cursor */:
|
|
291
|
+
return {
|
|
292
|
+
path: path2.join(homeDir, ".cursor", "mcp.json"),
|
|
293
|
+
configKey: "mcpServers",
|
|
294
|
+
format: "json" /* JSON */
|
|
295
|
+
};
|
|
296
|
+
case "warp" /* Warp */:
|
|
297
|
+
return {
|
|
298
|
+
path: "no-local-config",
|
|
299
|
+
// it's okay this isn't a real path, we never use it
|
|
300
|
+
configKey: "mcpServers",
|
|
301
|
+
format: "json" /* JSON */
|
|
302
|
+
};
|
|
303
|
+
case "gemini-cli" /* GeminiCli */:
|
|
304
|
+
return {
|
|
305
|
+
path: path2.join(homeDir, ".gemini", "settings.json"),
|
|
306
|
+
configKey: "mcpServers",
|
|
307
|
+
format: "json" /* JSON */
|
|
308
|
+
};
|
|
309
|
+
case "vscode" /* Vscode */:
|
|
310
|
+
return {
|
|
311
|
+
path: path2.join(baseDir, vscodePath, "mcp.json"),
|
|
312
|
+
configKey: "mcpServers",
|
|
313
|
+
format: "json" /* JSON */
|
|
314
|
+
};
|
|
315
|
+
case "claude-code" /* ClaudeCode */:
|
|
316
|
+
return {
|
|
317
|
+
path: path2.join(homeDir, ".claude.json"),
|
|
318
|
+
configKey: "mcpServers",
|
|
319
|
+
format: "json" /* JSON */
|
|
320
|
+
};
|
|
321
|
+
case "goose" /* Goose */:
|
|
322
|
+
return {
|
|
323
|
+
path: path2.join(homeDir, ".config", "goose", "config.yaml"),
|
|
324
|
+
configKey: "extensions",
|
|
325
|
+
format: "yaml" /* YAML */
|
|
326
|
+
};
|
|
327
|
+
case "zed" /* Zed */:
|
|
328
|
+
return {
|
|
329
|
+
path: process3.platform === "win32" ? path2.join(
|
|
330
|
+
process3.env.APPDATA ?? path2.join(homeDir, "AppData", "Roaming"),
|
|
331
|
+
"Zed",
|
|
332
|
+
"settings.json"
|
|
333
|
+
) : path2.join(homeDir, ".config", "zed", "settings.json"),
|
|
334
|
+
configKey: "context_servers",
|
|
335
|
+
format: "json" /* JSON */
|
|
336
|
+
};
|
|
337
|
+
case "codex" /* Codex */:
|
|
338
|
+
return {
|
|
339
|
+
path: path2.join(
|
|
340
|
+
process3.env.CODEX_HOME ?? path2.join(homeDir, ".codex"),
|
|
341
|
+
"config.toml"
|
|
342
|
+
),
|
|
343
|
+
configKey: "mcp_servers",
|
|
344
|
+
format: "toml" /* TOML */
|
|
345
|
+
};
|
|
346
|
+
case "opencode" /* Opencode */: {
|
|
347
|
+
const jsonPath = path2.join(
|
|
348
|
+
homeDir,
|
|
349
|
+
".config",
|
|
350
|
+
"opencode",
|
|
351
|
+
"opencode.json"
|
|
352
|
+
);
|
|
353
|
+
const jsoncPath = jsonPath.replace(".json", ".jsonc");
|
|
354
|
+
if (fs2.existsSync(jsoncPath)) {
|
|
355
|
+
log.info(`Found .jsonc file for OpenCode, using: ${jsoncPath}`);
|
|
356
|
+
return {
|
|
357
|
+
path: jsoncPath,
|
|
358
|
+
configKey: "mcp",
|
|
359
|
+
format: "json" /* JSON */
|
|
360
|
+
};
|
|
361
|
+
}
|
|
362
|
+
return {
|
|
363
|
+
path: jsonPath,
|
|
364
|
+
configKey: "mcp",
|
|
365
|
+
format: "json" /* JSON */
|
|
366
|
+
};
|
|
367
|
+
}
|
|
368
|
+
default:
|
|
369
|
+
throw new Error(`Unknown client: ${String(client)}`);
|
|
370
|
+
}
|
|
371
|
+
};
|
|
372
|
+
|
|
373
|
+
// src/install/2-add-server/lib/nested-values.ts
|
|
374
|
+
var getNestedValue = (obj, path3) => {
|
|
375
|
+
const keys = path3.split(".");
|
|
376
|
+
let current = obj;
|
|
377
|
+
for (const key of keys) {
|
|
378
|
+
if (current && typeof current === "object" && key in current) {
|
|
379
|
+
current = current[key];
|
|
380
|
+
} else {
|
|
381
|
+
return void 0;
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
return current;
|
|
385
|
+
};
|
|
386
|
+
var setNestedValue = (obj, path3, value) => {
|
|
387
|
+
const keys = path3.split(".");
|
|
388
|
+
const lastKey = keys.pop();
|
|
389
|
+
if (!lastKey) return;
|
|
390
|
+
const target = keys.reduce((current, key) => {
|
|
391
|
+
current[key] ??= {};
|
|
392
|
+
return current[key];
|
|
393
|
+
}, obj);
|
|
394
|
+
target[lastKey] = value;
|
|
395
|
+
};
|
|
396
|
+
|
|
397
|
+
// src/install/2-add-server/index.ts
|
|
398
|
+
var getMcpConfig = (globalFlags) => {
|
|
399
|
+
if (globalFlags.dev) {
|
|
400
|
+
return {
|
|
401
|
+
serverName: "x402",
|
|
402
|
+
command: "node",
|
|
403
|
+
args: [`${process.cwd()}/dist/index.js`, "--dev"]
|
|
404
|
+
};
|
|
405
|
+
}
|
|
406
|
+
return {
|
|
407
|
+
serverName: "x402",
|
|
408
|
+
command: "npx",
|
|
409
|
+
args: ["-y", "@x402scan/mcp@latest"]
|
|
410
|
+
};
|
|
411
|
+
};
|
|
412
|
+
async function addServer(client, globalFlags) {
|
|
413
|
+
const { serverName, command, args } = getMcpConfig(globalFlags);
|
|
414
|
+
if (client === "warp" /* Warp */) {
|
|
415
|
+
clackLog.info(
|
|
416
|
+
chalk2.bold.yellow("Warp requires a manual installation through their UI.")
|
|
417
|
+
);
|
|
418
|
+
clackLog.message(
|
|
419
|
+
"Please copy the following configuration object and add it to your Warp MCP config:"
|
|
420
|
+
);
|
|
421
|
+
console.log();
|
|
422
|
+
console.log(
|
|
423
|
+
JSON.stringify(
|
|
424
|
+
{
|
|
425
|
+
[serverName]: {
|
|
426
|
+
command,
|
|
427
|
+
args,
|
|
428
|
+
working_directory: null,
|
|
429
|
+
start_on_launch: true
|
|
430
|
+
}
|
|
431
|
+
},
|
|
432
|
+
null,
|
|
433
|
+
2
|
|
434
|
+
)
|
|
435
|
+
);
|
|
436
|
+
console.log();
|
|
437
|
+
clackLog.message(
|
|
438
|
+
`Read Warp's documentation at https://docs.warp.dev/knowledge-and-collaboration/mcp`
|
|
439
|
+
);
|
|
440
|
+
const addedToWarp = await confirm({
|
|
441
|
+
message: "Did you add the MCP server to your Warp config?"
|
|
442
|
+
});
|
|
443
|
+
if (!addedToWarp) {
|
|
444
|
+
throw new Error("Warp MCP server not added");
|
|
445
|
+
}
|
|
446
|
+
}
|
|
447
|
+
const clientFileTarget = getClientConfigFile(client);
|
|
448
|
+
const { name } = clientMetadata[client];
|
|
449
|
+
try {
|
|
450
|
+
let config = {};
|
|
451
|
+
let content = void 0;
|
|
452
|
+
log.info(`Checking if config file exists at: ${clientFileTarget.path}`);
|
|
453
|
+
if (!fs3.existsSync(clientFileTarget.path)) {
|
|
454
|
+
log.info("Config file not found, creating default empty config");
|
|
455
|
+
setNestedValue(config, clientFileTarget.configKey, {});
|
|
456
|
+
log.info("Config created successfully");
|
|
457
|
+
await wait({
|
|
458
|
+
startText: "Locating config file",
|
|
459
|
+
stopText: `No config found, creating default empty config`,
|
|
460
|
+
ms: 1e3
|
|
461
|
+
});
|
|
462
|
+
} else {
|
|
463
|
+
log.info("Config file found, reading config file content");
|
|
464
|
+
const { config: rawConfig, fileContent } = parseClientConfig(clientFileTarget);
|
|
465
|
+
config = rawConfig;
|
|
466
|
+
content = fileContent;
|
|
467
|
+
const existingValue = getNestedValue(
|
|
468
|
+
rawConfig,
|
|
469
|
+
clientFileTarget.configKey
|
|
470
|
+
);
|
|
471
|
+
if (!existingValue) {
|
|
472
|
+
setNestedValue(rawConfig, clientFileTarget.configKey, {});
|
|
473
|
+
}
|
|
474
|
+
log.info(
|
|
475
|
+
`Config loaded successfully: ${JSON.stringify(rawConfig, null, 2)}`
|
|
476
|
+
);
|
|
477
|
+
await wait({
|
|
478
|
+
startText: `Locating config file`,
|
|
479
|
+
stopText: `Config loaded from ${clientFileTarget.path}`,
|
|
480
|
+
ms: 1e3
|
|
481
|
+
});
|
|
482
|
+
}
|
|
483
|
+
const servers = getNestedValue(config, clientFileTarget.configKey);
|
|
484
|
+
if (!servers || typeof servers !== "object") {
|
|
485
|
+
log.error(`Invalid ${clientFileTarget.configKey} structure in config`);
|
|
486
|
+
clackLog.error(
|
|
487
|
+
chalk2.bold.red(
|
|
488
|
+
`Invalid ${clientFileTarget.configKey} structure in config`
|
|
489
|
+
)
|
|
490
|
+
);
|
|
491
|
+
throw new Error(`Invalid ${clientFileTarget.configKey} structure`);
|
|
492
|
+
}
|
|
493
|
+
if (client === "goose" /* Goose */) {
|
|
494
|
+
servers[serverName] = {
|
|
495
|
+
name: serverName,
|
|
496
|
+
cmd: command,
|
|
497
|
+
args,
|
|
498
|
+
enabled: true,
|
|
499
|
+
envs: {},
|
|
500
|
+
type: "stdio",
|
|
501
|
+
timeout: 300
|
|
502
|
+
};
|
|
503
|
+
} else if (client === "zed" /* Zed */) {
|
|
504
|
+
servers[serverName] = {
|
|
505
|
+
source: "custom",
|
|
506
|
+
command,
|
|
507
|
+
args,
|
|
508
|
+
env: {}
|
|
509
|
+
};
|
|
510
|
+
} else if (client === "opencode" /* Opencode */) {
|
|
511
|
+
servers[serverName] = {
|
|
512
|
+
type: "local",
|
|
513
|
+
command,
|
|
514
|
+
args,
|
|
515
|
+
enabled: true,
|
|
516
|
+
environment: {}
|
|
517
|
+
};
|
|
518
|
+
} else {
|
|
519
|
+
servers[serverName] = {
|
|
520
|
+
command,
|
|
521
|
+
args
|
|
522
|
+
};
|
|
523
|
+
}
|
|
524
|
+
await new Promise((resolve) => setTimeout(resolve, 1e3));
|
|
525
|
+
clackLog.step(`The following will be added to ${chalk2.bold.underline(clientFileTarget.path)}`);
|
|
526
|
+
const configStr = formatDiffByFormat(
|
|
527
|
+
{
|
|
528
|
+
[clientFileTarget.configKey]: {
|
|
529
|
+
[serverName]: servers[serverName]
|
|
530
|
+
}
|
|
531
|
+
},
|
|
532
|
+
clientFileTarget.format
|
|
533
|
+
);
|
|
534
|
+
await stream.message(
|
|
535
|
+
(async function* () {
|
|
536
|
+
for (const num of Array.from(
|
|
537
|
+
{ length: configStr.length },
|
|
538
|
+
(_, i) => i
|
|
539
|
+
)) {
|
|
540
|
+
const char = configStr[num];
|
|
541
|
+
yield char;
|
|
542
|
+
if (!["\n", " ", "\u2500", "\u256E", "\u256D", "\u2570", "\u256F", "\u2502"].includes(char)) {
|
|
543
|
+
await new Promise((resolve) => setTimeout(resolve, 5));
|
|
544
|
+
} else {
|
|
545
|
+
await new Promise((resolve) => setTimeout(resolve, 2));
|
|
546
|
+
}
|
|
547
|
+
}
|
|
548
|
+
})()
|
|
549
|
+
);
|
|
550
|
+
await new Promise((resolve) => setTimeout(resolve, 1e3));
|
|
551
|
+
const isConfirmed = await confirm({
|
|
552
|
+
message: `Would you like to proceed?`,
|
|
553
|
+
active: "Install MCP",
|
|
554
|
+
inactive: "Cancel"
|
|
555
|
+
});
|
|
556
|
+
if (isConfirmed !== true) {
|
|
557
|
+
outro2(chalk2.bold.red("Installation cancelled"));
|
|
558
|
+
process.exit(0);
|
|
559
|
+
}
|
|
560
|
+
const configContent = serializeClientConfig(
|
|
561
|
+
clientFileTarget,
|
|
562
|
+
config,
|
|
563
|
+
content
|
|
564
|
+
);
|
|
565
|
+
fs3.writeFileSync(clientFileTarget.path, configContent);
|
|
566
|
+
clackLog.success(chalk2.bold.green(`Added x402scan MCP to ${name}`));
|
|
567
|
+
} catch (e) {
|
|
568
|
+
clackLog.error(chalk2.bold.red(`Error adding x402scan MCP to ${name}`));
|
|
569
|
+
throw e;
|
|
570
|
+
}
|
|
571
|
+
}
|
|
572
|
+
var formatDiffByFormat = (obj, format) => {
|
|
573
|
+
const str = stringifyObject(obj, format);
|
|
574
|
+
switch (format) {
|
|
575
|
+
case "json" /* JSON */: {
|
|
576
|
+
const numLines = str.split("\n").length;
|
|
577
|
+
return str.split("\n").map((line, index) => {
|
|
578
|
+
const diffLines = [0, 1, numLines - 2, numLines - 1];
|
|
579
|
+
const isDiffLine = !diffLines.includes(index);
|
|
580
|
+
if (isDiffLine) {
|
|
581
|
+
return `${chalk2.bold.green(`+ ${line.slice(2)}`)}`;
|
|
582
|
+
}
|
|
583
|
+
return line;
|
|
584
|
+
}).join("\n");
|
|
585
|
+
}
|
|
586
|
+
case "yaml" /* YAML */: {
|
|
587
|
+
return str.split("\n").map((line, index) => {
|
|
588
|
+
const diffLines = [0, 1, str.length - 2, str.length - 1];
|
|
589
|
+
const isDiffLine = !diffLines.includes(index);
|
|
590
|
+
if (isDiffLine) {
|
|
591
|
+
return `${chalk2.bold.green(`+ ${line.slice(2)}`)}`;
|
|
592
|
+
}
|
|
593
|
+
return line;
|
|
594
|
+
}).join("\n");
|
|
595
|
+
}
|
|
596
|
+
case "toml" /* TOML */: {
|
|
597
|
+
return str.split("\n").filter((line) => line.trim() !== "").map((line) => {
|
|
598
|
+
return `${chalk2.bold.green(`+ ${line.trim()}`)}`;
|
|
599
|
+
}).join("\n");
|
|
600
|
+
}
|
|
601
|
+
}
|
|
602
|
+
};
|
|
603
|
+
|
|
604
|
+
// src/install/3-add-funds/index.ts
|
|
605
|
+
import chalk3 from "chalk";
|
|
606
|
+
import { log as log3 } from "@clack/prompts";
|
|
607
|
+
var addFunds = async ({ flags, address, isNew }) => {
|
|
608
|
+
if (isNew) {
|
|
609
|
+
await new Promise((resolve) => setTimeout(resolve, 1e3));
|
|
610
|
+
log3.info("To use paid API tools, you will need USDC in your wallet.");
|
|
611
|
+
await promptDeposit(address, flags);
|
|
612
|
+
} else {
|
|
613
|
+
const balance = await getUSDCBalance({ address });
|
|
614
|
+
await wait({
|
|
615
|
+
startText: "Checking balance...",
|
|
616
|
+
stopText: `Balance: ${chalk3.bold(`${balance} USDC`)} `,
|
|
617
|
+
ms: 1e3
|
|
618
|
+
});
|
|
619
|
+
if (balance < 1) {
|
|
620
|
+
log3.warning(
|
|
621
|
+
chalk3.bold(
|
|
622
|
+
`Your balance is low (${balance} USDC). Consider topping up.`
|
|
623
|
+
)
|
|
624
|
+
);
|
|
625
|
+
await promptDeposit(address, flags);
|
|
626
|
+
}
|
|
627
|
+
}
|
|
628
|
+
};
|
|
629
|
+
|
|
630
|
+
// src/install/index.ts
|
|
631
|
+
import { intro, outro as outro3 } from "@clack/prompts";
|
|
632
|
+
import chalk4 from "chalk";
|
|
633
|
+
var installMcpServer = async (flags) => {
|
|
634
|
+
const {
|
|
635
|
+
account: { address },
|
|
636
|
+
isNew
|
|
637
|
+
} = await getWallet();
|
|
638
|
+
intro(chalk4.green.bold(`Install x402scan MCP`));
|
|
639
|
+
const client = await getClient(flags);
|
|
640
|
+
await addServer(client, flags);
|
|
641
|
+
await addFunds({ flags, address, isNew });
|
|
642
|
+
outro3(chalk4.bold.green("Your x402scan MCP server is ready to use!"));
|
|
643
|
+
};
|
|
644
|
+
export {
|
|
645
|
+
installMcpServer
|
|
646
|
+
};
|