web3-tools-mcp 1.5.0 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (109) hide show
  1. package/CHANGELOG.md +95 -0
  2. package/README.md +346 -164
  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 -216
  17. package/dist/client.js.map +1 -1
  18. package/dist/http-server.d.ts +18 -0
  19. package/dist/http-server.d.ts.map +1 -0
  20. package/dist/http-server.js +89 -0
  21. package/dist/http-server.js.map +1 -0
  22. package/dist/index.js +77 -32
  23. package/dist/index.js.map +1 -1
  24. package/dist/kv-storage.d.ts +23 -0
  25. package/dist/kv-storage.d.ts.map +1 -0
  26. package/dist/kv-storage.js +69 -0
  27. package/dist/kv-storage.js.map +1 -0
  28. package/dist/oauth.d.ts +31 -0
  29. package/dist/oauth.d.ts.map +1 -0
  30. package/dist/oauth.js +227 -0
  31. package/dist/oauth.js.map +1 -0
  32. package/dist/preview.d.ts.map +1 -1
  33. package/dist/preview.js +14 -4
  34. package/dist/preview.js.map +1 -1
  35. package/dist/tools/advanced.d.ts +4 -4
  36. package/dist/tools/advanced.d.ts.map +1 -1
  37. package/dist/tools/advanced.js +228 -247
  38. package/dist/tools/advanced.js.map +1 -1
  39. package/dist/tools/balance.d.ts +1 -1
  40. package/dist/tools/balance.d.ts.map +1 -1
  41. package/dist/tools/balance.js +97 -103
  42. package/dist/tools/balance.js.map +1 -1
  43. package/dist/tools/contract-info.d.ts +3 -3
  44. package/dist/tools/contract-info.d.ts.map +1 -1
  45. package/dist/tools/contract-info.js +150 -161
  46. package/dist/tools/contract-info.js.map +1 -1
  47. package/dist/tools/contract.d.ts +4 -4
  48. package/dist/tools/contract.d.ts.map +1 -1
  49. package/dist/tools/contract.js +91 -110
  50. package/dist/tools/contract.js.map +1 -1
  51. package/dist/tools/ens.d.ts +6 -6
  52. package/dist/tools/ens.d.ts.map +1 -1
  53. package/dist/tools/ens.js +239 -297
  54. package/dist/tools/ens.js.map +1 -1
  55. package/dist/tools/gas.d.ts +4 -4
  56. package/dist/tools/gas.d.ts.map +1 -1
  57. package/dist/tools/gas.js +90 -138
  58. package/dist/tools/gas.js.map +1 -1
  59. package/dist/tools/index.d.ts +1 -1
  60. package/dist/tools/index.d.ts.map +1 -1
  61. package/dist/tools/logs.d.ts +1 -1
  62. package/dist/tools/logs.d.ts.map +1 -1
  63. package/dist/tools/logs.js +36 -37
  64. package/dist/tools/logs.js.map +1 -1
  65. package/dist/tools/signatures.d.ts.map +1 -1
  66. package/dist/tools/signatures.js +67 -89
  67. package/dist/tools/signatures.js.map +1 -1
  68. package/dist/tools/transactions.d.ts +48 -4
  69. package/dist/tools/transactions.d.ts.map +1 -1
  70. package/dist/tools/transactions.js +228 -44
  71. package/dist/tools/transactions.js.map +1 -1
  72. package/dist/types.d.ts +2 -1
  73. package/dist/types.d.ts.map +1 -1
  74. package/dist/utils.d.ts +3 -8
  75. package/dist/utils.d.ts.map +1 -1
  76. package/dist/utils.js +36 -98
  77. package/dist/utils.js.map +1 -1
  78. package/dist/wallet-client.d.ts +11 -1
  79. package/dist/wallet-client.d.ts.map +1 -1
  80. package/dist/wallet-client.js +27 -9
  81. package/dist/wallet-client.js.map +1 -1
  82. package/dist/walletconnect.d.ts +52 -0
  83. package/dist/walletconnect.d.ts.map +1 -0
  84. package/dist/walletconnect.js +221 -0
  85. package/dist/walletconnect.js.map +1 -0
  86. package/package.json +21 -9
  87. package/src/anvil.ts +15 -18
  88. package/src/chain-meta.ts +8 -4
  89. package/src/chains.ts +145 -0
  90. package/src/client.ts +39 -252
  91. package/src/http-server.ts +117 -0
  92. package/src/index.ts +98 -49
  93. package/src/kv-storage.ts +83 -0
  94. package/src/oauth.ts +270 -0
  95. package/src/preview.ts +15 -14
  96. package/src/tools/advanced.ts +195 -213
  97. package/src/tools/balance.ts +103 -108
  98. package/src/tools/contract-info.ts +163 -184
  99. package/src/tools/contract.ts +123 -144
  100. package/src/tools/ens.ts +290 -345
  101. package/src/tools/gas.ts +122 -170
  102. package/src/tools/index.ts +2 -2
  103. package/src/tools/logs.ts +45 -43
  104. package/src/tools/signatures.ts +68 -86
  105. package/src/tools/transactions.ts +283 -50
  106. package/src/types.ts +2 -15
  107. package/src/utils.ts +56 -127
  108. package/src/wallet-client.ts +31 -9
  109. package/src/walletconnect.ts +269 -0
