@newblock/iautopay-mcp 0.0.5 → 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.
@@ -7,11 +7,10 @@ This project supports both OpenCode and Claude CLI MCP servers.
7
7
  Configuration is automatically generated at installation via `opencode.json`.
8
8
 
9
9
  Available commands:
10
- - `/autopay_toA` - Quick payment of 0.01 USDC
11
- - `/autopay_toB` - Quick payment of 0.05 USDC (with confirmation)
12
- - `/autopay_buy_glm_nvidia_apikey` - Purchase GLM NVIDIA API Key
13
- - `/autopay_custom` - Custom payment
14
- - `/autopay_getInfo` - Get service information
10
+ - `/autopay_guide` - Show iAutoPay usage guide
11
+ - `/autopay_buy_apikey_1day` - Buy 1-day API Key (0.09 USDC)
12
+ - `/autopay_buy_apikey_7days` - Buy 7-day API Key (0.49 USDC)
13
+ - `/autopay_get_info` - Get iAutoPay server information
15
14
 
16
15
  ## Claude CLI
17
16
 
@@ -28,7 +27,7 @@ This method uses the configuration file generated at `mcp-config.json` during in
28
27
 
29
28
  ```bash
30
29
  # Add MCP server to Claude CLI
31
- BUYER_PRIVATE_KEY="your_private_key" claude mcp add iauto-pay \
30
+ BUYER_PRIVATE_KEY="your_private_key" claude mcp add autopay \
32
31
  -e BUYER_PRIVATE_KEY="your_private_key" \
33
32
  -- npx -y @newblock/iautopay-mcp
34
33
 
@@ -36,7 +35,7 @@ BUYER_PRIVATE_KEY="your_private_key" claude mcp add iauto-pay \
36
35
  claude mcp list
37
36
 
38
37
  # Should show:
39
- # iauto-pay: npx -y @newblock/iautopay-mcp - ✓ Connected
38
+ # autopay: npx -y @newblock/iautopay-mcp - ✓ Connected
40
39
  ```
41
40
 
42
41
  After adding, you can simply run `claude` without any additional flags.
@@ -47,7 +46,7 @@ After adding, you can simply run `claude` without any additional flags.
47
46
  # Create mcp-config.json manually:
