dennisonbertram/mcp-web3-wallet-tester
If you are the rightful owner of mcp-web3-wallet-tester and would like to certify it and/or have it hosted online, please leave a comment on the right or send an email to dayong@mcphub.com.
An MCP server that functions as an Ethereum wallet, enabling LLMs to manage Web3 dApp testing through Playwright.
MCP Web3 Wallet Tester
An MCP server that acts as an Ethereum wallet, allowing LLMs to control Web3 dApp testing via Playwright. When a dApp requests a transaction, the LLM can approve/reject it through MCP tools.
Prerequisites
Before using this MCP server, ensure you have:
- Node.js 18+ - Required for running the server
- Anvil (from Foundry) - Required for local Ethereum testing
- Install via:
curl -L https://foundry.paradigm.xyz | bash && foundryup - Verify with:
anvil --version
- Install via:
IMPORTANT: The wallet server must be running BEFORE Claude Code can use the wallet tools. The server persists across LLM calls to maintain state.
Quick Start
Follow these steps to get up and running:
1. Install Dependencies
npm install
2. Build the Project
npm run build
3. Start Anvil (Local Ethereum Node)
In a separate terminal, start Anvil:
anvil
Leave this running. You should see:
Listening on 127.0.0.1:8545
4. Start the Wallet Server
In another terminal, start the wallet server:
npm start
You should see:
MCP Server: http://localhost:3001/mcp
WebSocket Bridge: ws://localhost:8546
Keep this running - the server must stay active for Claude Code to use the wallet tools.
5. Add to Claude Code
In a third terminal, register the server with Claude Code:
claude mcp add --transport http wallet-tester http://localhost:3001/mcp
That's it! Claude Code can now use the wallet tools to interact with Web3 dApps in Playwright tests.
Architecture
┌─────────────────────────────────────────────────────────────────┐
│ Wallet Server Process │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ HTTP/SSE MCP Server (:3001) │ │
│ │ (Long-lived, persists across LLM calls) │ │
│ └─────────────────────────────────────────────────────────┘ │
│ │ │
│ ┌───────┴───────┐ │
│ │ Request Queue │ │
│ │ (in-memory) │ │
│ └───────┬───────┘ │
│ │ │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ WebSocket Bridge (:8546) │ │
│ │ (Browser provider connects here) │ │
│ └─────────────────────────────────────────────────────────┘ │
│ │ │
│ ┌───────┴───────┐ │
│ │ Viem Wallet │ │
│ │ (signing) │ │
│ └───────┬───────┘ │
└────────────────────────────│────────────────────────────────────┘
│
▼
┌─────────────────┐
│ Anvil │
│ (:8545) │
└─────────────────┘
Installation
npm install
npm run build
Usage
1. Start Anvil (local Ethereum node)
anvil
2. Start the wallet server
npm start
Output:
MCP Server: http://localhost:3001/mcp
WebSocket Bridge: ws://localhost:8546
3. Add to Claude Code
claude mcp add --transport http wallet-tester http://localhost:3001/mcp
4. Use in Playwright tests
Inject the provider before page loads:
import { readFileSync } from 'fs';
// Read the provider bundle
const providerScript = readFileSync('node_modules/mcp-web3-wallet-tester/dist/provider.js', 'utf-8');
// Inject before page loads
await page.addInitScript(providerScript);
// Navigate to dApp
await page.goto('https://example-dapp.com');
// Click connect wallet - the injected provider handles window.ethereum
await page.click('button:has-text("Connect Wallet")');
MCP Resources
The server exposes documentation as MCP resources that LLMs can read to understand how to use the wallet tester:
| Resource URI | Description |
|---|---|
wallet://docs/instructions | Concise LLM usage guide with step-by-step workflow and common pitfalls |
wallet://docs/testing-guide | Complete testing documentation with examples and troubleshooting |
wallet://docs/tools | List of all available MCP tools with parameters and usage patterns |
LLMs can access these resources to learn how to use the wallet tester effectively.
MCP Tools
| Tool | Description |
|---|---|
wallet_getAddress | Get the wallet address |
wallet_getBalance | Get ETH balance |
wallet_getPendingRequests | List pending requests |
wallet_approveRequest | Approve a pending request |
wallet_rejectRequest | Reject a pending request |
wallet_waitForRequest | Wait for a request to arrive |
wallet_setAutoApprove | Enable/disable auto-approve |
wallet_getTransactionReceipt | Get transaction receipt |
wallet_getChainId | Get chain ID |
wallet_getStatus | Get full wallet status |
wallet_listAccounts | List all 10 Anvil test accounts |
wallet_switchAccount | Switch to Anvil account by index (0-9) |
wallet_setPrivateKey | Switch to a custom private key |
Example LLM Workflow
User: "Test the swap feature on Uniswap"
LLM: I'll navigate to Uniswap and test the swap feature.
→ Uses Playwright to navigate to uniswap.org
→ Clicks "Connect Wallet"
LLM: wallet_waitForRequest()
→ Returns: {id: "req_1", method: "eth_requestAccounts", params: []}
LLM: wallet_approveRequest({requestId: "req_1"})
→ Returns wallet address
→ dApp shows "Connected"
LLM: I'll now swap 1 ETH for USDC
→ Fills in swap form, clicks "Swap"
LLM: wallet_waitForRequest()
→ Returns: {id: "req_2", method: "eth_sendTransaction", params: [{...}]}
LLM: wallet_approveRequest({requestId: "req_2"})
→ Transaction sent to Anvil
→ dApp shows "Transaction submitted"
Account Management
The LLM can dynamically switch between accounts during testing:
LLM: wallet_listAccounts()
→ Returns: [{index: 0, address: "0xf39..."}, {index: 1, address: "0x709..."}, ...]
LLM: wallet_switchAccount({accountIndex: 1})
→ Returns: {success: true, accountIndex: 1, address: "0x70997970...", balance: "10000 ETH"}
LLM: wallet_setPrivateKey({privateKey: "0xabcd..."})
→ Returns: {success: true, address: "0x123...", balance: "0 ETH"}
This allows testing multi-user scenarios (e.g., Alice sends to Bob) without restarting the server.
Configuration
Environment variables:
| Variable | Default | Description |
|---|---|---|
MCP_PORT | 3001 | HTTP MCP server port |
WS_PORT | 8546 | WebSocket bridge port |
ANVIL_RPC_URL | http://127.0.0.1:8545 | Anvil RPC URL |
ACCOUNT_INDEX | 0 | Anvil account index (0-9) to use |
PRIVATE_KEY | (from ACCOUNT_INDEX) | Wallet private key (overrides ACCOUNT_INDEX if set) |
CHAIN_ID | 31337 | Chain ID to report |
Using Multiple Accounts
The server supports all 10 of Anvil's default test accounts. Use the ACCOUNT_INDEX environment variable to select which account to use (0-9):
# Use account 0 (default)
npm start
# Use account 1
ACCOUNT_INDEX=1 npm start
# Use account 5
ACCOUNT_INDEX=5 npm start
Each account has 10000 ETH on a fresh Anvil instance. You can also provide a custom private key with PRIVATE_KEY to override the account selection.
Development
# Type check
npm run type-check
# Build
npm run build
# Watch mode
npm run dev
How It Works
-
Injectable Provider (
dist/provider.js): A script injected into the browser that implements the EIP-1193 provider interface onwindow.ethereum. When a dApp calls wallet methods, requests are sent to the WebSocket bridge. -
WebSocket Bridge: Receives requests from the browser provider, adds them to the queue, and waits for approval before responding.
-
Request Queue: Manages pending wallet requests. Each request is a Promise that resolves when the LLM approves it (or rejects when denied).
-
MCP Server: Exposes tools that let the LLM see pending requests and approve/reject them. Uses HTTP transport for persistence across test sessions.
-
Viem Wallet: Handles actual Ethereum operations (signing, sending transactions) against the Anvil local node.
License
MIT