Skip to main content
Glama

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:

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

  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

-
security - not tested
F
license - not found
-
quality - not tested

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/dennisonbertram/mcp-anvil-tools'

If you have feedback or need assistance with the MCP directory API, please join our Discord server