web3-tools-mcp 1.6.0 → 2.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (104) hide show
  1. package/CHANGELOG.md +109 -0
  2. package/README.md +328 -234
  3. package/dist/anvil.d.ts +1 -1
  4. package/dist/anvil.d.ts.map +1 -1
  5. package/dist/anvil.js +11 -9
  6. package/dist/anvil.js.map +1 -1
  7. package/dist/chain-meta.d.ts.map +1 -1
  8. package/dist/chain-meta.js +7 -3
  9. package/dist/chain-meta.js.map +1 -1
  10. package/dist/chains.d.ts +960 -0
  11. package/dist/chains.d.ts.map +1 -0
  12. package/dist/chains.js +108 -0
  13. package/dist/chains.js.map +1 -0
  14. package/dist/client.d.ts +10 -1717
  15. package/dist/client.d.ts.map +1 -1
  16. package/dist/client.js +33 -218
  17. package/dist/client.js.map +1 -1
  18. package/dist/http-server.d.ts +6 -0
  19. package/dist/http-server.d.ts.map +1 -1
  20. package/dist/http-server.js +55 -40
  21. package/dist/http-server.js.map +1 -1
  22. package/dist/index.js +50 -29
  23. package/dist/index.js.map +1 -1
  24. package/dist/oauth.d.ts +31 -0
  25. package/dist/oauth.d.ts.map +1 -0
  26. package/dist/oauth.js +227 -0
  27. package/dist/oauth.js.map +1 -0
  28. package/dist/preview.d.ts.map +1 -1
  29. package/dist/preview.js +2 -2
  30. package/dist/preview.js.map +1 -1
  31. package/dist/tools/advanced.d.ts +4 -4
  32. package/dist/tools/advanced.d.ts.map +1 -1
  33. package/dist/tools/advanced.js +228 -247
  34. package/dist/tools/advanced.js.map +1 -1
  35. package/dist/tools/balance.d.ts +1 -1
  36. package/dist/tools/balance.d.ts.map +1 -1
  37. package/dist/tools/balance.js +97 -103
  38. package/dist/tools/balance.js.map +1 -1
  39. package/dist/tools/contract-info.d.ts +3 -3
  40. package/dist/tools/contract-info.d.ts.map +1 -1
  41. package/dist/tools/contract-info.js +150 -161
  42. package/dist/tools/contract-info.js.map +1 -1
  43. package/dist/tools/contract.d.ts +4 -4
  44. package/dist/tools/contract.d.ts.map +1 -1
  45. package/dist/tools/contract.js +91 -110
  46. package/dist/tools/contract.js.map +1 -1
  47. package/dist/tools/ens.d.ts +6 -6
  48. package/dist/tools/ens.d.ts.map +1 -1
  49. package/dist/tools/ens.js +239 -297
  50. package/dist/tools/ens.js.map +1 -1
  51. package/dist/tools/gas.d.ts +4 -4
  52. package/dist/tools/gas.d.ts.map +1 -1
  53. package/dist/tools/gas.js +90 -138
  54. package/dist/tools/gas.js.map +1 -1
  55. package/dist/tools/index.d.ts +1 -1
  56. package/dist/tools/index.d.ts.map +1 -1
  57. package/dist/tools/logs.d.ts +1 -1
  58. package/dist/tools/logs.d.ts.map +1 -1
  59. package/dist/tools/logs.js +36 -37
  60. package/dist/tools/logs.js.map +1 -1
  61. package/dist/tools/signatures.d.ts.map +1 -1
  62. package/dist/tools/signatures.js +67 -89
  63. package/dist/tools/signatures.js.map +1 -1
  64. package/dist/tools/transactions.d.ts +35 -5
  65. package/dist/tools/transactions.d.ts.map +1 -1
  66. package/dist/tools/transactions.js +148 -74
  67. package/dist/tools/transactions.js.map +1 -1
  68. package/dist/types.d.ts +1 -1
  69. package/dist/types.d.ts.map +1 -1
  70. package/dist/utils.d.ts +1 -1
  71. package/dist/utils.d.ts.map +1 -1
  72. package/dist/utils.js +35 -98
  73. package/dist/utils.js.map +1 -1
  74. package/dist/wallet-client.d.ts +11 -1
  75. package/dist/wallet-client.d.ts.map +1 -1
  76. package/dist/wallet-client.js +27 -9
  77. package/dist/wallet-client.js.map +1 -1
  78. package/dist/walletconnect.d.ts +22 -1
  79. package/dist/walletconnect.d.ts.map +1 -1
  80. package/dist/walletconnect.js +106 -8
  81. package/dist/walletconnect.js.map +1 -1
  82. package/package.json +17 -9
  83. package/src/anvil.ts +15 -18
  84. package/src/chain-meta.ts +8 -4
  85. package/src/chains.ts +145 -0
  86. package/src/client.ts +39 -254
  87. package/src/http-server.ts +67 -44
  88. package/src/index.ts +77 -53
  89. package/src/oauth.ts +270 -0
  90. package/src/preview.ts +3 -12
  91. package/src/tools/advanced.ts +195 -213
  92. package/src/tools/balance.ts +103 -108
  93. package/src/tools/contract-info.ts +163 -184
  94. package/src/tools/contract.ts +123 -144
  95. package/src/tools/ens.ts +290 -345
  96. package/src/tools/gas.ts +122 -170
  97. package/src/tools/index.ts +2 -2
  98. package/src/tools/logs.ts +45 -43
  99. package/src/tools/signatures.ts +68 -86
  100. package/src/tools/transactions.ts +194 -87
  101. package/src/types.ts +1 -15
  102. package/src/utils.ts +52 -110
  103. package/src/wallet-client.ts +31 -9
  104. package/src/walletconnect.ts +124 -7
