以太坊交易MCP服务器

一个基于Rust实现的模型上下文协议(MCP)服务器,使AI代理能够与以太坊区块链进行交互,用于余额查询、价格查询和代币交换模拟。

  • by Leisiya
  • Rust
  • 本地部署
  • 更新于
在 GitHub 查看 Leisiya/ethereum-mcp-server

使用说明

以太坊交易MCP服务器

一个用Rust实现的模型上下文协议(MCP)服务器,使AI代理能够与以太坊区块链进行交互,执行余额查询、价格查询以及代币交换模拟。

特点/功能

  • get_balance - 查询任意钱包地址的以太坊(ETH)和ERC20代币余额
  • get_token_price - 从CoinGecko获取实时代币价格(以美元或以太坊计)
  • swap_tokens - 模拟Uniswap V2代币交换并估算燃气费用(不实际执行)

先决条件

设置

1. 克隆仓库

git clone <your-repo-url>
cd ethereum-mcp-server

2. 配置环境变量

复制示例环境文件:

# Linux/Mac
cp env.example .env

# Windows PowerShell
Copy-Item env.example .env

编辑 .env 并配置您的RPC端点和私钥:

RPC 端点(必需):

选项A:使用Infura(推荐)

ETH_RPC_URL=https://mainnet.infura.io/v3/YOUR_API_KEY

获取免费API密钥,请访问 infura.io(通常不直接翻译,保持原样,若需说明可译为“Infura网站”或“Infura.io平台”)

选项B:使用炼金术

ETH_RPC_URL=https://eth-mainnet.g.alchemy.com/v2/YOUR_API_KEY

在原文内容处填写:在获取免费API密钥 alchemy.com 翻译成中文可以是“炼金术.com”或者根据语境简化为“炼金.com”,但通常网址翻译时会保留原样,因为网址本身是一个专有名词,直接用于网络地址标识。不过,如果非要给出一个中文解释性的翻译,上述翻译是可行的。在实际应用中,网址一般还是直接使用原英文形式

选项C:使用公共RPC

ETH_RPC_URL=https://eth.llamarpc.com

无需API密钥,但可能会有限速。

私钥(交换模拟必需):

⚠️(警告符号,无具体文字含义,仅表示警告或注意) 重要仅使用测试钱包!切勿使用装有真实资金的钱包!

PRIVATE_KEY=0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80

其中的私钥 env.example 这是Hardhat中的一个知名测试密钥。它在开发环境中是安全的,但没有任何资金。如果由于余额不足导致交换模拟失败,这是预期行为——模拟仍然展示了交易签名和验证的流程。

3. 构建项目

cargo build --release

4. 运行测试

cargo test

运行服务器

启动MCP服务器:

cargo run --release

服务器监听在 标准输入/标准输出 遵循MCP协议规范。

使用示例

MCP协议通信

服务器使用JSON-RPC 2.0格式。所有请求/响应均通过标准输入/标准输出进行交换。

1. 初始化服务器

请求:

{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "initialize",
  "params": {
    "protocolVersion": "2024-11-05",
    "capabilities": {},
    "clientInfo": {
      "name": "example-client",
      "version": "1.0.0"
    }
  }
}

回应:

{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "protocolVersion": "2024-11-05",
    "capabilities": {
      "tools": {}
    },
    "serverInfo": {
      "name": "ethereum-mcp-server",
      "version": "0.1.0"
    }
  }
}

2. 列出可用工具

请求:

{
  "jsonrpc": "2.0",
  "id": 2,
  "method": "tools/list",
  "params": {}
}

回应:

