以太坊交易查询服务器

一个基于 Rust 的 MCP 服务器,使 AI 代理能够查询以太坊/BSC 链上余额、获取代币价格并模拟代币交换。

  • by HuntSweet
  • Rust
  • 本地部署
  • 更新于
在 GitHub 查看 HuntSweet/eth_trading_mcp

使用说明

以太坊交易 MCP 服务器

一个基于 Rust 的 MCP(Model Context Protocol)服务器,使 AI 代理能够查询以太坊/BSC 链上余额、获取代币价格并模拟代币交换。

功能特性

  • get_balance - 查询 ETH/BNB 和 ERC20 代币余额
  • get_token_price - 获取代币的 USD 和 ETH 价格(通过 Uniswap V2 链上数据)
  • swap_tokens - 在 PancakeSwap/Uniswap V2 上模拟代币交换(使用 debug_traceCall)

技术栈

  • Rust + Tokio 异步运行时
  • Alloy - 以太坊 RPC 客户端库
  • 手动实现的 MCP 协议 - JSON-RPC 2.0
  • Tracing - 结构化日志
  • rust_decimal - 金融精度计算
  • reqwest - HTTP 客户端(用于 debug_traceCall)

项目结构

eth_mcp_trading/
├── Cargo.toml              # 项目依赖配置
├── README.md               # 本文件
├── .env.example            # 环境变量示例
├── src/
│   ├── main.rs             # 入口点,启动 MCP 服务器
│   ├── lib.rs              # 库导出
│   ├── error.rs            # 错误类型定义
│   ├── config/
│   │   ├── mod.rs          # 配置模块
│   │   └── settings.rs     # 配置结构体
│   ├── ethereum/
│   │   ├── mod.rs          # 以太坊模块导出
│   │   ├── client.rs       # RPC 客户端封装
│   │   ├── erc20.rs        # ERC20 标准接口
│   │   ├── uniswap.rs      # Uniswap V2 交互
│   │   └── swap.rs         # 交换模拟器
│   └── mcp/
│       ├── mod.rs          # MCP 模块导出
│       ├── protocol.rs     # JSON-RPC 2.0 协议
│       ├── server.rs       # MCP 服务器核心
│       └── tools/
│           ├── mod.rs      # 工具模块导出
│           ├── balance.rs  # get_balance 实现
│           ├── price.rs    # get_token_price 实现
│           └── swap.rs     # swap_tokens 实现
└── tests/
    ├── erc20_tests.rs      # ERC20 测试
    ├── price_tests.rs      # 价格查询测试
    └── swap_tests.rs       # 交换模拟测试

设置说明

1. 环境要求

  • Rust 1.70+
  • Cargo

2. 克隆项目

git clone <repository-url>
cd eth_mcp_trading

3. 配置环境变量

复制环境变量示例文件并配置:

cp .env.example .env

编辑 .env 文件:

# BSC 主网节点(推荐用于 swap_tokens)
ETH_RPC_URL=https://bsc-mainnet.nodereal.io/v1/YOUR_API_KEY

# 或以太坊主网(用于 get_balance 和 get_token_price)
# ETH_RPC_URL=https://mainnet.infura.io/v3/YOUR_INFURA_KEY

# 网络名称
ETH_NETWORK=bsc

# 日志级别
RUST_LOG=info

4. 编译项目

cargo build

5. 运行测试

cargo test

6. 运行服务器

cargo run

服务器将从标准输入读取 JSON-RPC 请求,并将响应输出到标准输出。

MCP 工具调用示例

1. 初始化连接

请求:

{
  "jsonrpc": "2.0",
  "method": "initialize",
  "params": {
    "protocol_version": "2024-11-05",
    "capabilities": {},
    "client_info": {
      "name": "test-client",
      "version": "1.0.0"
    }
  },
  "id": 1
}

响应:

{
  "jsonrpc": "2.0",
  "result": {
    "protocol_version": "2024-11-05",
    "capabilities": {
      "tools": {
        "list_changed": false
      }
    },
    "server_info": {
      "name": "eth_mcp_trading",
      "version": "0.1.0"
    }
  },
  "id": 1
}

2. 列出可用工具

请求:

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

响应:

{
  "jsonrpc": "2.0",
  "result": {
    "tools": [
      {
        "name": "get_balance",
        "description": "查询以太坊地址的 ETH 或 ERC20 代币余额...",
        "input_schema": {...}
      },
      {
        "name": "get_token_price",
        "description": "获取代币的当前价格(以 ETH 和 USD 计价)...",
        "input_schema": {...}
      },
      {
        "name": "swap_tokens",
        "description": "在 PancakeSwap (BSC) 上模拟代币交换...",
        "input_schema": {...}
      }
    ]
  },
  "id": 2
}

3. get_balance - 查询余额

查询 ETH 余额:

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

查询 ERC20 代币余额:

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

响应示例:

{
  "jsonrpc": "2.0",
  "result": {
    "content": [
      {
        "type": "text",
        "text": "ETH 余额查询成功\n\n地址: 0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045\n原始余额: 1234567890000000000 wei\n格式化余额: 1.23456789 ETH"
      }
    ],
    "is_error": false
  },
  "id": 3
}

