x402-proxy 0.8.5 → 0.9.0

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/CHANGELOG.md CHANGED
@@ -7,6 +7,28 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [0.9.0] - 2026-03-25
11
+
12
+ ### Added
13
+ - `mcp add` command - onboarding wizard to install MCP servers into Claude Code, Cursor, VS Code, and 16+ other AI clients via `@getmcp/generators`
14
+ - Auto-detects installed AI clients and highlights them in the selection list
15
+ - Shows config diff preview with green markers before writing
16
+ - Prompts to overwrite if server name already exists (shows current config)
17
+ - Wallet setup runs automatically if not yet configured
18
+ - Balance check and funding hints shown after successful install
19
+ - `-c` / `--config-dir` global flag to override config directory for all commands
20
+ - Custom config directory injected as `XDG_CONFIG_HOME` env var into generated MCP server configs
21
+ - Tempo address shown alongside Base address in setup wizard
22
+
23
+ ### Fixed
24
+ - Solana USDC balance shows `0` instead of `?` for fresh wallets (non-existent ATA means zero balance, not unknown)
25
+ - MPP payment protocol description corrected from "streaming micropayments" to "machine payments over HTTP 402"
26
+
27
+ ## [0.8.6] - 2026-03-25
28
+
29
+ ### Fixed
30
+ - Example URLs in help output and setup wizard: `/user/` corrected to `/users/` (was returning 404)
31
+
10
32
  ## [0.8.5] - 2026-03-24
11
33
 
12
34
  ### Fixed
@@ -241,7 +263,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
241
263
  - `appendHistory` / `readHistory` / `calcSpend` - JSONL transaction history
242
264
  - Re-exports from `@x402/fetch`, `@x402/svm`, `@x402/evm`
243
265
 
244
- [Unreleased]: https://github.com/cascade-protocol/x402-proxy/compare/v0.8.4...HEAD
266
+ [Unreleased]: https://github.com/cascade-protocol/x402-proxy/compare/v0.9.0...HEAD
267
+ [0.9.0]: https://github.com/cascade-protocol/x402-proxy/compare/v0.8.6...v0.9.0
268
+ [0.8.6]: https://github.com/cascade-protocol/x402-proxy/compare/v0.8.5...v0.8.6
245
269
  [0.8.5]: https://github.com/cascade-protocol/x402-proxy/compare/v0.8.4...v0.8.5
246
270
  [0.8.4]: https://github.com/cascade-protocol/x402-proxy/compare/v0.8.3...v0.8.4
247
271
  [0.8.3]: https://github.com/cascade-protocol/x402-proxy/compare/v0.8.2...v0.8.3
package/README.md CHANGED
@@ -14,7 +14,19 @@ No wallet? It'll walk you through setup automatically. One mnemonic derives both
14
14
 
15
15
  ## MCP Proxy
16
16
 
17
- Let your AI agent consume any paid MCP server. Configure in Claude, Cursor, or any MCP client:
17
+ Let your AI agent consume any paid MCP server.
18
+
19
+ ### Quick setup
20
+
21
+ ```bash
22
+ npx x402-proxy mcp add my-service https://mcp.example.com/sse
23
+ ```
24
+
25
+ Auto-detects installed AI clients (Claude Code, Cursor, VS Code, and 16+ others), shows a config preview, and writes it for you. Runs wallet setup if needed.
26
+
27
+ ### Manual config
28
+
29
+ Or add to your client config directly:
18
30
 
19
31
  ```json
20
32
  {
@@ -67,6 +79,7 @@ $ npx x402-proxy https://api.example.com/data | jq '.results'
67
79
  ```bash
68
80
  $ npx x402-proxy <url> # paid HTTP request (default command)
69
81
  $ npx x402-proxy mcp <url> # MCP stdio proxy for agents
82
+ $ npx x402-proxy mcp add <name> <url> # install MCP server into your AI client
70
83
  $ npx x402-proxy setup # onboarding wizard
71
84
  $ npx x402-proxy status # config + wallet + spend summary
72
85
  $ npx x402-proxy config # show current configuration
@@ -77,7 +90,7 @@ $ npx x402-proxy wallet history # payment history
77
90
  $ npx x402-proxy wallet export-key <target> # bare key/mnemonic to stdout (evm|solana|mnemonic)