{
  "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. 获取以太坊余额

请求:

{
  "jsonrpc": "2.0",
  "id": 3,
  "method": "tools/call",
  "params": {
    "name": "get_balance",
    "arguments": {
      "address": "0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb"
    }
  }
}

回应:

{
  "jsonrpc": "2.0",
  "id": 3,
  "result": {
    "content": [
      {
        "type": "text",
        "text": "{\"address\":\"0x742d35cc6634c0532925a3b844bc9e7595f0beb\",\"balance\":\"1234567890123456789\",\"decimals\":18,\"symbol\":\"ETH\",\"formatted_balance\":\"1.234567890123456789\"}"
      }
    ]
  }
}

4. 获取ERC20代币余额

请求:

{
  "jsonrpc": "2.0",
  "id": 4,
  "method": "tools/call",
  "params": {
    "name": "get_balance",
    "arguments": {
      "address": "0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb",
      "token_address": "0xdAC17F958D2ee523a2206206994597C13D831ec7"
    }
  }
}

5. 获取代币价格

请求:

{
  "jsonrpc": "2.0",
  "id": 5,
  "method": "tools/call",
  "params": {
    "name": "get_token_price",
    "arguments": {
      "token": "USDT",
      "currency": "usd"
    }
  }
}

回答:

{
  "jsonrpc": "2.0",
  "id": 5,
  "result": {
    "content": [
      {
        "type": "text",
        "text": "{\"token\":\"USDT\",\"price\":1.0,\"currency\":\"usd\",\"source\":\"CoinGecko\"}"
      }
    ]
  }
}

6. 模拟代币交换

请求:

{
  "jsonrpc": "2.0",
  "id": 6,
  "method": "tools/call",
  "params": {
    "name": "swap_tokens",
    "arguments": {
      "from_token": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2",
      "to_token": "0xdAC17F958D2ee523a2206206994597C13D831ec7",
      "amount": "1000000000000000000",
      "slippage": 0.5
    }
  }
}

回答:

{
  "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...\"]}"
      }
    ]
  }
}

设计决策

  1. MCP协议实现手动实现了JSON-RPC 2.0,以便对协议流程拥有完全控制权。这使得错误处理和日志记录比使用更高层次的SDK更为完善。服务器遵循MCP规范,通过stdin/stdout进行通信。

  2. 异步架构使用Tokio作为异步运行时,以高效处理并发区块链查询。以太坊RPC调用可能会很慢,而async/await机制可避免阻塞。所有区块链交互均为非阻塞的。

  3. 用于交换模拟的真实交易签名这个 swap_tokens 工具构建 真实的、已签名的Uniswap交易 使用环境中的私钥,然后通过(某种方式)模拟它们 eth_call 或者 estimate_gas这种方法:

    • 创建包含所有必要参数(发件人地址、随机数、燃气费等)的真实交易对象
    • 使用钱包的私钥签署交易 SignerMiddleware
    • 在不广播的情况下模拟区块链上的执行
    • 提供准确的气体消耗估计,并验证交易将成功执行
    • 这满足了“构建一个真实的Uniswap交易并将其提交到区块链上进行模拟”的要求
  4. 钱包管理私钥从(某个地方)加载 PRIVATE_KEY 环境变量。系统使用 ethers-rs 的 LocalWallet 和 SignerMiddleware 收件人:

    • 解析并验证私钥
    • 派生钱包地址
    • 使用正确的链ID签署交易(主网 = 1)
    • 如果未配置私钥,则存在一种备用估计方法,但更推荐使用签名模拟
  5. Uniswap V2 用于交换选择Uniswap V2而非V3,因为其更简洁可靠。V2具有以下特点:

    • 直接的路由机制(直接交换或通过WETH交换)
    • 更广泛的货币对可用性和流动性
    • 更简洁的ABI(应用程序二进制接口)和更可预测的行为
    • 交换路径会自动使用WETH作为代币间交换的中介
  6. 金融精确度所有代币数量在API中均作为字符串处理,以防止浮点精度错误。在内部,我们使用 U256 来自ethers-rs,用于实现精确的任意精度计算。滑点计算保持精度,仅在最终转换时使用浮点数。

  7. 价格数据来源CoinGecko API为大多数代币提供免费、可靠的价格数据,无需API密钥。为方便起见,代币符号和地址已映射到CoinGecko ID。

