使用Claude AI创建一个EVM MCP服务器
概述
模型上下文协议 (MCP) 使得大型语言模型 (LLM) 能够使用标准化的基于消息的协议与外部工具(如 HTTP API、文件,甚至区块链)进行交互。可以将其视为 Claude 或 Cursor 等 agent 可以接入的“函数调用”接口,从而将脚本或服务转变为 AI 原生扩展。
在本指南中,你将学习如何构建和部署一个 MCP 服务器,该服务器使 LLM agent 能够跨多个 EVM 兼容网络访问区块链数据。这种强大的集成使 Claude 等 AI 模型能够直接与区块链数据交互,从而为 Web3 自动化和分析开辟新的可能性。
你将做什么
- 构建一个与多个 EVM 链交互的 MCP 服务器
- 使 LLM 能够使用 Viem 和 QuickNode 的 多链 RPC 获取链上数据
- 注册工具、提示和资源以指导 LLM 的行为
- 在 Claude Desktop 中运行服务器并使用自然语言请求进行测试
你需要的
- Node.js v20 或更高版本
- 一个免费的 QuickNode 账户
- Claude Desktop(或兼容的 agent 运行器)
- 以太坊 区块链经验
什么是 MCP?
模型上下文协议(MCP)是一个开放标准,允许 AI agent 与外部工具和数据源进行交互。它在语言模型和工具之间创建了一个结构化的通信通道。
如果没有 MCP,AI 模型将仅限于:
- 它们接受过训练的信息
- 它们当前正在进行的对话
- 无法检查外部数据源
- 无法在现实世界中执行操作
MCP 通过创建 AI 访问外部工具和数据的标准化方式来弥补这一差距。
来源(针对我们正在构建的服务器进行了修改):Model Context Protocol
关键概念
MCP 服务器如何工作
MCP 服务器负责处理来自客户端的传入请求并返回适当的数据。它们使用 MCP 协议与 LLM 通信,并且可以使用任何编程语言或框架来实现。
每个服务器都通过标准通道(stdio、HTTP 或 sockets)与 LLM 通信,并返回结构良好的输出。这允许 LLM 理解请求的上下文和意图,并做出适当的响应。MCP 协议被设计为可扩展的,允许开发人员根据需要添加新的工具、资源和提示。
工具:AI 可以调用以执行特定操作的函数。 它们可以是简单的 API 调用,也可以是复杂的任务。
- 示例:
eth_getBalance
用于检查钱包的余额 - 示例:
weather_forecast
用于获取当前天气数据
资源:AI 可以引用的静态知识。 这些会影响模型的依据和假设——例如,添加 gas-reference
资源可以帮助 Claude 了解特定链的 gas 价格是低、中等还是高,而无需调用任何工具。
- 示例:有关特定链上 gas 价格的详细信息
- 示例:有关 API 参数的文档
提示:指导 AI 的预先编写的指令。 它们就像可重复使用的思考模板。 每个提示定义了 LLM 应如何使用工具和结构化推理来处理任务(例如,“分析此钱包”)。
- 示例:用于分析钱包活动的模板
- 示例:用于执行复杂任务的逐步指南
当你将 MCP 服务器连接到像 Claude 这样的 AI 时:
- AI 发现有哪些工具、资源和提示可用
- 在需要时,AI 可以使用特定参数调用这些工具
- 服务器处理这些请求并返回结构化数据
- AI 解释结果并将其纳入其响应中
以下是相同用户问题在使用和不使用 MCP 服务器的情况下的表现:
简单示例:检查钱包余额
没有 MCP | 有 MCP | |
---|---|---|
用户 | “钱包 0x123... 的余额是多少?” | “钱包 0x123... 的余额是多少?” |
AI 进程 | 无法访问外部数据 | [通过 MCP 调用 eth_getBalance 工具] |
AI 响应 | “我无法访问当前的区块链数据,因此无法检查该钱包的余额。” | “该钱包目前在以太坊上持有 0.45 ETH。” |
结果 | 无法实现用户请求 | 提供实时区块链数据 |
MCP 服务器中的请求生命周期
以下是 agent 通过提示发出请求时发生的情况:
- 解析请求以确定操作和参数
- 验证参数
- 选择适当的链客户端
- 通过 Viem 到 QuickNode 执行请求
- 格式化响应并将其返回给 agent
我们了解了 MCP 服务器的工作原理。 现在,让我们构建一个!
项目结构
项目结构如下:
evm-mcp-server/
├── index.ts # 入口点,设置 MCP 服务器
├── chains.ts # 链配置 + QuickNode 端点映射
├── clients.ts # Viem public client 创建器
├── package.json # 依赖项和脚本
├── prompts.ts # LLM 提示定义
├── resources.ts # 外部参考(gas 价格,浏览器)
├── tools.ts # MCP 工具:getCode,getBalance,gasPrice
└── tsconfig.json # TypeScript 配置
首先,让我们看一下每个文件及其用途。 但是,如果你想直接跳转到代码,请随时跳到 构建你的 EVM MCP 服务器 部分。
项目代码
本指南的所有代码都可以在 QuickNode GitHub 存储库 中找到。 我们在这里通过提供代码的高级概述来解释事物的工作原理,但是我们将在 构建你的 MCP 服务器 部分中使用 GitHub 存储库。
入口点:index.ts
此文件是初始化并启动 MCP 服务器的入口点。 它注册工具、提示和资源:
index.ts 文件的一部分
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js'
import { registerTools } from './tools'
import { registerPrompts } from './prompts'
import { registerResources } from './resources'
async function main() {
try {
// 创建 MCP 服务器
const server = new McpServer({
name: 'EVM MCP Server',
version: '0.1.0',
description: 'A server for LLM agent to access EVM blockchain data', // 用于LLM agent 访问 EVM 区块链数据的服务器
})
// 注册所有工具、提示和资源
registerTools(server)
registerPrompts(server)
registerResources(server)
// 启动 MCP 服务器
const transport = new StdioServerTransport()
await server.connect(transport)
} catch (error) {
console.error(' Failed to start server:', error) // 启动服务器失败
process.exit(1)
}
}
// 运行 main 函数
main().catch(error => {
console.error(' Unhandled error:', error) // 未处理的错误
process.exit(1)
})
链配置:chains.ts
此文件定义区块链配置,并基于 QuickNode 的多链格式构建 RPC URL。
chains.ts 文件的一部分
// 从环境变量获取端点名称和Token ID
const QN_ENDPOINT_NAME = validateEnvVar('QN_ENDPOINT_NAME')
const QN_TOKEN_ID = validateEnvVar('QN_TOKEN_ID')
// 用于基于网络名称构建 QuickNode RPC URL 的函数
const buildRpcUrl = (networkName: string): string => {
// 以太坊主网的特殊情况
if (networkName === 'mainnet') {
return `https://${QN_ENDPOINT_NAME}.quiknode.pro/${QN_TOKEN_ID}/`
}
// Avalanche 主网的特殊情况
if (networkName === 'avalanche-mainnet') {
return `https://${QN_ENDPOINT_NAME}.${networkName}.quiknode.pro/${QN_TOKEN_ID}/ext/bc/C/rpc`
}
// 对于其他网络,在 URL 中包含网络名称
return `https://${QN_ENDPOINT_NAME}.${networkName}.quiknode.pro/${QN_TOKEN_ID}/`
}
export const CHAINS = {
ethereum: {
network: 'mainnet',
rpc: buildRpcUrl('mainnet'),
name: 'Ethereum',
symbol: 'ETH',
decimals: 18,
},
// 其他链...
}
// 代码的其余部分...
客户端创建器:clients.ts
此文件使用 Viem 库中的 createPublicClient
函数为每个链创建客户端,以使用 QuickNode RPC 端点建立与链的连接。
clients.ts 文件的一部分
import { createPublicClient, http } from 'viem'
import { ChainId, getChain } from './chains'
// viem 客户端的缓存,以避免创建重复的客户端
const clientCache = new Map<ChainId, ReturnType<typeof createPublicClient>>()
export const getPublicClient = (chainId: ChainId) => {
// 如果存在则从缓存返回
if (clientCache.has(chainId)) {
return clientCache.get(chainId)!
}
// 获取链配置
const chain = getChain(chainId)
// 创建新的 public client
const client = createPublicClient({
transport: http(chain.rpc),
})
// 缓存以供将来使用
clientCache.set(chainId, client)
return client
}
提示:prompts.ts
此文件定义 LLM agent 要使用的提示。 提示对象包含 description
和 messages
属性,MCP 服务器使用这些属性来生成提示。 提示包括用于调用工具、解释结果和格式化响应的说明。
prompts.ts 文件的一部分
// 注册 check-wallet 提示
server.prompt(
'check-wallet',
checkWalletSchema.shape,
({ address, chain }: { address: string; chain: string }) => ({
description: "Guide for analyzing a wallet's balance and context", // 用于分析钱包余额和上下文的指南
messages: [
{
role: 'user',
content: {
type: 'text',
text: `Please analyze this Ethereum wallet address: ${address} on ${chain} chain.
You need to analyze a wallet address on an EVM blockchain.
First, use the eth_getBalance tool to check the wallet's balance.
Next, use the eth_getCode tool to verify if it's a regular wallet or a contract.
Once you have this information, provide a summary of:
1. The wallet's address
2. The chain it's on
3. Its balance in the native token
4. Whether it's a regular wallet (EOA) or a contract
5. Any relevant observations about the balance (e.g., if it's empty, has significant funds, etc.)
Aim to be concise but informative in your analysis.`, // 请分析以太坊钱包地址:${address} 在 ${chain} 链上。 你需要在 EVM 区块链上分析钱包地址。 首先,使用 eth_getBalance 工具检查钱包的余额。 接下来,使用 eth_getCode 工具验证它是否是常规钱包或合约。 获得此信息后,请提供以下摘要: 1. 钱包的地址 2. 它所在的链 3. 其在本机Token中的余额 4. 它是常规钱包 (EOA) 还是合约 5. 关于余额的任何相关观察(例如,如果它是空的、有大量资金等) 旨在在你的分析中保持简洁但内容丰富。
},
},
],
})
)
// check-wallet 提示的 Schema
const checkWalletSchema = z.object({
address: z.string().refine(isAddress, {
message: 'Invalid Ethereum address format', // 以太坊地址格式无效
}),
chain: z
.string()
.refine((val): val is ChainId => Object.keys(CHAINS).includes(val), {
message:
'Unsupported chain. Use one of: ethereum, base, arbitrum, avalanche, bsc', // 不支持的链。 请使用以下链之一:ethereum、base、arbitrum、avalanche、bsc
}),
})
// 代码的其余部分...
资源:resources.ts
此文件定义可由 LLM agent 使用的外部引用。 在这种情况下,我们让他们可以访问每个链的 gas 价格水平、每个链的区块浏览器链接以及有关链本身的一些详细信息。
resources.ts 文件的一部分
export const registerResources = (server: any) => {
// 注册 gas 参考资源
server.resource(
'gas-reference',
'evm://docs/gas-reference',
async (uri: URL) => {
return {
contents: [
{
uri: uri.href,
text: JSON.stringify(gasReferencePoints, null, 2),
},
],
}
}
)
// 其他资源...
}
// 每个链的 Gas 参考点
const gasReferencePoints = {
ethereum: {
low: 20,
average: 40,
high: 100,
veryHigh: 200,
},
base: {
low: 0.05,
average: 0.1,
high: 0.3,
veryHigh: 0.5,
},
// 其他链...
}
// 代码的其余部分...
工具:tools.ts
此文件定义服务器可以调用的工具。 在这种情况下,我们使用 eth_getBalance
、eth_getCode
和 eth_gasPrice
工具。 每个工具都是一个异步函数,通过 Viem 查询区块链,并返回 LLM 使用的结构化数据。
tools.ts 文件的一部分
// 向 MCP 服务器注册工具
export const registerTools = (server: any) => {
// 注册 eth_getBalance 工具
server.tool(
'eth_getBalance',
balanceSchema.shape,
async (args: z.infer<typeof balanceSchema>) => {
try {
const result = await getBalance(args)
return {
content: [
{
type: 'text',
text: JSON.stringify(result, null, 2),
},
],
}
} catch (error) {
// 处理错误
}
}
)
// 其他工具...
}
// eth_getBalance 工具的 Schema
const balanceSchema = z.object({
address: z.string().refine(isAddress, {
message: 'Invalid Ethereum address format', // 以太坊地址格式无效
}),
chain: z
.string()
.refine((val): val is ChainId => Object.keys(CHAINS).includes(val), {
message:
'Unsupported chain. Use one of: ethereum, base, arbitrum, avalanche, bsc', // 不支持的链。 请使用以下链之一:ethereum、base、arbitrum、avalanche、bsc
}),
})
// 其他工具 Schema...
/**
* 获取指定链上以太坊地址的余额
*/
export const getBalance = async (params: z.infer<typeof balanceSchema>) => {
const { address, chain } = balanceSchema.parse(params)
try {
const client = getPublicClient(chain as ChainId)
const chainInfo = getChain(chain as ChainId)
// 获取 wei 中的余额
const balanceWei = await client.getBalance({ address })
// 将余额格式化为 ETH/本机Token
const balanceFormatted = formatEther(balanceWei)
return {
address,
chain: chainInfo.name,
balanceWei: balanceWei.toString(),
balanceFormatted: `${balanceFormatted} ${chainInfo.symbol}`,
symbol: chainInfo.symbol,
decimals: chainInfo.decimals,
}
} catch (error) {
return {
error: `Failed to get balance: ${(error as Error).message}`, // 无法获取余额
}
}
}
// 代码的其余部分...
构建你的 EVM MCP 服务器
我们了解了每个文件如何在 MCP 服务器中发挥作用。 现在,让我们构建并运行我们的服务器。
获取多链端点
我们正在构建的 MCP 服务器将支持多个 EVM 链(以太坊、Base、Arbitrum、Avalanche 和 BSC)。 通过利用 QuickNode 的多链格式,我们可以使用单个端点轻松连接到这些链。 如果你没有 QuickNode 帐户,可以在 此处 免费获取一个。
- 登录到你的 QuickNode 帐户。
- 转到“端点”选项卡。
- 单击“创建端点”。
- 选择以太坊主网或其中一个其他 EVM 链。
- 创建端点后,激活多链格式。
- 记下你的端点 URL,它看起来像
https://{endpoint_name}.quiknode.pro/{token_id}/
或https://{endpoint_name}.{chain_name}.quiknode.pro/{token_id}
。 - 从 URL 中提取端点名称和Token ID。
由于有了多链格式,我们现在可以使用单个端点连接到任何 EVM 链。 端点名称和Token ID 用于标识链及其配置。
安装说明
现在我们有了端点,让我们设置我们的 MCP 服务器。
步骤 1:克隆存储库
git clone https://github.com/quiknode-labs/qn-guide-examples.git
cd qn-guide-examples/AI/evm-mcp-server
步骤 2:安装依赖项
npm install
这将安装项目所需的依赖项:
- @modelcontextprotocol/sdk:用于构建 MCP 服务器的 TypeScript SDK。
- viem:用于与 EVM 区块链交互的 TypeScript 库。
- zod:用于定义 Schema 和验证数据的 TypeScript 库。
- typescript:TypeScript 编译器。
- @types/node:Node.js 的 TypeScript 类型定义。
步骤 3:构建项目
npm run build
这将生成包含已编译的 index.js
文件的 build/
目录,该文件用作服务器的入口点。
步骤 4:配置 Claude Desktop
服务器使用在 Claude Desktop 的配置文件 (claude_desktop_config.json
) 中定义的环境变量来连接到 QuickNode 并运行服务器。
- 打开 Claude Desktop,导航到 Claude > Settings > Developer
- 编辑
claude_desktop_config.json
以包含以下内容(如果存在其他配置,请在mcpServers
下添加):
{
"mcpServers": {
"evm": {
"command": "node",
"args": ["/absolute-path-to/build/index.js"],
"env": {
"QN_ENDPOINT_NAME": "your-quicknode-endpoint-name",
"QN_TOKEN_ID": "your-quicknode-token-id"
}
}
}
}
- 将 your-quicknode-endpoint-name 替换为你的 QuickNode 端点名称。
- 将 your-quicknode-token-id 替换为你的 QuickNode Token ID。
- 将 /absolute-path-to 替换为项目目录的绝对路径(例如,/Users/username/qn-guide-examples/AI/evm-mcp-server)。
保存文件并重新启动 Claude Desktop。 你的 MCP 服务器的工具、资源和提示现在应该在 Claude 中可用。
测试你的 MCP 服务器
让我们开始提问,看看服务器是如何工作的。
钱包分析
使用以下提示或使用我们预先构建的提示来指导 Claude 分析钱包的余额和上下文:
Give the balance of 0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045 on Ethereum
或者,要求 Claude 分析所有受支持链上的钱包余额:
Give the balance of 0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045 address across all networks you support.
克劳德会:
- 调用
eth_getBalance
工具 - 根据提示返回响应
请注意,由于 supported-chains
资源,Claude 将仅针对其支持的链调用 eth_getBalance
工具。
合约检测
使用以下提示或使用我们预先构建的提示来指导 Claude 检测钱包是否是合约:
What kind of contract is 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2?
克劳德会:
- 检测到它是一个合约(使用字节码存在)
- 解释它是否是已知的合约(使用资源或历史数据)
Gas 评估
使用以下提示或使用我们预先构建的提示来指导 Claude 评估以太坊网络上的 gas 价格:
Analyze current gas price on Ethereum. Is now a good time to transact?
克劳德会:
- 调用
eth_gasPrice
工具以从 QuickNode 获取当前 gas 价格 - 引用你提供的
gas-reference
资源,该资源包括每个链的低、中、高和非常高的 gas 价格的阈值 - 将实时 gas 数据与这些参考点进行比较
- 传递一条上下文感知的响应,指示现在是否是交易的好时机
恭喜! 你已经构建了你自己的 LLM 驱动的区块链数据分析工具。 现在,你可以使用 Claude 分析区块链数据并与之交互,使你能够构建智能应用程序并自动执行流程。
接下来是什么?
一旦你的 EVM MCP 服务器启动并运行,就可以通过多种方式扩展其功能并加深其与 AI 工作流程的集成。 以下是几个需要探索的领域:
扩展 EVM 功能
添加更多本机 EVM 方法以增加服务器可以执行的操作:
eth_getLogs
:监视合约事件,例如Token转移或 DAO 投票eth_call
:读取智能合约数据(例如,Token余额、配置)eth_blockNumber
:获取最新的区块以进行链健康/状态跟踪eth_getTransactionByHash
:分析特定交易
构建 AI 特定增强功能
当 LLM agent 在特定于领域的推理和上下文的指导下,会变得更加有用。 考虑:
- 专用提示:为 DeFi 分析、合约审计、钱包分析等设计特定于任务的说明。
- ENS 支持:解析
.eth
域名以获得更好的用户体验 - ERC20 Token和 NFT 数据探索:使用 Token和 NFT API v2 捆绑包 来获取Token余额、NFT 元数据等
- 实时价格数据:使用 QuickNode Marketplace 插件(例如 DEX Aggregator Trading API)集成Token价格
- 交易功能:如果你想超越只读查询,请查看我们的 在 Base 上构建电报交易机器人 指南。 想象一下将 MCP 提示与交易操作相结合以创建自主交易 agent。
- 自定义 agent:将 MCP 与 LangChain、AutoGen 或 CrewAI 相结合以创建具有内存、计划和区块链访问权限的完全自主的 agent
- 探索多链扩展:有兴趣支持 EVM 链旁边的 Solana 吗? 请按照我们的 如何构建用于 LLM 集成的 Solana MCP 服务器 指南来扩展你的 agent 在生态系统中的影响力。
添加缓存和性能优化
对于经常查询的数据,缓存可以减少延迟并避免重复的 RPC 调用:
- 使用 Redis、SQLite 或简单的基于文件的缓存来存储
eth_getBalance
和eth_gasPrice
- 为每个链/方法设置 TTL(生存时间)值,以确保新鲜度
- 使用 memoization 模式或自定义包装器来避免每次运行重复的 Viem 调用
跟踪分析和使用情况
了解你的工具是如何使用的:
- 记录传入的工具调用和提示使用情况
- 监视 哪些链 查询最多
- 添加基本使用指标(例如,每个链的交易量、每个工具的延迟)
此数据可以帮助指导未来的改进,例如优化提示模板或扩展基础架构。
加强安全性和稳定性
由于 MCP 服务器接受来自 agent 的输入,因此保护表面积非常重要:
- 使用 Zod Schema 来严格验证和清理所有输入
- 阅读 MCP 安全注意事项 以防止提示注入或滥用
- 如果公开 MCP 服务器,请考虑限制速率或添加身份验证层
结论
EVM MCP 服务器在 LLM agent 和区块链数据之间提供了一个强大的桥梁。 通过实施模型上下文协议,我们创建了一个标准化接口,该接口允许 AI 模型访问和分析多个 EVM 兼容网络上的链上信息。
这个技术基础为 AI 驱动的区块链应用程序开辟了广阔的前景,从自动化监控到智能分析和推荐系统。 无论你是为分析师、dApp 还是内部自动化构建 agent,这都是你的基础——构建一次,然后在任何地方扩展它。
如果你有任何疑问或需要帮助,请随时在我们的 Discord 或 Twitter 上与我们联系。
附加资源
- 模型上下文协议文档
- Viem 文档
- QuickNode 多链指南
- EVM JSON-RPC 规范
- Claude Desktop 文档
- MCP Inspector - 用于调试 MCP 服务器的有用工具
- MCP 安全注意事项 - 构建 MCP 服务器时的重要安全注意事项
我们️反馈!
如果你对新主题有任何反馈或请求,请告诉我们。 我们很乐意听到你的声音。
- 原文链接: quicknode.com/guides/ai/...
- 登链社区 AI 助手,为大家转译优秀英文文章,如有翻译不通的地方,还请包涵~
版权声明
本文仅代表作者观点,不代表区块链技术网立场。
本文系作者授权本站发表,未经许可,不得转载。
发表评论:
◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。