78
91
  ```
79
92
 
80
- All commands support `--help` for details.
93
+ All commands support `--help` for details. Use `-c <dir>` to override the config directory.
81
94
 
82
95
  ## Wallet
83
96
 
package/dist/bin/cli.js CHANGED
@@ -1,10 +1,13 @@
1
1
  #!/usr/bin/env node
2
- import { a as getHistoryPath, c as loadConfig, i as getConfigDirShort, l as loadWalletFile, s as isConfigured, u as saveConfig } from "../derive-BR6N1ZjI.js";
3
- import { _ as error, b as warn, c as resolveWallet, d as displayNetwork, f as formatAmount, g as dim, h as readHistory, l as appendHistory, m as formatUsdcValue, o as walletInfoCommand, p as formatTxLine, s as buildX402Client, u as calcSpend, v as info, y as isTTY } from "../wallet-BiX5_XFY.js";
4
- import { n as setupCommand } from "../setup-Di_b5Vp9.js";
5
- import { n as statusCommand } from "../status-DvSu8reM.js";
2
+ import { a as getHistoryPath, c as loadConfig, i as getConfigDirShort, l as loadWalletFile, s as isConfigured, u as saveConfig } from "../derive-CAYmX-Yz.js";
3
+ import { _ as error, b as warn, c as resolveWallet, d as displayNetwork, f as formatAmount, g as dim, h as readHistory, l as appendHistory, m as formatUsdcValue, n as fetchAllBalances, o as walletInfoCommand, p as formatTxLine, s as buildX402Client, u as calcSpend, v as info, y as isTTY } from "../wallet-DZsXptY7.js";
4
+ import { n as setupCommand, t as runSetup } from "../setup-BjyoqzT3.js";
5
+ import { n as statusCommand } from "../status-D3f5IVf6.js";
6
+ import { dirname, join, normalize, resolve } from "node:path";
6
7
  import { buildApplication, buildCommand, buildRouteMap, run } from "@stricli/core";
7
8
  import pc from "picocolors";
9
+ import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
10
+ import { homedir } from "node:os";
8
11
  import { decodePaymentResponseHeader, wrapFetchWithPayment } from "@x402/fetch";
9
12
  import { base58 } from "@scure/base";
10
13
  import * as prompts from "@clack/prompts";
@@ -310,7 +313,7 @@ const fetchCommand = buildCommand({
310
313
  fullDescription: `Make a paid HTTP request. Payment is automatic when the server returns 402.
311
314
 
312
315
  Examples:
313
- $ x402-proxy https://twitter.surf.cascade.fyi/user/cascade_fyi
316
+ $ x402-proxy https://twitter.surf.cascade.fyi/users/cascade_fyi
314
317
  $ x402-proxy -X POST -d '{"url":"https://x402.org"}' https://web.surf.cascade.fyi/v1/crawl
315
318
  $ x402-proxy https://api.example.com/data | jq '.results'`
316
319
  },
@@ -398,7 +401,7 @@ Examples:
398
401
  };