package/README.md CHANGED
@@ -1,79 +1,188 @@
1
- # Web3 Tools MCP Server
1
+ <div align="center">
2
2
 
3
- A Model Context Protocol (MCP) server for blockchain interactions using [viem](https://viem.sh/), [Etherscan](https://etherscan.io), and [Hypersync](https://docs.envio.dev/docs/HyperSync/overview).
3
+ # web3-tools-mcp
4
4
 
5
- ## Features
5
+ **Your agent proposes the transaction. You approve it — in your own wallet, on your phone.** 📱
6
6
 
7
- - Multi-chain support (Ethereum, Arbitrum, Avalanche, Base, BNB Chain, Gnosis, Sonic, Optimism, Polygon, zkSync Era, Linea, Unichain)
8
- - **🔐 Transaction signing** in a browser wallet (MetaMask, Rabby, Coinbase) or on your phone over WalletConnect
9
- - Clear signing: transactions are decoded, named and simulated before you approve them
10
- - Smart contract interactions (read & write functions, ABI retrieval, source code)
11
- - Contract simulation & gas estimation (simulate transactions, estimate costs)
12
- - Real-time gas price tracking (legacy & EIP-1559)
13
- - ENS resolution (names ↔ addresses, text records, avatars)
14
- - Token balances & transfers (native & ERC20, batch queries)
15
- - Event log queries with Hypersync acceleration
16
- - Transaction tracing and analysis
17
- - Storage slot reading with type decoding
7
+ 30 MCP tools for reading any EVM network and signing transactions in *your own* wallet.
8
+ Every transaction is decoded, named and simulated before you approve it.
18
9
 
19
- ## Quick Start
10
+ [![npm](https://img.shields.io/npm/v/web3-tools-mcp?color=%233856d6&label=npm)](https://www.npmjs.com/package/web3-tools-mcp)
11
+ [![downloads](https://img.shields.io/npm/dm/web3-tools-mcp?color=%233856d6)](https://www.npmjs.com/package/web3-tools-mcp)
12
+ [![node](https://img.shields.io/node/v/web3-tools-mcp?color=%233856d6)](https://nodejs.org)
13
+ [![license](https://img.shields.io/npm/l/web3-tools-mcp?color=%233856d6)](LICENSE)
20
14
 
21
- ### Claude Code
22
- ```bash
23
- claude mcp add --scope user --transport stdio web3-tools -- npx -y web3-tools-mcp
24
- ```
15
+ </div>
16
+
17
+ **Claude Desktop, Cursor, VS Code, Windsurf** and **Claude Code** launch it on your machine.
18
+ One entry in that client's MCP config:
25
19
 
26
- ### Claude Desktop
27
- Add to `config.json`:
28
20
  ```json
29
- {
30
- "mcpServers": {
31
- "web3-tools": {
32
- "command": "npx",
33
- "args": ["-y", "web3-tools-mcp"]
34
- }
35
- }
36
- }
21
+ { "mcpServers": { "web3-tools": { "command": "npx", "args": ["-y", "web3-tools-mcp"] } } }
37
22
  ```
38
23
 
39
- ## API Keys (Optional)
24
+ Each app keeps that config somewhere different —
25
+ [the file paths are below ↓](#-setup). You need Node.js ≥ 20; `npx` fetches the rest.
40
26
 
41
- All API keys are optional. The server uses public RPCs by default. Add keys to unlock additional features:
27
+ **ChatGPT, Grok** and **claude.ai** cannot launch anything locally — they only reach a URL.
28
+ [Host it once ↓](#-hosting) and add it as a connector, and there is nothing running on your
29
+ laptop at all.
42
30
 
43
- **Configuration options:**
44
- - `--etherscan-api-key` or `ETHERSCAN_API_KEY` - Enables contract ABI/source retrieval
45
- - `--hypersync-api-key` or `HYPERSYNC_API_KEY` - Fast event queries (10-100x faster)
46
- - `--alchemy-api-key` or `ALCHEMY_API_KEY` - Enhanced RPC reliability
47
- - `--infura-api-key` or `INFURA_API_KEY` - Additional RPC provider
48
- - `--custom-rpc` - Custom RPC URLs as JSON
49
- - `--walletconnect-project-id` or `WALLETCONNECT_PROJECT_ID` - Sign from a phone
31
+ It runs with no API keys at all — reads on recent state work on public RPCs, and signing
32
+ previews still decode. Keys widen what it can reach; [see what each unlocks ↓](#-setup).
50
33
 
51
- **Wallet relay (all optional):**
52
- - `WALLET_SERVER_URL` + `WALLET_TOKEN` - Use a hosted relay instead of a local one
53
- - `PORT`, `HOST`, `WALLET_PUBLIC_URL` - Read by the relay itself when you host it
34
+ ## 🔍 No blind signing
54
35
 
55
- **Get free API keys:**
56
- - Etherscan: [etherscan.io/apis](https://etherscan.io/apis)
57
- - Hypersync: [hypersync.xyz](https://hypersync.xyz)
58
- - Alchemy: [alchemy.com](https://alchemy.com)
59
- - Infura: [infura.io](https://infura.io)
36
+ Your agent proposes. You see what it actually does, then approve it in your own wallet.
37
+ The server never holds a private key.
60
38
 
61
- **Example with API keys:**
62
- ```bash
63
- # Claude Code
64
- claude mcp add --scope user --transport stdio web3-tools -- npx -y web3-tools-mcp --etherscan-api-key YOUR_KEY --hypersync-api-key YOUR_KEY
39
+ <table>
40
+ <tr><th>What a wallet usually shows</th><th>What you get here</th></tr>
41
+ <tr><td>
42
+
43
+ ```
44
+ To 0x87870Bca…B4fA4E2
45
+ Data 0x617ba037000000000…
46
+ Value 0
47
+ ```
48
+
49
+ *Unknown contract, unknown call.*
50
+
51
+ </td><td>
65
52
 
66
- # Environment variables
67
- export ETHERSCAN_API_KEY=your_key
68
- export HYPERSYNC_API_KEY=your_key
69
- npx web3-tools-mcp
70
53
  ```
54
+ Supply · Aave V3
55
+ Amount to supply 250 USDC
56
+ On behalf of you
57
+
58
+ −250 USDC → +250 aUSDC
59
+ 184,207 gas · will succeed
60
+ ```
61
+
62
+ </td></tr>
63
+ </table>
64
+
65
+ Four things go into that panel:
66
+
67
+ | | | |
68
+ | --- | --- | --- |
69
+ | 🏷️ | **Intent** | Field labels straight from the protocol, via the [ERC-7730 registry](https://github.com/LedgerHQ/clear-signing-erc7730-registry) — 600+ contracts, 3,000+ selectors, bundled offline and refreshed weekly by a PR |
70
+ | 🔎 | **Decoded call** | Otherwise the function and named arguments, from the verified ABI (Sourcify / Etherscan) — or recovered straight from bytecode with [WhatsABI](https://github.com/shazow/whatsabi) when a contract is unverified. Proxies resolve to their implementation |
71
+ | 💰 | **Real amounts** | Formatted with on-chain decimals and symbol. Unlimited approvals are called out |
72
+ | 🧪 | **Simulation** | `eth_simulateV1` reports the gas and every ERC-20 movement the transaction would cause, marked in or out. A transaction that would revert says so before you can sign it |
71
73
 
72
- ## Supported Networks
74
+ ## 📱 Sign on your phone
75
+
76
+ **Your agent runs wherever it likes. Your keys stay in your pocket.**
77
+
78
+ A phone can't host a local signing page — so it doesn't have to. Point the server at a
79
+ [WalletConnect](https://dashboard.walletconnect.com) project id and it talks to your wallet
80
+ app directly, over WalletConnect's own end-to-end encrypted relay. Nothing to load, nothing
81
+ to host, no browser anywhere in the path.
82
+
83
+ ```bash
84
+ npx web3-tools-mcp --walletconnect-project-id YOUR_PROJECT_ID
85
+ ```
86
+
87
+ | | |
88
+ | --- | --- |
89
+ | 🌍 | **Works hosted.** A deployed server can sign on your phone with nothing running beside you — and now in your browser too, from the page it serves itself |
90
+ | 📷 | **Pair once.** Ask the agent to run `pair_phone_wallet`. You get a QR to scan — or, when the agent is already on your phone, a tap-through link straight into your wallet app |
91
+ | 💾 | **It sticks.** The session is stored on disk (or in Redis when hosted), so it survives restarts and redeploys. Pair once, not once a day |
92
+ | ✍️ | **You choose each time.** Every signing tool takes a required `signWith`, so the agent asks whether this one goes to your phone or the browser. A paired phone never quietly claims a request |
93
+ | 🧾 | **You still see the decode.** The full preview comes back in the tool response — your wallet shows its own summary, so read ours before you approve theirs |
94
+ | 🔌 | **Drop it any time.** `disconnect_phone_wallet` clears every session and pairing |
95
+
96
+ Works with **MetaMask · Rabby · Trust · Coinbase Wallet** — anything speaking WalletConnect v2.
97
+
98
+ > ### ☁️ + 📱 The combination that unlocks everything
99
+ >
100
+ > Because signing no longer needs anything next to you, the server can live in the cloud and
101
+ > **still** have your phone sign. Host it once and every client you own — laptop, browser,
102
+ > the Claude phone app — drives the same instance, with approvals landing on your phone
103
+ > wherever you are. [Hosting takes about a minute ↓](#-hosting)
104
+
105
+ <details>
106
+ <summary>💻 <b>On a laptop?</b> Sign in the wallet extension you already run — zero configuration</summary>
107
+
108
+ Nothing to install and nothing to set up: the server serves a local page, and that page talks
109
+ to whatever wallet extension your browser already has. The first transaction opens it, you
110
+ connect MetaMask, Rabby or Coinbase once, and every later request lands in that same tab.
111
+
112
+ **One relay per machine** — all your editor sessions share the page, so you connect once and
113
+ a transaction from any session shows up there. The page and the server are both clients of a
114
+ local relay on `127.0.0.1:3456` (next free port up to 3460), authenticated with a pairing
115
+ token carried in the URL fragment (`#t=…`) of the link the server prints. The token lives in
116
+ `~/.config/web3-tools-mcp/relay-token` (mode 0600) — delete it to rotate.
117
+
118
+ Works with MetaMask, Rabby, Coinbase Wallet, and any EIP-1193 browser wallet. `wallet_status`
119
+ returns the page URL any time you want to open it yourself.
120
+
121
+ </details>
122
+
123
+ ## 🧰 Tools
124
+
125
+ <details>
126
+ <summary><b>30 tools</b> — reads, writes, ENS, logs, tracing</summary>
127
+
128
+ ### ✍️ Transactions & signing
129
+ | Tool | |
130
+ | --- | --- |
131
+ | `write_contract` | Send a transaction calling a state-changing function, via your wallet |
132
+ | `send_native_token` | Send ETH or a native token |
133
+ | `send_erc20_token` | Send an ERC-20 |
134
+ | `sign_message` | Sign a message |
135
+ | `wallet_status` | Which signer is connected — phone or browser |
136
+ | `pair_phone_wallet` | Pair a phone over WalletConnect, returns a QR |
137
+ | `disconnect_phone_wallet` | Drop every WalletConnect session and pairing |
138
+
139
+ The four signing tools take a required `signWith` of `phone` or `browser`. There is no
140
+ default on purpose — the agent has to ask you, so a request never lands on a device you are
141
+ not holding.
142
+
143
+ ### 📜 Contracts
144
+ | Tool | |
145
+ | --- | --- |
146
+ | `read_contract` | Read state via view/pure functions — batched, no wallet, no gas |
147
+ | `simulate_contract` | Simulate without broadcasting, with gas |
148
+ | `get_contract_abi` | ABI, with proxy detection and verification status |
149
+ | `get_contract_source_code` | Verified source, proxies included |
150
+ | `get_contract_source_file` | One file out of the cached source |
151
+ | `is_contract` | Contract or EOA |
152
+ | `encode_function_data` | Calldata from an ABI and arguments |
153
+ | `get_function_signature` | 4-byte selector |
154
+ | `get_event_signature` | 32-byte topic0 |
155
+ | `get_error_signature` | 4-byte error selector |
156
+
157
+ ### ⛓️ Chain data
158
+ | Tool | |
159
+ | --- | --- |
160
+ | `get_balance` | Native or ERC-20 balances — batched |
161
+ | `get_logs` | Query and decode events, with Hypersync fallback |
162
+ | `get_block_info` | Block data |
163
+ | `get_storage_at` | Storage slots, with type decoding |
164
+ | `get_gas_price` | Current gas — legacy and EIP-1559 |
165
+ | `estimate_gas` | Gas for any transaction |
166
+ | `trace_transaction` | Call tree, VM trace, state diff |
167
+ | `debug_call` | Trace a call without broadcasting, falling back to a local anvil fork |
168
+
169
+ ### 🏷️ ENS
170
+ | Tool | |
171
+ | --- | --- |
172
+ | `resolve_ens_name` | Name → address |
173
+ | `reverse_resolve_ens` | Address → name |
174
+ | `get_ens_text_record` | Text records |
175
+ | `get_ens_avatar` | Avatar URI |
176
+ | `batch_resolve_ens_names` | Many names at once |
177
+
178
+ </details>
179
+
180
+ <details>
181
+ <summary>🌐 <b>13 networks</b></summary>
73
182
 
74
183
  | Network | Chain ID | Hypersync |
75
- |---------|----------|-----------|
76
- | Ethereum Mainnet | 1 | ✅ |
184
+ | --- | --- | --- |
185
+ | Ethereum | 1 | ✅ |
77
186
  | Arbitrum | 42161 | ✅ |
78
187
  | Avalanche | 43114 | ✅ |
79
188
  | Base | 8453 | ✅ |
@@ -87,247 +196,232 @@ npx web3-tools-mcp
87
196
  | Unichain | 130 | ✅ |
88
197
  | Localhost | 1337 | ❌ |
89
198
 
90
- ## 🔐 Browser Wallet Integration
199
+ Adding one is a single entry in [`mcp/src/chains.ts`](mcp/src/chains.ts).
91
200
 
92
- The server includes a built-in wallet interface for secure transaction signing without exposing private keys.
201
+ </details>
93
202
 
94
- ### How It Works
203
+ ## 🔧 Setup
95
204
 
96
- 1. When you use a transaction tool (e.g., `send_native_token`), the server automatically:
97
- - Starts a local wallet relay on `http://127.0.0.1:3456` (the next free port up to 3460)
98
- - Opens your browser to connect your wallet (MetaMask, Rabby, Coinbase Wallet, etc.)
99
- 2. You connect your wallet once in the browser
100
- 3. The transaction is decoded and simulated, then the request appears in the browser for approval
101
- 4. Sign or reject transactions directly in your wallet
205
+ <details open>
206
+ <summary>🖥️ <b>Local clients</b> — where the config file lives</summary>
102
207
 
103
- The browser page and the MCP server are both clients of the relay, authenticated with a
104
- pairing token that travels in the URL fragment (`#t=…`) of the link the server prints.
208
+ Add the entry below to your client's MCP config, then restart the app. Every one of these
209
+ also has a UI route that creates the file for you, which is usually quicker than finding it:
105
210
 
106
- **One relay per machine.** Every local MCP process looks for an existing relay on ports
107
- 3456-3460 before starting one, so all your editor sessions share a single wallet page —
108
- connect once, and a transaction from any session lands in that tab. They authenticate with
109
- a token kept in `~/.config/web3-tools-mcp/relay-token` (mode 0600); delete it to rotate.
211
+ | Client | Config file | Or via the UI |
212
+ | --- | --- | --- |
213
+ | **Claude Desktop** | macOS `~/Library/Application Support/Claude/claude_desktop_config.json`<br>Windows `%APPDATA%\Claude\claude_desktop_config.json`<br>Linux `~/.config/Claude/claude_desktop_config.json` | Settings → Developer → **Edit Config** |
214
+ | **Cursor** | `~/.cursor/mcp.json` (all projects)<br>`.cursor/mcp.json` (this project) | Settings → Tools & MCP → **Add new MCP server** |
215
+ | **VS Code** | `.vscode/mcp.json` (workspace)<br>or your user profile | Command Palette → **MCP: Add Server** |
216
+ | **Windsurf** | `~/.codeium/windsurf/mcp_config.json`<br>global only, no per-project | Cascade panel → **MCP** icon |
110
217
 
111
- ### Before You Sign
218
+ ```json
219
+ {
220
+ "mcpServers": {
221
+ "web3-tools": {
222
+ "command": "npx",
223
+ "args": ["-y", "web3-tools-mcp"],
224
+ "env": {
225
+ "WALLETCONNECT_PROJECT_ID": "<your project id>",
226
+ "ETHERSCAN_API_KEY": "<your key>"
227
+ }
228
+ }
229
+ }
230
+ }
231
+ ```
112
232
 
113
- Each request shows what the transaction actually does, not just calldata:
233
+ Drop the whole `env` block if you have no keys yet: the server runs without them, with less
234
+ reach. **🔑 API keys** below says exactly what each one turns on.
114
235
 
115
- - **What it means** — for contracts in the [Ledger ERC-7730 registry](https://github.com/LedgerHQ/clear-signing-erc7730-registry)
116
- (651 contracts, 3253 selectors), the protocol's own intent and field labels: *Supply ·
117
- Aave · Amount to supply: 250 USDC*, rather than `supply(address,uint256,address,uint16)`.
118
- The index ships gzipped (~60KB) and a weekly workflow opens a PR when it changes.
119
- - **Decoded call** — otherwise the function name and named arguments, from the verified ABI
120
- (Sourcify / Etherscan) or, for unverified contracts, from selectors recovered from bytecode
121
- via [WhatsABI](https://github.com/shazow/whatsabi). Proxies resolve to their implementation.
122
- - **Token amounts** — formatted with on-chain decimals and symbol; unlimited approvals are
123
- flagged explicitly.
124
- - **Simulation** — `eth_simulateV1` (falling back to `eth_call` + `estimateGas`) reports the
125
- gas estimate and every ERC20 transfer the transaction would cause, marked in/out for your
126
- account. A reverting transaction is shown as such before you can approve it.
236
+ > ⚠️ **VS Code is the exception.** Its `mcp.json` nests servers under `"servers"`, not
237
+ > `"mcpServers"` — paste the block above unchanged and it is silently ignored:
238
+ >
239
+ > ```json
240
+ > { "servers": { "web3-tools": { "command": "npx", "args": ["-y", "web3-tools-mcp"] } } }
241
+ > ```
127
242
 
128
- ### Signing From a Phone
243
+ </details>
129
244
 
130
- A phone cannot run the relay, so it does not have to: with a
131
- [WalletConnect](https://dashboard.reown.com) project id the MCP server talks to your phone
132
- wallet directly, over WalletConnect's own (end-to-end encrypted) relay. No page to load,
133
- nothing to host.
245
+ <details>
246
+ <summary>⌨️ <b>Claude Code</b></summary>
134
247
 
135
248
  ```bash
136
- npx web3-tools-mcp --walletconnect-project-id YOUR_PROJECT_ID
249
+ claude mcp add --scope user --transport stdio web3-tools -- npx -y web3-tools-mcp
137
250
  ```
138
251
 
139
- Then ask the agent to pair — `pair_phone_wallet` returns a QR code to scan with MetaMask,
140
- Rabby, Trust or any WalletConnect wallet. The session is stored in
141
- `~/.config/web3-tools-mcp/walletconnect.db`, so you pair once and it survives restarts.
252
+ Or, against a hosted instance:
142
253
 
143
- While a phone is paired it signs everything; the browser page takes over again when it is
144
- not. Either way the transaction is decoded and simulated first, and that summary comes back
145
- in the tool response — your phone wallet shows its own preview, so read ours before you
146
- approve theirs.
254
+ ```bash
255
+ claude mcp add --transport http web3-tools https://your-host/mcp \
256
+ --header "Authorization: Bearer <MCP_TOKEN>"
257
+ ```
147
258
 
148
- ### Hosting Your Own
259
+ </details>
149
260
 
150
- With WalletConnect there is nothing left that has to run next to you — no browser to open,
151
- no page to reach — so the server can live in the cloud and still have your phone sign.
261
+ <details>
262
+ <summary>🤖 <b>ChatGPT</b>, 🦾 <b>Grok</b> and 🌐 <b>claude.ai</b> — remote only</summary>
152
263
 
153
- Run your own instance rather than sharing one: it keeps your wallet, your API keys and your
154
- WalletConnect quota to yourself, and there is no multi-tenant server in the middle that
155
- could send someone else's transaction to your phone.
264
+ None of these can launch a local process, so they need a hosted instance:
265
+ [deploy one ↓](#-hosting), then point the client at `https://your-host/mcp`.
156
266
 
157
- [![Deploy to Render](https://render.com/images/deploy-to-render-button.svg)](https://render.com/deploy?repo=https://github.com/hajnalben/web3-tools-mcp)
267
+ **ChatGPT** — Settings → Apps & Connectors → Advanced → enable Developer mode, then
268
+ **Create**. Give it a name and the server URL. The URL has to include the `/mcp` path; that
269
+ is the usual mistake. Pick OAuth and it walks you through the login page the server serves,
270
+ or pick token and paste `MCP_TOKEN`. Needs a paid plan.
158
271
 
159
- Render reads `render.yaml`, generates `MCP_TOKEN` for you and asks for
160
- `WALLETCONNECT_PROJECT_ID` (free from [dashboard.reown.com](https://dashboard.reown.com)).
161
- Or on [Fly](https://fly.io), where volumes come with any plan, so the pairing survives
162
- redeploys without paying for a disk:
272
+ **Grok** — [grok.com/connectors](https://grok.com/connectors) → **New Connector** →
273
+ **Custom**, then the same URL and authentication. Needs a paid plan.
163
274
 
164
- ```bash
165
- fly launch --no-deploy --copy-config # pick a name and region
166
- fly volumes create data --size 1
167
- fly secrets set MCP_TOKEN=$(openssl rand -hex 24) WALLETCONNECT_PROJECT_ID=<id>
168
- fly deploy
169
- ```
275
+ **claude.ai** — Settings → Connectors → **Add custom connector**, then the URL. It uses
276
+ OAuth, which the server implements against `MCP_TOKEN`: it shows a page asking for the
277
+ token and issues one once you paste it.
170
278
 
171
- There is also a plain `Dockerfile`, so Railway, Cloud Run or your own box work the same way:
279
+ Once connected, pair your phone and approvals arrive there — no laptop in the loop at all.
172
280
 
173
- ```bash
174
- docker build -t web3-tools-mcp .
175
- docker run -p 8080:8080 \
176
- -e MCP_TOKEN=<long random string> \
177
- -e WALLETCONNECT_PROJECT_ID=<id> \
178
- web3-tools-mcp
179
- ```
281
+ </details>
180
282
 
181
- Or without any host at all:
283
+ <details>
284
+ <summary>🔑 <b>API keys</b> — none required, but they decide how much works</summary>
182
285
 
183
- ```bash
184
- MCP_HTTP_PORT=3457 MCP_TOKEN=<long random string> \
185
- WALLETCONNECT_PROJECT_ID=<id> npx web3-tools-mcp
186
- ```
286
+ Nothing here is required to start, and the server will not refuse to run without any of it.
287
+ What you lose is reach, not stability — so here is the honest version:
288
+
289
+ | Key | Free from | Without it |
290
+ | --- | --- | --- |
291
+ | `WALLETCONNECT_PROJECT_ID` | [walletconnect](https://dashboard.walletconnect.com) | 📱 **No phone signing at all.** Browser wallet only, so a hosted instance has no way to sign |
292
+ | `ALCHEMY_API_KEY`<br>or `INFURA_API_KEY`<br>or `CUSTOM_RPC` | [alchemy](https://alchemy.com) · [infura](https://infura.io) | **No historical state.** Public endpoints answer `403 Archive requests require a personal token`, which takes out balances, storage and calls at a past block, event ranges, and `trace_transaction` |
293
+ | `ETHERSCAN_API_KEY` | [etherscan](https://etherscan.io/apis) | `get_contract_abi`, `get_contract_source_code` and `get_contract_source_file` refuse. Signing previews still decode — they try Sourcify first, then recover the ABI from bytecode |
294
+ | `HYPERSYNC_API_KEY` | [envio](https://envio.dev) | Event queries fall back to plain RPC — slower, and past ranges then need one of the provider keys above |
295
+
296
+ So with nothing configured you get current balances, contract reads, gas, ENS, simulation
297
+ and browser signing. Add `WALLETCONNECT_PROJECT_ID` for your phone and one provider key for
298
+ history, and everything above lights up.
299
+
300
+ Every key has a matching flag (`--etherscan-api-key`, …), RPC selection falls back
301
+ Alchemy → Infura → public, and `CUSTOM_RPC` overrides all of it.
302
+ `npx web3-tools-mcp --help` lists them; [.env.example](.env.example) documents each one.
187
303
 
188
304
  ```bash
189
- claude mcp add --transport http web3-tools https://your-host/mcp \
190
- --header "Authorization: Bearer <MCP_TOKEN>"
305
+ npx web3-tools-mcp --etherscan-api-key KEY --walletconnect-project-id ID
191
306
  ```
192
307
 
193
- `MCP_TOKEN` is mandatory and the server refuses to start without it: anyone who can reach
194
- `/mcp` while your phone is paired can push signing prompts at it. You would still approve
195
- each one, but that is a phishing surface, not a feature.
196
-
197
- Two things decide whether the pairing survives:
308
+ </details>
198
309
 
199
- - **Keep the instance awake.** Sleeping drops the WalletConnect socket your phone pairing
200
- depends on, so the first transaction after an idle period waits for the host to wake
201
- (about a minute on a free tier) before it reaches your phone.
202
- - **Give the session somewhere durable to live.** Most hosts have an ephemeral filesystem,
203
- so a plain file is lost on every redeploy and you rescan the QR. Either attach a volume
204
- and point `XDG_CONFIG_HOME` at it (what `render.yaml` does), or set
205
- `UPSTASH_REDIS_REST_URL` and `UPSTASH_REDIS_REST_TOKEN`
206
- ([Upstash](https://upstash.com) has a free plan) and the session moves to Redis.
310
+ ## 🚀 Hosting
207
311
 
208
- Render's own free Key Value instance is not an option for this: it has no persistence, so
209
- the pairing would disappear on its next maintenance.
312
+ With WalletConnect nothing has to run next to you, so the server can live in the cloud and
313
+ still have your phone sign. Run your own rather than sharing one: your wallet, your keys,
314
+ your quota, and no multi-tenant server in the middle that could push someone else's
315
+ transaction at your phone.
210
316
 
211
- A hosted server skips the wallet relay entirely — there is no browser on the host to open —
212
- so WalletConnect is its only way to sign.
317
+ <a href="https://render.com/deploy?repo=https://github.com/hajnalben/web3-tools-mcp"><img src="https://render.com/images/deploy-to-render-button.svg" alt="Deploy to Render" height="32"></a>
318
+ &nbsp;
319
+ <a href="https://fly.io/docs/launch/"><img src="https://img.shields.io/badge/Deploy%20on-Fly.io-8b5cf6?style=for-the-badge&logo=flydotio&logoColor=white" alt="Deploy on Fly.io" height="32"></a>
213
320
 
214
- ### Hosting the Wallet Page
321
+ **Render** reads `render.yaml`, generates `MCP_TOKEN` and asks for `WALLETCONNECT_PROJECT_ID`
322
+ — genuinely one click.
215
323
 
216
- The relay lives in its own workspace, [`wallet/`](wallet), and depends only on express, cors
217
- and ws (~4MB installed, against ~180MB for the MCP server). It deploys on its own to any host
218
- that keeps a Node process alive and supports WebSockets — Render, Railway, Fly:
324
+ **Fly** ships no deploy button, so it is four commands. Worth it for a personal instance:
325
+ volumes come with any plan, so the pairing survives redeploys without paying for a disk.
219
326
 
220
327
  ```bash
221
- # On the host, from wallet/ — PORT is provided by the platform
222
- WALLET_TOKEN=<long random string> WALLET_PUBLIC_URL=https://wallet.example.com npm start
328
+ fly launch --no-deploy --copy-config
329
+ fly volumes create data --size 1
330
+ fly secrets set MCP_TOKEN=$(openssl rand -hex 24) WALLETCONNECT_PROJECT_ID=<id>
331
+ fly deploy
223
332
  ```
224
333
 
225
- Then point the MCP server at it:
334
+ <details>
335
+ <summary>🐳 <b>Docker, and connecting a client</b></summary>
336
+
337
+ There is a plain `Dockerfile` too, so Railway, Cloud Run or your own box work the same way:
226
338
 
227
339
  ```bash
228
- export WALLET_SERVER_URL=https://wallet.example.com
229
- export WALLET_TOKEN=<the same token>
230
- npx web3-tools-mcp
340
+ docker run -p 8080:8080 \
341
+ -e MCP_TOKEN=<long random string> \
342
+ -e WALLETCONNECT_PROJECT_ID=<id> \
343
+ web3-tools-mcp
231
344
  ```
232
345
 
233
- `render.yaml` deploys the relay as-is (`rootDir: wallet`, so only its dependencies are
234
- installed). Anyone holding `WALLET_TOKEN` can send your browser transactions to sign, so
235
- treat it like a password and always serve the page over HTTPS.
346
+ Then point a client at it:
236
347
 
237
- Locally nothing changes: the MCP server embeds the same relay and `npm run start:wallet`
238
- runs it from the workspace.
348
+ ```bash
349
+ claude mcp add --transport http web3-tools https://your-host/mcp \
350
+ --header "Authorization: Bearer <MCP_TOKEN>"
351
+ ```
239
352
 
240
- ### Supported Wallets
353
+ Clients that cannot send a header — claude.ai connectors, and the browser and phone apps —
354
+ use OAuth, which the server implements against the same credential: it shows a page asking
355
+ for `MCP_TOKEN` and issues a token once you paste it. No identity provider, no accounts. Set
356
+ `MCP_PUBLIC_URL` to the address clients reach you on, since OAuth metadata must advertise it.
241
357
 
242
- - MetaMask
243
- - Rabby
244
- - Coinbase Wallet
245
- - Any browser wallet supporting EIP-1193
358
+ > 🔐 **`MCP_TOKEN` is mandatory** and the server refuses to start without it. Anyone who
359
+ > reaches `/mcp` while your phone is paired can push signing prompts at it. You would still
360
+ > approve each one, but that is a phishing surface, not a feature.
246
361
 
247
- ### Manual Access
362
+ Two things decide whether the pairing survives:
248
363
 
249
- Visit the wallet URL printed by the server (`wallet_status` also returns it) anytime to:
250
- - Check wallet connection status
251
- - See pending transactions
252
- - View transaction history
364
+ - ⏰ **Keep the instance awake.** Sleeping drops the WalletConnect socket, so the first
365
+ transaction after an idle period waits for the host to wake — about a minute on a free tier.
366
+ - 💾 **Give the session somewhere durable.** Most hosts have an ephemeral filesystem, so a
367
+ plain file is lost on redeploy and you rescan the QR. Attach a volume and point
368
+ `XDG_CONFIG_HOME` at it (what `render.yaml` does), or set `UPSTASH_REDIS_REST_URL` and
369
+ `UPSTASH_REDIS_REST_TOKEN` ([Upstash](https://upstash.com) has a free plan).
253
370
 
254
- **Note:** The relay starts automatically with the MCP server. No additional setup required.
371
+ Render's free Key Value instance is not an option here — no persistence, so the pairing
372
+ disappears at its next maintenance.
255
373
 
256
- ## Available Tools
374
+ Both signers work on a hosted instance. The signing page is served from the same port as
375
+ `/mcp`, so `https://your-host/#t=<relay token>` is your wallet page — no second service to
376
+ deploy. Ask the agent for `wallet_status` to get the link; it is behind `MCP_TOKEN`, and the
377
+ relay token is minted fresh each boot rather than stored, so the URL changes when you
378
+ redeploy.
257
379
 
258
- ### Signatures
259
- - `get_function_signature` - Generate 4-byte function selectors
260
- - `get_event_signature` - Generate 32-byte event topic0 hashes
261
- - `get_error_signature` - Generate 4-byte error selectors
262
- - `encode_function_data` - Encode a call's calldata from its ABI and arguments
380
+ </details>
263
381
 
264
- ### Contract Info
265
- - `get_contract_abi` - Get ABI with proxy detection and verification status
266
- - `get_contract_source_code` - Get verified source code with proxy support
267
- - `get_contract_source_file` - Retrieve specific source file from cache
268
- - `is_contract` - Check if address is contract or EOA
382
+ <details>
383
+ <summary>🖇️ <b>Host the signing page</b> separately</summary>
269
384
 
270
- ### Contract Interaction
271
- - `call_contract_function` - Call view/pure functions (supports batch)
272
- - `call_contract_write` - Execute state-changing contract functions via browser wallet
273
- - `simulate_contract` - Simulate contract calls without broadcasting (includes gas estimate)
385
+ The relay is its own package, [`wallet-relay/`](wallet-relay) — express, cors and ws, about
386
+ 4 MB installed against ~180 MB for the server. It runs anywhere that keeps a Node process
387
+ alive and supports WebSockets.
274
388
 
275
- ### Transactions (Browser Wallet Required)
276
- - `send_native_token` - Send ETH/native tokens to an address
277
- - `send_erc20_token` - Send ERC20 tokens to an address
278
- - `sign_message` - Sign messages with your wallet
279
- - `wallet_status` - Check which signer is connected (phone or browser)
280
- - `pair_phone_wallet` - Pair a phone wallet over WalletConnect, returning a QR to scan
389
+ ```bash
390
+ WALLET_TOKEN=<long random string> \
391
+ WALLET_PUBLIC_URL=https://wallet.example.com \
392
+ npx web3-wallet-relay
393
+ ```
281
394
 
282
- ### Gas & Simulation
283
- - `estimate_gas` - Estimate gas cost for any transaction
284
- - `get_gas_price` - Get current gas prices (legacy & EIP-1559)
395
+ Then point the server at it with `WALLET_SERVER_URL` and the same `WALLET_TOKEN`.
396
+ `render.yaml` deploys it as-is. Anyone holding `WALLET_TOKEN` can send your browser a
397
+ transaction to sign — treat it like a password, and always serve over HTTPS.
285
398
 
286
- ### ENS
287
- - `resolve_ens_name` - ENS name → address
288
- - `reverse_resolve_ens` - Address → ENS name
289
- - `get_ens_text_record` - Get text records (avatar, email, twitter, etc.)
290
- - `get_ens_avatar` - Get avatar URI
291
- - `batch_resolve_ens_names` - Batch resolve multiple names
399
+ Locally nothing changes: the server embeds the same relay.
292
400
 
293
- ### Balances
294
- - `get_balance` - Get native or ERC20 balances (supports batch)
401
+ </details>
295
402
 
296
- ### Events & Logs
297
- - `get_logs` - Query and decode events with Hypersync fallback
403
+ ## 🔄 How signing works
298
404
 
299
- ### Advanced
300
- - `get_storage_at` - Read storage slots with type decoding
301
- - `get_block_info` - Get block data (timestamp, hash, etc.)
302
- - `trace_transaction` - Trace execution (call tree, VM, state diff)
303
- - `debug_call` - Trace a call without broadcasting it, falling back to a local anvil fork
405
+ 1. 🤖 A transaction tool runs. The server decodes and simulates the transaction first.
406
+ 2. 📨 It goes to the signer you picked — your phone, or the browser page.
407
+ 3. 👀 You read the summary and approve or reject in your wallet.
408
+ 4. 🔗 The result, with an explorer link, comes back to the agent.
304
409
 
305
- ## Advanced Configuration
410
+ ## 🛠️ Development
306
411
 
307
- ### Custom RPC
308
412
  ```bash
309
- npx web3-tools-mcp --custom-rpc '{"mainnet":"https://my-rpc.com","base":"https://base-rpc.com"}'
413
+ npm install
414
+ npm run lint # Biome; npm run format fixes what it can
415
+ npm run typecheck
416
+ npm test
310
417
  ```
311
418
 
312
- ### RPC Failover
313
- Automatic provider selection: Alchemy → Infura → Public RPCs
314
-
315
- ### Batch Operations
316
- Many tools support batching for improved efficiency (contract calls, balances, ENS resolution).
419
+ Two workspaces: [`mcp/`](mcp) is this server, [`wallet-relay/`](wallet-relay) is the signing
420
+ page. [CONTRIBUTING.md](CONTRIBUTING.md) covers running a checkout against a client, the
421
+ layout, and how to add a chain or a tool. Releases: [CHANGELOG.md](CHANGELOG.md).
317
422
 
318
- ## Requirements
319
-
320
- - Node.js ≥ 20.0.0
321
- - Internet connection for RPC calls
322
-
323
- ## Testing
324
-
325
- ```bash
326
- npm test # Run all tests
327
- npm run test:watch # Watch mode
328
- npm run test:ui # UI mode
329
- ```
423
+ Requires Node.js ≥ 20.
330
424
 
331
- ## License
425
+ ## 📄 License
332
426
 
333
427
  MIT