48
47
  {
49
48
  "mcpServers": {
50
- "iauto-pay": {
49
+ "autopay": {
51
50
  "command": "npx",
52
51
  "args": ["-y", "@newblock/iautopay-mcp"],
53
52
  "env": {
@@ -65,10 +64,10 @@ claude --mcp-config mcp-config.json
65
64
 
66
65
  When using Claude CLI with MCP enabled, the following tools are available:
67
66
 
68
- - `pay_stablecoin` - Pay USDC to any address (auto-detects mainnet/testnet based on CUR_ENV)
69
- - `buy_glm_nvidia_apikey` - Purchase GLM NVIDIA API Key
70
- - `get_info` - Get server information (stock, price, network config)
71
- - `pay_preset` - Quick preset payments (toA: 0.01 USDC, toB: 0.05 USDC)
67
+ - `guide` - Display complete iAutoPay usage guide
68
+ - `info` - Get server information (stock, prices, network config)
69
+ - `buy_apikey` - Buy API key (supports 1/7/30 day durations)
70
+ - `refresh_pricing` - Refresh prices from server
72
71
 
73
72
  ## Usage Examples
74
73
 
@@ -91,14 +90,14 @@ claude
91
90
  claude mcp list
92
91
 
93
92
  # Get details of specific server
94
- claude mcp get iauto-pay
93
+ claude mcp get autopay
95
94
  ```
96
95
 
97
96
  ## Removing MCP Server
98
97
 
99
98
  If you added to local config:
100
99
  ```bash
101
- claude mcp remove iauto-pay -s local
100
+ claude mcp remove autopay -s local
102
101
  ```
103
102
 
104
103
  If using config file, simply remove the `--mcp-config mcp-config.json` flag when running `claude`.
@@ -112,7 +111,7 @@ If using config file, simply remove the `--mcp-config mcp-config.json` flag when
112
111
 
113
112
  **Tools not showing up:**
114
113
  1. Verify MCP connection: `claude mcp list`
115
- 2. Check server health: `claude mcp get iauto-pay`
114
+ 2. Check server health: `claude mcp get autopay`
116
115
  3. Restart Claude CLI
117
116
 
118
117
  **Wrong environment (dev vs prod):**
package/README.md CHANGED
@@ -1,22 +1,6 @@
1
1
  # iAutoPay MCP Service
2
2
 
3
- An MCP (Model Context Protocol) service that enables AI agents to automatically pay for purchases. It currently runs on Base chain (operated by Coinbase) and supports USDC payments. It can be used by intelligent agents to automatically purchase paid AI-related services and data.
4
-
5
- ## Features
6
-
7
- - 🚀 **Smart Payment**: Small automatic payments, large amount manual approval
8
- - 💳 **USDC Payments**: Support USDC-based payments on Base chain
9
- - 🔐 **Secure**: Environment variable based configuration for private keys
10
- - 🤖 **AI-Native**: Full MCP integration designed for AI agents
11
- - 💸 **Fixed Transfer**: Preset fixed transfer account command, direct transfer by command
12
- - 🔑 **API Key Purchase**: Support GLM4.7 LLM API Key purchase service with dynamic pricing
13
-
14
- ## Supported Models
15
-
16
- API keys purchased through this service provide access to:
17
- - `z-ai/glm4.7` (GLM4.7 with thinking chain support)
18
- - `minimaxai/minimax-m2.1` (MiniMax general LLM)
19
- - `deepseek-ai/deepseek-v3.2` (DeepSeek with thinking chain)
3
+ iAutoPay is an MCP (Model Context Protocol) service that enables AI agents to automatically pay for purchases. It supports all EVM-compatible public chains and USDC payments. Agents can use it to automatically purchase paid AI-related services and data.
20
4
 
21
5
  ## Installation
22
6
 
@@ -34,27 +18,10 @@ This will automatically download and cache the package.
34
18
 
35
19
  ```bash
36
20
  npm install -g @newblock/iautopay-mcp
37
- @newblock/iautopay-mcp
38
- ```
39
-
40
- ### Option 3: Project Dependency
41
-
42
- ```bash
43
- npm install @newblock/iautopay-mcp
44
- node node_modules/@newblock/iautopay-mcp/dist/iautopay-mcp.js
45
21
  ```
46
22
 
47
23
  ## Configuration
48
24
 
49
- ### Environment Variables
50
-
51
- Set required environment variables:
52
-
53
- ```bash
54
- # Required: Your wallet private key for signing payments
55
- export BUYER_PRIVATE_KEY="0x..."
56
- ```
57
-
58
25
  ### OpenCode Configuration
59
26
 
60
27
  Add to your `opencode.json`:
@@ -63,12 +30,12 @@ Add to your `opencode.json`:
63
30
  {
64
31
  "$schema": "https://opencode.ai/config.json",
65
32
  "mcp": {
66
- "iauto-pay": {
33
+ "autopay": {
67
34
  "type": "local",
68
35
  "command": ["npx", "-y", "@newblock/iautopay-mcp"],
69
36
  "enabled": true,
70
37
  "environment": {
71
- "BUYER_PRIVATE_KEY": "{env:BUYER_PRIVATE_KEY}"
38
+ "BUYER_PRIVATE_KEY": "0xEVM_wallet_private_key"
72
39
  }
73
40
  }
74
41
  }
@@ -83,7 +50,7 @@ For detailed instructions on using Claude CLI with MCP, see [CLAUDE_CLI_MCP_SETU
83
50
 
84
51
  ```bash
85
52
  # Install and add to Claude CLI
86
- BUYER_PRIVATE_KEY="your_private_key" claude mcp add iauto-pay \
53
+ BUYER_PRIVATE_KEY="your_private_key" claude mcp add autopay \
87
54
  -e BUYER_PRIVATE_KEY="your_private_key" \
88
55
  -- npx -y @newblock/iautopay-mcp
89
56
 
@@ -98,179 +65,122 @@ Add to your `~/.claude/claude_desktop_config.json`:
98
65
  ```json
99
66
  {
100
67
  "mcpServers": {
101
- "iauto-pay": {
68
+ "autopay": {
102
69
  "command": "npx",
103
- "args": ["@newblock/iautopay-mcp"],
70
+ "args": ["-y", "@newblock/iautopay-mcp"],
104
71
  "env": {
105
- "BUYER_PRIVATE_KEY": "{env:BUYER_PRIVATE_KEY}"
72
+ "BUYER_PRIVATE_KEY": "0xEVM_wallet_private_key"
106
73
  }
107
74
  }
108
75
  }
109
76
  }
110
77
  ```
111
78
 
112
- ## MCP Tools
113
-
114
- ### guide
115
-
116
- **FIRST TIME?** Run this guide to learn how to use iAutoPay tools and commands.
79
+ > **Basic Knowledge About Cryptocurrency and Wallets**
80
+ >
81
+ > Before using iAutoPay, you need to understand some basic cryptocurrency concepts:
82
+ >
83
+ > - **Wallet Private Key**: A key similar to a password, used to sign transactions. **Keep it safe and never share it with anyone!**
84
+ > - **Testnet**: A network for testing where test coins can be obtained for free from faucets
85
+ > - **Mainnet**: The official network that requires real funds
86
+ > - **USDC**: A stablecoin pegged to US dollar (1 USDC ≈ 1 USD)
87
+ >
88
+ > How to get test coins:
89
+ > 1. Visit the Base Sepolia faucet: https://sepoliafaucet.com/
90
+ > 2. Enter your wallet address
91
+ > 3. Get free test USDC
92
+ >
93
+ > Security tips:
94
+ > - Never share your private key
95
+ > - Test thoroughly on testnet before using mainnet
96
+ > - Use a dedicated wallet, don't store large amounts of funds
97
+ >
98
+ > For more blockchain basics, refer to: https://www.wtf.academy/zh/course/ethers101/HelloVitalik
117
99
 
118
- **Parameters:**
119
- ```json
120
- {}
121
- ```
100
+ ### opencode autopay command loading success
122
101
 
123
- **Returns:**
124
- - Complete guide with all tools and commands
125
- - Pricing information
126
- - Network configuration
102
+ ![MCP usage screenshot](doc/opencode_cmd.jpg)
127
103
 
128
- ### info
104
+ ## MCP Tools Usage
129
105
 
130
- Get iAutoPay server information (API key stock, price, network config).
106
+ ### Quick Commands Configuration
131
107
 
132
- **Parameters:**
133
- ```json
134
- {}
135
- ```
108
+ Add these shortcuts to your `opencode.json` for faster access:
136
109
 
137
- **Returns:**
138
110
  ```json
139
111
  {
140
- "stock": 100,
141
- "prices": {
142
- "1day": "0.09 USDC",
143
- "7days": "0.49 USDC",
144
- "30days": "0.99 USDC"
112
+ "$schema": "https://opencode.ai/config.json",
113
+ "mcp": {
114
+ "autopay": {
115
+ "type": "local",
116
+ "command": ["npx", "-y", "@newblock/iautopay-mcp"],
117
+ "enabled": true,
118
+ "environment": {
119
+ "BUYER_PRIVATE_KEY": "0xEVM_wallet_private_key"
120
+ }
121
+ }
145
122
  },
146
- "network": {
147
- "chainId": 84532,
148
- "rpcUrl": "https://sepolia.base.org"
123
+ "command": {
124
+ "autopay_buy_apikey_1day": {
125
+ "template": "Use buy_apikey tool to buy 1-day API Key, params: {\"duration\": 1}",
126
+ "description": "Buy 1-day API Key (0.09 USDC)"
127
+ },
128
+ "autopay_buy_apikey_7days": {
129
+ "template": "Use buy_apikey tool to buy 7-day API Key, params: {\"duration\": 7}",
130
+ "description": "Buy 7-day API Key (0.49 USDC)"
131
+ },
132
+ "autopay_get_info": {
133
+ "template": "Use info tool to get server information (API Key stock, prices, network config)",
134
+ "description": "Get iAutoPay server information"
135
+ },
136
+ "autopay_guide": {
137
+ "template": "Use guide tool to show iAutoPay usage guide",
138
+ "description": "Show iAutoPay usage guide"
139
+ }
149
140
  }
150
141
  }
151
142
  ```
152
143
 
153
- ### buy_apikey
144
+ ### Opencode Quick Commands Usage Examples
154
145
 
155
- Purchase an API key with optional duration (1/7/30 days).
146
+ ### 1: /autopay_guide
156
147
 
157
- **Parameters:**
158
- ```json
159
- {
160
- "duration": 1
161
- }
162
- ```
148
+ Output:
163
149
 
164
- **Duration Options:**
165
- - `1`: 1 day validity
166
- - `7`: 7 days validity
167
- - `30`: 30 days validity
150
+ iAutoPay Usage Guide
151
+ Available Tools
152
+ - guide - Display complete usage guide
153
+ - info - Get server information (stock, prices, network config)
154
+ - buy_apikey - Buy API key (supports 1/7/30 day durations)
155
+ - refresh_pricing - Refresh prices from server
156
+ Quick Commands
157
+ - autopay_buy_apikey_1day - Buy 1-day API Key (0.1 USDC)
158
+ - autopay_buy_apikey_7days - Buy 7-day API Key (0.9 USDC)
159
+ - autopay_get_info - Quick get server information
160
+ Network Information
161
+ - Testnet: Base Sepolia (84532)
162
+ - Mainnet: Base Mainnet (8453)
163
+ - Current Network: Base Sepolia (84532)
164
+ Pricing
165
+ - 1 day: 0.1 USDC
166
+ - 7 days: 0.9 USDC
167
+ Environment: dev
168
168
 
169
- **Returns:**
170
- ```json
171
- {
172
- "apiKey": "sk-ABCD12345678901234567890",
173
- "txHash": "0x4d757c7e121ad31607ee1e9c5af65bfe13b82c112fcf077638814c031ecc3a6b",
174
- "payState": "paid",
175
- "price": "0.09 USDC",
176
- "deductedAmount": "0.09 USDC",
177
- "currentBalance": "9.91 USDC"
178
- }
179
- ```
169
+ ### 2: /autopay_buy_apikey_1day
180
170
 
181
- ### pay_stablecoin
171
+ Output:
182
172
 
183
- Pay stablecoin to any address using EIP-3009.
173
+ Purchasing 1-day API Key...
174
+ Price: 0.09 USDC
175
+ Processing payment...
176
+ Transaction hash: 0xghi789...
177
+ Purchase successful!
184
178
 
185
- **Parameters:**
186
- ```json
187
- {
188
- "to": "0x1234567890123456789012345678901234567890",
189
- "amount": "100000"
190
- }
191
- ```
192
-
193
- **Amount is in smallest units** (e.g., 100000 = 0.1 USDC, 1000000 = 1 USDC)
194
-
195
- **Returns:**
196
- ```json
197
- {
198
- "from": "0x...",
199
- "to": "0x...",
200
- "amount": "0.1 USDC",
201
- "txHash": "0x...",
202
- "deductedAmount": "0.1 USDC",
203
- "currentBalance": "9.9 USDC"
204
- }
205
- ```
206
-
207
- ### sync_opencode_config
208
-
209
- Auto-configure opencode.json with quick commands (autopay_toA, autopay_toB, etc.).
210
-
211
- **Parameters:**
212
- ```json
213
- {}
214
- ```
215
-
216
- **Returns:**
217
- ```json
218
- {
219
- "message": "✅ 已添加 7 个命令到 opencode.json"
220
- }
221
- ```
222
-
223
- ### refresh_pricing
224
-
225
- Refresh pricing from API. Use this if prices are changed on the server.
179
+ Your API Key: sk-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
180
+ Valid for: 1 day
226
181
 
227
- **Parameters:**
228
- ```json
229
- {}
230
- ```
231
-
232
- **Returns:**
233
- ```json
234
- {
235
- "1day": "0.09 USDC",
236
- "7days": "0.49 USDC",
237
- "30days": "0.99 USDC"
238
- }
239
- ```
240
-
241
- ## Environment Configuration
242
-
243
- The MCP server supports two environments configured in `src/server.ts`:
244
-
245
- ### Development (Base Sepolia)
246
- - Chain ID: 84532
247
- - RPC URL: https://sepolia.base.org
248
- - USDC Address: 0x036CbD53842c5426634e7929541eC2318f3dCF7e
249
- - Token Name: "USDC"
182
+ 👉 Check [LLM Services Guide](doc/LLM_SERVICES_GUIDE.md) to learn how to use the API Key to access supported models
250
183
 
251
- ### Production (Base Mainnet)
252
- - Chain ID: 8453
253
- - RPC URL: https://mainnet.base.org
254
- - USDC Address: 0x833589fcd6edb6e08f4c7c32d4f71b54bda02913
255
- - Token Name: "USD Coin"
256
-
257
- ## Example Workflows
258
-
259
- ### Example 1: Purchase GLM4.7 API Key
260
-
261
- ```
262
- Use info tool to check stock and pricing
263
- Use buy_apikey tool with duration: 1
264
- Receive API key in response
265
- ```
266
-
267
- ### Example 2: Direct USDC Payment
268
-
269
- ```
270
- Use pay_stablecoin tool with to: "0x1a85156c2943b63febeee7883bd84a7d1cf0da0c" and amount: "10000"
271
- Transaction executes automatically
272
- Receive transaction hash
273
- ```
274
184
 
275
185
  ## License
276
186
 
@@ -286,5 +196,6 @@ For issues and questions, please use the [GitHub Issues](https://github.com/newb
286
196
 
287
197
  ## Documentation
288
198
 
199
+ - [LLM Services Guide](doc/LLM_SERVICES_GUIDE.md) - Supported models and API Key purchase guide
289
200
  - [CLAUDE_CLI_MCP_SETUP.md](CLAUDE_CLI_MCP_SETUP.md) - Claude CLI integration guide
290
201
  - [mcp-config.json.example](mcp-config.json.example) - MCP configuration template
@@ -53,10 +53,10 @@ const paymentRequirementsSchema = z.object({
53
53
  price: z.string().min(1),
54
54
  payee: z.string().optional(),
55
55
  });
56
- const payStablecoinInput = z.object({
57
- to: z.string().min(1),
58
- amount: z.string().min(1),
59
- });
56
+ // const payStablecoinInput = z.object({
57
+ // to: z.string().min(1),
58
+ // amount: z.string().min(1),
59
+ // });
60
60
  const buyApikeyInput = z.object({
61
61
  duration: z.number().optional().refine(val => !val || [1, 7, 30].includes(val), {
62
62
  message: "Duration must be 1, 7, or 30 days"
@@ -64,7 +64,7 @@ const buyApikeyInput = z.object({
64
64
  });
65
65
  const getInfoInput = z.object({});
66
66
  const guideInput = z.object({});
67
- const syncOpencodeConfigInput = z.object({});
67
+ // const syncOpencodeConfigInput = z.object({});
68
68
  const refreshPricingInput = z.object({});
69
69
  // ============================================================================
70
70
  // Dynamic Pricing from Fact API
@@ -326,16 +326,16 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
326
326
  description: "Purchase an API key with optional duration (1/7/30 days). Prices: 1 day=0.9 USDC, 7 days=4.9 USDC, 30 days=9.9 USDC. Run 'info' first to confirm stock.",
327
327
  inputSchema: zodToJsonSchema(buyApikeyInput),
328
328
  },
329
- {
330
- name: "pay_stablecoin",
331
- description: "Pay stablecoin to any address using EIP-3009. Amount is in smallest unit (e.g., 100000 = 0.1 USDC).",
332
- inputSchema: zodToJsonSchema(payStablecoinInput),
333
- },
334
- {
335
- name: "sync_opencode_config",
336
- description: "Auto-configure opencode.json with quick commands (autopay_toA, autopay_toB, etc.)",
337
- inputSchema: zodToJsonSchema(syncOpencodeConfigInput),
338
- },
329
+ // {
330
+ // name: "pay_stablecoin",
331
+ // description: "Pay stablecoin to any address using EIP-3009. Amount is in smallest unit (e.g., 100000 = 0.1 USDC).",
332
+ // inputSchema: zodToJsonSchema(payStablecoinInput),
333
+ // },
334
+ // {
335
+ // name: "sync_opencode_config",
336
+ // description: "Auto-configure opencode.json with quick commands (autopay_toA, autopay_toB, etc.)",
337
+ // inputSchema: zodToJsonSchema(syncOpencodeConfigInput),
338
+ // },
339
339
  {
340
340
  name: "refresh_pricing",
341
341
  description: "Refresh pricing from API. Use this if prices are changed on the server.",
@@ -346,21 +346,20 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
346
346
  });
347
347
  server.setRequestHandler(CallToolRequestSchema, async (request) => {
348
348
  const { name, arguments: args } = request.params;
349
- if (name === "pay_stablecoin") {
350
- const parsed = payStablecoinInput.parse(args);
351
- try {
352
- const result = await payStablecoin({
353
- to: parsed.to,
354
- amount: parsed.amount,
355
- asset: CURRENT_USDC,
356
- isTestnet: CUR_ENV === 'dev',
357
- });
358
- return { content: [{ type: "text", text: JSON.stringify(result) }] };
359
- }
360
- catch (error) {
361
- throw error;
362
- }
363
- }
349
+ // if (name === "pay_stablecoin") {
350
+ // const parsed = payStablecoinInput.parse(args);
351
+ // try {
352
+ // const result = await payStablecoin({
353
+ // to: parsed.to,
354
+ // amount: parsed.amount,
355
+ // asset: CURRENT_USDC,
356
+ // isTestnet: (CUR_ENV as string) === 'dev',
357
+ // });
358
+ // return { content: [{ type: "text", text: JSON.stringify(result) }] };
359
+ // } catch (error) {
360
+ // throw error;
361
+ // }
362
+ // }
364
363
  if (name === "buy_apikey") {
365
364
  const parsed = buyApikeyInput.parse(args);
366
365
  const duration = parsed.duration || 1;
@@ -452,13 +451,9 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
452
451
  { name: "guide", description: "显示完整使用指南" },
453
452
  { name: "info", description: "获取服务器信息(库存、价格、网络配置)" },
454
453
  { name: "buy_apikey", description: "购买 API key(支持1/7/30天时长)" },
455
- { name: "pay_stablecoin", description: "支付稳定币到指定地址" },
456
- { name: "sync_opencode_config", description: "自动配置 opencode.json 快捷命令" },
457
454
  { name: "refresh_pricing", description: "从服务器刷新价格" }
458
455
  ],
459
456
  commands: [
460
- { name: "autopay_toA", description: "快速支付 0.01 USDC" },
461
- { name: "autopay_toB", description: "支付 0.05 USDC(需确认)" },
462
457
  { name: "autopay_buy_apikey_1day", description: `购买1天API Key(${pricing["1day"]})` },
463
458
  { name: "autopay_buy_apikey_7days", description: `购买7天API Key(${pricing["7days"]})` },
464
459
  { name: "autopay_buy_apikey_30days", description: `购买30天API Key(${pricing["30days"]})` },
@@ -474,80 +469,78 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
474
469
  };
475
470
  return { content: [{ type: "text", text: JSON.stringify(toolsData, null, 2) }] };
476
471
  }
477
- if (name === "sync_opencode_config") {
478
- const parsed = syncOpencodeConfigInput.parse(args);
479
- try {
480
- const fs = await import('fs/promises');
481
- const opencodePath = '/Users/michael/opc/proj/iautopay/opencode.json';
482
- const opencodeData = JSON.parse(await fs.readFile(opencodePath, 'utf-8'));
483
- const pricing = CACHED_PRICING || {
484
- "1day": "0.09 USDC",
485
- "7days": "0.49 USDC",
486
- "30days": "0.99 USDC"
487
- };
488
- const requiredCommands = {
489
- "autopay_toA": {
490
- "template": "使用 pay_stablecoin 工具向 0x1a85156c2943b63febeee7883bd84a7d1cf0da0c 支付 0.01 USDC,参数为:to=\"0x1a85156c2943b63febeee7883bd84a7d1cf0da0c\", amount=\"10000\"",
491
- "description": "支付0.01 USDC给A账户"
492
- },
493
- "autopay_toB": {
494
- "template": "首先使用 question 工具询问用户确认,选项包括:1) 确认(继续支付),2) 取消(不进行支付)。显示支付详情:向 0x1a85156c2943b63febeee7883bd84a7d1cf0da0c 支付 0.05 USDC,参数为:to=\"0x1a85156c2943b63febeee7883bd84a7d1cf0da0c\", amount=\"50000\"。只有用户选择确认时才继续支付。",
495
- "description": "支付0.05 USDC给A账户(需要确认)"
496
- },
497
- "autopay_buy_apikey_1day": {
498
- "template": "使用 buy_apikey 工具购买1天API Key,参数为:{\"duration\": 1}",
499
- "description": `购买1天API Key(${pricing["1day"]})`
500
- },
501
- "autopay_buy_apikey_7days": {
502
- "template": "使用 buy_apikey 工具购买7天API Key,参数为:{\"duration\": 7}",
503
- "description": `购买7天API Key(${pricing["7days"]})`
504
- },
505
- "autopay_buy_apikey_30days": {
506
- "template": "使用 buy_apikey 工具购买30天API Key,参数为:{\"duration\": 30}",
507
- "description": `购买30天API Key(${pricing["30days"]})`
508
- },
509
- "autopay_get_info": {
510
- "template": "使用 info 工具获取服务器信息(API Key 库存、价格、网络配置)",
511
- "description": "获取iAutoPay服务器信息"
512
- },
513
- "autopay_guide": {
514
- "template": "使用 guide 工具显示 iAutoPay 使用指南",
515
- "description": "显示iAutoPay使用指南"
516
- }
517
- };
518
- let addedCommands = [];
519
- let updatedCommands = [];
520
- if (!opencodeData.command) {
521
- opencodeData.command = {};
522
- }
523
- for (const [key, value] of Object.entries(requiredCommands)) {
524
- if (!opencodeData.command[key]) {
525
- opencodeData.command[key] = value;
526
- addedCommands.push(key);
527
- }
528
- }
529
- if (addedCommands.length > 0) {
530
- await fs.writeFile(opencodePath, JSON.stringify(opencodeData, null, 2), 'utf-8');
531
- return {
532
- content: [{
533
- type: "text",
534
- text: `✅ 已添加 ${addedCommands.length} 个命令到 opencode.json:\n${addedCommands.map(c => ` - ${c}`).join('\n')}`
535
- }]
536
- };
537
- }
538
- else {
539
- return {
540
- content: [{
541
- type: "text",
542
- text: "✅ 所有 autopay_ 命令已存在,无需更新"
543
- }]
544
- };
545
- }
546
- }
547
- catch (error) {
548
- throw new Error(`同步配置失败: ${error}`);
549
- }
550
- }
472
+ // if (name === "sync_opencode_config") {
473
+ // const parsed = syncOpencodeConfigInput.parse(args);
474
+ // try {
475
+ // const fs = await import('fs/promises');
476
+ // const opencodePath = '/Users/michael/opc/proj/iautopay/opencode.json';
477
+ // const opencodeData = JSON.parse(await fs.readFile(opencodePath, 'utf-8'));
478
+ // const pricing = CACHED_PRICING || {
479
+ // "1day": "0.09 USDC",
480
+ // "7days": "0.49 USDC",
481
+ // "30days": "0.99 USDC"
482
+ // };
483
+ // const requiredCommands = {
484
+ // "autopay_toA": {
485
+ // "template": "使用 pay_stablecoin 工具向 0x1a85156c2943b63febeee7883bd84a7d1cf0da0c 支付 0.01 USDC,参数为:to=\"0x1a85156c2943b63febeee7883bd84a7d1cf0da0c\", amount=\"10000\"",
486
+ // "description": "支付0.01 USDC给A账户"
487
+ // },
488
+ // "autopay_toB": {
489
+ // "template": "首先使用 question 工具询问用户确认,选项包括:1) 确认(继续支付),2) 取消(不进行支付)。显示支付详情:向 0x1a85156c2943b63febeee7883bd84a7d1cf0da0c 支付 0.05 USDC,参数为:to=\"0x1a85156c2943b63febeee7883bd84a7d1cf0da0c\", amount=\"50000\"。只有用户选择确认时才继续支付。",
490
+ // "description": "支付0.05 USDC给A账户(需要确认)"
491
+ // },
492
+ // "autopay_buy_apikey_1day": {
493
+ // "template": "使用 buy_apikey 工具购买1天API Key,参数为:{\"duration\": 1}",
494
+ // "description": `购买1天API Key(${pricing["1day"]})`
495
+ // },
496
+ // "autopay_buy_apikey_7days": {
497
+ // "template": "使用 buy_apikey 工具购买7天API Key,参数为:{\"duration\": 7}",
498
+ // "description": `购买7天API Key(${pricing["7days"]})`
499
+ // },
500
+ // "autopay_buy_apikey_30days": {
501
+ // "template": "使用 buy_apikey 工具购买30天API Key,参数为:{\"duration\": 30}",
502
+ // "description": `购买30天API Key(${pricing["30days"]})`
503
+ // },
504
+ // "autopay_get_info": {
505
+ // "template": "使用 info 工具获取服务器信息(API Key 库存、价格、网络配置)",
506
+ // "description": "获取iAutoPay服务器信息"
507
+ // },
508
+ // "autopay_guide": {
509
+ // "template": "使用 guide 工具显示 iAutoPay 使用指南",
510
+ // "description": "显示iAutoPay使用指南"
511
+ // }
512
+ // };
513
+ // let addedCommands: string[] = [];
514
+ // let updatedCommands: string[] = [];
515
+ // if (!opencodeData.command) {
516
+ // opencodeData.command = {};
517
+ // }
518
+ // for (const [key, value] of Object.entries(requiredCommands)) {
519
+ // if (!opencodeData.command[key]) {
520
+ // opencodeData.command[key] = value;
521
+ // addedCommands.push(key);
522
+ // }
523
+ // }
524
+ // if (addedCommands.length > 0) {
525
+ // await fs.writeFile(opencodePath, JSON.stringify(opencodeData, null, 2), 'utf-8');
526
+ // return {
527
+ // content: [{
528
+ // type: "text",
529
+ // text: `✅ 已添加 ${addedCommands.length} 个命令到 opencode.json:\n${addedCommands.map(c => ` - ${c}`).join('\n')}`
530
+ // }]
531
+ // };
532
+ // } else {
533
+ // return {
534
+ // content: [{
535
+ // type: "text",
536
+ // text: "✅ 所有 autopay_ 命令已存在,无需更新"
537
+ // }]
538
+ // };
539
+ // }
540
+ // } catch (error) {
541
+ // throw new Error(`同步配置失败: ${error}`);
542
+ // }
543
+ // }
551
544
  if (name === "refresh_pricing") {
552
545
  const parsed = refreshPricingInput.parse(args);
553
546
  try {
@@ -1,10 +1,10 @@
1
1
  {
2
2
  "mcpServers": {
3
- "iauto-pay": {
3
+ "autopay": {
4
4
  "command": "npx",
5
5
  "args": ["-y", "@newblock/iautopay-mcp"],
6
6
  "env": {
7
- "BUYER_PRIVATE_KEY": "{env:BUYER_PRIVATE_KEY}"
7
+ "BUYER_PRIVATE_KEY": "0xEVM_wallet_private_key"
8
8
  }
9
9
  }
10
10
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@newblock/iautopay-mcp",
3
- "version": "0.0.5",
3
+ "version": "0.0.7",
4
4
  "description": "iAutoPay is an MCP service that enables AI agents to automatically pay for purchases. It currently runs on Base chain (operated by Coinbase) and supports USDC payments.",
5
5
  "type": "module",
6
6
  "main": "dist/iautopay-mcp.js",
package/dist/server.js DELETED
@@ -1,585 +0,0 @@
1
- import crypto from "node:crypto";
2
- import { fileURLToPath } from "node:url";
3
- import { dirname } from "node:path";
4
- const __filename = fileURLToPath(import.meta.url);
5
- const __dirname = dirname(__filename);
6
- import { Server, } from "@modelcontextprotocol/sdk/server/index.js";
7
- import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
8
- import { CallToolRequestSchema, ListToolsRequestSchema, } from "@modelcontextprotocol/sdk/types.js";
9
- import { z } from "zod";
10
- import { zodToJsonSchema } from "zod-to-json-schema";
11
- import { createPublicClient, createWalletClient, hexToSignature, http, isAddress, } from "viem";
12
- import { privateKeyToAccount } from "viem/accounts";
13
- // ============================================================================
14
- // Hardcoded Configuration (no .env dependency)
15
- // ============================================================================
16
- const CUR_ENV = 'dev';
17
- const CONFIG = {
18
- // User's private key for signing payments (provided via opencode.json environment)
19
- BUYER_PRIVATE_KEY: process.env.BUYER_PRIVATE_KEY,
20
- // Remote Fact API server
21
- FACT_API_URL: CUR_ENV == 'dev' ? "https://apipaymcp.okart.fun" : "https://apipaymcp.okart.fun",
22
- // Blockchain configuration (Base Sepolia for dev, Base Mainnet for prod)
23
- RPC_URL: CUR_ENV == 'dev' ? "https://sepolia.base.org" : "https://mainnet.base.org",
24
- CHAIN_ID: CUR_ENV == 'dev' ? "84532" : "8453",
25
- // Payment token details
26
- PAYMENT_TOKEN_NAME: "USDC",
27
- };
28
- // Validate required configuration
29
- if (!CONFIG.BUYER_PRIVATE_KEY) {
30
- throw new Error("BUYER_PRIVATE_KEY must be provided via opencode.json environment");
31
- }
32
- // Validate private key format
33
- try {
34
- privateKeyToAccount(CONFIG.BUYER_PRIVATE_KEY);
35
- }
36
- catch (error) {
37
- throw new Error(`Invalid BUYER_PRIVATE_KEY format: ${error}`);
38
- }
39
- // Derive values from config
40
- const BUYER_CHAIN_ID = CONFIG.CHAIN_ID;
41
- const BUYER_RPC_URL = CONFIG.RPC_URL;
42
- const FACT_API_URL = CONFIG.FACT_API_URL;
43
- // USDC addresses
44
- const USDC_ADDRESSES = {
45
- dev: "0x036CbD53842c5426634e7929541eC2318f3dCF7e",
46
- prod: "0x833589fcd6edb6e08f4c7c32d4f71b54bda02913"
47
- };
48
- const CURRENT_USDC = USDC_ADDRESSES[CUR_ENV];
49
- const paymentRequirementsSchema = z.object({
50
- scheme: z.string().optional(),
51
- network: z.string().min(1),
52
- asset: z.string().min(1),
53
- price: z.string().min(1),
54
- payee: z.string().optional(),
55
- });
56
- const payStablecoinInput = z.object({
57
- to: z.string().min(1),
58
- amount: z.string().min(1),
59
- });
60
- const buyApikeyInput = z.object({
61
- duration: z.number().optional().refine(val => !val || [1, 7, 30].includes(val), {
62
- message: "Duration must be 1, 7, or 30 days"
63
- })
64
- });
65
- const getInfoInput = z.object({});
66
- const guideInput = z.object({});
67
- const syncOpencodeConfigInput = z.object({});
68
- const refreshPricingInput = z.object({});
69
- // ============================================================================
70
- // Dynamic Pricing from Fact API
71
- // ============================================================================
72
- let CACHED_PRICING = null;
73
- async function fetchPricingFromFactAPI() {
74
- try {
75
- const res = await fetch(`${FACT_API_URL}/info`);
76
- if (res.ok) {
77
- const data = await res.json();
78
- CACHED_PRICING = {
79
- "1day": `${data.prices?.["1dayUsdc"] || 0.09} USDC`,
80
- "7days": `${data.prices?.["7daysUsdc"] || 0.49} USDC`,
81
- "30days": `${data.prices?.["30daysUsdc"] || 0.99} USDC`
82
- };
83
- return CACHED_PRICING;
84
- }
85
- }
86
- catch (error) {
87
- }
88
- CACHED_PRICING = {
89
- "1day": "0.09 USDC",
90
- "7days": "0.49 USDC",
91
- "30days": "0.99 USDC"
92
- };
93
- return CACHED_PRICING;
94
- }
95
- const buyerAccount = privateKeyToAccount(CONFIG.BUYER_PRIVATE_KEY);
96
- const publicClient = createPublicClient({
97
- transport: http(BUYER_RPC_URL),
98
- });
99
- const walletClient = createWalletClient({
100
- account: buyerAccount,
101
- transport: http(BUYER_RPC_URL),
102
- });
103
- // ============================================================================
104
- // Retry Configuration
105
- // ============================================================================
106
- const RETRY_CONFIG = {
107
- MAX_RETRIES: 3,
108
- BASE_DELAY: 1000,
109
- };
110
- async function fetchWithRetry(url, options, context = 'API Request') {
111
- for (let i = 0; i < RETRY_CONFIG.MAX_RETRIES; i++) {
112
- try {
113
- const response = await fetch(url, options);
114
- if (response.ok || response.status < 500) {
115
- return response;
116
- }
117
- }
118
- catch (error) {
119
- }
120
- if (i < RETRY_CONFIG.MAX_RETRIES - 1) {
121
- const delay = RETRY_CONFIG.BASE_DELAY * Math.pow(2, i);
122
- await new Promise(resolve => setTimeout(resolve, delay));
123
- }
124
- }
125
- throw new Error(`${context} failed after ${RETRY_CONFIG.MAX_RETRIES} retries`);
126
- }
127
- // ============================================================================
128
- // Token ABI
129
- // ============================================================================
130
- const tokenAbi = [
131
- {
132
- type: "function",
133
- name: "name",
134
- stateMutability: "view",
135
- inputs: [],
136
- outputs: [{ name: "", type: "string" }],
137
- },
138
- {
139
- type: "function",
140
- name: "balanceOf",
141
- stateMutability: "view",
142
- inputs: [{ name: "account", type: "address" }],
143
- outputs: [{ name: "", type: "uint256" }],
144
- },
145
- {
146
- type: "function",
147
- name: "decimals",
148
- stateMutability: "view",
149
- inputs: [],
150
- outputs: [{ name: "", type: "uint8" }],
151
- },
152
- {
153
- type: "function",
154
- name: "transferWithAuthorization",
155
- stateMutability: "nonpayable",
156
- inputs: [
157
- { name: "from", type: "address" },
158
- { name: "to", type: "address" },
159
- { name: "value", type: "uint256" },
160
- { name: "validAfter", type: "uint256" },
161
- { name: "validBefore", type: "uint256" },
162
- { name: "nonce", type: "bytes32" },
163
- { name: "v", type: "uint8" },
164
- { name: "r", type: "bytes32" },
165
- { name: "s", type: "bytes32" },
166
- ],
167
- outputs: [{ name: "", type: "bool" }],
168
- },
169
- ];
170
- const transferWithAuthorizationTypes = {
171
- TransferWithAuthorization: [
172
- { name: "from", type: "address" },
173
- { name: "to", type: "address" },
174
- { name: "value", type: "uint256" },
175
- { name: "validAfter", type: "uint256" },
176
- { name: "validBefore", type: "uint256" },
177
- { name: "nonce", type: "bytes32" },
178
- ],
179
- };
180
- function parseChainId(network) {
181
- const parts = network.split(":");
182
- if (parts.length === 2 && parts[0] === "eip155") {
183
- const value = Number(parts[1]);
184
- if (!Number.isNaN(value))
185
- return value;
186
- }
187
- return Number(BUYER_CHAIN_ID);
188
- }
189
- async function buildPaymentSignature(requirements) {
190
- const chainId = parseChainId(requirements.network);
191
- const verifyingContract = requirements.asset;
192
- if (!isAddress(verifyingContract)) {
193
- throw new Error("Invalid payment asset address");
194
- }
195
- let tokenName = await publicClient
196
- .readContract({
197
- address: verifyingContract,
198
- abi: tokenAbi,
199
- functionName: "name",
200
- })
201
- .catch(() => CONFIG.PAYMENT_TOKEN_NAME);
202
- let version = "1";
203
- // Special handling for Base Sepolia USDC and Base Mainnet USDC
204
- const sepoliaUSDC = "0x036cbd53842c5426634e7929541ec2318f3dcf7e";
205
- const mainnetUSDC = "0x833589fcd6edb6e08f4c7c32d4f71b54bda02913";
206
- if (requirements.network === "eip155:84532" &&
207
- requirements.asset.toLowerCase() === sepoliaUSDC.toLowerCase()) {
208
- tokenName = "USDC";
209
- version = "2";
210
- }
211
- else if (requirements.network === "eip155:8453" &&
212
- requirements.asset.toLowerCase() === mainnetUSDC.toLowerCase()) {
213
- tokenName = "USD Coin";
214
- version = "2";
215
- }
216
- const nonce = `0x${crypto.randomBytes(32).toString("hex")}`;
217
- const now = Math.floor(Date.now() / 1000);
218
- const validAfter = BigInt(0);
219
- const validBefore = BigInt(now + 28800);
220
- const payee = requirements.payee ?? buyerAccount.address;
221
- const signature = await walletClient.signTypedData({
222
- domain: {
223
- name: tokenName,
224
- version,
225
- chainId,
226
- verifyingContract,
227
- },
228
- types: transferWithAuthorizationTypes,
229
- primaryType: "TransferWithAuthorization",
230
- message: {
231
- from: buyerAccount.address,
232
- to: payee,
233
- value: BigInt(requirements.price),
234
- validAfter,
235
- validBefore,
236
- nonce,
237
- },
238
- });
239
- const { v, r, s } = hexToSignature(signature);
240
- return {
241
- from: buyerAccount.address,
242
- to: payee,
243
- value: requirements.price,
244
- validAfter: validAfter.toString(),
245
- validBefore: validBefore.toString(),
246
- nonce,
247
- v: Number(v),
248
- r,
249
- s,
250
- };
251
- }
252
- async function payStablecoin(params) {
253
- const [balance, decimals] = await Promise.all([
254
- publicClient.readContract({
255
- address: params.asset,
256
- abi: tokenAbi,
257
- functionName: 'balanceOf',
258
- args: [buyerAccount.address]
259
- }),
260
- publicClient.readContract({
261
- address: params.asset,
262
- abi: tokenAbi,
263
- functionName: 'decimals'
264
- })
265
- ]);
266
- const balanceNumber = Number(balance) / (10 ** Number(decimals));
267
- const amountNumber = Number(params.amount) / 1e6;
268
- if (balanceNumber < amountNumber) {
269
- throw new Error(`Insufficient balance: required ${amountNumber.toFixed(6)} USDC, available ${balanceNumber.toFixed(6)} USDC`);
270
- }
271
- const requirements = {
272
- scheme: "exact",
273
- network: params.isTestnet ? "eip155:84532" : `eip155:${BUYER_CHAIN_ID}`,
274
- asset: params.asset,
275
- price: params.amount,
276
- payee: params.to,
277
- };
278
- const signaturePayload = await buildPaymentSignature(requirements);
279
- const transferRes = await fetchWithRetry(`${FACT_API_URL}/v1/transfer`, {
280
- method: "POST",
281
- headers: {
282
- "content-type": "application/json",
283
- "PAYMENT-SIGNATURE": JSON.stringify(signaturePayload),
284
- },
285
- body: JSON.stringify({
286
- to: params.to,
287
- amount: params.amount,
288
- asset: params.asset,
289
- }),
290
- }, 'PAY_STABLECOIN Transfer');
291
- if (!transferRes.ok) {
292
- const error = await transferRes.text();
293
- const networkInfo = params.isTestnet ? "Testnet (Base Sepolia 84532)" : `Mainnet (Base ${BUYER_CHAIN_ID === '8453' ? 'Mainnet' : BUYER_CHAIN_ID})`;
294
- throw new Error(`Transfer failed (${networkInfo}): ${error}`);
295
- }
296
- const result = await transferRes.json();
297
- const deductedAmount = amountNumber.toFixed(6);
298
- const currentBalance = (balanceNumber - amountNumber).toFixed(6);
299
- return {
300
- ...result,
301
- from: buyerAccount.address,
302
- to: params.to,
303
- amount: `${amountNumber.toFixed(6)} USDC`,
304
- asset: params.asset,
305
- network: params.isTestnet ? "Testnet (Base Sepolia)" : "Mainnet (Base)",
306
- deductedAmount: `${deductedAmount} USDC`,
307
- currentBalance: `${currentBalance} USDC`
308
- };
309
- }
310
- const server = new Server({ name: "autopay-server", version: "0.1.0" }, { capabilities: { tools: {} } });
311
- server.setRequestHandler(ListToolsRequestSchema, async () => {
312
- return {
313
- tools: [
314
- {
315
- name: "guide",
316
- description: "⭐ FIRST TIME? Run this guide to learn how to use iAutoPay tools and commands.",
317
- inputSchema: zodToJsonSchema(guideInput),
318
- },
319
- {
320
- name: "info",
321
- description: "Get iAutoPay server information (API key stock, price, network config). Tip: Check before buying API keys.",
322
- inputSchema: zodToJsonSchema(getInfoInput),
323
- },
324
- {
325
- name: "buy_apikey",
326
- description: "Purchase an API key with optional duration (1/7/30 days). Prices: 1 day=0.9 USDC, 7 days=4.9 USDC, 30 days=9.9 USDC. Run 'info' first to confirm stock.",
327
- inputSchema: zodToJsonSchema(buyApikeyInput),
328
- },
329
- {
330
- name: "pay_stablecoin",
331
- description: "Pay stablecoin to any address using EIP-3009. Amount is in smallest unit (e.g., 100000 = 0.1 USDC).",
332
- inputSchema: zodToJsonSchema(payStablecoinInput),
333
- },
334
- {
335
- name: "sync_opencode_config",
336
- description: "Auto-configure opencode.json with quick commands (autopay_toA, autopay_toB, etc.)",
337
- inputSchema: zodToJsonSchema(syncOpencodeConfigInput),
338
- },
339
- {
340
- name: "refresh_pricing",
341
- description: "Refresh pricing from API. Use this if prices are changed on the server.",
342
- inputSchema: zodToJsonSchema(refreshPricingInput),
343
- },
344
- ],
345
- };
346
- });
347
- server.setRequestHandler(CallToolRequestSchema, async (request) => {
348
- const { name, arguments: args } = request.params;
349
- if (name === "pay_stablecoin") {
350
- const parsed = payStablecoinInput.parse(args);
351
- try {
352
- const result = await payStablecoin({
353
- to: parsed.to,
354
- amount: parsed.amount,
355
- asset: CURRENT_USDC,
356
- isTestnet: CUR_ENV === 'dev',
357
- });
358
- return { content: [{ type: "text", text: JSON.stringify(result) }] };
359
- }
360
- catch (error) {
361
- throw error;
362
- }
363
- }
364
- if (name === "buy_apikey") {
365
- const parsed = buyApikeyInput.parse(args);
366
- const duration = parsed.duration || 1;
367
- const [balance, decimals] = await Promise.all([
368
- publicClient.readContract({
369
- address: CURRENT_USDC,
370
- abi: tokenAbi,
371
- functionName: 'balanceOf',
372
- args: [buyerAccount.address]
373
- }),
374
- publicClient.readContract({
375
- address: CURRENT_USDC,
376
- abi: tokenAbi,
377
- functionName: 'decimals'
378
- })
379
- ]);
380
- const balanceNumber = Number(balance) / (10 ** Number(decimals));
381
- const priceMap = {
382
- 1: CACHED_PRICING?.["1day"] || "0.09 USDC",
383
- 7: CACHED_PRICING?.["7days"] || "0.49 USDC",
384
- 30: CACHED_PRICING?.["30days"] || "0.99 USDC",
385
- };
386
- const priceString = priceMap[duration];
387
- const priceNumber = parseFloat(priceString);
388
- const priceWei = (priceNumber * 1e6).toString();
389
- if (balanceNumber < priceNumber) {
390
- throw new Error(`Insufficient balance: required ${priceNumber.toFixed(6)} USDC, available ${balanceNumber.toFixed(6)} USDC`);
391
- }
392
- const requirements = {
393
- scheme: "exact",
394
- network: CUR_ENV === 'dev' ? "eip155:84532" : `eip155:${BUYER_CHAIN_ID}`,
395
- asset: CURRENT_USDC,
396
- price: priceWei,
397
- payee: "0x1a85156c2943b63febeee7883bd84a7d1cf0da0c",
398
- };
399
- const signaturePayload = await buildPaymentSignature(requirements);
400
- const buyRes = await fetch(`${FACT_API_URL}/v1/buy-apikey`, {
401
- method: "POST",
402
- headers: {
403
- "content-type": "application/json",
404
- "PAYMENT-SIGNATURE": JSON.stringify(signaturePayload),
405
- },
406
- body: JSON.stringify({ duration })
407
- });
408
- if (!buyRes.ok) {
409
- const error = await buyRes.text();
410
- const networkInfo = CUR_ENV === 'dev' ? "Testnet (Base Sepolia 84532)" : `Mainnet (Base ${BUYER_CHAIN_ID})`;
411
- throw new Error(`Buy API key failed (${networkInfo}): ${error}`);
412
- }
413
- const result = await buyRes.json();
414
- return {
415
- content: [{
416
- type: "text",
417
- text: JSON.stringify({
418
- ...result,
419
- price: `${priceNumber.toFixed(6)} USDC`,
420
- deductedAmount: `${priceNumber.toFixed(6)} USDC`,
421
- currentBalance: `${(balanceNumber - priceNumber).toFixed(6)} USDC`
422
- })
423
- }]
424
- };
425
- }
426
- if (name === "info") {
427
- const parsed = getInfoInput.parse(args);
428
- try {
429
- const res = await fetch(`${FACT_API_URL}/info`);
430
- if (res.ok) {
431
- const data = await res.json();
432
- return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
433
- }
434
- else {
435
- throw new Error(`Failed to fetch info: ${res.statusText}`);
436
- }
437
- }
438
- catch (error) {
439
- throw error;
440
- }
441
- }
442
- if (name === "guide") {
443
- const parsed = guideInput.parse(args);
444
- const networkInfo = `${BUYER_CHAIN_ID === '84532' ? 'Base Sepolia' : 'Base Mainnet'} (${BUYER_CHAIN_ID})`;
445
- const pricing = CACHED_PRICING || {
446
- "1day": "0.09 USDC",
447
- "7days": "0.49 USDC",
448
- "30days": "0.99 USDC"
449
- };
450
- const toolsData = {
451
- tools: [
452
- { name: "guide", description: "显示完整使用指南" },
453
- { name: "info", description: "获取服务器信息(库存、价格、网络配置)" },
454
- { name: "buy_apikey", description: "购买 API key(支持1/7/30天时长)" },
455
- { name: "pay_stablecoin", description: "支付稳定币到指定地址" },
456
- { name: "sync_opencode_config", description: "自动配置 opencode.json 快捷命令" },
457
- { name: "refresh_pricing", description: "从服务器刷新价格" }
458
- ],
459
- commands: [
460
- { name: "autopay_toA", description: "快速支付 0.01 USDC" },
461
- { name: "autopay_toB", description: "支付 0.05 USDC(需确认)" },
462
- { name: "autopay_buy_apikey_1day", description: `购买1天API Key(${pricing["1day"]})` },
463
- { name: "autopay_buy_apikey_7days", description: `购买7天API Key(${pricing["7days"]})` },
464
- { name: "autopay_buy_apikey_30days", description: `购买30天API Key(${pricing["30days"]})` },
465
- { name: "autopay_get_info", description: "快速获取服务器信息" }
466
- ],
467
- network: {
468
- testnet: "Base Sepolia (84532)",
469
- mainnet: "Base Mainnet (8453)",
470
- current: networkInfo
471
- },
472
- pricing,
473
- environment: CUR_ENV
474
- };
475
- return { content: [{ type: "text", text: JSON.stringify(toolsData, null, 2) }] };
476
- }
477
- if (name === "sync_opencode_config") {
478
- const parsed = syncOpencodeConfigInput.parse(args);
479
- try {
480
- const fs = await import('fs/promises');
481
- const opencodePath = '/Users/michael/opc/proj/iautopay/opencode.json';
482
- const opencodeData = JSON.parse(await fs.readFile(opencodePath, 'utf-8'));
483
- const pricing = CACHED_PRICING || {
484
- "1day": "0.09 USDC",
485
- "7days": "0.49 USDC",
486
- "30days": "0.99 USDC"
487
- };
488
- const requiredCommands = {
489
- "autopay_toA": {
490
- "template": "使用 pay_stablecoin 工具向 0x1a85156c2943b63febeee7883bd84a7d1cf0da0c 支付 0.01 USDC,参数为:to=\"0x1a85156c2943b63febeee7883bd84a7d1cf0da0c\", amount=\"10000\"",
491
- "description": "支付0.01 USDC给A账户"
492
- },
493
- "autopay_toB": {
494
- "template": "首先使用 question 工具询问用户确认,选项包括:1) 确认(继续支付),2) 取消(不进行支付)。显示支付详情:向 0x1a85156c2943b63febeee7883bd84a7d1cf0da0c 支付 0.05 USDC,参数为:to=\"0x1a85156c2943b63febeee7883bd84a7d1cf0da0c\", amount=\"50000\"。只有用户选择确认时才继续支付。",
495
- "description": "支付0.05 USDC给A账户(需要确认)"
496
- },
497
- "autopay_buy_apikey_1day": {
498
- "template": "使用 buy_apikey 工具购买1天API Key,参数为:{\"duration\": 1}",
499
- "description": `购买1天API Key(${pricing["1day"]})`
500
- },
501
- "autopay_buy_apikey_7days": {
502
- "template": "使用 buy_apikey 工具购买7天API Key,参数为:{\"duration\": 7}",
503
- "description": `购买7天API Key(${pricing["7days"]})`
504
- },
505
- "autopay_buy_apikey_30days": {
506
- "template": "使用 buy_apikey 工具购买30天API Key,参数为:{\"duration\": 30}",
507
- "description": `购买30天API Key(${pricing["30days"]})`
508
- },
509
- "autopay_get_info": {
510
- "template": "使用 info 工具获取服务器信息(API Key 库存、价格、网络配置)",
511
- "description": "获取iAutoPay服务器信息"
512
- },
513
- "autopay_guide": {
514
- "template": "使用 guide 工具显示 iAutoPay 使用指南",
515
- "description": "显示iAutoPay使用指南"
516
- }
517
- };
518
- let addedCommands = [];
519
- let updatedCommands = [];
520
- if (!opencodeData.command) {
521
- opencodeData.command = {};
522
- }
523
- for (const [key, value] of Object.entries(requiredCommands)) {
524
- if (!opencodeData.command[key]) {
525
- opencodeData.command[key] = value;
526
- addedCommands.push(key);
527
- }
528
- }
529
- if (addedCommands.length > 0) {
530
- await fs.writeFile(opencodePath, JSON.stringify(opencodeData, null, 2), 'utf-8');
531
- return {
532
- content: [{
533
- type: "text",
534
- text: `✅ 已添加 ${addedCommands.length} 个命令到 opencode.json:\n${addedCommands.map(c => ` - ${c}`).join('\n')}`
535
- }]
536
- };
537
- }
538
- else {
539
- return {
540
- content: [{
541
- type: "text",
542
- text: "✅ 所有 autopay_ 命令已存在,无需更新"
543
- }]
544
- };
545
- }
546
- }
547
- catch (error) {
548
- throw new Error(`同步配置失败: ${error}`);
549
- }
550
- }
551
- if (name === "refresh_pricing") {
552
- const parsed = refreshPricingInput.parse(args);
553
- try {
554
- await fetchPricingFromFactAPI();
555
- return {
556
- content: [{
557
- type: "text",
558
- text: `✅ 价格已刷新:\n${JSON.stringify(CACHED_PRICING, null, 2)}`
559
- }]
560
- };
561
- }
562
- catch (error) {
563
- throw new Error(`刷新价格失败: ${error}`);
564
- }
565
- }
566
- throw new Error(`Unknown tool: ${name}`);
567
- });
568
- const transport = new StdioServerTransport();
569
- await fetchPricingFromFactAPI();
570
- try {
571
- const usdcBalance = await publicClient.readContract({
572
- address: CURRENT_USDC,
573
- abi: tokenAbi,
574
- functionName: 'balanceOf',
575
- args: [buyerAccount.address]
576
- });
577
- const decimals = await publicClient.readContract({
578
- address: CURRENT_USDC,
579
- abi: tokenAbi,
580
- functionName: 'decimals'
581
- });
582
- }
583
- catch (error) {
584
- }
585
- await server.connect(transport);