399
402
  if (!url) {
400
403
  if (isConfigured()) {
401
- const { displayStatus } = await import("../status-DjudJ6fD.js");
404
+ const { displayStatus } = await import("../status-BkURZYDA.js");
402
405
  await displayStatus();
403
406
  console.log();
404
407
  console.log(pc.dim(" Commands:"));
@@ -408,7 +411,7 @@ Examples:
408
411
  console.log(` ${pc.cyan("$ npx x402-proxy wallet")} Addresses and balances`);
409
412
  console.log(` ${pc.cyan("$ npx x402-proxy wallet history")} Full payment history`);
410
413
  console.log();
411
- console.log(pc.dim(" try: ") + pc.cyan("$ npx x402-proxy https://twitter.surf.cascade.fyi/user/cascade_fyi"));
414
+ console.log(pc.dim(" try: ") + pc.cyan("$ npx x402-proxy https://twitter.surf.cascade.fyi/users/cascade_fyi"));
412
415
  console.log();
413
416
  console.log(pc.dim(" https://github.com/cascade-protocol/x402-proxy"));
414
417
  console.log();
@@ -450,7 +453,7 @@ Examples:
450
453
  process.exit(1);
451
454
  }
452
455
  dim(" No wallet found. Let's set one up first.\n");
453
- const { runSetup } = await import("../setup-CJwYRd78.js");
456
+ const { runSetup } = await import("../setup-CJgw4opQ.js");
454
457
  await runSetup();
455
458
  console.log();
456
459
  wallet = resolveWallet();
@@ -463,7 +466,7 @@ Examples:
463
466
  verbose(`protocol: ${resolvedProtocol ?? "auto-detect"}, maxDeposit: ${maxDeposit}`);
464
467
  let preferredNetwork = config?.defaultNetwork;
465
468
  if (!preferredNetwork && wallet.evmAddress && wallet.solanaAddress) {
466
- const { fetchAllBalances } = await import("../wallet-BkZ0DOJL.js");
469
+ const { fetchAllBalances } = await import("../wallet-BM0ngyqk.js");
467
470
  const balances = await fetchAllBalances(wallet.evmAddress, wallet.solanaAddress);
468
471
  const evmUsdc = balances.evm ? Number(balances.evm.usdc) : 0;
469
472
  const solUsdc = balances.sol ? Number(balances.sol.usdc) : 0;
@@ -630,7 +633,7 @@ Examples:
630
633
  const hasSolana = accepts.some((a) => a.network.startsWith("solana:"));
631
634
  const hasMpp = detected.mpp;
632
635
  const hasOther = accepts.some((a) => !a.network.startsWith("eip155:") && !a.network.startsWith("solana:"));
633
- const { fetchAllBalances } = await import("../wallet-BkZ0DOJL.js");
636
+ const { fetchAllBalances } = await import("../wallet-BM0ngyqk.js");
634
637
  const balances = await fetchAllBalances(wallet.evmAddress, wallet.solanaAddress);
635
638
  const evmUsdc = hasEvm && balances.evm ? Number(balances.evm.usdc) : 0;
636
639
  const solUsdc = hasSolana && balances.sol ? Number(balances.sol.usdc) : 0;
@@ -840,7 +843,7 @@ Add to your MCP client config (Claude, Cursor, etc.):
840
843
  async function startX402Proxy() {
841
844
  let preferredNetwork = config?.defaultNetwork;
842
845
  if (!preferredNetwork && wallet.evmAddress && wallet.solanaAddress) {
843
- const { fetchAllBalances } = await import("../wallet-BkZ0DOJL.js");
846
+ const { fetchAllBalances } = await import("../wallet-BM0ngyqk.js");
844
847
  const balances = await fetchAllBalances(wallet.evmAddress, wallet.solanaAddress);
845
848
  const evmUsdc = balances.evm ? Number(balances.evm.usdc) : 0;
846
849
  const solUsdc = balances.sol ? Number(balances.sol.usdc) : 0;
@@ -860,7 +863,7 @@ Add to your MCP client config (Claude, Cursor, etc.):
860
863
  }
861
864
  const remoteClient = new Client({
862
865
  name: "x402-proxy",
863
- version: "0.8.5"
866
+ version: "0.9.0"
864
867
  });
865
868
  const x402Mcp = new x402MCPClient(remoteClient, x402PaymentClient, {
866
869
  autoPayment: true,
@@ -898,7 +901,7 @@ Add to your MCP client config (Claude, Cursor, etc.):
898
901
  }
899
902
  const localServer = new Server({
900
903
  name: "x402-proxy",
901
- version: "0.8.5"
904
+ version: "0.9.0"
902
905
  }, { capabilities: {
903
906
  tools: tools.length > 0 ? {} : void 0,
904
907
  resources: remoteResources.length > 0 ? {} : void 0
@@ -993,7 +996,7 @@ Add to your MCP client config (Claude, Cursor, etc.):
993
996
  }));
994
997
  const remoteClient = new Client({
995
998
  name: "x402-proxy",
996
- version: "0.8.5"
999
+ version: "0.9.0"
997
1000
  });
998
1001
  await connectTransport(remoteClient);
999
1002
  const mppClient = McpClient.wrap(remoteClient, { methods: wrappedMethods });
@@ -1008,7 +1011,7 @@ Add to your MCP client config (Claude, Cursor, etc.):
1008
1011
  }
1009
1012
  const localServer = new Server({
1010
1013
  name: "x402-proxy",
1011
- version: "0.8.5"
1014
+ version: "0.9.0"
1012
1015
  }, { capabilities: {
1013
1016
  tools: tools.length > 0 ? {} : void 0,
1014
1017
  resources: remoteResources.length > 0 ? {} : void 0
@@ -1085,6 +1088,189 @@ Add to your MCP client config (Claude, Cursor, etc.):
1085
1088
  }
1086
1089
  });
1087
1090
 
1091
+ //#endregion
1092
+ //#region src/commands/mcp-add.ts
1093
+ function resolvePlatformPath(raw) {
1094
+ let p = raw;
1095
+ if (p.startsWith("~/")) p = join(homedir(), p.slice(2));
1096
+ p = p.replace(/%UserProfile%/gi, homedir());
1097
+ p = p.replace(/%AppData%/gi, process.env.APPDATA ?? join(homedir(), "AppData", "Roaming"));
1098
+ p = p.replace(/%LocalAppData%/gi, process.env.LOCALAPPDATA ?? join(homedir(), "AppData", "Local"));
1099
+ return normalize(p);
1100
+ }
1101
+ function parseConfigFile(path, format) {
1102
+ if (!existsSync(path)) return {};
1103
+ const raw = readFileSync(path, "utf-8").trim();
1104
+ if (!raw) return {};
1105
+ if (format === "json" || format === "jsonc") {
1106
+ const stripped = format === "jsonc" ? raw.replace(/\/\/.*$/gm, "").replace(/\/\*[\s\S]*?\*\//g, "") : raw;
1107
+ return JSON.parse(stripped);
1108
+ }
1109
+ return JSON.parse(raw);
1110
+ }
1111
+ const mcpAddCommand = buildCommand({
1112
+ docs: {
1113
+ brief: "Add an MCP server to your AI client",
1114
+ fullDescription: "Add a remote MCP server to Claude Code, Cursor, VS Code, or other AI clients with automatic x402 payment proxy."
1115
+ },
1116
+ parameters: {
1117
+ flags: {
1118
+ client: {
1119
+ kind: "parsed",
1120
+ brief: "Target client (claude-code, cursor, vscode, etc.)",
1121
+ parse: String,
1122
+ optional: true
1123
+ },
1124
+ yes: {
1125
+ kind: "boolean",
1126
+ brief: "Skip confirmation prompt",
1127
+ default: false
1128
+ }
1129
+ },
1130
+ positional: {
1131
+ kind: "tuple",
1132
+ parameters: [{
1133
+ brief: "Server name",
1134
+ parse: String
1135
+ }, {
1136
+ brief: "Remote MCP server URL",
1137
+ parse: String
1138
+ }]
1139
+ }
1140
+ },
1141
+ async func(flags, name, url) {
1142
+ prompts.intro(pc.cyan("Add MCP server"));
1143
+ try {
1144
+ new URL(url);
1145
+ } catch {
1146
+ prompts.log.error(`Invalid URL: ${url}`);
1147
+ prompts.cancel("Aborted.");
1148
+ process.exit(1);
1149
+ }
1150
+ const serverName = name;
1151
+ if (!isConfigured()) {
1152
+ prompts.log.warn("No wallet configured. Let's set one up first.\n");
1153
+ await runSetup();
1154
+ console.log();
1155
+ prompts.log.step(pc.cyan("Continuing MCP setup..."));
1156
+ }
1157
+ const { generators, getAppIds, generateConfig, deepMerge } = await import("@getmcp/generators");
1158
+ let clientId;
1159
+ if (flags.client) {
1160
+ const appIds = getAppIds();
1161
+ if (!appIds.includes(flags.client)) {
1162
+ prompts.log.error(`Unknown client: ${flags.client}`);
1163
+ prompts.log.info(`Supported: ${appIds.join(", ")}`);
1164
+ prompts.cancel("Aborted.");
1165
+ process.exit(1);
1166
+ }
1167
+ clientId = flags.client;
1168
+ } else {
1169
+ const appIds = getAppIds();
1170
+ const detected = appIds.filter((id) => generators[id].detectInstalled());
1171
+ const selected = await prompts.select({
1172
+ message: "Where would you like to install the MCP server?",
1173
+ options: appIds.map((id) => ({
1174
+ value: id,
1175
+ label: `${generators[id].app.name}${detected.includes(id) ? pc.dim(" (detected)") : ""}`
1176
+ })),
1177
+ initialValue: detected.includes("claude-code") ? "claude-code" : detected[0] ?? "claude-code"
1178
+ });
1179
+ if (prompts.isCancel(selected)) {
1180
+ prompts.cancel("Cancelled.");
1181
+ process.exit(0);
1182
+ }
1183
+ clientId = selected;
1184
+ }
1185
+ const generator = generators[clientId];
1186
+ const globalPaths = generator.app.globalConfigPaths;
1187
+ const platform = process.platform;
1188
+ const rawPath = globalPaths?.[platform];
1189
+ if (!rawPath) {
1190
+ prompts.log.error(`No global config path for ${generator.app.name} on ${platform}`);
1191
+ prompts.cancel("Aborted.");
1192
+ process.exit(1);
1193
+ }
1194
+ const configPath = resolvePlatformPath(rawPath);
1195
+ const configFormat = generator.app.configFormat;
1196
+ const configDirOverride = process.env.X402_PROXY_CONFIG_DIR_OVERRIDE;
1197
+ const generated = generateConfig(clientId, serverName, {
1198
+ command: "npx",
1199
+ args: [
1200
+ "x402-proxy",
1201
+ "mcp",
1202
+ url
1203
+ ],
1204
+ env: configDirOverride ? { XDG_CONFIG_HOME: configDirOverride } : {},
1205
+ transport: "stdio"
1206
+ });
1207
+ let existing;
1208
+ if (configFormat === "yaml") {
1209
+ const { default: YAML } = await import("yaml");
1210
+ if (existsSync(configPath)) {
1211
+ const raw = readFileSync(configPath, "utf-8").trim();
1212
+ existing = raw ? YAML.parse(raw) ?? {} : {};
1213
+ } else existing = {};
1214
+ } else existing = parseConfigFile(configPath, configFormat);
1215
+ const rootKey = Object.keys(generated)[0] ?? "mcpServers";
1216
+ const existingServers = existing[rootKey] ?? {};
1217
+ if (existingServers[serverName]) {
1218
+ prompts.log.warn(`Server ${pc.bold(serverName)} already exists in config`);
1219
+ prompts.log.message(pc.dim(JSON.stringify({ [serverName]: existingServers[serverName] }, null, 2)));
1220
+ const overwrite = await prompts.confirm({ message: "Overwrite?" });
1221
+ if (prompts.isCancel(overwrite) || !overwrite) {
1222
+ prompts.cancel("Cancelled.");
1223
+ process.exit(0);
1224
+ }
1225
+ }
1226
+ prompts.log.info(`Config will be added to ${pc.dim(configPath)}`);
1227
+ const previewLines = generator.serialize(generated).split("\n");
1228
+ const formatted = previewLines.map((line, i) => {
1229
+ if (i === 0 || i === previewLines.length - 1) return line;
1230
+ const trimmed = line.trimStart();
1231
+ if (trimmed.startsWith(`"${rootKey}"`) || trimmed.startsWith(`${rootKey}:`)) return line;
1232
+ return `${pc.green("+")} ${line}`;
1233
+ }).join("\n");
1234
+ prompts.log.message(formatted);
1235
+ if (!flags.yes) {
1236
+ const proceed = await prompts.confirm({ message: "Would you like to proceed?" });
1237
+ if (prompts.isCancel(proceed) || !proceed) {
1238
+ prompts.cancel("Cancelled.");
1239
+ process.exit(0);
1240
+ }
1241
+ }
1242
+ const merged = deepMerge(existing, generated);
1243
+ const dir = dirname(configPath);
1244
+ if (!existsSync(dir)) mkdirSync(dir, { recursive: true });
1245
+ const serialized = generator.serialize(merged);
1246
+ writeFileSync(configPath, serialized.endsWith("\n") ? serialized : `${serialized}\n`);
1247
+ prompts.log.success(`Added ${pc.bold(serverName)} MCP to ${pc.bold(generator.app.name)}`);
1248
+ const wallet = resolveWallet();
1249
+ if (wallet.source !== "none") {
1250
+ const balances = await fetchAllBalances(wallet.evmAddress, wallet.solanaAddress);
1251
+ const evmUsdc = balances.evm ? Number(balances.evm.usdc) : 0;
1252
+ const solUsdc = balances.sol ? Number(balances.sol.usdc) : 0;
1253
+ const tempoUsdc = balances.tempo ? Number(balances.tempo.usdc) : 0;
1254
+ if (evmUsdc === 0 && solUsdc === 0 && tempoUsdc === 0) {
1255
+ prompts.log.warn("Balance: 0 USDC");
1256
+ prompts.log.info("To use paid MCP tools, send USDC to your wallet:");
1257
+ if (wallet.evmAddress) prompts.log.message(` Base: ${pc.cyan(wallet.evmAddress)}`);
1258
+ if (wallet.solanaAddress) prompts.log.message(` Solana: ${pc.cyan(wallet.solanaAddress)}`);
1259
+ } else {
1260
+ const parts = [];
1261
+ if (balances.evm) parts.push(`Base: ${balances.evm.usdc} USDC`);
1262
+ if (balances.sol) parts.push(`Solana: ${balances.sol.usdc} USDC`);
1263
+ if (balances.tempo) parts.push(`Tempo: ${balances.tempo.usdc} USDC`);
1264
+ prompts.log.success(`Balance: ${parts.join(" | ")}`);
1265
+ }
1266
+ }
1267
+ prompts.log.step("Try your first request:");
1268
+ prompts.log.message(` ${pc.cyan("$ npx x402-proxy https://twitter.surf.cascade.fyi/users/cascade_fyi")}`);
1269
+ prompts.log.message(` ${pc.dim("Run")} ${pc.cyan("npx x402-proxy")} ${pc.dim("to see your wallet and balance")}`);
1270
+ prompts.outro(pc.green(`MCP server ${pc.bold(serverName)} is ready to use!`));
1271
+ }
1272
+ });
1273
+
1088
1274
  //#endregion
1089
1275
  //#region src/commands/wallet-export.ts
1090
1276
  const walletExportCommand = buildCommand({
@@ -1190,28 +1376,37 @@ const walletHistoryCommand = buildCommand({
1190
1376
 
1191
1377
  //#endregion
1192
1378
  //#region src/app.ts
1379
+ const walletRoutes = buildRouteMap({
1380
+ routes: {
1381
+ info: walletInfoCommand,
1382
+ history: walletHistoryCommand,
1383
+ "export-key": walletExportCommand
1384
+ },
1385
+ defaultCommand: "info",
1386
+ docs: { brief: "Wallet management" }
1387
+ });
1388
+ const configRoutes = buildRouteMap({
1389
+ routes: {
1390
+ show: configShowCommand,
1391
+ set: configSetCommand,
1392
+ unset: configUnsetCommand
1393
+ },
1394
+ defaultCommand: "show",
1395
+ docs: { brief: "Manage configuration" }
1396
+ });
1193
1397
  const routes = buildRouteMap({
1194
1398
  routes: {
1195
1399
  fetch: fetchCommand,
1196
- mcp: mcpCommand,
1197
- wallet: buildRouteMap({
1400
+ mcp: buildRouteMap({
1198
1401
  routes: {
1199
- info: walletInfoCommand,
1200
- history: walletHistoryCommand,
1201
- "export-key": walletExportCommand
1402
+ proxy: mcpCommand,
1403
+ add: mcpAddCommand
1202
1404
  },
1203
- defaultCommand: "info",
1204
- docs: { brief: "Wallet management" }
1205
- }),
1206
- config: buildRouteMap({
1207
- routes: {
1208
- show: configShowCommand,
1209
- set: configSetCommand,
1210
- unset: configUnsetCommand
1211
- },
1212
- defaultCommand: "show",
1213
- docs: { brief: "Manage configuration" }
1405
+ defaultCommand: "proxy",
1406
+ docs: { brief: "MCP proxy and management" }
1214
1407
  }),
1408
+ wallet: walletRoutes,
1409
+ config: configRoutes,
1215
1410
  setup: setupCommand,
1216
1411
  status: statusCommand
1217
1412
  },
@@ -1220,7 +1415,7 @@ const routes = buildRouteMap({
1220
1415
  });
1221
1416
  const app = buildApplication(routes, {
1222
1417
  name: "x402-proxy",
1223
- versionInfo: { currentVersion: "0.8.5" },
1418
+ versionInfo: { currentVersion: "0.9.0" },
1224
1419
  scanner: { caseStyle: "allow-kebab-for-camel" }
1225
1420
  });
1226
1421
 
@@ -1232,7 +1427,23 @@ function buildContext(process) {
1232
1427
 
1233
1428
  //#endregion
1234
1429
  //#region src/bin/cli.ts
1235
- await run(app, process.argv.slice(2).map((a) => a === "-H" ? "--header" : a), buildContext(process));
1430
+ process.on("SIGINT", () => process.exit(130));
1431
+ const rawArgs = process.argv.slice(2);
1432
+ const args = [];
1433
+ for (let i = 0; i < rawArgs.length; i++) {
1434
+ const a = rawArgs[i];
1435
+ if (a === "-H") args.push("--header");
1436
+ else if ((a === "--config-dir" || a === "-c") && i + 1 < rawArgs.length) {
1437
+ const dir = resolve(rawArgs[++i]);
1438
+ process.env.XDG_CONFIG_HOME = dir;
1439
+ process.env.X402_PROXY_CONFIG_DIR_OVERRIDE = dir;
1440
+ } else if (a.startsWith("--config-dir=")) {
1441
+ const dir = resolve(a.slice(13));
1442
+ process.env.XDG_CONFIG_HOME = dir;
1443
+ process.env.X402_PROXY_CONFIG_DIR_OVERRIDE = dir;
1444
+ } else args.push(a);
1445
+ }
1446
+ await run(app, args, buildContext(process));
1236
1447
 
1237
1448
  //#endregion
1238
1449
  export { };
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
+ import path from "node:path";
2
3
  import fs from "node:fs";
3
4
  import os from "node:os";
4
- import path from "node:path";
5
5
  import { parse, stringify } from "yaml";
6
6
  import { ed25519 } from "@noble/curves/ed25519.js";
7
7
  import { base58 } from "@scure/base";
@@ -726,7 +726,7 @@ function createWalletCommand(ctx) {
726
726
  try {
727
727
  const snap = await getWalletSnapshot(ctx.rpcUrl, walletAddress, ctx.historyPath);
728
728
  const solscanUrl = `https://solscan.io/account/${walletAddress}`;
729
- const lines = [`x402-proxy v0.8.5`];
729
+ const lines = [`x402-proxy v0.9.0`];
730
730
  const defaultModel = ctx.allModels[0];
731
731
  if (defaultModel) lines.push("", `**Model** - ${defaultModel.name} (${defaultModel.provider})`);
732
732
  lines.push("", `**[Wallet](${solscanUrl})**`, `\`${walletAddress}\``);
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import { d as saveWalletFile, i as getConfigDirShort, n as deriveSolanaKeypair, o as getWalletPath, r as generateMnemonic, s as isConfigured, t as deriveEvmKeypair, u as saveConfig } from "./derive-BR6N1ZjI.js";
2
+ import { d as saveWalletFile, i as getConfigDirShort, n as deriveSolanaKeypair, o as getWalletPath, r as generateMnemonic, s as isConfigured, t as deriveEvmKeypair, u as saveConfig } from "./derive-CAYmX-Yz.js";
3
3
  import { buildCommand } from "@stricli/core";
4
4
  import pc from "picocolors";
5
5
  import * as prompts from "@clack/prompts";
@@ -48,6 +48,7 @@ async function runSetup(opts) {
48
48
  const evm = deriveEvmKeypair(mnemonic);
49
49
  const sol = deriveSolanaKeypair(mnemonic);
50
50
  prompts.log.success(`Base address: ${pc.green(evm.address)}`);
51
+ prompts.log.success(`Tempo address: ${pc.green(evm.address)}`);
51
52
  prompts.log.success(`Solana address: ${pc.green(sol.address)}`);
52
53
  saveWalletFile({
53
54
  version: 1,
@@ -64,7 +65,7 @@ async function runSetup(opts) {
64
65
  label: "x402 - on-chain payments (Base, Solana)"
65
66
  }, {
66
67
  value: "mpp",
67
- label: "MPP - streaming micropayments (Tempo)"
68
+ label: "MPP - machine payments over HTTP 402 (Tempo)"
68
69
  }]
69
70
  });
70
71
  if (prompts.isCancel(protocol)) {
@@ -104,7 +105,7 @@ async function runSetup(opts) {
104
105
  prompts.log.message(` Solana (USDC): Send USDC to ${pc.cyan(sol.address)}`);
105
106
  prompts.log.message(` Base (USDC): Send USDC to ${pc.cyan(evm.address)}`);
106
107
  prompts.log.step("Try your first request:");
107
- prompts.log.message(` ${pc.cyan("$ npx x402-proxy https://twitter.surf.cascade.fyi/user/cascade_fyi")}`);
108
+ prompts.log.message(` ${pc.cyan("$ npx x402-proxy https://twitter.surf.cascade.fyi/users/cascade_fyi")}`);
108
109
  prompts.outro(pc.green("Setup complete!"));
109
110
  }
110
111
  const setupCommand = buildCommand({
@@ -0,0 +1,4 @@
1
+ #!/usr/bin/env node
2
+ import { n as setupCommand, t as runSetup } from "./setup-BjyoqzT3.js";
3
+
4
+ export { runSetup };
@@ -1,4 +1,4 @@
1
1
  #!/usr/bin/env node
2
- import { n as statusCommand, t as displayStatus } from "./status-DvSu8reM.js";
2
+ import { n as statusCommand, t as displayStatus } from "./status-D3f5IVf6.js";
3
3
 
4
4
  export { displayStatus };
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
- import { a as getHistoryPath, c as loadConfig, i as getConfigDirShort } from "./derive-BR6N1ZjI.js";
3
- import { c as resolveWallet, f as formatAmount, g as dim, h as readHistory, m as formatUsdcValue, n as fetchAllBalances, p as formatTxLine, t as balanceLine, u as calcSpend } from "./wallet-BiX5_XFY.js";
2
+ import { a as getHistoryPath, c as loadConfig, i as getConfigDirShort } from "./derive-CAYmX-Yz.js";
3
+ import { c as resolveWallet, f as formatAmount, g as dim, h as readHistory, m as formatUsdcValue, n as fetchAllBalances, p as formatTxLine, t as balanceLine, u as calcSpend } from "./wallet-DZsXptY7.js";
4
4
  import { buildCommand } from "@stricli/core";
5
5
  import pc from "picocolors";
6
6
 
@@ -1,4 +1,4 @@
1
1
  #!/usr/bin/env node
2
- import { a as fetchTempoBalances, i as fetchSolanaBalances, n as fetchAllBalances, o as walletInfoCommand, r as fetchEvmBalances, t as balanceLine } from "./wallet-BiX5_XFY.js";
2
+ import { a as fetchTempoBalances, i as fetchSolanaBalances, n as fetchAllBalances, o as walletInfoCommand, r as fetchEvmBalances, t as balanceLine } from "./wallet-DZsXptY7.js";
3
3
 
4
4
  export { fetchAllBalances };
@@ -1,9 +1,9 @@
1
1
  #!/usr/bin/env node
2
- import { a as getHistoryPath, l as loadWalletFile, n as deriveSolanaKeypair, t as deriveEvmKeypair } from "./derive-BR6N1ZjI.js";
2
+ import { a as getHistoryPath, l as loadWalletFile, n as deriveSolanaKeypair, t as deriveEvmKeypair } from "./derive-CAYmX-Yz.js";
3
+ import { dirname } from "node:path";
3
4
  import { buildCommand } from "@stricli/core";
4
5
  import pc from "picocolors";
5
6
  import { appendFileSync, existsSync, mkdirSync, readFileSync, statSync, writeFileSync } from "node:fs";
6
- import { dirname } from "node:path";
7
7
  import { x402Client } from "@x402/fetch";
8
8
  import { ed25519 } from "@noble/curves/ed25519.js";
9
9
  import { base58 } from "@scure/base";
@@ -374,7 +374,7 @@ async function fetchSolanaBalances(ownerAddress) {
374
374
  const usdcVal = usdcRes.result?.value;
375
375
  return {
376
376
  sol,
377
- usdc: usdcVal ? formatUsdcValue(Number(usdcVal.uiAmountString)) : usdcVal === void 0 ? "?" : "0"
377
+ usdc: usdcVal ? formatUsdcValue(Number(usdcVal.uiAmountString)) : "0"
378
378
  };
379
379
  }
380
380
  function balanceLine(usdc, native, nativeSymbol) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "x402-proxy",
3
- "version": "0.8.5",
3
+ "version": "0.9.0",
4
4
  "description": "curl for x402 paid APIs. Auto-pays any endpoint on Base, Solana, and Tempo. Also works as an OpenClaw plugin.",
5
5
  "type": "module",
6
6
  "sideEffects": false,
@@ -27,21 +27,22 @@
27
27
  },
28
28
  "dependencies": {
29
29
  "@clack/prompts": "^1.1.0",
30
+ "@getmcp/generators": "^0.10.1",
30
31
  "@modelcontextprotocol/sdk": "^1.27.1",
31
32
  "@noble/curves": "^2.0.1",
32
33
  "@noble/hashes": "^2.0.1",
33
34
  "@scure/base": "^2.0.0",
34
35
  "@scure/bip32": "^2.0.1",
35
36
  "@scure/bip39": "^2.0.1",
36
- "@solana/kit": "^6.0.0",
37
37
  "@sinclair/typebox": "^0.34.48",
38
+ "@solana/kit": "^6.0.0",
38
39
  "@stricli/core": "^1.2.6",
39
40
  "@x402/evm": "^2.6.0",
40
41
  "@x402/fetch": "^2.6.0",
41
42
  "@x402/mcp": "^2.6.0",
42
- "mppx": "^0.4.9",
43
43
  "@x402/svm": "^2.6.0",
44
44
  "ethers": "^6.0.0",
45
+ "mppx": "^0.4.9",
45
46
  "picocolors": "^1.1.1",
46
47
  "viem": "^2.0.0",
47
48
  "yaml": "^2.8.2"
package/skills/SKILL.md CHANGED
@@ -42,6 +42,7 @@ npx x402-proxy https://api.example.com/data > response.json
42
42
  ```
43
43
  x402-proxy <url> # paid HTTP request (default)
44
44
  x402-proxy mcp <url> # MCP stdio proxy for AI agents
45
+ x402-proxy mcp add <name> <url> # install MCP server into AI client
45
46
  x402-proxy setup # wallet onboarding wizard
46
47
  x402-proxy setup --force # re-run setup (overwrite existing wallet)
47
48
  x402-proxy status # config + wallet + daily spend summary
@@ -70,7 +71,13 @@ x402-proxy wallet export-key mnemonic # bare mnemonic to stdout
70
71
 
71
72
  ## MCP proxy for AI agents
72
73
 
73
- Drop into Claude, Cursor, or any MCP client config:
74
+ Quick setup (auto-detects installed AI clients):
75
+
76
+ ```bash
77
+ x402-proxy mcp add my-service https://mcp.example.com/sse
78
+ ```
79
+
80
+ Or drop into your client config manually:
74
81
 
75
82
  ```json
76
83
  {
@@ -1,4 +0,0 @@
1
- #!/usr/bin/env node
2
- import { n as setupCommand, t as runSetup } from "./setup-Di_b5Vp9.js";
3
-
4
- export { runSetup };