MCP Anvil Tools
Model Context Protocol (MCP) server providing Ethereum development and testing tools for AI agents. Built on Anvil (Foundry's local Ethereum node) and viem for robust blockchain interactions.
Overview
MCP Anvil Tools enables AI agents to:
- Read Solidity source code and contract storage
- Simulate and execute transactions on local Anvil or testnets
- Manipulate blockchain state with snapshots and impersonation
- Query events and decode bytecode
- Test smart contracts in isolated environments
Perfect for AI-powered smart contract auditing, testing workflows, and blockchain development automation.
Key Features
- Dual Transport Modes: Stateless HTTP via
/mcpendpoint or stdio for CLI/desktop integration - Reading Tools (4): Source code, storage, bytecode, and event log access
- Execution Tools (5): Transaction simulation, sending, and state manipulation
- Tracing Tools (2): Transaction and call tracing with multiple tracer types
- Anvil Integration: Automatic Anvil process management with snapshot/revert support
- State Persistence: SQLite-backed deployment and session tracking
- Type Safety: Full TypeScript support with Zod validation
Quick Start
Installation
# Clone the repository
git clone https://github.com/yourusername/mcp-anvil-tools.git
cd mcp-anvil-tools
# Install dependencies
npm install
# Build the project
npm run build
Configuration
# Copy example environment file
cp .env.example .env
# Edit .env with your configuration
nano .env
Required environment variables:
AUDIT_MCP_PORT- Server port (default: 3000)MAINNET_RPC_URL- RPC endpoint for mainnet interactionsETHERSCAN_API_KEY- Optional, for source code verification
Running the Server
HTTP/SSE Mode (for web clients, multi-agent systems):
npm start
# Server runs on http://localhost:3000
stdio Mode (for Claude Desktop, CLI tools):
npm run start:stdio
# Communicates via stdin/stdout
Development Mode (with hot reload):
npm run dev
Transport Modes
HTTP Mode
Use HTTP mode for:
- Web-based AI clients
- Multi-agent architectures
- Stateless MCP connections
- RESTful API interactions
Endpoints:
GET /health- Health check (unauthenticated)GET /metrics- Deployment and instance statisticsPOST /mcp- MCP protocol endpoint (StreamableHTTPServerTransport)
Example Connection:
# Health check
curl http://localhost:3000/health
# Metrics
curl http://localhost:3000/metrics
# MCP protocol request
curl -X POST http://localhost:3000/mcp \
-H "Content-Type: application/json" \
-H "Accept: application/json, text/event-stream" \
-d '{
"jsonrpc": "2.0",
"id": 1,
"method": "initialize",
"params": {
"protocolVersion": "2024-11-05",
"capabilities": {},
"clientInfo": {
"name": "test-client",
"version": "1.0.0"
}
}
}'
stdio Mode
Use stdio for:
- Claude Desktop integration
- Command-line MCP clients
- Programmatic testing
- Shell script automation
Example Test:
# Simple echo test
echo '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2024-11-05","capabilities":{},"clientInfo":{"name":"test","version":"1.0.0"}}}' | npm run start:stdio
# Automated test suite
npx tsx test-stdio.ts
# Manual test script
./test-stdio-manual.sh
Available Tools
Reading Tools
1. read_source
Read Solidity source code files from the v4-core repository.
Input:
path(string): Relative path fromlib/v4-core/src/(e.g.,PoolManager.sol)
Output:
content(string): Full source codelines(number): Total line countpath(string): Absolute file pathsize(number): File size in byteslastModified(string): ISO timestamp
Example:
{
"path": "PoolManager.sol"
}
2. read_storage
Read contract storage slots (persistent storage only, not transient).
Input:
address(string): Contract addressslot(string): Storage slot (hex, e.g.,0x0)blockTag(optional):latest,earliest,pending, block number, or block hashrpc(optional): RPC URL (default:http://localhost:8545)
Output:
value(string): Raw 32-byte hex valuedecoded(optional): Best-effort interpretation (uint256, address, bool, bytes32)
Example:
{
"address": "0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb",
"slot": "0x0",
"blockTag": "latest"
}
3. read_bytecode
Retrieve deployed bytecode from a contract address.
Input:
address(string): Contract addressblockTag(optional): Block identifierrpc(optional): RPC URL
Output:
bytecode(string): Hex-encoded bytecodesize(number): Bytecode size in bytescodeHash(string): Keccak256 hashisEmpty(boolean): True if no code deployed (EOA)
Example:
{
"address": "0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb"
}
4. read_events
Query and decode contract event logs.
Input:
address(string): Contract addresseventSignature(optional): Event signature (e.g.,Transfer(address,address,uint256))topics(optional): Indexed topics filterfromBlock(optional): Starting block (default:earliest)toBlock(optional): Ending block (default:latest)rpc(optional): RPC URL
Output:
events(array): Event logs with block infocount(number): Total events returnedfromBlock(string): Actual starting blocktoBlock(string): Actual ending block
Example:
{
"address": "0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb",
"eventSignature": "Transfer(address,address,uint256)",
"fromBlock": 1000000,
"toBlock": 1000100
}
Execution Tools
5. simulate_tx
Simulate transactions without sending them to the network.
Input:
to(string): Target contract addressdata(string): Calldata (hex)from(optional): Sender addressgasLimit(optional): Gas limitvalue(optional): ETH value in wei (hex)abi(optional): Contract ABI for decodingfunctionName(optional): Function name for decodingblockNumber(optional): Block to simulate atstateOverrides(optional): State overrides by addressrpc(optional): RPC endpoint
Output:
result(string): Return data (hex)decoded(optional): Decoded return valuereverted(boolean): Whether call revertedrevertReason(optional): Decoded revert reasonrevertData(optional): Raw revert data
Example:
{
"to": "0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb",
"data": "0x70a08231000000000000000000000000f39fd6e51aad88f6f4ce6ab8827279cfffb92266",
"abi": [...],
"functionName": "balanceOf"
}
6. send_tx
Send actual transactions to the network.
Input:
to(optional): Target address (omit for deployment)data(string): Transaction data / bytecodefrom(optional): Sender addressvalue(optional): ETH value in wei (hex)gasLimit(optional): Gas limit (auto-estimated)gasPrice(optional): Legacy gas pricemaxFeePerGas(optional): EIP-1559 max feemaxPriorityFeePerGas(optional): EIP-1559 priority feenonce(optional): Transaction nonceprivateKey(optional): Private key for signingconfirmations(optional): Confirmations to wait (default: 1)rpc(optional): RPC endpoint
Output:
txHash(string): Transaction hashblockNumber(string): Block numberblockHash(string): Block hashgasUsed(string): Gas consumedeffectiveGasPrice(string): Actual gas pricestatus(enum):successorrevertedlogs(array): Event logscontractAddress(optional): Deployed contract addressfrom(string): Sender addressto(optional): Recipient address
Example:
{
"to": "0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb",
"data": "0xa9059cbb...",
"value": "0x0",
"privateKey": "0x..."
}
7. impersonate
Impersonate any address on Anvil (testing only).
Input:
address(string): Address to impersonatestopImpersonating(optional): Stop impersonation (default: false)rpc(optional): RPC endpoint (must be Anvil)
Output:
success(boolean): Whether operation succeededaddress(string): Impersonated addressactive(boolean): Current impersonation statusbalance(optional): Current balance
Example:
{
"address": "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045"
}
8. create_snapshot
Create Anvil state snapshot for later revert.
Input:
name(optional): Human-readable snapshot namedescription(optional): Snapshot descriptionrpc(optional): RPC endpoint (must be Anvil)
Output:
snapshotId(string): Unique snapshot identifiername(optional): Snapshot nameblockNumber(number): Block at snapshotblockHash(string): Block hashtimestamp(number): Block timestampcreated(number): Unix timestamp created
Example:
{
"name": "before-attack-simulation",
"description": "State before testing exploit scenario"
}
9. revert_snapshot
Revert blockchain state to a previous snapshot.
Input:
snapshotId(string): Snapshot ID or namerpc(optional): RPC endpoint (must be Anvil)
Output:
success(boolean): Whether revert succeededsnapshotId(string): Reverted snapshot IDblockNumber(number): Block after revertblockHash(string): Block hash after reverttimestamp(number): Block timestampreverted(boolean): State revert confirmation
Example:
{
"snapshotId": "before-attack-simulation"
}
Tracing Tools
10. trace_transaction
Trace an existing transaction by hash using debug_traceTransaction.
Input:
txHash(string): Transaction hash to trace (64 hex characters)tracer(optional): Tracer type -callTracer,prestateTracer,4byteTracer, or omit for raw opcode tracetracerConfig(optional): Tracer-specific configuration object- For
callTracer:{ onlyTopCall: true }to exclude subcalls
- For
rpc(optional): RPC URL (default:http://localhost:8545)
Output:
result: Trace result (format depends on tracer type)- callTracer: Call tree with
type,from,to,value,gas,input,output - prestateTracer: Pre-execution state of all touched accounts
- 4byteTracer: Map of function selectors to call counts
- No tracer: Full opcode trace with
structLogsarray
- callTracer: Call tree with
txHash(string): Transaction hash that was traced
Example:
{
"txHash": "0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef",
"tracer": "callTracer",
"tracerConfig": {
"onlyTopCall": true
}
}
Use Cases:
- Debug failed transactions
- Analyze gas usage patterns
- Understand contract interactions
- Detect reentrancy or complex call paths
11. trace_call
Trace a call without sending transaction using debug_traceCall.
Input:
to(string): Target contract addressdata(string): Calldata (hex encoded)from(optional): Sender addressvalue(optional): ETH value in wei (hex)blockTag(optional): Block to trace at -latest,earliest,pending,safe,finalized, or block numbertracer(optional): Tracer type (same astrace_transaction)tracerConfig(optional): Tracer configurationrpc(optional): RPC URL
Output:
result: Trace result (format depends on tracer type, same astrace_transaction)
Example:
{
"to": "0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb",
"data": "0xa9059cbb000000000000000000000000f39fd6e51aad88f6f4ce6ab8827279cfffb922660000000000000000000000000000000000000000000000000de0b6b3a7640000",
"from": "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045",
"tracer": "callTracer"
}
Use Cases:
- Debug before sending actual transactions
- Analyze call behavior at specific blocks
- Test state override scenarios
- Investigate potential exploits safely
Claude Desktop Integration
Add to your Claude Desktop configuration (~/Library/Application Support/Claude/claude_desktop_config.json on macOS):
{
"mcpServers": {
"anvil-tools": {
"command": "node",
"args": [
"/absolute/path/to/mcp-anvil-tools/dist/index.js",
"--stdio"
],
"env": {
"AUDIT_MCP_PORT": "3000",
"MAINNET_RPC_URL": "https://eth-mainnet.g.alchemy.com/v2/YOUR_KEY",
"ETHERSCAN_API_KEY": "your_etherscan_api_key"
}
}
}
}
Important: Use absolute paths for the command args. Restart Claude Desktop after configuration changes.
Configuration
Alchemy Multi-Network Support
Set ALCHEMY_API_KEY to enable access to any Alchemy-supported network without additional configuration:
ALCHEMY_API_KEY=your_alchemy_api_key
Use any Alchemy network slug directly:
| Network | Slug |
|---|---|
| Ethereum | eth-mainnet, eth-sepolia |
| Arbitrum | arb-mainnet, arb-sepolia |
| Optimism | opt-mainnet, opt-sepolia |
| Polygon | polygon-mainnet, polygon-amoy |
| Base | base-mainnet, base-sepolia |
New networks are supported automatically as Alchemy adds them - no code changes needed.
Environment Variables
| Variable | Description | Default |
|---|---|---|
AUDIT_MCP_PORT | HTTP server port | 3000 |
AUDIT_MCP_HOST | HTTP server host | 0.0.0.0 |
AUDIT_MCP_DB_PATH | SQLite database path | ./audit-mcp.db |
ANVIL_PORT_START | Anvil port range start | 8545 |
ANVIL_PORT_END | Anvil port range end | 8555 |
ANVIL_DEFAULT_CHAIN_ID | Default chain ID | 31337 |
ALCHEMY_API_KEY | Alchemy API key (enables multi-network) | - |
MAINNET_RPC_URL | Mainnet RPC (overrides Alchemy) | - |
SEPOLIA_RPC_URL | Sepolia RPC (overrides Alchemy) | - |
ETHERSCAN_API_KEY | Etherscan API key | - |
ARBISCAN_API_KEY | Arbiscan API key | - |
LOG_LEVEL | Logging level | info |
LOG_FILE | Log file path | ./audit-mcp.log |
SLITHER_PATH | Path to Slither binary | /usr/local/bin/slither |
SOLC_PATH | Path to Solc binary | /usr/local/bin/solc |
Architecture
Project Structure
src/
├── index.ts # Entry point (HTTP/stdio mode detection)
├── server.ts # Express app + McpServer setup
├── config.ts # Configuration management
├── anvil/
│ ├── manager.ts # Anvil process lifecycle
│ └── types.ts # Anvil-related types
├── state/
│ └── manager.ts # SQLite state management
├── tools/
│ ├── index.ts # Tool registration with McpServer.registerTool()
│ ├── reading.ts # Reading tools (4): source, storage, bytecode, events
│ ├── execution.ts # Execution tools (5): simulate, send, impersonate, snapshots
│ └── tracing.ts # Tracing tools (2): trace_transaction, trace_call
└── utils/
├── errors.ts # Error handling
└── validation.ts # Zod schemas
Database Schema
SQLite tables for state persistence:
- deployments - Contract deployment records
- anvil_instances - Running Anvil instances
- audit_sessions - Audit session metadata
- audit_findings - Discovered vulnerabilities
- audit_notes - Session notes
Transport Architecture
┌─────────────────┐
│ AI Agent/User │
└────────┬────────┘
│
┌────┴────┐
│ HTTP │ stdio
│ /mcp │ (stdin/stdout)
└────┬────┘
│
┌────┴──────────────────┐
│ McpServer (stateless)│
│ + registerTool API │
└────┬──────────────────┘
│
┌────┴────────┐
│ 11 Tools │
│ Reading: 4 │
│ Execution: 5│
│ Tracing: 2 │
└────┬────────┘
│
┌────┴────────┐
│ viem + │
│ Anvil │
└─────────────┘
Testing
Automated Tests
# Run stdio transport tests
npx tsx test-stdio.ts
# Run all tool tests
npm test
Manual Testing
# Test stdio transport
./test-stdio-manual.sh
# Test specific tools
npm run test:tools
Example Workflows
1. Read and analyze contract:
# Read source
read_source { "path": "PoolManager.sol" }
# Get bytecode
read_bytecode { "address": "0x..." }
# Read storage
read_storage { "address": "0x...", "slot": "0x0" }
2. Simulate and execute transaction:
# Simulate first
simulate_tx {
"to": "0x...",
"data": "0x...",
"abi": [...]
}
# If successful, send
send_tx {
"to": "0x...",
"data": "0x...",
"privateKey": "0x..."
}
3. Test with snapshots:
# Create snapshot
create_snapshot { "name": "clean-state" }
# Run test transactions
send_tx { ... }
# Revert to clean state
revert_snapshot { "snapshotId": "clean-state" }
Development
Building
# Build TypeScript
npm run build
# Watch mode
npm run dev
Linting
# Run ESLint
npm run lint
# Format code
npm run format
Adding New Tools
- Define input/output schemas with Zod in
src/tools/ - Implement handler function
- Export tool in tools object
- Register in
src/tools/index.ts - Add documentation to TOOLS.md
Security Considerations
- Impersonation: Only works on Anvil, not production networks
- Private Keys: Never log or expose private keys
- RPC Access: Use secure RPC endpoints with authentication
- State Overrides: Validate carefully to prevent unintended behavior
- Gas Limits: Always set reasonable gas limits to prevent DoS
- Input Validation: All inputs validated with Zod schemas
Troubleshooting
Common Issues
Server won't start:
- Check port availability:
lsof -i :3000 - Verify environment variables in
.env - Check database permissions for
AUDIT_MCP_DB_PATH
Anvil connection fails:
- Ensure Anvil is installed:
which anvil - Check port range configuration
- Verify no port conflicts
Tool execution errors:
- Check RPC endpoint availability
- Verify contract address exists
- Ensure sufficient gas for transactions
- Check impersonation is only used on Anvil
stdio mode issues:
- Ensure one JSON-RPC message per line
- Check stderr for log messages (stdout is for responses)
- Verify MCP protocol version compatibility
Performance
- Connection Pooling: Reuses viem clients across requests
- State Caching: SQLite for fast state retrieval
- Snapshot Registry: In-memory tracking for quick snapshot operations
- Concurrent Requests: Express handles multiple concurrent MCP connections
Roadmap
- Advanced analysis tools (Slither integration)
- Call graph visualization
- AST parsing utilities
- Multi-chain support
- Enhanced trace analysis (debug_traceTransaction, debug_traceCall)
- Gas optimization suggestions
- Security pattern detection
Contributing
Contributions welcome! Please:
- Fork the repository
- Create a feature branch
- Add tests for new functionality
- Update documentation
- Submit a pull request
License
MIT
Resources
- Model Context Protocol Documentation
- viem Documentation
- Foundry Anvil
- TOOLS.md - Detailed tool reference
Support
- Issues: GitHub Issues
- Documentation: TOOLS.md
- Examples: See
test-tools.tsfor usage examples
