使用说明
Ethereum MCP Server
一个基于 MCP (Model Context Protocol) 协议的以太坊钱包管理和智能合约交互服务器,使用 Rust 开发,提供完整的钱包管理、ERC20 代币操作和 Uniswap V2 交互功能。
📋 目录
✨ 功能特性
钱包管理
- ✅ 生成新钱包(随机私钥)
- ✅ 从私钥导入钱包
- ✅ 从助记词导入钱包(支持自定义派生路径)
- ✅ 钱包信息存储和检索
- ✅ 消息签名功能
- ✅ 多钱包管理
ERC20 代币操作
- ✅ 部署 ERC20 代币合约
- ✅ 转账 ERC20 代币
- ✅ 查询 ERC20 代币余额
Uniswap V2 交互
- ✅ 查询交易对信息(储备量、价格)
- ✅ 添加流动性(支持滑点设置)
- ✅ 代币兑换(支持滑点设置)
- ✅ 自动计算最优兑换路径
🚀 快速开始
环境要求
- Rust 1.70+
- 以太坊节点(如 Anvil、Hardhat 或远程 RPC)
- Foundry(用于运行 Anvil)
安装
# 克隆仓库
git clone <repository-url>
cd mcp-demo
# 编译项目
cargo build --release
运行
1. 启动本地测试节点(Anvil)
# 使用 Foundry 的 Anvil 启动本地测试网络
anvil
# 或者 fork 主网(测试 Uniswap 功能必需)
anvil --fork-url https://eth-mainnet.alchemyapi.io/v2/YOUR_API_KEY
# 或者使用提供的脚本
./scripts/start_anvil_fork_simple.sh
注意: Uniswap V2 功能需要 fork 主网环境,因为 Uniswap 合约只存在于主网。
2. 启动 MCP 服务器
# 基础运行(仅钱包管理功能)
cargo run
# 启用 ERC20 和 Uniswap 功能(需要提供私钥)
cargo run -- --private-key "0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80"
# 自定义端口和 RPC
cargo run -- \
--mcp-port 8081 \
--rpc-url "http://127.0.0.1:8545" \
--private-key "YOUR_PRIVATE_KEY" \
--log-level info
3. 测试 MCP 服务器
# 使用提供的测试脚本
./scripts/test_wallet.sh
./scripts/test_uniswapv2_mcp.sh
# 或使用 Python 测试客户端(更可靠)
python3 scripts/mcp_test_client.py
# 运行 Rust 测试示例
cargo run --example test_uniswap_v2
# 运行完整测试套件
./scripts/test_mcp_all.sh
🔧 MCP 工具列表
MCP 服务器提供以下 13 个工具,可通过 MCP 协议调用:
钱包管理工具
1. create_wallet
创建新的以太坊钱包。
参数:
{
"wallet_type": "generate | private_key | mnemonic",
"name": "钱包名称(可选)",
"private_key": "私钥(private_key 类型时必需)",
"mnemonic": "助记词(mnemonic 类型时必需)",
"passphrase": "助记词密码(可选)",
"derivation_path": "派生路径(可选)",
"index": 0 // 钱包索引(可选,默认0)
}
返回:
{
"address": "0x...",
"wallet_type": "PrivateKey | Mnemonic",
"name": "钱包名称",
"created_at": "2024-01-01T00:00:00Z"
}
2. list_wallets
列出所有已保存的钱包。
参数: 无
返回:
[
{
"address": "0x...",
"wallet_type": "PrivateKey",
"name": "wallet1",
"created_at": "2024-01-01T00:00:00Z"
}
]
3. get_wallet
获取指定钱包的详细信息。
参数:
{
"address": "0x..."
}
返回:
{
"address": "0x...",
"wallet_type": "PrivateKey",
"name": "wallet1",
"created_at": "2024-01-01T00:00:00Z"
}
4. delete_wallet
删除指定的钱包。
参数:
{
"address": "0x..."
}
返回:
"Wallet deleted successfully"
5. sign_message
使用钱包签名消息。
参数:
{
"address": "0x...",
"message": "要签名的消息"
}
返回:
{
"signature": "0x...",
"address": "0x...",
"message": "要签名的消息"
}
ERC20 代币工具
6. deploy_erc20
部署新的 ERC20 代币合约。
参数:
{
"name": "代币名称",
"symbol": "代币符号",
"initial_supply": "1000000000000000000000" // 支持大整数(U256)
}
返回:
{
"contract_address": "0x...",
"name": "代币名称",
"symbol": "代币符号",
"initial_supply": "1000000000000000000000"
}
7. transfer_erc20
转账 ERC20 代币。
参数:
{
"contract_address": "0x...",
"to": "0x...",
"amount": "1000000000000000000" // 原始值,包含精度
}
返回:
{
"transaction_hash": "0x...",
"contract_address": "0x...",
"to": "0x...",
"amount": "1000000000000000000"
}
8. balance_erc20
查询 ERC20 代币余额。
参数:
{
"contract_address": "0x...",
"address": "0x..."
}
返回:
{
"balance": "1000000000000000000000",
"contract_address": "0x...",
"address": "0x..."
}
Uniswap V2 工具
9. get_uniswap_pair_info
获取 Uniswap V2 交易对的储备量和价格信息。
参数:
{
"token_a": "0x...",
"token_b": "0x...",
"decimals_a": 18, // 可选,默认18
"decimals_b": 18 // 可选,默认18
}
返回:
{
"pair_address": "0x...",
"token_a": "0x...",
"token_b": "0x...",
"reserves": {
"token_a": {
"raw": "1000000000000000000000",
"readable": "1000",
"decimals": 18
},
"token_b": {
"raw": "2000000000000000000000",
"readable": "2000",
"decimals": 18
}
},
"prices": {
"token_a_to_token_b": "2.0000",
"token_b_to_token_a": "0.5000"
}
}
10. uniswap_add_liquidity
向 Uniswap V2 交易对添加流动性。
参数:
{
"token_a": "0x...",
"token_b": "0x...",
"amount_a": "10000000000000000000", // 原始值,包含精度
"amount_b": "20000000000000000000", // 原始值,包含精度
"slippage_percent": 1 // 可选,默认1%
}
返回:
{
"transaction_hash": "0x...",
"token_a": "0x...",
"token_b": "0x...",
"amount_a": "10000000000000000000",
"amount_b": "20000000000000000000",
"slippage_percent": 1,
"status": "success",
"pair_info": {
"pair_address": "0x...",
"reserve_a": "10000000000000000000",
"reserve_b": "20000000000000000000"
}
}
11. uniswap_swap_tokens
在 Uniswap V2 交易对中兑换代币。
参数:
{
"token_in": "0x...",
"token_out": "0x...",
"amount_in": "1000000000000000000", // 原始值,包含精度
"slippage_percent": 5 // 可选,默认5%
}
返回:
{
"transaction_hash": "0x...",
"token_in": "0x...",
"token_out": "0x...",
"amount_in": "1000000000000000000",
"slippage_percent": 5,
"status": "success",
"pair_info": {
"pair_address": "0x...",
"reserve_in": "11000000000000000000",
"reserve_out": "18187000000000000000"
}
}
余额和价格查询工具
12. get_balance
查询 ETH 或 ERC20 代币余额。
参数:
{
"address": "0x...", // 钱包地址
"token_address": "0x..." // 可选,代币合约地址(不提供则查询 ETH 余额)
}
返回(查询 ETH):
{
"balance": "1000000000000000000",
"balance_formatted": "1",
"address": "0x...",
"decimals": 18,
"symbol": "ETH"
}
返回(查询 ERC20):
{
"balance": "1000000000000000000000",
"balance_formatted": "1000",
"address": "0x...",
"token_address": "0x...",
"decimals": 18,
"symbol": "ERC20"
}
13. get_token_price
从 Uniswap V2 获取代币价格。
参数:
{
"token_address": "0x...", // 代币地址
"quote_token": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", // 可选,报价代币地址(默认 WETH)
"decimals_token": 18, // 可选,代币精度(默认 18)
"decimals_quote": 18 // 可选,报价代币精度(默认 18)
}
返回:
{
"token_address": "0x...",
"quote_token": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2",
"price": "2000000000000000000",
"price_formatted": "2",
"pair_address": "0x...",
"liquidity": {
"reserve_token": "1000000000000000000000",
"reserve_quote": "2000000000000000000000",
"reserve_token_formatted": "1000",
"reserve_quote_formatted": "2000"
}
}
📝 使用示例
示例 1: 创建钱包并签名消息
# 1. 创建一个新钱包
echo '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"create_wallet","arguments":{"wallet_type":"generate","name":"my_wallet"}}}' | nc localhost 8081
# 2. 使用钱包签名消息
echo '{"jsonrpc":"2.0","id":2,"method":"tools/call","params":{"name":"sign_message","arguments":{"address":"0x...","message":"Hello, Ethereum!"}}}' | nc localhost 8081
示例 2: 部署 ERC20 并转账
# 1. 部署 ERC20 代币(1000 tokens,18位小数)
echo '{"jsonrpc":"2.0","id":3,"method":"tools/call","params":{"name":"deploy_erc20","arguments":{"name":"MyToken","symbol":"MTK","initial_supply":"1000000000000000000000"}}}' | nc localhost 8081
# 2. 查询余额
echo '{"jsonrpc":"2.0","id":4,"method":"tools/call","params":{"name":"balance_erc20","arguments":{"contract_address":"0x...","address":"0x..."}}}' | nc localhost 8081
# 3. 转账代币(1 token)
echo '{"jsonrpc":"2.0","id":5,"method":"tools/call","params":{"name":"transfer_erc20","arguments":{"contract_address":"0x...","to":"0x...","amount":"1000000000000000000"}}}' | nc localhost 8081
示例 3: Uniswap V2 完整流程
# 1. 查询交易对信息
echo '{"jsonrpc":"2.0","id":6,"method":"tools/call","params":{"name":"get_uniswap_pair_info","arguments":{"token_a":"0x...","token_b":"0x..."}}}' | nc localhost 8081
# 2. 添加流动性(10 TokenA + 20 TokenB)
echo '{"jsonrpc":"2.0","id":7,"method":"tools/call","params":{"name":"uniswap_add_liquidity","arguments":{"token_a":"0x...","token_b":"0x...","amount_a":"10000000000000000000","amount_b":"20000000000000000000","slippage_percent":1}}}' | nc localhost 8081
# 3. 兑换代币(1 TokenA -> TokenB)
echo '{"jsonrpc":"2.0","id":8,"method":"tools/call","params":{"name":"uniswap_swap_tokens","arguments":{"token_in":"0x...","token_out":"0x...","amount_in":"1000000000000000000","slippage_percent":5}}}' | nc localhost 8081
使用 Rust 测试示例
项目包含完整的 Rust 测试示例,演示了完整的 Uniswap V2 交互流程:
# 测试 Uniswap V2 交互(部署代币、创建池子、添加流动性、兑换)
cargo run --example test_uniswap_v2
# 或使用测试脚本
./scripts/test_uniswap_rust.sh
使用 Python 测试客户端
Python 客户端提供了更可靠的 MCP 协议通信:
# 运行 Python 测试客户端
python3 scripts/mcp_test_client.py
示例 4: 查询余额和价格
# 1. 查询 ETH 余额
echo '{"jsonrpc":"2.0","id":9,"method":"tools/call","params":{"name":"get_balance","arguments":{"address":"0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266"}}}' | nc localhost 8081
# 2. 查询 ERC20 代币余额
echo '{"jsonrpc":"2.0","id":10,"method":"tools/call","params":{"name":"get_balance","arguments":{"address":"0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266","token_address":"0x..."}}}' | nc localhost 8081
# 3. 查询代币价格(相对于 WETH)
echo '{"jsonrpc":"2.0","id":11,"method":"tools/call","params":{"name":"get_token_price","arguments":{"token_address":"0x..."}}}' | nc localhost 8081
# 4. 查询代币价格(自定义报价代币)
echo '{"jsonrpc":"2.0","id":12,"method":"tools/call","params":{"name":"get_token_price","arguments":{"token_address":"0x...","quote_token":"0x..."}}}' | nc localhost 8081
⚙️ 配置说明
命令行参数
--wallet-path <PATH> 钱包存储路径(默认: ./wallets)
--mcp-port <PORT> MCP 服务器端口(默认: 8081)
--log-level <LEVEL> 日志级别(默认: info)
--rpc-url <URL> 以太坊 RPC URL(默认: http://127.0.0.1:8545)
--private-key <KEY> 私钥(用于 ERC20 和 Uniswap 操作)
--test-deploy 测试模式:直接部署 ERC20 合约
环境变量
# 设置 RPC URL
export RPC_URL="http://127.0.0.1:8545"
# 设置私钥
export PRIVATE_KEY="0x..."
# 设置日志级别
export RUST_LOG="ethereum_mcp_server=debug"
🛠️ 开发指南
项目结构
mcp-demo/
├── src/
│ ├── main.rs # 主程序入口
│ ├── lib.rs # 库入口
│ ├── basic_wallet.rs # 钱包管理模块
│ ├── mcp_server.rs # MCP 服务器实现(11个工具)
│ ├── erc20.rs # ERC20 代币交互
│ ├── uniswapv2.rs # Uniswap V2 交互
│ └── wallets/ # Foundry 钱包集成
├── examples/
│ └── test_uniswap_v2.rs # Uniswap V2 测试示例
├── scripts/
│ ├── start_anvil_fork_simple.sh # 启动 Anvil fork 节点
│ ├── test_wallet.sh # 钱包测试脚本
│ ├── test_uniswapv2_mcp.sh # Uniswap MCP 测试(Shell)
│ ├── mcp_test_client.py # MCP 测试客户端(Python)
│ ├── simple_deploy_test.sh # 简单部署测试
│ └── test_mcp_all.sh # 完整测试套件
├── abis/ # 智能合约 ABI 文件
│ ├── SimpleERC20.json
│ ├── UniswapV2Factory.json
│ └── UniswapV2Router02.json
├── wallets/ # 钱包存储目录
├── README.md # 项目文档
└── TESTING.md # 测试指南
添加新的 MCP 工具
- 在
src/mcp_server.rs的get_tools()方法中添加工具定义 - 在
execute_tool()方法中实现工具逻辑 - 更新 README.md 文档
- 添加测试用例
示例:
// 1. 在 get_tools() 中添加工具定义
McpTool {
name: "your_tool_name".to_string(),
description: "工具描述".to_string(),
input_schema: serde_json::json!({
"type": "object",
"properties": {
"param": {
"type": "string",
"description": "参数描述"
}
},
"required": ["param"]
}),
}
// 2. 在 execute_tool() 中添加处理逻辑
"your_tool_name" => {
let param = arguments.get("param")
.and_then(|v| v.as_str())
.ok_or("Missing param")?;
// 实现工具逻辑
let result = your_function(param).await?;
Ok(serde_json::to_string_pretty(&result)?)
}
运行测试
# 运行所有单元测试
cargo test
# 运行特定测试
cargo test test_create_wallet_tool
# 运行集成测试
cargo run --example test_uniswap_v2
# 运行完整测试套件
./scripts/test_mcp_all.sh
构建发布版本
# 构建优化版本
cargo build --release
# 运行发布版本
./target/release/ethereum-mcp-server --help
🧪 测试指南
详细的测试指南请参考 TESTING.md 文档。
快速测试
# 1. 启动 Anvil fork 节点
./scripts/start_anvil_fork_simple.sh
# 2. 启动 MCP 服务器
cargo run -- --private-key "0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80"
# 3. 运行测试
./scripts/test_mcp_all.sh
测试环境说明
- 本地 Anvil 节点: 适合测试钱包管理和 ERC20 功能
- Anvil Fork 主网: 必需用于测试 Uniswap V2 功能(因为 Uniswap 合约只存在于主网)
📚 技术栈
- Rust 1.70+ - 系统编程语言
- Tokio - 异步运行时
- Alloy - 以太坊库(合约交互、签名等)
- Serde - 序列化/反序列化
- Foundry - 以太坊开发工具链
- MCP 协议 - JSON-RPC 2.0 based protocol
🎯 设计决策
为什么选择 Alloy 而不是 ethers-rs
- 现代化架构: Alloy 是 Paradigm 团队开发的新一代以太坊库,采用更现代的设计理念
- 更好的类型系统: 提供更严格的类型检查,减少运行时错误
- 性能优化: 在编译时进行更多优化,运行时性能更好
- 异步优先: 从设计之初就考虑异步场景,与 Tokio 集成更自然
- 社区支持: 得到以太坊社区的广泛支持,是 ethers-rs 的继任者
大整数(U256)处理
- 精度保证: 使用 Alloy 的
U256类型处理所有金额,避免浮点数精度损失 - 字符串传递: MCP 工具的输入输出使用字符串格式传递大整数,避免 JSON Number 类型的限制
- 计算安全: 使用
saturating_mul、saturating_add等方法防止溢出 - 格式化输出: 提供
balance_formatted等人类可读字段,便于用户理解
代币价格计算方法
基于 Uniswap V2 的恒定乘积做市商(CPMM)模型:
- 价格公式:
price = reserve_quote / reserve_token - 精度处理: 为保持精度,先乘以 10^18 再除法计算
- 流动性信息: 返回交易对储备量,便于用户评估价格可靠性
- 限制: 仅支持直接交易对,不支持多跳路径的价格聚合
交易执行策略
- 实际交易: 所有交易操作直接在链上执行,确保结果真实可靠
- 滑点保护: 支持用户自定义滑点容忍度(默认 1-5%)
- 授权管理: 自动处理 ERC20 代币授权(approve),简化用户操作
- 确认等待: 交易发送后等待确认,并返回最新的链上状态
- 错误重试: 网络请求失败时自动重试(最多 3 次),提高稳定性
MCP 协议实现
- JSON-RPC 2.0: 遵循标准协议规范,确保兼容性
- 工具化设计: 每个功能封装为独立的 MCP 工具,便于 AI 理解和调用
- 详细文档: 每个工具提供完整的参数和返回值说明
- 错误处理: 统一的错误格式,便于调试和问题追踪
🔒 安全注意事项
-
私钥安全:
- ⚠️ 生产环境中永远不要在命令行或环境变量中明文传递私钥
- 建议使用硬件钱包或 KMS(Key Management Service)
- 钱包文件使用 JSON 加密存储
- 测试私钥仅用于本地开发,切勿在主网使用
-
RPC 安全:
- 不要将私钥发送给不信任的 RPC 节点
- 使用 HTTPS 连接远程 RPC 节点
- 建议使用 Infura、Alchemy 等知名 RPC 提供商
-
网络安全:
- MCP 服务器默认绑定到 0.0.0.0,建议在生产环境使用防火墙限制访问
- 考虑添加身份验证和授权机制
- 使用 TLS/SSL 加密网络通信
-
金额处理:
- 所有金额使用 U256 类型,避免溢出
- 转账前检查余额和授权额度
- 使用合理的滑点设置(1-5%)防止价格冲击
📊 性能指标
基于本地测试环境(Anvil fork 主网):
- 钱包创建: < 10ms
- ERC20 部署: ~2s(包含交易确认)
- ERC20 转账: ~1s
- 添加流动性: ~3s(包含两次 approve + addLiquidity)
- 代币兑换: ~2s(包含 approve + swap)
- 查询余额: < 100ms
- 查询交易对信息: < 500ms
🐛 已知问题和限制
-
Uniswap V2 依赖主网合约
- Uniswap Factory 和 Router 只存在于主网
- 测试必须使用
anvil --fork-urlfork 主网 - 无法在纯本地环境测试 Uniswap 功能
-
网络稳定性
- Fork 模式下与主网 RPC 通信可能不稳定
- 已添加超时和重试机制
- 建议使用可靠的 RPC 提供商(Infura、Alchemy)
-
大整数支持
- 所有金额必须使用字符串格式传递
- 支持最大值: U256::MAX (2^256 - 1)
- JavaScript Number 类型不适合大整数,需使用 BigInt
📄 许可证
MIT License
🤝 贡献
欢迎提交 Issue 和 Pull Request!
贡献指南
- Fork 本仓库
- 创建功能分支 (
git checkout -b feature/AmazingFeature) - 提交更改 (
git commit -m 'Add some AmazingFeature') - 推送到分支 (
git push origin feature/AmazingFeature) - 开启 Pull Request
📧 联系方式
如有问题或建议,请通过以下方式联系:
- GitHub Issues: /issues
- Email: your-email@example.com
注意: 本项目仅用于开发和测试目的。在生产环境使用前,请确保进行充分的安全审计和测试。
测试私钥警告: README 中提到的私钥(0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80)是 Anvil 的默认测试私钥,仅用于本地测试,切勿在主网使用!