MCP Hub
Back to servers

MCP Anvil Tools

A specialized MCP server for Ethereum development and auditing that connects AI agents to Anvil for smart contract analysis, transaction simulation, and blockchain state manipulation.

Tools
11
Updated
Dec 3, 2025

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 /mcp endpoint 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 interactions
  • ETHERSCAN_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 statistics
  • POST /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 from lib/v4-core/src/ (e.g., PoolManager.sol)

Output:

  • content (string): Full source code
  • lines (number): Total line count
  • path (string): Absolute file path
  • size (number): File size in bytes
  • lastModified (string): ISO timestamp

Example:

{
  "path": "PoolManager.sol"
}

2. read_storage

Read contract storage slots (persistent storage only, not transient).

Input:

  • address (string): Contract address
  • slot (string): Storage slot (hex, e.g., 0x0)
  • blockTag (optional): latest, earliest, pending, block number, or block hash
  • rpc (optional): RPC URL (default: http://localhost:8545)

Output:

  • value (string): Raw 32-byte hex value
  • decoded (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 address
  • blockTag (optional): Block identifier
  • rpc (optional): RPC URL

Output:

  • bytecode (string): Hex-encoded bytecode
  • size (number): Bytecode size in bytes
  • codeHash (string): Keccak256 hash
  • isEmpty (boolean): True if no code deployed (EOA)

Example:

{
  "address": "0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb"
}

4. read_events

Query and decode contract event logs.

Input:

  • address (string): Contract address
  • eventSignature (optional): Event signature (e.g., Transfer(address,address,uint256))
  • topics (optional): Indexed topics filter
  • fromBlock (optional): Starting block (default: earliest)
  • toBlock (optional): Ending block (default: latest)
  • rpc (optional): RPC URL

Output:

  • events (array): Event logs with block info
  • count (number): Total events returned
  • fromBlock (string): Actual starting block
  • toBlock (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 address
  • data (string): Calldata (hex)
  • from (optional): Sender address
  • gasLimit (optional): Gas limit
  • value (optional): ETH value in wei (hex)
  • abi (optional): Contract ABI for decoding
  • functionName (optional): Function name for decoding
  • blockNumber (optional): Block to simulate at
  • stateOverrides (optional): State overrides by address
  • rpc (optional): RPC endpoint

Output:

  • result (string): Return data (hex)
  • decoded (optional): Decoded return value
  • reverted (boolean): Whether call reverted
  • revertReason (optional): Decoded revert reason
  • revertData (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 / bytecode
  • from (optional): Sender address
  • value (optional): ETH value in wei (hex)
  • gasLimit (optional): Gas limit (auto-estimated)
  • gasPrice (optional): Legacy gas price
  • maxFeePerGas (optional): EIP-1559 max fee
  • maxPriorityFeePerGas (optional): EIP-1559 priority fee
  • nonce (optional): Transaction nonce
  • privateKey (optional): Private key for signing
  • confirmations (optional): Confirmations to wait (default: 1)
  • rpc (optional): RPC endpoint

Output:

  • txHash (string): Transaction hash
  • blockNumber (string): Block number
  • blockHash (string): Block hash
  • gasUsed (string): Gas consumed
  • effectiveGasPrice (string): Actual gas price
  • status (enum): success or reverted
  • logs (array): Event logs
  • contractAddress (optional): Deployed contract address
  • from (string): Sender address
  • to (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 impersonate
  • stopImpersonating (optional): Stop impersonation (default: false)
  • rpc (optional): RPC endpoint (must be Anvil)

Output:

  • success (boolean): Whether operation succeeded
  • address (string): Impersonated address
  • active (boolean): Current impersonation status
  • balance (optional): Current balance

Example:

{
  "address": "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045"
}

8. create_snapshot

Create Anvil state snapshot for later revert.

Input:

  • name (optional): Human-readable snapshot name
  • description (optional): Snapshot description
  • rpc (optional): RPC endpoint (must be Anvil)

Output:

  • snapshotId (string): Unique snapshot identifier
  • name (optional): Snapshot name
  • blockNumber (number): Block at snapshot
  • blockHash (string): Block hash
  • timestamp (number): Block timestamp
  • created (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 name
  • rpc (optional): RPC endpoint (must be Anvil)

Output:

  • success (boolean): Whether revert succeeded
  • snapshotId (string): Reverted snapshot ID
  • blockNumber (number): Block after revert
  • blockHash (string): Block hash after revert
  • timestamp (number): Block timestamp
  • reverted (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 trace
  • tracerConfig (optional): Tracer-specific configuration object
    • For callTracer: { onlyTopCall: true } to exclude subcalls
  • 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 structLogs array
  • 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 address
  • data (string): Calldata (hex encoded)
  • from (optional): Sender address
  • value (optional): ETH value in wei (hex)
  • blockTag (optional): Block to trace at - latest, earliest, pending, safe, finalized, or block number
  • tracer (optional): Tracer type (same as trace_transaction)
  • tracerConfig (optional): Tracer configuration
  • rpc (optional): RPC URL

Output:

  • result: Trace result (format depends on tracer type, same as trace_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:

NetworkSlug
Ethereumeth-mainnet, eth-sepolia
Arbitrumarb-mainnet, arb-sepolia
Optimismopt-mainnet, opt-sepolia
Polygonpolygon-mainnet, polygon-amoy
Basebase-mainnet, base-sepolia

New networks are supported automatically as Alchemy adds them - no code changes needed.

Environment Variables

VariableDescriptionDefault
AUDIT_MCP_PORTHTTP server port3000
AUDIT_MCP_HOSTHTTP server host0.0.0.0
AUDIT_MCP_DB_PATHSQLite database path./audit-mcp.db
ANVIL_PORT_STARTAnvil port range start8545
ANVIL_PORT_ENDAnvil port range end8555
ANVIL_DEFAULT_CHAIN_IDDefault chain ID31337
ALCHEMY_API_KEYAlchemy API key (enables multi-network)-
MAINNET_RPC_URLMainnet RPC (overrides Alchemy)-
SEPOLIA_RPC_URLSepolia RPC (overrides Alchemy)-
ETHERSCAN_API_KEYEtherscan API key-
ARBISCAN_API_KEYArbiscan API key-
LOG_LEVELLogging levelinfo
LOG_FILELog file path./audit-mcp.log
SLITHER_PATHPath to Slither binary/usr/local/bin/slither
SOLC_PATHPath 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

  1. Define input/output schemas with Zod in src/tools/
  2. Implement handler function
  3. Export tool in tools object
  4. Register in src/tools/index.ts
  5. 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:

  1. Fork the repository
  2. Create a feature branch
  3. Add tests for new functionality
  4. Update documentation
  5. Submit a pull request

License

MIT

Resources

Support

Reviews

No reviews yet

Sign in to write a review