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 +25 -1
- package/README.md +15 -2
- package/dist/bin/cli.js +244 -33
- package/dist/{derive-BR6N1ZjI.js → derive-CAYmX-Yz.js} +1 -1
- package/dist/openclaw/plugin.js +1 -1
- package/dist/{setup-Di_b5Vp9.js → setup-BjyoqzT3.js} +4 -3
- package/dist/setup-CJgw4opQ.js +4 -0
- package/dist/{status-DjudJ6fD.js → status-BkURZYDA.js} +1 -1
- package/dist/{status-DvSu8reM.js → status-D3f5IVf6.js} +2 -2
- package/dist/{wallet-BkZ0DOJL.js → wallet-BM0ngyqk.js} +1 -1
- package/dist/{wallet-BiX5_XFY.js → wallet-DZsXptY7.js} +3 -3
- package/package.json +4 -3
- package/skills/SKILL.md +8 -1
- package/dist/setup-CJwYRd78.js +0 -4
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.
|
|
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.
|
|
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-
|
|
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-
|
|
4
|
-
import { n as setupCommand } from "../setup-
|
|
5
|
-
import { n as statusCommand } from "../status-
|
|
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/
|
|
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-
|
|
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/
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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:
|
|
1197
|
-
wallet: buildRouteMap({
|
|
1400
|
+
mcp: buildRouteMap({
|
|
1198
1401
|
routes: {
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
"export-key": walletExportCommand
|
|
1402
|
+
proxy: mcpCommand,
|
|
1403
|
+
add: mcpAddCommand
|
|
1202
1404
|
},
|
|
1203
|
-
defaultCommand: "
|
|
1204
|
-
docs: { brief: "
|
|
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.
|
|
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
|
-
|
|
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";
|
package/dist/openclaw/plugin.js
CHANGED
|
@@ -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.
|
|
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-
|
|
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 -
|
|
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/
|
|
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({
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { a as getHistoryPath, c as loadConfig, i as getConfigDirShort } from "./derive-
|
|
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-
|
|
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-
|
|
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-
|
|
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)) :
|
|
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.
|
|
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
|
-
|
|
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
|
{
|
package/dist/setup-CJwYRd78.js
DELETED