@newblock/iautopay-mcp 0.0.3 → 0.0.6
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/CLAUDE_CLI_MCP_SETUP.md +16 -13
- package/README.md +120 -171
- package/bin/iautopay-mcp.js +0 -1
- package/dist/iautopay-mcp.js +102 -170
- package/dist/server.js +1 -66
- package/mcp-config.json.example +2 -2
- package/package.json +2 -2
package/CLAUDE_CLI_MCP_SETUP.md
CHANGED
|
@@ -7,11 +7,12 @@ 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_guide` - Show iAutoPay usage guide
|
|
10
11
|
- `/autopay_toA` - Quick payment of 0.01 USDC
|
|
11
12
|
- `/autopay_toB` - Quick payment of 0.05 USDC (with confirmation)
|
|
12
|
-
- `/
|
|
13
|
-
- `/
|
|
14
|
-
- `/
|
|
13
|
+
- `/autopay_buy_apikey_1day` - Buy 1-day API Key (0.09 USDC)
|
|
14
|
+
- `/autopay_buy_apikey_7days` - Buy 7-day API Key (0.49 USDC)
|
|
15
|
+
- `/autopay_get_info` - Get iAutoPay server information
|
|
15
16
|
|
|
16
17
|
## Claude CLI
|
|
17
18
|
|
|
@@ -28,7 +29,7 @@ This method uses the configuration file generated at `mcp-config.json` during in
|
|
|
28
29
|
|
|
29
30
|
```bash
|
|
30
31
|
# Add MCP server to Claude CLI
|
|
31
|
-
BUYER_PRIVATE_KEY="your_private_key" claude mcp add
|
|
32
|
+
BUYER_PRIVATE_KEY="your_private_key" claude mcp add autopay \
|
|
32
33
|
-e BUYER_PRIVATE_KEY="your_private_key" \
|
|
33
34
|
-- npx -y @newblock/iautopay-mcp
|
|
34
35
|
|
|
@@ -36,7 +37,7 @@ BUYER_PRIVATE_KEY="your_private_key" claude mcp add iauto-pay \
|
|
|
36
37
|
claude mcp list
|
|
37
38
|
|
|
38
39
|
# Should show:
|
|
39
|
-
#
|
|
40
|
+
# autopay: npx -y @newblock/iautopay-mcp - ✓ Connected
|
|
40
41
|
```
|
|
41
42
|
|
|
42
43
|
After adding, you can simply run `claude` without any additional flags.
|
|
@@ -47,7 +48,7 @@ After adding, you can simply run `claude` without any additional flags.
|
|
|
47
48
|
# Create mcp-config.json manually:
|
|
48
49
|
{
|
|
49
50
|
"mcpServers": {
|
|
50
|
-
"
|
|
51
|
+
"autopay": {
|
|
51
52
|
"command": "npx",
|
|
52
53
|
"args": ["-y", "@newblock/iautopay-mcp"],
|
|
53
54
|
"env": {
|
|
@@ -65,10 +66,12 @@ claude --mcp-config mcp-config.json
|
|
|
65
66
|
|
|
66
67
|
When using Claude CLI with MCP enabled, the following tools are available:
|
|
67
68
|
|
|
68
|
-
- `
|
|
69
|
-
- `
|
|
70
|
-
- `
|
|
71
|
-
- `
|
|
69
|
+
- `guide` - Display complete iAutoPay usage guide
|
|
70
|
+
- `info` - Get server information (stock, prices, network config)
|
|
71
|
+
- `buy_apikey` - Buy API key (supports 1/7 day durations)
|
|
72
|
+
- `pay_stablecoin` - Pay stablecoin to specified address
|
|
73
|
+
- `sync_opencode_config` - Auto-configure opencode.json shortcuts
|
|
74
|
+
- `refresh_pricing` - Refresh prices from server
|
|
72
75
|
|
|
73
76
|
## Usage Examples
|
|
74
77
|
|
|
@@ -91,14 +94,14 @@ claude
|
|
|
91
94
|
claude mcp list
|
|
92
95
|
|
|
93
96
|
# Get details of specific server
|
|
94
|
-
claude mcp get
|
|
97
|
+
claude mcp get autopay
|
|
95
98
|
```
|
|
96
99
|
|
|
97
100
|
## Removing MCP Server
|
|
98
101
|
|
|
99
102
|
If you added to local config:
|
|
100
103
|
```bash
|
|
101
|
-
claude mcp remove
|
|
104
|
+
claude mcp remove autopay -s local
|
|
102
105
|
```
|
|
103
106
|
|
|
104
107
|
If using config file, simply remove the `--mcp-config mcp-config.json` flag when running `claude`.
|
|
@@ -112,7 +115,7 @@ If using config file, simply remove the `--mcp-config mcp-config.json` flag when
|
|
|
112
115
|
|
|
113
116
|
**Tools not showing up:**
|
|
114
117
|
1. Verify MCP connection: `claude mcp list`
|
|
115
|
-
2. Check server health: `claude mcp get
|
|
118
|
+
2. Check server health: `claude mcp get autopay`
|
|
116
119
|
3. Restart Claude CLI
|
|
117
120
|
|
|
118
121
|
**Wrong environment (dev vs prod):**
|
package/README.md
CHANGED
|
@@ -1,22 +1,6 @@
|
|
|
1
1
|
# iAutoPay MCP Service
|
|
2
2
|
|
|
3
|
-
|
|
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
|
-
"
|
|
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": "
|
|
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
|
|
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,160 @@ Add to your `~/.claude/claude_desktop_config.json`:
|
|
|
98
65
|
```json
|
|
99
66
|
{
|
|
100
67
|
"mcpServers": {
|
|
101
|
-
"
|
|
68
|
+
"autopay": {
|
|
102
69
|
"command": "npx",
|
|
103
|
-
"args": ["@newblock/iautopay-mcp"],
|
|
70
|
+
"args": ["-y", "@newblock/iautopay-mcp"],
|
|
104
71
|
"env": {
|
|
105
|
-
"BUYER_PRIVATE_KEY": "
|
|
72
|
+
"BUYER_PRIVATE_KEY": "0xEVM_wallet_private_key"
|
|
106
73
|
}
|
|
107
74
|
}
|
|
108
75
|
}
|
|
109
76
|
}
|
|
110
77
|
```
|
|
111
78
|
|
|
112
|
-
|
|
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
|
|
113
99
|
|
|
114
|
-
###
|
|
115
|
-
|
|
116
|
-
⭐ **FIRST TIME?** Run this guide to learn how to use iAutoPay tools and commands.
|
|
117
|
-
|
|
118
|
-
**Parameters:**
|
|
119
|
-
```json
|
|
120
|
-
{}
|
|
121
|
-
```
|
|
100
|
+
### opencode autopay command loading success
|
|
122
101
|
|
|
123
|
-
|
|
124
|
-
- Complete guide with all tools and commands
|
|
125
|
-
- Pricing information
|
|
126
|
-
- Network configuration
|
|
102
|
+

|
|
127
103
|
|
|
128
|
-
|
|
104
|
+
## MCP Tools Usage
|
|
129
105
|
|
|
130
|
-
|
|
106
|
+
### Quick Commands Configuration
|
|
131
107
|
|
|
132
|
-
|
|
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
|
-
"
|
|
141
|
-
"
|
|
142
|
-
"
|
|
143
|
-
|
|
144
|
-
|
|
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
|
-
"
|
|
147
|
-
"
|
|
148
|
-
|
|
123
|
+
"command": {
|
|
124
|
+
"autopay_toA": {
|
|
125
|
+
"template": "Use pay_stablecoin tool to pay 0.01 USDC to 0x1a85156c2943b63febeee7883bd84a7d1cf0da0c, params: to=\"0x1a85156c2943b63febeee7883bd84a7d1cf0da0c\", amount=\"10000\"",
|
|
126
|
+
"description": "Pay 0.01 USDC to account A"
|
|
127
|
+
},
|
|
128
|
+
"autopay_toB": {
|
|
129
|
+
"template": "First use question tool to ask user confirmation with options: 1) Confirm (continue payment), 2) Cancel (do not pay). Show payment details: Pay 0.05 USDC to 0x1a85156c2943b63febeee7883bd84a7d1cf0da0c, params: to=\"0x1a85156c2943b63febeee7883bd84a7d1cf0da0c\", amount=\"50000\". Only proceed if user confirms.",
|
|
130
|
+
"description": "Pay 0.05 USDC to account A (requires confirmation)"
|
|
131
|
+
},
|
|
132
|
+
"autopay_buy_apikey_1day": {
|
|
133
|
+
"template": "Use buy_apikey tool to buy 1-day API Key, params: {\"duration\": 1}",
|
|
134
|
+
"description": "Buy 1-day API Key (0.09 USDC)"
|
|
135
|
+
},
|
|
136
|
+
"autopay_buy_apikey_7days": {
|
|
137
|
+
"template": "Use buy_apikey tool to buy 7-day API Key, params: {\"duration\": 7}",
|
|
138
|
+
"description": "Buy 7-day API Key (0.49 USDC)"
|
|
139
|
+
},
|
|
140
|
+
"autopay_get_info": {
|
|
141
|
+
"template": "Use info tool to get server information (API Key stock, prices, network config)",
|
|
142
|
+
"description": "Get iAutoPay server information"
|
|
143
|
+
},
|
|
144
|
+
"autopay_guide": {
|
|
145
|
+
"template": "Use guide tool to show iAutoPay usage guide",
|
|
146
|
+
"description": "Show iAutoPay usage guide"
|
|
147
|
+
}
|
|
149
148
|
}
|
|
150
149
|
}
|
|
151
150
|
```
|
|
152
151
|
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
Purchase an API key with optional duration (1/7/30 days).
|
|
156
|
-
|
|
157
|
-
**Parameters:**
|
|
158
|
-
```json
|
|
159
|
-
{
|
|
160
|
-
"duration": 1
|
|
161
|
-
}
|
|
162
|
-
```
|
|
163
|
-
|
|
164
|
-
**Duration Options:**
|
|
165
|
-
- `1`: 1 day validity
|
|
166
|
-
- `7`: 7 days validity
|
|
167
|
-
- `30`: 30 days validity
|
|
152
|
+
Run `sync_opencode_config` tool to auto-add these commands to your config.
|
|
168
153
|
|
|
169
|
-
|
|
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
|
-
```
|
|
180
|
-
|
|
181
|
-
### pay_stablecoin
|
|
182
|
-
|
|
183
|
-
Pay stablecoin to any address using EIP-3009.
|
|
184
|
-
|
|
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
|
-
```
|
|
154
|
+
### Opencode Quick Commands Usage Examples
|
|
206
155
|
|
|
207
|
-
###
|
|
156
|
+
### 1: /autopay_guide
|
|
208
157
|
|
|
209
|
-
|
|
158
|
+
Output:
|
|
210
159
|
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
160
|
+
iAutoPay Usage Guide
|
|
161
|
+
Available Tools
|
|
162
|
+
- guide - Display complete usage guide
|
|
163
|
+
- info - Get server information (stock, prices, network config)
|
|
164
|
+
- buy_apikey - Buy API key (supports 1/7 day durations)
|
|
165
|
+
- pay_stablecoin - Pay stablecoin to specified address
|
|
166
|
+
- sync_opencode_config - Auto-configure opencode.json shortcuts
|
|
167
|
+
- refresh_pricing - Refresh prices from server
|
|
168
|
+
Quick Commands
|
|
169
|
+
- autopay_toA - Quick pay 0.01 USDC
|
|
170
|
+
- autopay_toB - Pay 0.1 USDC (requires confirmation)
|
|
171
|
+
- autopay_buy_apikey_1day - Buy 1-day API Key (0.1 USDC)
|
|
172
|
+
- autopay_buy_apikey_7days - Buy 7-day API Key (0.9 USDC)
|
|
173
|
+
- autopay_get_info - Quick get server information
|
|
174
|
+
Network Information
|
|
175
|
+
- Testnet: Base Sepolia (84532)
|
|
176
|
+
- Mainnet: Base Mainnet (8453)
|
|
177
|
+
- Current Network: Base Sepolia (84532)
|
|
178
|
+
Pricing
|
|
179
|
+
- 1 day: 0.1 USDC
|
|
180
|
+
- 7 days: 0.9 USDC
|
|
181
|
+
Environment: dev
|
|
215
182
|
|
|
216
|
-
|
|
217
|
-
```json
|
|
218
|
-
{
|
|
219
|
-
"message": "✅ 已添加 7 个命令到 opencode.json"
|
|
220
|
-
}
|
|
221
|
-
```
|
|
183
|
+
### 2: /autopay_toA
|
|
222
184
|
|
|
223
|
-
|
|
185
|
+
Output:
|
|
224
186
|
|
|
225
|
-
|
|
187
|
+
Paying 0.01 USDC to 0x1a85156c2943b63febeee7883bd84a7d1cf0da0c...
|
|
188
|
+
Transaction hash: 0xabc123...
|
|
189
|
+
Payment successful!
|
|
226
190
|
|
|
227
|
-
|
|
228
|
-
```json
|
|
229
|
-
{}
|
|
230
|
-
```
|
|
191
|
+
### 3: /autopay_toB
|
|
231
192
|
|
|
232
|
-
|
|
233
|
-
```json
|
|
234
|
-
{
|
|
235
|
-
"1day": "0.09 USDC",
|
|
236
|
-
"7days": "0.49 USDC",
|
|
237
|
-
"30days": "0.99 USDC"
|
|
238
|
-
}
|
|
239
|
-
```
|
|
193
|
+
Output:
|
|
240
194
|
|
|
241
|
-
|
|
195
|
+
Please confirm payment:
|
|
196
|
+
- Amount: 0.05 USDC
|
|
197
|
+
- Recipient: 0x1a85156c2943b63febeee7883bd84a7d1cf0da0c
|
|
198
|
+
- Network: Base Sepolia (84532)
|
|
242
199
|
|
|
243
|
-
|
|
200
|
+
Select: 1) Confirm 2) Cancel
|
|
201
|
+
[User selects confirm]
|
|
244
202
|
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
- USDC Address: 0x036CbD53842c5426634e7929541eC2318f3dCF7e
|
|
249
|
-
- Token Name: "USDC"
|
|
203
|
+
Paying 0.05 USDC to 0x1a85156c2943b63febeee7883bd84a7d1cf0da0c...
|
|
204
|
+
Transaction hash: 0xdef456...
|
|
205
|
+
Payment successful!
|
|
250
206
|
|
|
251
|
-
###
|
|
252
|
-
- Chain ID: 8453
|
|
253
|
-
- RPC URL: https://mainnet.base.org
|
|
254
|
-
- USDC Address: 0x833589fcd6edb6e08f4c7c32d4f71b54bda02913
|
|
255
|
-
- Token Name: "USD Coin"
|
|
207
|
+
### 4: /autopay_buy_apikey_1day
|
|
256
208
|
|
|
257
|
-
|
|
209
|
+
Output:
|
|
258
210
|
|
|
259
|
-
|
|
211
|
+
Purchasing 1-day API Key...
|
|
212
|
+
Price: 0.09 USDC
|
|
213
|
+
Processing payment...
|
|
214
|
+
Transaction hash: 0xghi789...
|
|
215
|
+
Purchase successful!
|
|
260
216
|
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
Use buy_apikey tool with duration: 1
|
|
264
|
-
Receive API key in response
|
|
265
|
-
```
|
|
217
|
+
Your API Key: sk-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
|
218
|
+
Valid for: 1 day
|
|
266
219
|
|
|
267
|
-
|
|
220
|
+
👉 Check [LLM Services Guide](doc/LLM_SERVICES_GUIDE.md) to learn how to use the API Key to access supported models
|
|
268
221
|
|
|
269
|
-
```
|
|
270
|
-
Use pay_stablecoin tool with to: "0x1a85156c2943b63febeee7883bd84a7d1cf0da0c" and amount: "10000"
|
|
271
|
-
Transaction executes automatically
|
|
272
|
-
Receive transaction hash
|
|
273
|
-
```
|
|
274
222
|
|
|
275
223
|
## License
|
|
276
224
|
|
|
@@ -286,5 +234,6 @@ For issues and questions, please use the [GitHub Issues](https://github.com/newb
|
|
|
286
234
|
|
|
287
235
|
## Documentation
|
|
288
236
|
|
|
237
|
+
- [LLM Services Guide](doc/LLM_SERVICES_GUIDE.md) - Supported models and API Key purchase guide
|
|
289
238
|
- [CLAUDE_CLI_MCP_SETUP.md](CLAUDE_CLI_MCP_SETUP.md) - Claude CLI integration guide
|
|
290
239
|
- [mcp-config.json.example](mcp-config.json.example) - MCP configuration template
|
package/bin/iautopay-mcp.js
CHANGED
package/dist/iautopay-mcp.js
CHANGED
|
@@ -31,8 +31,7 @@ if (!CONFIG.BUYER_PRIVATE_KEY) {
|
|
|
31
31
|
}
|
|
32
32
|
// Validate private key format
|
|
33
33
|
try {
|
|
34
|
-
|
|
35
|
-
console.log(`[CONFIG] Private key validated, account: ${account.address}`);
|
|
34
|
+
privateKeyToAccount(CONFIG.BUYER_PRIVATE_KEY);
|
|
36
35
|
}
|
|
37
36
|
catch (error) {
|
|
38
37
|
throw new Error(`Invalid BUYER_PRIVATE_KEY format: ${error}`);
|
|
@@ -54,10 +53,10 @@ const paymentRequirementsSchema = z.object({
|
|
|
54
53
|
price: z.string().min(1),
|
|
55
54
|
payee: z.string().optional(),
|
|
56
55
|
});
|
|
57
|
-
const payStablecoinInput = z.object({
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
});
|
|
56
|
+
// const payStablecoinInput = z.object({
|
|
57
|
+
// to: z.string().min(1),
|
|
58
|
+
// amount: z.string().min(1),
|
|
59
|
+
// });
|
|
61
60
|
const buyApikeyInput = z.object({
|
|
62
61
|
duration: z.number().optional().refine(val => !val || [1, 7, 30].includes(val), {
|
|
63
62
|
message: "Duration must be 1, 7, or 30 days"
|
|
@@ -65,7 +64,7 @@ const buyApikeyInput = z.object({
|
|
|
65
64
|
});
|
|
66
65
|
const getInfoInput = z.object({});
|
|
67
66
|
const guideInput = z.object({});
|
|
68
|
-
const syncOpencodeConfigInput = z.object({});
|
|
67
|
+
// const syncOpencodeConfigInput = z.object({});
|
|
69
68
|
const refreshPricingInput = z.object({});
|
|
70
69
|
// ============================================================================
|
|
71
70
|
// Dynamic Pricing from Fact API
|
|
@@ -81,20 +80,16 @@ async function fetchPricingFromFactAPI() {
|
|
|
81
80
|
"7days": `${data.prices?.["7daysUsdc"] || 0.49} USDC`,
|
|
82
81
|
"30days": `${data.prices?.["30daysUsdc"] || 0.99} USDC`
|
|
83
82
|
};
|
|
84
|
-
console.log(`[PRICING] Loaded from fact-api:`, CACHED_PRICING);
|
|
85
83
|
return CACHED_PRICING;
|
|
86
84
|
}
|
|
87
85
|
}
|
|
88
86
|
catch (error) {
|
|
89
|
-
console.warn(`[PRICING] Failed to fetch from fact-api, using defaults. Error:`, error);
|
|
90
87
|
}
|
|
91
|
-
// Default pricing as fallback
|
|
92
88
|
CACHED_PRICING = {
|
|
93
89
|
"1day": "0.09 USDC",
|
|
94
90
|
"7days": "0.49 USDC",
|
|
95
91
|
"30days": "0.99 USDC"
|
|
96
92
|
};
|
|
97
|
-
console.log(`[PRICING] Using default pricing:`, CACHED_PRICING);
|
|
98
93
|
return CACHED_PRICING;
|
|
99
94
|
}
|
|
100
95
|
const buyerAccount = privateKeyToAccount(CONFIG.BUYER_PRIVATE_KEY);
|
|
@@ -119,14 +114,11 @@ async function fetchWithRetry(url, options, context = 'API Request') {
|
|
|
119
114
|
if (response.ok || response.status < 500) {
|
|
120
115
|
return response;
|
|
121
116
|
}
|
|
122
|
-
console.log(`[RETRY] ${context} - Attempt ${i + 1}/${RETRY_CONFIG.MAX_RETRIES} failed, status: ${response.status}`);
|
|
123
117
|
}
|
|
124
118
|
catch (error) {
|
|
125
|
-
console.log(`[RETRY] ${context} - Attempt ${i + 1}/${RETRY_CONFIG.MAX_RETRIES} error:`, error);
|
|
126
119
|
}
|
|
127
120
|
if (i < RETRY_CONFIG.MAX_RETRIES - 1) {
|
|
128
121
|
const delay = RETRY_CONFIG.BASE_DELAY * Math.pow(2, i);
|
|
129
|
-
console.log(`[RETRY] ${context} - Waiting ${delay}ms before retry...`);
|
|
130
122
|
await new Promise(resolve => setTimeout(resolve, delay));
|
|
131
123
|
}
|
|
132
124
|
}
|
|
@@ -258,11 +250,6 @@ async function buildPaymentSignature(requirements) {
|
|
|
258
250
|
};
|
|
259
251
|
}
|
|
260
252
|
async function payStablecoin(params) {
|
|
261
|
-
console.log(`[PAY_STABLECOIN] Starting payment...`);
|
|
262
|
-
console.log(`[PAY_STABLECOIN] Network: ${params.isTestnet ? "eip155:84532 (Testnet)" : `eip155:${BUYER_CHAIN_ID}`}`);
|
|
263
|
-
console.log(`[PAY_STABLECOIN] Asset: ${params.asset}`);
|
|
264
|
-
console.log(`[PAY_STABLECOIN] Amount: ${params.amount}`);
|
|
265
|
-
console.log(`[PAY_STABLECOIN] To: ${params.to}`);
|
|
266
253
|
const [balance, decimals] = await Promise.all([
|
|
267
254
|
publicClient.readContract({
|
|
268
255
|
address: params.asset,
|
|
@@ -278,10 +265,7 @@ async function payStablecoin(params) {
|
|
|
278
265
|
]);
|
|
279
266
|
const balanceNumber = Number(balance) / (10 ** Number(decimals));
|
|
280
267
|
const amountNumber = Number(params.amount) / 1e6;
|
|
281
|
-
console.log(`[PAY_STABLECOIN] Current balance: ${balanceNumber.toFixed(6)} USDC`);
|
|
282
|
-
console.log(`[PAY_STABLECOIN] Required: ${amountNumber.toFixed(6)} USDC`);
|
|
283
268
|
if (balanceNumber < amountNumber) {
|
|
284
|
-
console.log(`[PAY_STABLECOIN] Insufficient balance!`);
|
|
285
269
|
throw new Error(`Insufficient balance: required ${amountNumber.toFixed(6)} USDC, available ${balanceNumber.toFixed(6)} USDC`);
|
|
286
270
|
}
|
|
287
271
|
const requirements = {
|
|
@@ -291,10 +275,7 @@ async function payStablecoin(params) {
|
|
|
291
275
|
price: params.amount,
|
|
292
276
|
payee: params.to,
|
|
293
277
|
};
|
|
294
|
-
console.log(`[PAY_STABLECOIN] Building payment signature...`);
|
|
295
278
|
const signaturePayload = await buildPaymentSignature(requirements);
|
|
296
|
-
console.log(`[PAY_STABLECOIN] Signature built, calling fact-api...`);
|
|
297
|
-
console.log(`[PAY_STABLECOIN] Fact API URL: ${FACT_API_URL}/v1/transfer`);
|
|
298
279
|
const transferRes = await fetchWithRetry(`${FACT_API_URL}/v1/transfer`, {
|
|
299
280
|
method: "POST",
|
|
300
281
|
headers: {
|
|
@@ -307,15 +288,12 @@ async function payStablecoin(params) {
|
|
|
307
288
|
asset: params.asset,
|
|
308
289
|
}),
|
|
309
290
|
}, 'PAY_STABLECOIN Transfer');
|
|
310
|
-
console.log(`[PAY_STABLECOIN] Fact API response status: ${transferRes.status}`);
|
|
311
291
|
if (!transferRes.ok) {
|
|
312
292
|
const error = await transferRes.text();
|
|
313
|
-
console.log(`[PAY_STABLECOIN] Transfer failed: ${error}`);
|
|
314
293
|
const networkInfo = params.isTestnet ? "Testnet (Base Sepolia 84532)" : `Mainnet (Base ${BUYER_CHAIN_ID === '8453' ? 'Mainnet' : BUYER_CHAIN_ID})`;
|
|
315
294
|
throw new Error(`Transfer failed (${networkInfo}): ${error}`);
|
|
316
295
|
}
|
|
317
296
|
const result = await transferRes.json();
|
|
318
|
-
console.log(`[PAY_STABLECOIN] Transfer successful:`, result);
|
|
319
297
|
const deductedAmount = amountNumber.toFixed(6);
|
|
320
298
|
const currentBalance = (balanceNumber - amountNumber).toFixed(6);
|
|
321
299
|
return {
|
|
@@ -348,16 +326,16 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
|
348
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.",
|
|
349
327
|
inputSchema: zodToJsonSchema(buyApikeyInput),
|
|
350
328
|
},
|
|
351
|
-
{
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
},
|
|
356
|
-
{
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
},
|
|
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
|
+
// },
|
|
361
339
|
{
|
|
362
340
|
name: "refresh_pricing",
|
|
363
341
|
description: "Refresh pricing from API. Use this if prices are changed on the server.",
|
|
@@ -368,21 +346,20 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
|
368
346
|
});
|
|
369
347
|
server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
370
348
|
const { name, arguments: args } = request.params;
|
|
371
|
-
if (name === "pay_stablecoin") {
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
}
|
|
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
|
+
// }
|
|
386
363
|
if (name === "buy_apikey") {
|
|
387
364
|
const parsed = buyApikeyInput.parse(args);
|
|
388
365
|
const duration = parsed.duration || 1;
|
|
@@ -408,8 +385,6 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
408
385
|
const priceString = priceMap[duration];
|
|
409
386
|
const priceNumber = parseFloat(priceString);
|
|
410
387
|
const priceWei = (priceNumber * 1e6).toString();
|
|
411
|
-
console.log(`[BUY_APIKEY] Checking balance...`);
|
|
412
|
-
console.log(`[BUY_APIKEY] Required: ${priceNumber.toFixed(6)} USDC, Available: ${balanceNumber.toFixed(6)} USDC`);
|
|
413
388
|
if (balanceNumber < priceNumber) {
|
|
414
389
|
throw new Error(`Insufficient balance: required ${priceNumber.toFixed(6)} USDC, available ${balanceNumber.toFixed(6)} USDC`);
|
|
415
390
|
}
|
|
@@ -420,11 +395,7 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
420
395
|
price: priceWei,
|
|
421
396
|
payee: "0x1a85156c2943b63febeee7883bd84a7d1cf0da0c",
|
|
422
397
|
};
|
|
423
|
-
console.log(`[BUY_APIKEY] Building payment signature...`);
|
|
424
398
|
const signaturePayload = await buildPaymentSignature(requirements);
|
|
425
|
-
console.log(`[BUY_APIKEY] Signature built, calling fact-api...`);
|
|
426
|
-
console.log(`[BUY_APIKEY] Fact API URL: ${FACT_API_URL}/v1/buy-apikey`);
|
|
427
|
-
console.log(`[BUY_APIKEY] Sending request to fact-api (no retry, generate new nonce on failure)...`);
|
|
428
399
|
const buyRes = await fetch(`${FACT_API_URL}/v1/buy-apikey`, {
|
|
429
400
|
method: "POST",
|
|
430
401
|
headers: {
|
|
@@ -433,15 +404,12 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
433
404
|
},
|
|
434
405
|
body: JSON.stringify({ duration })
|
|
435
406
|
});
|
|
436
|
-
console.log(`[BUY_APIKEY] Fact API response status: ${buyRes.status}`);
|
|
437
407
|
if (!buyRes.ok) {
|
|
438
408
|
const error = await buyRes.text();
|
|
439
|
-
console.log(`[BUY_APIKEY] Buy API key failed ${error}`);
|
|
440
409
|
const networkInfo = CUR_ENV === 'dev' ? "Testnet (Base Sepolia 84532)" : `Mainnet (Base ${BUYER_CHAIN_ID})`;
|
|
441
410
|
throw new Error(`Buy API key failed (${networkInfo}): ${error}`);
|
|
442
411
|
}
|
|
443
412
|
const result = await buyRes.json();
|
|
444
|
-
console.log(`[BUY_APIKEY] Buy API key successful:`, result);
|
|
445
413
|
return {
|
|
446
414
|
content: [{
|
|
447
415
|
type: "text",
|
|
@@ -505,80 +473,78 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
505
473
|
};
|
|
506
474
|
return { content: [{ type: "text", text: JSON.stringify(toolsData, null, 2) }] };
|
|
507
475
|
}
|
|
508
|
-
if (name === "sync_opencode_config") {
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
}
|
|
581
|
-
}
|
|
476
|
+
// if (name === "sync_opencode_config") {
|
|
477
|
+
// const parsed = syncOpencodeConfigInput.parse(args);
|
|
478
|
+
// try {
|
|
479
|
+
// const fs = await import('fs/promises');
|
|
480
|
+
// const opencodePath = '/Users/michael/opc/proj/iautopay/opencode.json';
|
|
481
|
+
// const opencodeData = JSON.parse(await fs.readFile(opencodePath, 'utf-8'));
|
|
482
|
+
// const pricing = CACHED_PRICING || {
|
|
483
|
+
// "1day": "0.09 USDC",
|
|
484
|
+
// "7days": "0.49 USDC",
|
|
485
|
+
// "30days": "0.99 USDC"
|
|
486
|
+
// };
|
|
487
|
+
// const requiredCommands = {
|
|
488
|
+
// "autopay_toA": {
|
|
489
|
+
// "template": "使用 pay_stablecoin 工具向 0x1a85156c2943b63febeee7883bd84a7d1cf0da0c 支付 0.01 USDC,参数为:to=\"0x1a85156c2943b63febeee7883bd84a7d1cf0da0c\", amount=\"10000\"",
|
|
490
|
+
// "description": "支付0.01 USDC给A账户"
|
|
491
|
+
// },
|
|
492
|
+
// "autopay_toB": {
|
|
493
|
+
// "template": "首先使用 question 工具询问用户确认,选项包括:1) 确认(继续支付),2) 取消(不进行支付)。显示支付详情:向 0x1a85156c2943b63febeee7883bd84a7d1cf0da0c 支付 0.05 USDC,参数为:to=\"0x1a85156c2943b63febeee7883bd84a7d1cf0da0c\", amount=\"50000\"。只有用户选择确认时才继续支付。",
|
|
494
|
+
// "description": "支付0.05 USDC给A账户(需要确认)"
|
|
495
|
+
// },
|
|
496
|
+
// "autopay_buy_apikey_1day": {
|
|
497
|
+
// "template": "使用 buy_apikey 工具购买1天API Key,参数为:{\"duration\": 1}",
|
|
498
|
+
// "description": `购买1天API Key(${pricing["1day"]})`
|
|
499
|
+
// },
|
|
500
|
+
// "autopay_buy_apikey_7days": {
|
|
501
|
+
// "template": "使用 buy_apikey 工具购买7天API Key,参数为:{\"duration\": 7}",
|
|
502
|
+
// "description": `购买7天API Key(${pricing["7days"]})`
|
|
503
|
+
// },
|
|
504
|
+
// "autopay_buy_apikey_30days": {
|
|
505
|
+
// "template": "使用 buy_apikey 工具购买30天API Key,参数为:{\"duration\": 30}",
|
|
506
|
+
// "description": `购买30天API Key(${pricing["30days"]})`
|
|
507
|
+
// },
|
|
508
|
+
// "autopay_get_info": {
|
|
509
|
+
// "template": "使用 info 工具获取服务器信息(API Key 库存、价格、网络配置)",
|
|
510
|
+
// "description": "获取iAutoPay服务器信息"
|
|
511
|
+
// },
|
|
512
|
+
// "autopay_guide": {
|
|
513
|
+
// "template": "使用 guide 工具显示 iAutoPay 使用指南",
|
|
514
|
+
// "description": "显示iAutoPay使用指南"
|
|
515
|
+
// }
|
|
516
|
+
// };
|
|
517
|
+
// let addedCommands: string[] = [];
|
|
518
|
+
// let updatedCommands: string[] = [];
|
|
519
|
+
// if (!opencodeData.command) {
|
|
520
|
+
// opencodeData.command = {};
|
|
521
|
+
// }
|
|
522
|
+
// for (const [key, value] of Object.entries(requiredCommands)) {
|
|
523
|
+
// if (!opencodeData.command[key]) {
|
|
524
|
+
// opencodeData.command[key] = value;
|
|
525
|
+
// addedCommands.push(key);
|
|
526
|
+
// }
|
|
527
|
+
// }
|
|
528
|
+
// if (addedCommands.length > 0) {
|
|
529
|
+
// await fs.writeFile(opencodePath, JSON.stringify(opencodeData, null, 2), 'utf-8');
|
|
530
|
+
// return {
|
|
531
|
+
// content: [{
|
|
532
|
+
// type: "text",
|
|
533
|
+
// text: `✅ 已添加 ${addedCommands.length} 个命令到 opencode.json:\n${addedCommands.map(c => ` - ${c}`).join('\n')}`
|
|
534
|
+
// }]
|
|
535
|
+
// };
|
|
536
|
+
// } else {
|
|
537
|
+
// return {
|
|
538
|
+
// content: [{
|
|
539
|
+
// type: "text",
|
|
540
|
+
// text: "✅ 所有 autopay_ 命令已存在,无需更新"
|
|
541
|
+
// }]
|
|
542
|
+
// };
|
|
543
|
+
// }
|
|
544
|
+
// } catch (error) {
|
|
545
|
+
// throw new Error(`同步配置失败: ${error}`);
|
|
546
|
+
// }
|
|
547
|
+
// }
|
|
582
548
|
if (name === "refresh_pricing") {
|
|
583
549
|
const parsed = refreshPricingInput.parse(args);
|
|
584
550
|
try {
|
|
@@ -597,21 +563,7 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
597
563
|
throw new Error(`Unknown tool: ${name}`);
|
|
598
564
|
});
|
|
599
565
|
const transport = new StdioServerTransport();
|
|
600
|
-
console.log(`========================================`);
|
|
601
|
-
console.log(`[CONFIG] Environment: ${CUR_ENV}`);
|
|
602
|
-
console.log(`[CONFIG] RPC URL: ${BUYER_RPC_URL}`);
|
|
603
|
-
console.log(`[CONFIG] Chain ID: ${BUYER_CHAIN_ID}`);
|
|
604
|
-
console.log(`[CONFIG] Fact API: ${FACT_API_URL}`);
|
|
605
|
-
console.log(`[CONFIG] USDC Address: ${CURRENT_USDC}`);
|
|
606
|
-
console.log(`[CONFIG] Buyer Address: ${buyerAccount.address}`);
|
|
607
|
-
console.log(`========================================`);
|
|
608
|
-
// Fetch pricing from Fact API on startup
|
|
609
566
|
await fetchPricingFromFactAPI();
|
|
610
|
-
console.log(`========================================`);
|
|
611
|
-
console.log(`[PRICING] 1 Day: ${CACHED_PRICING?.["1day"]}`);
|
|
612
|
-
console.log(`[PRICING] 7 Days: ${CACHED_PRICING?.["7days"]}`);
|
|
613
|
-
console.log(`[PRICING] 30 Days: ${CACHED_PRICING?.["30days"]}`);
|
|
614
|
-
// Check USDC balance on startup
|
|
615
567
|
try {
|
|
616
568
|
const usdcBalance = await publicClient.readContract({
|
|
617
569
|
address: CURRENT_USDC,
|
|
@@ -624,27 +576,7 @@ try {
|
|
|
624
576
|
abi: tokenAbi,
|
|
625
577
|
functionName: 'decimals'
|
|
626
578
|
});
|
|
627
|
-
const balanceNumber = Number(usdcBalance) / (10 ** Number(decimals));
|
|
628
|
-
console.log(`[BALANCE] USDC Balance: ${balanceNumber.toFixed(6)} USDC`);
|
|
629
579
|
}
|
|
630
580
|
catch (error) {
|
|
631
|
-
console.warn(`[BALANCE] Failed to check USDC balance:`, error);
|
|
632
581
|
}
|
|
633
|
-
console.log(`========================================`);
|
|
634
582
|
await server.connect(transport);
|
|
635
|
-
// Display startup message for users
|
|
636
|
-
setTimeout(() => {
|
|
637
|
-
console.log(`
|
|
638
|
-
╔════════════════════════════════════════════════════════════╗
|
|
639
|
-
║ iAutoPay MCP Server 已启动 ║
|
|
640
|
-
╠════════════════════════════════════════════════════════════╣
|
|
641
|
-
║ 快速开始: ║
|
|
642
|
-
║ 1. 输入 "guide" 查看完整使用指南 ║
|
|
643
|
-
║ 2. 输入 "info" 查看服务器信息和价格 ║
|
|
644
|
-
║ 3. 输入 "buy_apikey" 购买 API Key (可选1/7/30天) ║
|
|
645
|
-
╠════════════════════════════════════════════════════════════╣
|
|
646
|
-
║ 提示:请确保 opencode.json 已配置 autopay_ 命令 ║
|
|
647
|
-
║ 运行 "sync_opencode_config" 自动添加缺失的命令 ║
|
|
648
|
-
╚════════════════════════════════════════════════════════════╝
|
|
649
|
-
`);
|
|
650
|
-
}, 1000);
|
package/dist/server.js
CHANGED
|
@@ -31,8 +31,7 @@ if (!CONFIG.BUYER_PRIVATE_KEY) {
|
|
|
31
31
|
}
|
|
32
32
|
// Validate private key format
|
|
33
33
|
try {
|
|
34
|
-
|
|
35
|
-
console.log(`[CONFIG] Private key validated, account: ${account.address}`);
|
|
34
|
+
privateKeyToAccount(CONFIG.BUYER_PRIVATE_KEY);
|
|
36
35
|
}
|
|
37
36
|
catch (error) {
|
|
38
37
|
throw new Error(`Invalid BUYER_PRIVATE_KEY format: ${error}`);
|
|
@@ -81,20 +80,16 @@ async function fetchPricingFromFactAPI() {
|
|
|
81
80
|
"7days": `${data.prices?.["7daysUsdc"] || 0.49} USDC`,
|
|
82
81
|
"30days": `${data.prices?.["30daysUsdc"] || 0.99} USDC`
|
|
83
82
|
};
|
|
84
|
-
console.log(`[PRICING] Loaded from fact-api:`, CACHED_PRICING);
|
|
85
83
|
return CACHED_PRICING;
|
|
86
84
|
}
|
|
87
85
|
}
|
|
88
86
|
catch (error) {
|
|
89
|
-
console.warn(`[PRICING] Failed to fetch from fact-api, using defaults. Error:`, error);
|
|
90
87
|
}
|
|
91
|
-
// Default pricing as fallback
|
|
92
88
|
CACHED_PRICING = {
|
|
93
89
|
"1day": "0.09 USDC",
|
|
94
90
|
"7days": "0.49 USDC",
|
|
95
91
|
"30days": "0.99 USDC"
|
|
96
92
|
};
|
|
97
|
-
console.log(`[PRICING] Using default pricing:`, CACHED_PRICING);
|
|
98
93
|
return CACHED_PRICING;
|
|
99
94
|
}
|
|
100
95
|
const buyerAccount = privateKeyToAccount(CONFIG.BUYER_PRIVATE_KEY);
|
|
@@ -119,14 +114,11 @@ async function fetchWithRetry(url, options, context = 'API Request') {
|
|
|
119
114
|
if (response.ok || response.status < 500) {
|
|
120
115
|
return response;
|
|
121
116
|
}
|
|
122
|
-
console.log(`[RETRY] ${context} - Attempt ${i + 1}/${RETRY_CONFIG.MAX_RETRIES} failed, status: ${response.status}`);
|
|
123
117
|
}
|
|
124
118
|
catch (error) {
|
|
125
|
-
console.log(`[RETRY] ${context} - Attempt ${i + 1}/${RETRY_CONFIG.MAX_RETRIES} error:`, error);
|
|
126
119
|
}
|
|
127
120
|
if (i < RETRY_CONFIG.MAX_RETRIES - 1) {
|
|
128
121
|
const delay = RETRY_CONFIG.BASE_DELAY * Math.pow(2, i);
|
|
129
|
-
console.log(`[RETRY] ${context} - Waiting ${delay}ms before retry...`);
|
|
130
122
|
await new Promise(resolve => setTimeout(resolve, delay));
|
|
131
123
|
}
|
|
132
124
|
}
|
|
@@ -258,11 +250,6 @@ async function buildPaymentSignature(requirements) {
|
|
|
258
250
|
};
|
|
259
251
|
}
|
|
260
252
|
async function payStablecoin(params) {
|
|
261
|
-
console.log(`[PAY_STABLECOIN] Starting payment...`);
|
|
262
|
-
console.log(`[PAY_STABLECOIN] Network: ${params.isTestnet ? "eip155:84532 (Testnet)" : `eip155:${BUYER_CHAIN_ID}`}`);
|
|
263
|
-
console.log(`[PAY_STABLECOIN] Asset: ${params.asset}`);
|
|
264
|
-
console.log(`[PAY_STABLECOIN] Amount: ${params.amount}`);
|
|
265
|
-
console.log(`[PAY_STABLECOIN] To: ${params.to}`);
|
|
266
253
|
const [balance, decimals] = await Promise.all([
|
|
267
254
|
publicClient.readContract({
|
|
268
255
|
address: params.asset,
|
|
@@ -278,10 +265,7 @@ async function payStablecoin(params) {
|
|
|
278
265
|
]);
|
|
279
266
|
const balanceNumber = Number(balance) / (10 ** Number(decimals));
|
|
280
267
|
const amountNumber = Number(params.amount) / 1e6;
|
|
281
|
-
console.log(`[PAY_STABLECOIN] Current balance: ${balanceNumber.toFixed(6)} USDC`);
|
|
282
|
-
console.log(`[PAY_STABLECOIN] Required: ${amountNumber.toFixed(6)} USDC`);
|
|
283
268
|
if (balanceNumber < amountNumber) {
|
|
284
|
-
console.log(`[PAY_STABLECOIN] Insufficient balance!`);
|
|
285
269
|
throw new Error(`Insufficient balance: required ${amountNumber.toFixed(6)} USDC, available ${balanceNumber.toFixed(6)} USDC`);
|
|
286
270
|
}
|
|
287
271
|
const requirements = {
|
|
@@ -291,10 +275,7 @@ async function payStablecoin(params) {
|
|
|
291
275
|
price: params.amount,
|
|
292
276
|
payee: params.to,
|
|
293
277
|
};
|
|
294
|
-
console.log(`[PAY_STABLECOIN] Building payment signature...`);
|
|
295
278
|
const signaturePayload = await buildPaymentSignature(requirements);
|
|
296
|
-
console.log(`[PAY_STABLECOIN] Signature built, calling fact-api...`);
|
|
297
|
-
console.log(`[PAY_STABLECOIN] Fact API URL: ${FACT_API_URL}/v1/transfer`);
|
|
298
279
|
const transferRes = await fetchWithRetry(`${FACT_API_URL}/v1/transfer`, {
|
|
299
280
|
method: "POST",
|
|
300
281
|
headers: {
|
|
@@ -307,15 +288,12 @@ async function payStablecoin(params) {
|
|
|
307
288
|
asset: params.asset,
|
|
308
289
|
}),
|
|
309
290
|
}, 'PAY_STABLECOIN Transfer');
|
|
310
|
-
console.log(`[PAY_STABLECOIN] Fact API response status: ${transferRes.status}`);
|
|
311
291
|
if (!transferRes.ok) {
|
|
312
292
|
const error = await transferRes.text();
|
|
313
|
-
console.log(`[PAY_STABLECOIN] Transfer failed: ${error}`);
|
|
314
293
|
const networkInfo = params.isTestnet ? "Testnet (Base Sepolia 84532)" : `Mainnet (Base ${BUYER_CHAIN_ID === '8453' ? 'Mainnet' : BUYER_CHAIN_ID})`;
|
|
315
294
|
throw new Error(`Transfer failed (${networkInfo}): ${error}`);
|
|
316
295
|
}
|
|
317
296
|
const result = await transferRes.json();
|
|
318
|
-
console.log(`[PAY_STABLECOIN] Transfer successful:`, result);
|
|
319
297
|
const deductedAmount = amountNumber.toFixed(6);
|
|
320
298
|
const currentBalance = (balanceNumber - amountNumber).toFixed(6);
|
|
321
299
|
return {
|
|
@@ -408,8 +386,6 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
408
386
|
const priceString = priceMap[duration];
|
|
409
387
|
const priceNumber = parseFloat(priceString);
|
|
410
388
|
const priceWei = (priceNumber * 1e6).toString();
|
|
411
|
-
console.log(`[BUY_APIKEY] Checking balance...`);
|
|
412
|
-
console.log(`[BUY_APIKEY] Required: ${priceNumber.toFixed(6)} USDC, Available: ${balanceNumber.toFixed(6)} USDC`);
|
|
413
389
|
if (balanceNumber < priceNumber) {
|
|
414
390
|
throw new Error(`Insufficient balance: required ${priceNumber.toFixed(6)} USDC, available ${balanceNumber.toFixed(6)} USDC`);
|
|
415
391
|
}
|
|
@@ -420,11 +396,7 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
420
396
|
price: priceWei,
|
|
421
397
|
payee: "0x1a85156c2943b63febeee7883bd84a7d1cf0da0c",
|
|
422
398
|
};
|
|
423
|
-
console.log(`[BUY_APIKEY] Building payment signature...`);
|
|
424
399
|
const signaturePayload = await buildPaymentSignature(requirements);
|
|
425
|
-
console.log(`[BUY_APIKEY] Signature built, calling fact-api...`);
|
|
426
|
-
console.log(`[BUY_APIKEY] Fact API URL: ${FACT_API_URL}/v1/buy-apikey`);
|
|
427
|
-
console.log(`[BUY_APIKEY] Sending request to fact-api (no retry, generate new nonce on failure)...`);
|
|
428
400
|
const buyRes = await fetch(`${FACT_API_URL}/v1/buy-apikey`, {
|
|
429
401
|
method: "POST",
|
|
430
402
|
headers: {
|
|
@@ -433,15 +405,12 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
433
405
|
},
|
|
434
406
|
body: JSON.stringify({ duration })
|
|
435
407
|
});
|
|
436
|
-
console.log(`[BUY_APIKEY] Fact API response status: ${buyRes.status}`);
|
|
437
408
|
if (!buyRes.ok) {
|
|
438
409
|
const error = await buyRes.text();
|
|
439
|
-
console.log(`[BUY_APIKEY] Buy API key failed ${error}`);
|
|
440
410
|
const networkInfo = CUR_ENV === 'dev' ? "Testnet (Base Sepolia 84532)" : `Mainnet (Base ${BUYER_CHAIN_ID})`;
|
|
441
411
|
throw new Error(`Buy API key failed (${networkInfo}): ${error}`);
|
|
442
412
|
}
|
|
443
413
|
const result = await buyRes.json();
|
|
444
|
-
console.log(`[BUY_APIKEY] Buy API key successful:`, result);
|
|
445
414
|
return {
|
|
446
415
|
content: [{
|
|
447
416
|
type: "text",
|
|
@@ -597,21 +566,7 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
597
566
|
throw new Error(`Unknown tool: ${name}`);
|
|
598
567
|
});
|
|
599
568
|
const transport = new StdioServerTransport();
|
|
600
|
-
console.log(`========================================`);
|
|
601
|
-
console.log(`[CONFIG] Environment: ${CUR_ENV}`);
|
|
602
|
-
console.log(`[CONFIG] RPC URL: ${BUYER_RPC_URL}`);
|
|
603
|
-
console.log(`[CONFIG] Chain ID: ${BUYER_CHAIN_ID}`);
|
|
604
|
-
console.log(`[CONFIG] Fact API: ${FACT_API_URL}`);
|
|
605
|
-
console.log(`[CONFIG] USDC Address: ${CURRENT_USDC}`);
|
|
606
|
-
console.log(`[CONFIG] Buyer Address: ${buyerAccount.address}`);
|
|
607
|
-
console.log(`========================================`);
|
|
608
|
-
// Fetch pricing from Fact API on startup
|
|
609
569
|
await fetchPricingFromFactAPI();
|
|
610
|
-
console.log(`========================================`);
|
|
611
|
-
console.log(`[PRICING] 1 Day: ${CACHED_PRICING?.["1day"]}`);
|
|
612
|
-
console.log(`[PRICING] 7 Days: ${CACHED_PRICING?.["7days"]}`);
|
|
613
|
-
console.log(`[PRICING] 30 Days: ${CACHED_PRICING?.["30days"]}`);
|
|
614
|
-
// Check USDC balance on startup
|
|
615
570
|
try {
|
|
616
571
|
const usdcBalance = await publicClient.readContract({
|
|
617
572
|
address: CURRENT_USDC,
|
|
@@ -624,27 +579,7 @@ try {
|
|
|
624
579
|
abi: tokenAbi,
|
|
625
580
|
functionName: 'decimals'
|
|
626
581
|
});
|
|
627
|
-
const balanceNumber = Number(usdcBalance) / (10 ** Number(decimals));
|
|
628
|
-
console.log(`[BALANCE] USDC Balance: ${balanceNumber.toFixed(6)} USDC`);
|
|
629
582
|
}
|
|
630
583
|
catch (error) {
|
|
631
|
-
console.warn(`[BALANCE] Failed to check USDC balance:`, error);
|
|
632
584
|
}
|
|
633
|
-
console.log(`========================================`);
|
|
634
585
|
await server.connect(transport);
|
|
635
|
-
// Display startup message for users
|
|
636
|
-
setTimeout(() => {
|
|
637
|
-
console.log(`
|
|
638
|
-
╔════════════════════════════════════════════════════════════╗
|
|
639
|
-
║ iAutoPay MCP Server 已启动 ║
|
|
640
|
-
╠════════════════════════════════════════════════════════════╣
|
|
641
|
-
║ 快速开始: ║
|
|
642
|
-
║ 1. 输入 "guide" 查看完整使用指南 ║
|
|
643
|
-
║ 2. 输入 "info" 查看服务器信息和价格 ║
|
|
644
|
-
║ 3. 输入 "buy_apikey" 购买 API Key (可选1/7/30天) ║
|
|
645
|
-
╠════════════════════════════════════════════════════════════╣
|
|
646
|
-
║ 提示:请确保 opencode.json 已配置 autopay_ 命令 ║
|
|
647
|
-
║ 运行 "sync_opencode_config" 自动添加缺失的命令 ║
|
|
648
|
-
╚════════════════════════════════════════════════════════════╝
|
|
649
|
-
`);
|
|
650
|
-
}, 1000);
|
package/mcp-config.json.example
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@newblock/iautopay-mcp",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.6",
|
|
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",
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
],
|
|
18
18
|
"scripts": {
|
|
19
19
|
"build": "tsc",
|
|
20
|
-
"dev": "tsx src/
|
|
20
|
+
"dev": "tsx src/iautopay-mcp.ts",
|
|
21
21
|
"test": "vitest",
|
|
22
22
|
"install:opencode-config": "node scripts/generate-opencode-config.js",
|
|
23
23
|
"prepublishOnly": "npm run build"
|