4. get_token_price - 获取代币价格

通过符号查询:

{
  "jsonrpc": "2.0",
  "method": "tools/call",
  "params": {
    "name": "get_token_price",
    "arguments": {
      "token": "WETH"
    }
  },
  "id": 4
}

通过地址查询:

{
  "jsonrpc": "2.0",
  "method": "tools/call",
  "params": {
    "name": "get_token_price",
    "arguments": {
      "token": "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48"
    }
  },
  "id": 4
}

响应示例:

{
  "jsonrpc": "2.0",
  "result": {
    "content": [
      {
        "type": "text",
        "text": "代币价格查询成功\n\n代币地址: 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2\n代币符号: WETH\nETH 价格: 1.0000 ETH\nUSD 价格: $3500.00\nETH/USD 参考价格: $3500.00\n数据来源: Uniswap V2"
      }
    ],
    "is_error": false
  },
  "id": 4
}

5. swap_tokens - 模拟代币交换

请求:

{
  "jsonrpc": "2.0",
  "method": "tools/call",
  "params": {
    "name": "swap_tokens",
    "arguments": {
      "token_in": "WBNB",
      "token_out": "USDT",
      "amount": "1.0",
      "slippage": 0.5
    }
  },
  "id": 5
}

响应示例:

{
  "jsonrpc": "2.0",
  "result": {
    "content": [
      {
        "type": "text",
        "text": "交换模拟成功\n\n=== 交换详情 ===\n输入代币: WBNB (0xbb4cdb9cbd36b01bd1cbaebf2de08d9173bc095c)\n输出代币: USDT (0x55d398326f99059ff775485246999027b3197955)\n交换类型: Native -> Token\n\n=== 数量信息 ===\n输入数量: 1.000000000000000000 WBNB\n预估输出: 847.199046506193874112 USDT\n最小输出(含滑点): 842.975389997873156129 USDT\n\n=== 交易信息 ===\n交易路径: 0xbb4c... -> 0x55d3...\n预估 Gas: 104572 units\n价格影响: 0%\n\n注意: 这是模拟结果,实际交易可能因市场波动而有所不同。"
      }
    ],
    "is_error": false
  },
  "id": 5
}

设计决策

  1. 选择 Alloy 而非 ethers-rs:Alloy 是更新的以太坊库,提供更安全的类型系统和更好的 API 设计,是 Rust 以太坊生态的未来趋势。

  2. 手动实现 MCP 协议:由于 rmcp SDK 不够成熟,手动实现 JSON-RPC 2.0 协议提供了更好的可控性和灵活性,便于调试和扩展。

  3. 使用 debug_traceCall 进行交换模拟:debug_traceCall 可以获取真实的 gas 消耗和详细的执行跟踪,提供更准确的模拟结果。

  4. 链上价格数据:通过 Uniswap V2 池子的储备量计算价格,确保价格数据的实时性和准确性,而非依赖第三方 API。

  5. 使用 rust_decimal 处理金融计算:避免浮点数精度问题,确保代币余额和价格计算的准确性。

已知限制和假设

限制

  1. 网络支持:当前主要支持 BSC 主网(用于 swap_tokens)和以太坊主网(用于 get_balance 和 get_token_price)
  2. DEX 支持:仅支持 Uniswap V2 / PancakeSwap V2 协议
  3. 代币符号:预定义的代币符号有限(WETH, USDC, USDT, DAI, WBTC, WBNB, BUSD, CAKE)
  4. 交换模拟:
    • 对于 Native -> Token(如 WBNB -> USDT):模拟成功,返回准确的 gas 消耗
    • 对于 Token -> Native 或 Token -> Token:由于模拟地址没有对 Router 进行 ERC20 approve,debug_traceCall 会返回 execution reverted,但 预估输出金额仍然准确(通过 getAmountsOut 获取)
    • 这是预期行为,因为真实交易需要先调用代币的 approve 方法授权 Router 合约

假设

  1. 用户提供有效的以太坊/BSC 地址
  2. 代币地址对应有效的 ERC20 合约
  3. Uniswap/PancakeSwap 池子存在且有足够流动性
  4. RPC 端点稳定可用且支持 debug_traceCall 方法

支持的代币

以太坊主网

  • WETH (0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2)
  • USDC (0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48)
  • USDT (0xdAC17F958D2ee523a2206206994597C13D831ec7)
  • DAI (0x6B175474E89094C44Da98b954EescdeCB5BE3d7f)
  • WBTC (0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599)

BSC 主网

  • WBNB (0xbb4CdB9CBd36B01bD1cBaEBF2De08d9173bc095c)
  • USDT (0x55d398326f99059fF775485246999027B3197955)
  • BUSD (0xe9e7CEA3DedcA5984780Bafc599bD69ADd087D56)
  • USDC (0x8AC76a51cc950d9822D68b83fE1Ad97B32Cd580d)
  • CAKE (0x0E09FaBB73Bd3Ade0a17ECC321fD13a19e81cE82)

测试

运行所有测试:

cargo test

运行特定测试并查看输出:

cargo test test_swap_wbnb_to_usdt -- --nocapture