package/README.md CHANGED
@@ -1,78 +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 via Browser Wallet** (MetaMask, Rabby, Coinbase Wallet)
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
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).
49
33
 
50
- **Wallet relay (all optional):**
51
- - `WALLET_SERVER_URL` + `WALLET_TOKEN` - Use a hosted relay instead of a local one
52
- - `PORT`, `HOST`, `WALLET_PUBLIC_URL` - Read by the relay itself when you host it
34
+ ## 🔍 No blind signing
53
35
 
54
- **Get free API keys:**
55
- - Etherscan: [etherscan.io/apis](https://etherscan.io/apis)
56
- - Hypersync: [hypersync.xyz](https://hypersync.xyz)
57
- - Alchemy: [alchemy.com](https://alchemy.com)
58
- - 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.
59
38
 
60
- **Example with API keys:**
61
- ```bash
62
- # Claude Code
63
- 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>
64
42
 
65
- # Environment variables
66
- export ETHERSCAN_API_KEY=your_key
67
- export HYPERSYNC_API_KEY=your_key
68
- npx web3-tools-mcp
43
+ ```
44
+ To 0x87870Bca…B4fA4E2
45
+ Data 0x617ba037000000000…
46
+ Value 0
69
47
  ```
70
48
 
71
- ## Supported Networks
49
+ *Unknown contract, unknown call.*
50
+
51
+ </td><td>
52
+
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 |
73
+
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>
72
182
 
73
183
  | Network | Chain ID | Hypersync |
74
- |---------|----------|-----------|
75
- | Ethereum Mainnet | 1 | ✅ |
184
+ | --- | --- | --- |
185
+ | Ethereum | 1 | ✅ |
76
186
  | Arbitrum | 42161 | ✅ |
77
187
  | Avalanche | 43114 | ✅ |
78
188
  | Base | 8453 | ✅ |
@@ -86,160 +196,232 @@ npx web3-tools-mcp
86
196
  | Unichain | 130 | ✅ |
87
197
  | Localhost | 1337 | ❌ |
88
198
 
89
- ## 🔐 Browser Wallet Integration
199
+ Adding one is a single entry in [`mcp/src/chains.ts`](mcp/src/chains.ts).
200
+
201
+ </details>
90
202
 
91
- The server includes a built-in wallet interface for secure transaction signing without exposing private keys.
203
+ ## 🔧 Setup
92
204
 
93
- ### How It Works
205
+ <details open>
206
+ <summary>🖥️ <b>Local clients</b> — where the config file lives</summary>
94
207
 
95
- 1. When you use a transaction tool (e.g., `send_native_token`), the server automatically:
96
- - Starts a local wallet relay on `http://127.0.0.1:3456` (the next free port up to 3460)
97
- - Opens your browser to connect your wallet (MetaMask, Rabby, Coinbase Wallet, etc.)
98
- 2. You connect your wallet once in the browser
99
- 3. The transaction is decoded and simulated, then the request appears in the browser for approval
100
- 4. Sign or reject transactions directly in your wallet
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:
101
210
 
102
- The browser page and the MCP server are both clients of the relay, authenticated with a
103
- pairing token that travels in the URL fragment (`#t=…`) of the link the server prints.
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 |
217
+
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
+ ```
104
232
 
105
- **One relay per machine.** Every local MCP process looks for an existing relay on ports
106
- 3456-3460 before starting one, so all your editor sessions share a single wallet page —
107
- connect once, and a transaction from any session lands in that tab. They authenticate with
108
- a token kept in `~/.config/web3-tools-mcp/relay-token` (mode 0600); delete it to rotate.
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.
109
235
 
110
- ### Before You Sign
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
+ > ```
111
242
 
112
- Each request shows what the transaction actually does, not just calldata:
243
+ </details>
113
244
 
114
- - **What it means** — for contracts in the [Ledger ERC-7730 registry](https://github.com/LedgerHQ/clear-signing-erc7730-registry)
115
- (651 contracts, 3253 selectors), the protocol's own intent and field labels: *Supply ·
116
- Aave · Amount to supply: 250 USDC*, rather than `supply(address,uint256,address,uint16)`.
117
- The index ships gzipped (~60KB) and a weekly workflow opens a PR when it changes.
118
- - **Decoded call** — otherwise the function name and named arguments, from the verified ABI
119
- (Sourcify / Etherscan) or, for unverified contracts, from selectors recovered from bytecode
120
- via [WhatsABI](https://github.com/shazow/whatsabi). Proxies resolve to their implementation.
121
- - **Token amounts** — formatted with on-chain decimals and symbol; unlimited approvals are
122
- flagged explicitly.
123
- - **Simulation** — `eth_simulateV1` (falling back to `eth_call` + `estimateGas`) reports the
124
- gas estimate and every ERC20 transfer the transaction would cause, marked in/out for your
125
- account. A reverting transaction is shown as such before you can approve it.
245
+ <details>
246
+ <summary>⌨️ <b>Claude Code</b></summary>
126
247
 
127
- ### Hosting the Wallet Page
248
+ ```bash
249
+ claude mcp add --scope user --transport stdio web3-tools -- npx -y web3-tools-mcp
250
+ ```
128
251
 
129
- The relay lives in its own workspace, [`wallet/`](wallet), and depends only on express, cors
130
- and ws (~4MB installed, against ~180MB for the MCP server). It deploys on its own to any host
131
- that keeps a Node process alive and supports WebSockets — Render, Railway, Fly:
252
+ Or, against a hosted instance:
132
253
 
133
254
  ```bash
134
- # On the host, from wallet/ — PORT is provided by the platform
135
- WALLET_TOKEN=<long random string> WALLET_PUBLIC_URL=https://wallet.example.com npm start
255
+ claude mcp add --transport http web3-tools https://your-host/mcp \
256
+ --header "Authorization: Bearer <MCP_TOKEN>"
136
257
  ```
137
258
 
138
- Then point the MCP server at it:
259
+ </details>
260
+
261
+ <details>
262
+ <summary>🤖 <b>ChatGPT</b>, 🦾 <b>Grok</b> and 🌐 <b>claude.ai</b> — remote only</summary>
263
+
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`.
266
+
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.
271
+
272
+ **Grok** — [grok.com/connectors](https://grok.com/connectors) → **New Connector** →
273
+ **Custom**, then the same URL and authentication. Needs a paid plan.
274
+
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.
278
+
279
+ Once connected, pair your phone and approvals arrive there — no laptop in the loop at all.
280
+
281
+ </details>
282
+
283
+ <details>
284
+ <summary>🔑 <b>API keys</b> — none required, but they decide how much works</summary>
285
+
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.
139
303
 
140
304
  ```bash
141
- export WALLET_SERVER_URL=https://wallet.example.com
142
- export WALLET_TOKEN=<the same token>
143
- npx web3-tools-mcp
305
+ npx web3-tools-mcp --etherscan-api-key KEY --walletconnect-project-id ID
144
306
  ```
145
307
 
146
- `render.yaml` deploys the relay as-is (`rootDir: wallet`, so only its dependencies are
147
- installed). Anyone holding `WALLET_TOKEN` can send your browser transactions to sign, so
148
- treat it like a password and always serve the page over HTTPS.
308
+ </details>
149
309
 
150
- Locally nothing changes: the MCP server embeds the same relay and `npm run start:wallet`
151
- runs it from the workspace.
310
+ ## 🚀 Hosting
152
311
 
153
- ### Supported Wallets
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.
154
316
 
155
- - MetaMask
156
- - Rabby
157
- - Coinbase Wallet
158
- - Any browser wallet supporting EIP-1193
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>
320
+
321
+ **Render** reads `render.yaml`, generates `MCP_TOKEN` and asks for `WALLETCONNECT_PROJECT_ID`
322
+ — genuinely one click.
323
+
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.
326
+
327
+ ```bash
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
332
+ ```
159
333
 
160
- ### Manual Access
334
+ <details>
335
+ <summary>🐳 <b>Docker, and connecting a client</b></summary>
161
336
 
162
- Visit the wallet URL printed by the server (`wallet_status` also returns it) anytime to:
163
- - Check wallet connection status
164
- - See pending transactions
165
- - View transaction history
337
+ There is a plain `Dockerfile` too, so Railway, Cloud Run or your own box work the same way:
166
338
 
167
- **Note:** The relay starts automatically with the MCP server. No additional setup required.
339
+ ```bash
340
+ docker run -p 8080:8080 \
341
+ -e MCP_TOKEN=<long random string> \
342
+ -e WALLETCONNECT_PROJECT_ID=<id> \
343
+ web3-tools-mcp
344
+ ```
168
345
 
169
- ## Available Tools
346
+ Then point a client at it:
170
347
 
171
- ### Signatures
172
- - `get_function_signature` - Generate 4-byte function selectors
173
- - `get_event_signature` - Generate 32-byte event topic0 hashes
174
- - `get_error_signature` - Generate 4-byte error selectors
175
- - `encode_function_data` - Encode a call's calldata from its ABI and arguments
348
+ ```bash
349
+ claude mcp add --transport http web3-tools https://your-host/mcp \
350
+ --header "Authorization: Bearer <MCP_TOKEN>"
351
+ ```
176
352
 
177
- ### Contract Info
178
- - `get_contract_abi` - Get ABI with proxy detection and verification status
179
- - `get_contract_source_code` - Get verified source code with proxy support
180
- - `get_contract_source_file` - Retrieve specific source file from cache
181
- - `is_contract` - Check if address is contract or EOA
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.
182
357
 
183
- ### Contract Interaction
184
- - `call_contract_function` - Call view/pure functions (supports batch)
185
- - `call_contract_write` - Execute state-changing contract functions via browser wallet
186
- - `simulate_contract` - Simulate contract calls without broadcasting (includes gas estimate)
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.
187
361
 
188
- ### Transactions (Browser Wallet Required)
189
- - `send_native_token` - Send ETH/native tokens to an address
190
- - `send_erc20_token` - Send ERC20 tokens to an address
191
- - `sign_message` - Sign messages with your wallet
192
- - `wallet_status` - Check wallet connection status
362
+ Two things decide whether the pairing survives:
193
363
 
194
- ### Gas & Simulation
195
- - `estimate_gas` - Estimate gas cost for any transaction
196
- - `get_gas_price` - Get current gas prices (legacy & EIP-1559)
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).
197
370
 
198
- ### ENS
199
- - `resolve_ens_name` - ENS name → address
200
- - `reverse_resolve_ens` - Address → ENS name
201
- - `get_ens_text_record` - Get text records (avatar, email, twitter, etc.)
202
- - `get_ens_avatar` - Get avatar URI
203
- - `batch_resolve_ens_names` - Batch resolve multiple names
371
+ Render's free Key Value instance is not an option here — no persistence, so the pairing
372
+ disappears at its next maintenance.
204
373
 
205
- ### Balances
206
- - `get_balance` - Get native or ERC20 balances (supports batch)
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.
207
379
 
208
- ### Events & Logs
209
- - `get_logs` - Query and decode events with Hypersync fallback
380
+ </details>
210
381
 
211
- ### Advanced
212
- - `get_storage_at` - Read storage slots with type decoding
213
- - `get_block_info` - Get block data (timestamp, hash, etc.)
214
- - `trace_transaction` - Trace execution (call tree, VM, state diff)
215
- - `debug_call` - Trace a call without broadcasting it, falling back to a local anvil fork
382
+ <details>
383
+ <summary>🖇️ <b>Host the signing page</b> separately</summary>
216
384
 
217
- ## Advanced Configuration
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.
218
388
 
219
- ### Custom RPC
220
389
  ```bash
221
- npx web3-tools-mcp --custom-rpc '{"mainnet":"https://my-rpc.com","base":"https://base-rpc.com"}'
390
+ WALLET_TOKEN=<long random string> \
391
+ WALLET_PUBLIC_URL=https://wallet.example.com \
392
+ npx web3-wallet-relay
222
393
  ```
223
394
 
224
- ### RPC Failover
225
- Automatic provider selection: Alchemy → Infura → Public RPCs
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.
398
+
399
+ Locally nothing changes: the server embeds the same relay.
226
400
 
227
- ### Batch Operations
228
- Many tools support batching for improved efficiency (contract calls, balances, ENS resolution).
401
+ </details>
229
402
 
230
- ## Requirements
403
+ ## 🔄 How signing works
231
404
 
232
- - Node.js ≥ 20.0.0
233
- - Internet connection for RPC calls
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.
234
409
 
235
- ## Testing
410
+ ## 🛠️ Development
236
411
 
237
412
  ```bash
238
- npm test # Run all tests
239
- npm run test:watch # Watch mode
240
- npm run test:ui # UI mode
413
+ npm install
414
+ npm run lint # Biome; npm run format fixes what it can
415
+ npm run typecheck
416
+ npm test
241
417
  ```
242
418
 
243
- ## License
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).
422
+
423
+ Requires Node.js ≥ 20.
424
+
425
+ ## 📄 License
244
426
 
245
427
  MIT
package/dist/anvil.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { ChildProcess } from 'child_process';
1
+ import { type ChildProcess } from 'node:child_process';
2
2
  import { createPublicClient } from 'viem';
3
3
  export interface AnvilInstance {
4
4
  process: ChildProcess;
@@ -1 +1 @@
1
- {"version":3,"file":"anvil.d.ts","sourceRoot":"","sources":["../src/anvil.ts"],"names":[],"mappings":"AAAA,OAAO,EAAS,YAAY,EAAE,MAAM,eAAe,CAAA;AACnD,OAAO,EAAE,kBAAkB,EAAQ,MAAM,MAAM,CAAA;AAG/C,MAAM,WAAW,aAAa;IAC5B,OAAO,EAAE,YAAY,CAAA;IACrB,IAAI,EAAE,MAAM,CAAA;IACZ,MAAM,EAAE,MAAM,CAAA;IACd,MAAM,EAAE,UAAU,CAAC,OAAO,kBAAkB,CAAC,CAAA;CAC9C;AAED,MAAM,WAAW,WAAW;IAC1B,OAAO,EAAE,MAAM,CAAA;IACf,eAAe,CAAC,EAAE,MAAM,CAAA;IACxB,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,OAAO,CAAC,EAAE,MAAM,CAAA;CACjB;AAGD,wBAAsB,gBAAgB,IAAI,OAAO,CAAC,OAAO,CAAC,CAMzD;AAuBD,wBAAsB,UAAU,CAAC,MAAM,EAAE,WAAW,GAAG,OAAO,CAAC,aAAa,CAAC,CAsF5E;AAGD,wBAAgB,SAAS,CAAC,QAAQ,EAAE,aAAa,GAAG,IAAI,CAIvD;AAGD,wBAAsB,SAAS,CAAC,CAAC,EAC/B,MAAM,EAAE,WAAW,EACnB,EAAE,EAAE,CAAC,QAAQ,EAAE,aAAa,KAAK,OAAO,CAAC,CAAC,CAAC,GAC1C,OAAO,CAAC,CAAC,CAAC,CAOZ;AAQD,wBAAsB,yBAAyB,CAC7C,OAAO,EAAE,MAAM,EACf,eAAe,EAAE,MAAM,EACvB,WAAW,EAAE,MAAM,EACnB,MAAM,GAAE,YAAY,GAAG,gBAAgB,GAAG,iBAAgC,EAC1E,SAAS,CAAC,EAAE,MAAM,GACjB,OAAO,CAAC,OAAO,CAAC,CAiDlB;AAGD,MAAM,WAAW,kBAAkB;IACjC,EAAE,EAAE,MAAM,CAAA;IACV,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,GAAG,CAAC,EAAE,MAAM,CAAA;CACb;AAED,wBAAsB,qBAAqB,CACzC,OAAO,EAAE,MAAM,EACf,MAAM,EAAE,kBAAkB,EAC1B,WAAW,CAAC,EAAE,MAAM,EACpB,MAAM,GAAE,YAAY,GAAG,gBAA+B,GACrD,OAAO,CAAC;IACT,MAAM,EAAE,MAAM,CAAA;IACd,KAAK,EAAE,OAAO,CAAA;IACd,OAAO,EAAE,MAAM,CAAA;IACf,OAAO,EAAE,OAAO,CAAA;IAChB,YAAY,CAAC,EAAE,MAAM,CAAA;CACtB,CAAC,CAmFD"}
1
+ {"version":3,"file":"anvil.d.ts","sourceRoot":"","sources":["../src/anvil.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,YAAY,EAAS,MAAM,oBAAoB,CAAA;AAC7D,OAAO,EAAE,kBAAkB,EAAQ,MAAM,MAAM,CAAA;AAG/C,MAAM,WAAW,aAAa;IAC5B,OAAO,EAAE,YAAY,CAAA;IACrB,IAAI,EAAE,MAAM,CAAA;IACZ,MAAM,EAAE,MAAM,CAAA;IACd,MAAM,EAAE,UAAU,CAAC,OAAO,kBAAkB,CAAC,CAAA;CAC9C;AAED,MAAM,WAAW,WAAW;IAC1B,OAAO,EAAE,MAAM,CAAA;IACf,eAAe,CAAC,EAAE,MAAM,CAAA;IACxB,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,OAAO,CAAC,EAAE,MAAM,CAAA;CACjB;AAGD,wBAAsB,gBAAgB,IAAI,OAAO,CAAC,OAAO,CAAC,CAMzD;AAyBD,wBAAsB,UAAU,CAAC,MAAM,EAAE,WAAW,GAAG,OAAO,CAAC,aAAa,CAAC,CAoF5E;AAGD,wBAAgB,SAAS,CAAC,QAAQ,EAAE,aAAa,GAAG,IAAI,CAIvD;AAGD,wBAAsB,SAAS,CAAC,CAAC,EAAE,MAAM,EAAE,WAAW,EAAE,EAAE,EAAE,CAAC,QAAQ,EAAE,aAAa,KAAK,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAO/G;AAQD,wBAAsB,yBAAyB,CAC7C,OAAO,EAAE,MAAM,EACf,eAAe,EAAE,MAAM,EACvB,WAAW,EAAE,MAAM,EACnB,MAAM,GAAE,YAAY,GAAG,gBAAgB,GAAG,iBAAgC,EAC1E,SAAS,CAAC,EAAE,MAAM,GACjB,OAAO,CAAC,OAAO,CAAC,CAiDlB;AAGD,MAAM,WAAW,kBAAkB;IACjC,EAAE,EAAE,MAAM,CAAA;IACV,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,GAAG,CAAC,EAAE,MAAM,CAAA;CACb;AAED,wBAAsB,qBAAqB,CACzC,OAAO,EAAE,MAAM,EACf,MAAM,EAAE,kBAAkB,EAC1B,WAAW,CAAC,EAAE,MAAM,EACpB,MAAM,GAAE,YAAY,GAAG,gBAA+B,GACrD,OAAO,CAAC;IACT,MAAM,EAAE,MAAM,CAAA;IACd,KAAK,EAAE,OAAO,CAAA;IACd,OAAO,EAAE,MAAM,CAAA;IACf,OAAO,EAAE,OAAO,CAAA;IAChB,YAAY,CAAC,EAAE,MAAM,CAAA;CACtB,CAAC,CAmFD"}