Leisiya/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.
The Ethereum Trading MCP Server is a Rust-based implementation that allows AI agents to interact with the Ethereum blockchain for various trading-related tasks.
Ethereum Trading MCP Server
A Model Context Protocol (MCP) server implementation in Rust that enables AI agents to interact with the Ethereum blockchain for balance queries, price lookups, and token swap simulations.
Features
get_balance- Query ETH and ERC20 token balances for any wallet addressget_token_price- Get real-time token prices in USD or ETH from CoinGeckoswap_tokens- Simulate Uniswap V2 token swaps with gas estimates (no actual execution)
Prerequisites
- Rust 1.70+ (install from rustup.rs)
- An Ethereum RPC endpoint (Infura, Alchemy, or public node)
Setup
1. Clone the Repository
git clone <your-repo-url>
cd ethereum-mcp-server
2. Configure Environment Variables
Copy the example environment file:
# Linux/Mac
cp env.example .env
# Windows PowerShell
Copy-Item env.example .env
Edit .env and configure your RPC endpoint and private key:
RPC Endpoint (Required):
Option A: Use Infura (Recommended)
ETH_RPC_URL=https://mainnet.infura.io/v3/YOUR_API_KEY
Get a free API key at infura.io
Option B: Use Alchemy
ETH_RPC_URL=https://eth-mainnet.g.alchemy.com/v2/YOUR_API_KEY
Get a free API key at alchemy.com
Option C: Use Public RPC
ETH_RPC_URL=https://eth.llamarpc.com
No API key needed, but may have rate limits.
Private Key (Required for swap simulation):
⚠️ IMPORTANT: Use a test wallet only! Never use a wallet with real funds!
PRIVATE_KEY=0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80
The private key in env.example is a well-known test key from Hardhat. It's safe for development but has no funds. If swap simulation fails due to insufficient balance, this is expected behavior - the simulation still demonstrates the transaction signing and validation flow.
3. Build the Project
cargo build --release
4. Run Tests
cargo test
Running the Server
Start the MCP server:
cargo run --release
The server listens on stdin/stdout following the MCP protocol specification.
Usage Examples
MCP Protocol Communication
The server uses JSON-RPC 2.0 format. All requests/responses are exchanged via stdin/stdout.
1. Initialize the Server
Request:
{
"jsonrpc": "2.0",
"id": 1,
"method": "initialize",
"params": {
"protocolVersion": "2024-11-05",
"capabilities": {},
"clientInfo": {
"name": "example-client",
"version": "1.0.0"
}
}
}
Response:
{
"jsonrpc": "2.0",
"id": 1,
"result": {
"protocolVersion": "2024-11-05",
"capabilities": {
"tools": {}
},
"serverInfo": {
"name": "ethereum-mcp-server",
"version": "0.1.0"
}
}
}
2. List Available Tools
Request:
{
"jsonrpc": "2.0",
"id": 2,
"method": "tools/list",
"params": {}
}
Response:
{
"jsonrpc": "2.0",
"id": 2,
"result": {
"tools": [
{
"name": "get_balance",
"description": "Query ETH and ERC20 token balances for a wallet address",
"inputSchema": { ... }
},
{
"name": "get_token_price",
"description": "Get current token price in USD or ETH",
"inputSchema": { ... }
},
{
"name": "swap_tokens",
"description": "Simulate a token swap on Uniswap V2",
"inputSchema": { ... }
}
]
}
}
3. Get ETH Balance
Request:
{
"jsonrpc": "2.0",
"id": 3,
"method": "tools/call",
"params": {
"name": "get_balance",
"arguments": {
"address": "0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb"
}
}
}
Response:
{
"jsonrpc": "2.0",
"id": 3,
"result": {
"content": [
{
"type": "text",
"text": "{\"address\":\"0x742d35cc6634c0532925a3b844bc9e7595f0beb\",\"balance\":\"1234567890123456789\",\"decimals\":18,\"symbol\":\"ETH\",\"formatted_balance\":\"1.234567890123456789\"}"
}
]
}
}
4. Get ERC20 Token Balance
Request:
{
"jsonrpc": "2.0",
"id": 4,
"method": "tools/call",
"params": {
"name": "get_balance",
"arguments": {
"address": "0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb",
"token_address": "0xdAC17F958D2ee523a2206206994597C13D831ec7"
}
}
}
5. Get Token Price
Request:
{
"jsonrpc": "2.0",
"id": 5,
"method": "tools/call",
"params": {
"name": "get_token_price",
"arguments": {
"token": "USDT",
"currency": "usd"
}
}
}
Response:
{
"jsonrpc": "2.0",
"id": 5,
"result": {
"content": [
{
"type": "text",
"text": "{\"token\":\"USDT\",\"price\":1.0,\"currency\":\"usd\",\"source\":\"CoinGecko\"}"
}
]
}
}
6. Simulate Token Swap
Request:
{
"jsonrpc": "2.0",
"id": 6,
"method": "tools/call",
"params": {
"name": "swap_tokens",
"arguments": {
"from_token": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2",
"to_token": "0xdAC17F958D2ee523a2206206994597C13D831ec7",
"amount": "1000000000000000000",
"slippage": 0.5
}
}
}
Response:
{
"jsonrpc": "2.0",
"id": 6,
"result": {
"content": [
{
"type": "text",
"text": "{\"from_token\":\"0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2\",\"to_token\":\"0xdac17f958d2ee523a2206206994597c13d831ec7\",\"amount_in\":\"1000000000000000000\",\"estimated_amount_out\":\"3456789012\",\"minimum_amount_out\":\"3439505127\",\"slippage\":0.5,\"price_impact\":\"< 1%\",\"gas_estimate\":\"150000\",\"path\":[\"0xc02...\",\"0xdac...\"]}"
}
]
}
}
Design Decisions
-
MCP Protocol Implementation: Implemented JSON-RPC 2.0 manually for full control over the protocol flow. This allows better error handling and logging compared to using a higher-level SDK. The server communicates via stdin/stdout following the MCP specification.
-
Async Architecture: Used Tokio for async runtime to handle concurrent blockchain queries efficiently. Ethereum RPC calls can be slow, and async/await prevents blocking. All blockchain interactions are non-blocking.
-
Real Transaction Signing for Swap Simulation: The
swap_tokenstool builds real, signed Uniswap transactions using a private key from the environment, then simulates them viaeth_callorestimate_gas. This approach:- Creates authentic transaction objects with all necessary parameters (from address, nonce, gas, etc.)
- Signs the transaction with a wallet's private key using
SignerMiddleware - Simulates execution on the blockchain without broadcasting
- Provides accurate gas estimates and validates the transaction would succeed
- This satisfies the requirement to "build a real Uniswap transaction and submit it to the blockchain for simulation"
-
Wallet Management: Private keys are loaded from the
PRIVATE_KEYenvironment variable. The system uses ethers-rs'sLocalWalletandSignerMiddlewareto:- Parse and validate private keys
- Derive wallet addresses
- Sign transactions with proper chain ID (mainnet = 1)
- A fallback estimation method exists if no private key is configured, but signed simulation is preferred
-
Uniswap V2 for Swaps: Chose Uniswap V2 over V3 for simplicity and reliability. V2 has:
- Straightforward routing mechanism (direct swap or via WETH)
- Wider pair availability and liquidity
- Simpler ABI and more predictable behavior
- The swap path automatically uses WETH as an intermediary for token-to-token swaps
-
Financial Precision: All token amounts are handled as strings in the API to prevent floating-point precision errors. Internally, we use
U256from ethers-rs for accurate arbitrary-precision calculations. Slippage calculations maintain precision using floating-point only for the final conversion. -
Price Data Source: CoinGecko API provides free, reliable price data for most tokens without requiring API keys. Token symbols and addresses are mapped to CoinGecko IDs for convenience.
Known Limitations & Assumptions
-
Testnet Support: Currently configured for Ethereum mainnet. To use testnets, change both the RPC URL in
.envand update the chain ID inethereum.rs(line 25). -
Uniswap V2 Only: Swap simulation only supports Uniswap V2. V3 has concentrated liquidity and multi-hop routing which requires more complex calculations and different ABIs.
-
Limited Token Pairs: Some exotic token pairs may not have liquidity on Uniswap V2. The swap will fail with an error message if no pair exists. Common pairs (WETH, USDT, USDC, DAI) are well-supported.
-
Gas Estimation Accuracy: Gas estimates are approximations based on current blockchain state. Actual gas usage may vary if:
- Network conditions change between simulation and execution
- Token contracts have dynamic behavior (e.g., fees that change)
- The wallet lacks sufficient token balance for ERC20 approvals
-
Price Impact: The price impact calculation is simplified (shows "< 1%" placeholder). For accurate impact calculation, you'd need to:
- Query the pool's reserves before and after the swap
- Calculate the effective price versus the pool's spot price
- Consider multi-hop swaps through WETH
-
No Transaction Execution: The
swap_tokenstool builds and signs real transactions but only simulates them. Transactions are never broadcast to the blockchain. To actually execute:- The signed transaction would need to be sent via
eth_sendRawTransaction - Requires the wallet to have sufficient ETH for gas and tokens for the swap
- Would need proper nonce management for multiple transactions
- The signed transaction would need to be sent via
-
Private Key Security: The test private key in
env.exampleis publicly known and should never be used with real funds. In production:- Use hardware wallets or secure key management systems
- Never commit private keys to version control
- Use
.gitignoreto exclude.envfiles
-
Rate Limiting: Public RPC endpoints (like LlamaRPC) and CoinGecko's free API have rate limits. For production use:
- Use paid RPC providers (Infura, Alchemy) with higher limits
- Implement request caching and rate limiting
- Consider running your own Ethereum node
-
Error Handling: Some edge cases (network failures, invalid addresses, insufficient liquidity) return basic error messages. Production code would need:
- More granular error types and codes
- Retry logic for transient network failures
- Better user-facing error messages with suggested fixes
Project Structure
ethereum-mcp-server/
├── src/
│ ├── main.rs # Entry point
│ ├── config.rs # Configuration from environment
│ ├── mcp.rs # MCP protocol server implementation
│ ├── ethereum.rs # Ethereum provider and contract ABIs
│ └── tools/ # MCP tool implementations
│ ├── mod.rs
│ ├── get_balance.rs
│ ├── get_token_price.rs
│ └── swap_tokens.rs
├── tests/
│ └── integration_test.rs
├── examples/
│ └── test_requests.json
├── Cargo.toml
├── env.example
├── SETUP_GUIDE.md # Detailed Chinese setup guide
├── ARCHITECTURE.md # Technical architecture documentation
└── README.md
Testing
Run the test suite:
# Run all tests
cargo test
# Run tests with output
cargo test -- --nocapture
# Run specific test
cargo test test_json_rpc_request_parsing
The tests include:
- JSON-RPC request/response parsing
- Address and amount validation
- Example MCP protocol interactions
Common Token Addresses (Ethereum Mainnet)
- WETH:
0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2 - USDT:
0xdAC17F958D2ee523a2206206994597C13D831ec7 - USDC:
0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48 - DAI:
0x6B175474E89094C44Da98b954EedeAC495271d0F
Troubleshooting
Windows: "linker link.exe not found" during build
- You need Visual Studio Build Tools with C++ support
- Download from: https://visualstudio.microsoft.com/downloads/
- Install "Desktop development with C++"
- Restart your computer after installation
- Reopen PowerShell and try
cargo buildagain
"Failed to create Ethereum provider"
- Check that your
ETH_RPC_URLin.envis correct - Verify your internet connection
- Try a different RPC endpoint
- Ensure the API key is valid if using Infura/Alchemy
"Invalid private key format"
- Ensure the private key starts with
0x - Should be 66 characters total (0x + 64 hex characters)
- Never use a real wallet's private key - use the test key from
env.example
"Failed to estimate gas" for swap
- The wallet may lack sufficient token balance (expected for test wallets)
- The token pair may not exist on Uniswap V2
- Try a well-known pair like WETH/USDT
- Check that token addresses are valid
"Rate limit exceeded"
- If using public RPC, switch to Infura/Alchemy
- Add delays between requests
- Reduce the number of concurrent requests
"Pair does not exist" for swap
- The token pair may not have liquidity on Uniswap V2
- Verify token addresses are correct (should be checksummed)
- Try a different token pair (see Common Token Addresses below)
Development
To enable debug logging:
# Unix/Linux/Mac
RUST_LOG=debug cargo run
# Windows PowerShell
$env:RUST_LOG="debug"; cargo run
# Windows CMD
set RUST_LOG=debug && cargo run
To format code:
cargo fmt
To run linter:
cargo clippy
Additional Documentation
- - 🇨🇳 快速开始指南(中文)- Quick start guide in Chinese
- - Example MCP requests for testing
- - Environment configuration template
License
MIT
Contact
For questions about this implementation, please refer to the code comments or open an issue.