已知的限制与假设

  • 测试网支持当前配置为以太坊主网。如需使用测试网,请更改RPC URL以及(其他相关设置,此处原文未完整,假设需更改的是与RPC URL相关的配置项) .env 并更新链ID ethereum.rs (第25行)。

  • 仅限Uniswap V2交换模拟仅支持Uniswap V2。V3具有集中流动性功能和多跳路由,这需要更复杂的计算和不同的应用二进制接口(ABIs)。

  • 有限的代币配对某些异域代币对在Uniswap V2上可能没有流动性。如果不存在相应的代币对,交换操作将失败并显示错误信息。常见代币对(WETH、USDT、USDC、DAI)得到了良好的支持。

  • 气体估算准确性“Gas estimates(燃气估算)是基于当前区块链状态的近似值。实际燃气使用量可能会因以下情况而有所不同:”

    • 在模拟和执行之间,网络条件会发生变化
    • 代币合约具有动态行为(例如,费用会变化)
    • 钱包中ERC20代币的余额不足以进行授权
  • 价格影响价格影响计算已简化(显示“< 1%”占位符)。如需准确计算影响,您需要:

    • 查询兑换前后的池子储备量
    • 计算有效价格与池子的现货价格之差
    • 考虑通过WETH进行多跳交换
  • 无交易执行该 swap_tokens 该工具构建并签署真实的交易,但仅限于 模拟 它们。交易永远不会广播到区块链上。要实际执行:

    • 已签名的交易需要通过 eth_sendRawTransaction
    • 需要钱包中有足够的以太币(ETH)作为手续费以及用于兑换的代币
    • 对于多笔交易,需要适当的随机数(nonce)管理
  • 私钥安全测试私钥在 env.example 是公开已知的,并且应该 永远 使用真实资金。在生产中:

    • 使用硬件钱包或安全密钥管理系统
    • 永远不要将私钥提交到版本控制系统中
    • 使用 .gitignore 排除 .env 文件
  • 速率限制公共RPC端点(如LlamaRPC)和CoinGecko的免费API都有速率限制。对于生产环境使用:

    • 使用限额更高的付费RPC提供商(Infura、Alchemy)
    • 实现请求缓存和速率限制
    • 考虑运行你自己的以太坊节点
  • 错误处理一些边缘情况(网络故障、无效地址、流动性不足)会返回基本错误信息。生产代码需要:

    • 更细粒度的错误类型和代码
    • 针对瞬时网络故障的重试逻辑
    • 提供更好的面向用户的错误信息,并附上修复建议

项目结构

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

测试

运行测试套件:

# Run all tests
cargo test

# Run tests with output
cargo test -- --nocapture

# Run specific test
cargo test test_json_rpc_request_parsing

测试内容包括:

  • JSON-RPC 请求/响应解析
  • 地址和金额验证
  • 示例MCP协议交互

常见代币地址(以太坊主网)

  • WETH(Wrapped Ethereum,以太坊封装币): 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2
  • USDT(泰达币): 0xdAC17F958D2ee523a2206206994597C13D831ec7
  • USDC(美元稳定币): 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48
  • DAI(戴伊/大额可转让存单/去中心化自治组织等,具体含义需根据上下文确定): 0x6B175474E89094C44Da98b954EedeAC495271d0F

故障排除

Windows:“链接器 link.exe 在构建过程中出现“not found”

  • 您需要带有C++支持的Visual Studio构建工具
  • 下载地址:https://visualstudio.microsoft.com/downloads/
  • 安装“使用 C++ 进行桌面开发”
  • 安装完成后重启您的电脑
  • 重新打开 PowerShell 并尝试 cargo build 再次

“无法创建以太坊提供者”

  • 检查一下你的 ETH_RPC_URL 在 .env 是正确的
  • 检查您的网络连接
  • 尝试使用不同的RPC端点
  • 确保使用Infura/Alchemy时API密钥有效

“私钥格式无效”

  • 确保私钥以以下内容开头 0x
  • 总长度应为66个字符(0x + 64个十六进制字符)
  • 永远不要使用真实钱包的私钥——请使用来自(此处应补充来源,但原文未给出具体来源)的测试密钥 env.example

“无法估算交换所需的气体(费用)”

  • 该钱包可能缺少足够的代币余额(测试钱包预期如此)
  • 该代币对可能在Uniswap V2上不存在
  • 尝试使用像WETH/USDT这样的知名币对
  • 检查代币地址是否有效

“请求速率超过限制”

  • 如果使用公共RPC,请切换到Infura/Alchemy
  • 在请求之间添加延迟
  • 减少并发请求数量

“兑换时配对不存在”

  • 该代币对在Uniswap V2上可能没有流动性
  • 验证代币地址是否正确(应使用校验和)
  • 尝试使用不同的代币对(见下文常见代币地址)

发展

要启用调试日志记录:

# Unix/Linux/Mac
RUST_LOG=debug cargo run

# Windows PowerShell
$env:RUST_LOG="debug"; cargo run

# Windows CMD
set RUST_LOG=debug && cargo run

格式化代码:

cargo fmt

运行代码检查工具:

cargo clippy

附加文件

许可证

麻省理工学院(MIT)

联系

关于此实现的任何问题,请参阅代码注释或提交一个问题。