Dannieeth/ethereum-mcp-server
If you are the rightful owner of ethereum-mcp-server 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.
Ethereum MCP Server is a Rust-based server implementation for Ethereum blockchain operations, enabling AI agents to interact with Ethereum for balance queries, token price fetching, and token swap simulations.
Ethereum MCP Server
A Model Context Protocol (MCP) server implementation in Rust for Ethereum blockchain operations. This server enables AI agents to query balances, fetch token prices from Chainlink oracles, and simulate token swaps on Uniswap V2.
Supports both stdio (MCP standard) and HTTP (REST API) modes for flexible integration.
Features
MCP Tools
-
get_balance- Query ETH and ERC20 token balances- Supports both native ETH and any ERC20 token
- Returns formatted balances with proper decimals
- Concurrent fetching of token metadata
-
get_token_price- Get current token prices from Chainlink price feeds- Fetches real-time USD prices from Chainlink oracles
- Calculates ETH-denominated prices
- Includes data staleness checks
- Cached with moka (60s TTL by default)
-
swap_tokens- Simulate token swaps on Uniswap V2- Constructs real Uniswap V2 transactions
- Simulates execution using
eth_call(no on-chain execution) - Calculates price impact and slippage protection
- Estimates gas costs
Architecture
Technology Stack
- Rust with async/await (tokio runtime)
- ethers-rs - Ethereum RPC client and contract bindings
- axum + tower - HTTP server framework (for HTTP mode)
- moka - In-memory async cache (can be replaced with Redis for distributed deployment)
- tracing - Structured logging
- serde - Serialization/deserialization
- rust_decimal - Financial precision calculations
- clap - Command-line argument parsing
Directory Structure
ethereum-mcp-server/
├── src/
│ ├── main.rs # Entry point, mode selection, tokio runtime
│ ├── lib.rs # Library root
│ ├── config.rs # Configuration management
│ ├── error.rs # Unified error types
│ ├── mcp/ # MCP protocol layer
│ │ ├── server.rs # JSON-RPC 2.0 server (stdio mode)
│ │ ├── http_server.rs # HTTP JSON-RPC server (HTTP mode)
│ │ ├── handler.rs # Tool call routing
│ │ └── schema.rs # Protocol schemas
│ ├── services/ # Business logic layer
│ │ ├── balance.rs # Balance query service
│ │ ├── price.rs # Price query service (Chainlink)
│ │ └── swap.rs # Swap simulation service
│ ├── providers/ # External provider layer
│ │ ├── ethereum.rs # Ethereum RPC client
│ │ ├── chainlink.rs # Chainlink oracle with moka cache
│ │ └── uniswap.rs # Uniswap V2 interaction
│ ├── contracts/ # Smart contract ABIs
│ │ ├── erc20.rs
│ │ ├── chainlink_feed.rs
│ │ └── uniswap_router.rs
│ └── utils/ # Utilities
│ ├── decimal.rs # Precision handling
│ ├── validation.rs # Input validation
│ └── wallet.rs # Wallet management
└── tests/
└── integration/ # Integration tests
Setup
Prerequisites
- Rust 1.70+ (install from https://rustup.rs)
- Ethereum RPC endpoint (Infura, Alchemy, or public endpoint)
Installation
- Clone the repository:
git clone <repository-url>
cd ethereum-mcp-server
- Copy environment configuration:
cp .env.example .env
- Edit
.envwith your configuration:
# Required
RPC_URL=https://eth-mainnet.g.alchemy.com/v2/YOUR_API_KEY
PRIVATE_KEY=0x0000000000000000000000000000000000000000000000000000000000000001
# Optional
LOG_LEVEL=info
PRICE_CACHE_TTL_SECS=60
CACHE_MAX_CAPACITY=1000
⚠️ Security Warning: Never commit your .env file with real private keys!
- Build the project:
cargo build --release
Running
The server supports two modes:
1. stdio Mode (Default - MCP Standard)
cargo run --release
The server communicates via stdin/stdout using JSON-RPC 2.0 protocol.
📝 Note: When sending requests via command line, JSON must be on a single line. See and for practical examples.
2. HTTP Mode (REST API)
# Start HTTP server on default port (3000)
cargo run --release -- --mode http
# Or specify custom host and port
cargo run --release -- --mode http --host 0.0.0.0 --port 8080
The server provides HTTP JSON-RPC endpoints:
POST /rpc- JSON-RPC 2.0 endpoint for all tool callsGET /health- Health check endpoint
📡 See for detailed HTTP API documentation, examples with curl/Python/JavaScript, and deployment guides.
CLI Options
OPTIONS:
-m, --mode <MODE> Server mode [default: stdio] [possible values: stdio, http]
--host <HOST> HTTP server host [default: 127.0.0.1]
-p, --port <PORT> HTTP server port [default: 3000]
-h, --help Print help
-V, --version Print version
Usage Examples
MCP Tool Call Examples
ⓘ The JSON examples below are formatted for readability. For actual command-line usage, compress them to single-line format (see ).
1. List Available Tools
Request:
{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/list",
"params": {}
}
Response:
{
"jsonrpc": "2.0",
"id": 1,
"result": {
"tools": [
{
"name": "get_balance",
"description": "Query ETH and ERC20 token balances...",
"input_schema": { ... }
},
{
"name": "get_token_price",
"description": "Get current token price...",
"input_schema": { ... }
},
{
"name": "swap_tokens",
"description": "Simulate a token swap...",
"input_schema": { ... }
}
]
}
}
2. Query ETH Balance
Request:
{
"jsonrpc": "2.0",
"id": 2,
"method": "tools/call",
"params": {
"name": "get_balance",
"arguments": {
"wallet_address": "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045"
}
}
}
Response:
{
"jsonrpc": "2.0",
"id": 2,
"result": {
"content": [
{
"type": "text",
"text": "{
\"wallet_address\": \"0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045\",
\"token_symbol\": \"ETH\",
\"token_name\": \"Ethereum\",
\"decimals\": 18,
\"balance\": \"1500000000000000000\",
\"balance_formatted\": \"1.5 ETH\",
\"balance_decimal\": \"1.5\"
}"
}
]
}
}
3. Query ERC20 Token Balance
Request:
{
"jsonrpc": "2.0",
"id": 3,
"method": "tools/call",
"params": {
"name": "get_balance",
"arguments": {
"wallet_address": "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045",
"token_address": "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48"
}
}
}
4. Get Token Price
Request:
{
"jsonrpc": "2.0",
"id": 4,
"method": "tools/call",
"params": {
"name": "get_token_price",
"arguments": {
"token": "ETH"
}
}
}
Response:
{
"jsonrpc": "2.0",
"id": 4,
"result": {
"content": [
{
"type": "text",
"text": "{
\"token\": \"ETH\",
\"usd_price\": 2450.75,
\"decimals\": 8,
\"round_id\": 12345,
\"updated_at\": \"2024-01-15T10:30:00Z\",
\"is_stale\": false
}"
}
]
}
}
5. Simulate Token Swap
Request:
{
"jsonrpc": "2.0",
"id": 5,
"method": "tools/call",
"params": {
"name": "swap_tokens",
"arguments": {
"from_token": "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
"to_token": "0x6B175474E89094C44Da98b954EedeAC495271d0F",
"amount": "100",
"slippage_tolerance": 0.5
}
}
}
Response:
{
"jsonrpc": "2.0",
"id": 5,
"result": {
"content": [
{
"type": "text",
"text": "{
\"from_token\": \"0xA0b8...\",
\"to_token\": \"0x6B17...\",
\"from_symbol\": \"USDC\",
\"to_symbol\": \"DAI\",
\"amount_in\": \"100000000\",
\"amount_in_formatted\": \"100 USDC\",
\"amount_out\": \"99500000000000000000\",
\"amount_out_formatted\": \"99.5 DAI\",
\"min_amount_out\": \"99002500000000000000\",
\"min_amount_out_formatted\": \"99.0025 DAI\",
\"price_impact\": 0.12,
\"slippage_tolerance\": 0.5,
\"path\": [\"0xA0b8...\", \"0xC02a...\", \"0x6B17...\"],
\"estimated_gas\": \"150000\",
\"gas_price\": \"30000000000\",
\"gas_cost\": \"4500000000000000\",
\"gas_cost_eth\": \"0.0045\",
\"simulation_successful\": true
}"
}
]
}
}
Design Decisions
1. Async Architecture with Tokio
- All I/O operations (RPC calls, file I/O) are fully asynchronous
- Tokio's multi-threaded runtime handles concurrent requests efficiently
tokio::join!andtokio::try_join!enable parallel RPC calls (e.g., fetching token info and balance simultaneously)
2. Chainlink for Price Data
- Chose Chainlink oracles for decentralized, tamper-proof price feeds
- Pre-configured mainnet price feed addresses for major tokens (ETH, BTC, USDC, etc.)
- Supports both symbol-based queries ("ETH") and address-based queries
3. Moka Cache (Upgradeable to Redis)
- Uses
mokafor in-memory async caching with configurable TTL (default 60s) - Price data is cached to reduce RPC calls and improve performance
- Architecture allows easy replacement with Redis for distributed deployments:
- Cache layer is abstracted in
ChainlinkProvider - Redis implementation template included in comments
- Simply swap
Cache<String, PriceData>withredis::aio::ConnectionManager
- Cache layer is abstracted in
4. Uniswap V2 for Swap Simulation
- Implemented Uniswap V2 Router integration (simpler than V3)
- Constructs real swap transactions but only simulates via
eth_call - Calculates price impact by comparing pool reserves vs execution price
- V3 support can be added as an extension
5. Error Handling and Validation
- Comprehensive error types using
thiserror - Input validation for addresses, amounts, and slippage
- Maps errors to appropriate JSON-RPC error codes
Known Limitations and Assumptions
-
Network Support: Currently configured for Ethereum Mainnet only
- Chainlink price feeds and Uniswap addresses are mainnet-specific
- Can be extended to support testnets or other EVM chains
-
Uniswap Version: Implements V2 only
- V3 support requires more complex tick and liquidity range logic
- V2 is sufficient for price discovery and basic swaps
-
Private Key Management: Uses environment variable for private key
- Suitable for development and testing
- Production deployments should use secure key management systems (HSM, KMS)
-
RPC Rate Limits: No built-in rate limiting
- Public RPC endpoints may throttle requests
- Recommend using paid providers (Alchemy, Infura) for production
-
Cache Distribution: Moka cache is in-memory (single-instance)
- For horizontal scaling, replace with Redis (implementation template provided)
- Cache invalidation is TTL-based only (no event-based invalidation)
-
Price Feed Coverage: Limited to pre-configured tokens
- Feed Registry support is optional (requires configuration)
- Tokens without Chainlink feeds will return "not found" errors
-
Transaction Simulation: Uses
eth_callfor swap simulation- Does not account for MEV or sandwich attacks
- Actual on-chain execution may differ from simulation
-
Gas Estimation: Basic gas estimation only
- Does not account for network congestion
- No EIP-1559 support (uses legacy gas pricing)
Testing
Run Unit Tests
cargo test --lib
Run Integration Tests
cargo test --test '*'
Run with Specific RPC (Integration Tests)
RPC_URL=https://eth.llamarpc.com cargo test --test '*' -- --ignored
Development
Enable Debug Logging
RUST_LOG=debug cargo run
Format Code
cargo fmt
Lint
cargo clippy -- -D warnings
Future Enhancements
- Redis cache support for distributed deployment
- Uniswap V3 integration
- Multi-chain support (Polygon, Arbitrum, etc.)
- EIP-1559 gas estimation
- WebSocket RPC support
- Historical price data queries
- Portfolio tracking features
License
MIT License - see LICENSE file for details
Contributing
Contributions are welcome! Please open an issue or submit a pull request.