阅读时间 14 分钟
概述
模型上下文协议(MCP)使大型语言模型(LLMs)能够通过一种基于消息的标准化协议与外部工具(如 HTTP API、文件,甚至区块链)进行交互。可以将其视为一种“函数调用”接口,像 Claude 或 Cursor 这样的智能代理可以接入该接口,从而将脚本或服务转化为原生 AI 扩展。
在本指南中,您将学习如何构建和部署一台 MCP 服务器,使 LLM 代理能够访问多个 EVM 兼容网络中的区块链数据。这种强大的集成使Claude等 AI 模型能够直接与区块链数据交互,为 Web3 的自动化和分析开辟了新的可能性。
您将负责的工作内容
- 构建一个可与多条 EVM 链交互的 MCP 服务器
- 利用Viem和 Quicknode 的多链 RPC,使大型语言模型能够获取链上数据
- 注册工具、提示和资源,以引导大型语言模型的行为
- 在Claude Desktop中运行服务器,并使用自然语言请求进行测试
您需要准备的物品
- Node.jsv20 或更高版本
- 一个免费的Quicknode账户
- Claude Desktop(或兼容的代理运行器)
- 以太坊区块链方面的经验
什么是MCP?
模型上下文协议(MCP)是一项开放标准,允许人工智能代理与外部工具和数据源进行交互。它在语言模型与工具之间建立了一条结构化的通信通道。
如果没有MCP,AI模型将仅限于:
- 他们接受培训时所涉及的内容
- 他们目前正在进行的对话
- 无法检查外部数据源
- 无法在现实世界中采取行动
MCP 通过为人工智能访问外部工具和数据建立标准化方式,弥合了这一差距。
来源(已根据我们正在构建的服务器进行修改):模型上下文协议
关键概念
MCP 服务器的运作原理
MCP 服务器负责处理来自客户端的请求并返回相应的数据。它们使用 MCP 协议与 LLM 进行通信,并可以使用任何编程语言或框架来实现。
每个服务器都通过标准通道(stdio、HTTP 或套接字)与 LLM 进行通信,并返回结构清晰的输出。这使得 LLM 能够理解请求的上下文和意图,并做出适当的响应。MCP 协议的设计具有可扩展性,允许开发人员根据需要添加新的工具、资源和提示词。
工具:AI 可调用以执行特定操作的函数。它们可以是任何形式,从简单的 API 调用到复杂的任务皆可。
- 示例:
eth_getBalance查询钱包余额 - 示例:
天气预报获取当前天气数据
资源: 人工智能可以参考的静态知识。这些知识会影响模型的现实关联和假设——例如,添加一个 gas-reference 该资源可帮助克劳德判断某条链上的 gas 价格是低、中等还是高,而无需调用任何工具。
- 示例:关于特定区块链上 gas 费用的详细信息
- 示例:关于 API 参数的文档
提示词:预先编写用于引导人工智能的指令。它们就像可重复使用的思维模板。每个提示词都定义了大型语言模型(LLM)应如何利用工具和结构化推理来处理一项任务(例如,“分析这个钱包”)。
- 示例:用于分析钱包活动的模板
- 示例:执行复杂任务的分步指南
当您将 MCP 服务器连接到 Claude 这样的 AI 时:
- AI 会发现有哪些工具、资源和提示可用
- 必要时,AI 可以使用特定参数调用这些工具
- 服务器处理这些请求并返回结构化数据
- AI会解读这些结果,并将它们纳入其回复中
以下是在有和没有 MCP 服务器的情况下,同一用户提问的处理过程:
简单示例:查询钱包余额
| 没有 MCP | 使用 MCP | |
|---|---|---|
| 用户 | “钱包 0x123... 的余额是多少?” | “钱包 0x123... 的余额是多少?” |
| AI 流程 | 无法访问外部数据 | [通过 MCP 调用 eth_getBalance 工具] |
| AI 回复 | “我无法访问最新的区块链数据,所以无法查询该钱包的余额。” | “该钱包目前在以太坊上持有 0.45 ETH。” |
| 结果 | ❌ 无法满足用户请求 | ✅ 提供实时区块链数据 |
MCP 服务器中的请求生命周期
当代理通过提示词发出请求时,情况如下:
- 解析请求以确定操作和参数
- 验证参数
- 选择合适的链客户端
- 通过 Viem 将请求转发至 Quicknode
- 对响应进行格式化,并将其返回给代理

我们已经了解了MCP服务器的运作原理。现在,让我们来搭建一个吧!
项目结构
该项目的结构如下:
evm-mcp-server/
├── index.ts # 入口点,用于初始化 MCP 服务器
├── chains.ts # 链配置 + Quicknode 端点映射
├── clients.ts # Viem 公共客户端生成器
├── package.json # 依赖项和脚本
├── prompts.ts # 大型语言模型提示词定义
├── resources.ts # 外部引用(Gas 价格、区块浏览器)
├── tools.ts # MCP 工具:getCode、getBalance、gasPrice
└── tsconfig.json # TypeScript 配置
首先,让我们来看看每个文件及其用途。不过,如果你想直接查看代码,可以跳到“构建你的 EVM MCP 服务器”一节。
本指南中的所有代码均可在Quicknode GitHub 代码库中找到。本文将通过对代码进行高层次概述来解释其工作原理,但在“构建您的 MCP 服务器”一节中,我们将使用该 GitHub 代码库。
入口点: index.ts
该文件是用于初始化和启动 MCP 服务器的入口点。它负责注册工具、提示和资源:
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 {
// Create the MCP server
const server = new McpServer({
name: 'EVM MCP Server',
version: '0.1.0',
description: 'A server for LLM agents to access EVM blockchain data',
})
// Register all tools, prompts, and resources
registerTools(server)
registerPrompts(server)
registerResources(server)
// Start the MCP server
const transport = new StdioServerTransport()
await server.connect(transport)
} catch (error) {
console.error('❌ Failed to start server:', error)
process.exit(1)
}
}
// Run the main function
main().catch(error => {
console.error('❌ Unhandled error:', error)
process.exit(1)
})
链配置: chains.ts
该文件定义了区块链配置,并根据 Quicknode 的多链格式构建 RPC URL。
// Get the endpoint name and token ID from environment variables
const QN_ENDPOINT_NAME = validateEnvVar('QN_ENDPOINT_NAME')
const QN_TOKEN_ID = validateEnvVar('QN_TOKEN_ID')
// Function to build Quicknode RPC URL based on network name
const buildRpcUrl = (networkName: string): string => {
// Special case for Ethereum mainnet
if (networkName === 'mainnet') {
return `https://${QN_ENDPOINT_NAME}.quiknode.pro/${QN_TOKEN_ID}/`
}
// Special case for Avalanche mainnet
if (networkName === 'avalanche-mainnet') {
return `https://${QN_ENDPOINT_NAME}.${networkName}.quiknode.pro/${QN_TOKEN_ID}/ext/bc/C/rpc`
}
// For other networks, include network name in the 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,
},
// Other chains...
}
// Rest of the code...
客户端创建者: clients.ts
该文件使用 createPublicClient 来自的函数 Viem 该库用于通过 Quicknode RPC 端点与该区块链建立连接。
import { createPublicClient, http } from 'viem'
import { ChainId, getChain } from './chains'
// Cache for viem clients to avoid creating duplicate clients
const clientCache = new Map<ChainId, ReturnType<typeof createPublicClient>>()
export const getPublicClient = (chainId: ChainId) => {
// Return from cache if exists
if (clientCache.has(chainId)) {
return clientCache.get(chainId)!
}
// Get chain configuration
const chain = getChain(chainId)
// Create new public client
const client = createPublicClient({
transport: http(chain.rpc),
})
// Cache for future use
clientCache.set(chainId, client)
return client
}
提示: prompts.ts
该文件定义了供 LLM 代理使用的提示词。提示词对象包含 描述 以及 消息 这些属性由 MCP 服务器用于生成提示信息。提示信息包括调用工具、解释结果以及格式化响应的说明。
// Register check-wallet prompt
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.`,
},
},
],
})
)
// Schema for check-wallet prompt
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',
}),
})
// Rest of the code...
资源: resources.ts
该文件定义了 LLM 代理可使用的外部引用。在此情况下,我们向它们提供了各条链的 gas 价格水平、各条链的区块浏览器链接,以及关于这些链本身的一些详细信息。
export const registerResources = (server: any) => {
// Register gas reference resource
server.resource(
'gas-reference',
'evm://docs/gas-reference',
async (uri: URL) => {
return {
contents: [
{
uri: uri.href,
text: JSON.stringify(gasReferencePoints, null, 2),
},
],
}
}
)
// Other resources...
}
// Gas reference points for each chain
const gasReferencePoints = {
ethereum: {
low: 20,
average: 40,
high: 100,
veryHigh: 200,
},
base: {
low: 0.05,
average: 0.1,
high: 0.3,
veryHigh: 0.5,
},
// Other chains...
}
// Rest of the code...
工具: tools.ts
该文件定义了服务器可以调用的工具。在此情况下,我们使用的是 eth_getBalance, eth_getCode,以及 eth_gasPrice 工具。每个工具都是一个异步函数,通过 Viem 查询区块链,并返回结构化数据供大型语言模型(LLM)使用。
// Register tools with the MCP server
export const registerTools = (server: any) => {
// Register eth_getBalance tool
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) {
// Handle errors
}
}
)
// Other tools...
}
// Schema for eth_getBalance tool
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',
}),
})
// Other tool schemas...
/**
* Get the balance of an Ethereum address on the specified chain
*/
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)
// Get balance in wei
const balanceWei = await client.getBalance({ address })
// Format balance to ETH/native 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}`,
}
}
}
// Rest of the code...
构建您的 EVM MCP 服务器
我们已经了解了每个文件在 MCP 服务器中的作用。现在,让我们来构建并运行我们的服务器。
获取 Multichain 端点
我们正在构建的 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 中提取端点名称和令牌 ID。
得益于多链格式,我们现在可以通过单一端点连接到任何 EVM 链。端点名称和代币 ID 用于识别该链及其配置。

设置说明
既然已经有了端点,接下来我们就来配置 MCP 服务器吧。
步骤 1:克隆代码库
git clone https://github.com/quiknode-labs/qn-guide-examples.git
cd qn-guide-examples/AI/evm-mcp-server
步骤 2:安装依赖项
npm 安装
这将安装该项目所需的依赖项:
- @modelcontextprotocol/sdk:用于构建 MCP 服务器的 TypeScript SDK。
- viem:一个用于与 EVM 区块链交互的 TypeScript 库。
- zod:一个用于定义模式和验证数据的 TypeScript 库。
- typescript:一个 TypeScript 编译器。
- @types/node:Node.js 的 TypeScript 类型定义。
步骤 3:构建项目
npm 运行 build
这会生成 build/ 包含已编译文件的目录 index.js 文件,该文件作为服务器的入口点。
第 4 步:配置 Claude Desktop
该服务器使用 Claude Desktop 配置文件中定义的环境变量(claude_desktop_config.json) 以连接到 Quicknode 并运行服务器。
- 打开Claude Desktop,依次进入Claude>设置>开发者
- 编辑
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 令牌 ID。
- 请将/absolute-path-to替换为项目目录的绝对路径(例如:/Users/username/qn-guide-examples/AI/evm-mcp-server)。
保存文件并重新启动 Claude Desktop。现在,您的 MCP 服务器中的工具、资源和提示应该已经在 Claude 中可用。

测试您的 MCP 服务器
让我们开始提问,看看服务器是如何工作的。
钱包分析
使用以下提示语,或使用我们预设的提示语,引导克劳德分析钱包的余额和上下文:
在以太坊上查询余额 0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045
或者,请克劳德分析该钱包在所有支持的区块链上的余额:
请提供您所支持的所有网络中地址 0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045 的余额。

克劳德将:
- 拨打
eth_getBalance工具 - 根据提示返回一个响应
请注意,克劳德将调用该 eth_getBalance 该工具仅适用于它所支持的链,这要归功于 支持的链 资源。
合同检测
使用以下提示,或使用我们预设的提示,引导克劳德判断一个钱包是否为合约:
0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2 是什么类型的合约?
克劳德将:
- 检测是否为合约(通过检查是否存在字节码)
- 如果这是一份已知的合同(使用资源或历史数据),请说明
天然气评估
请使用以下提示词,或使用我们预设的提示词,引导克劳德评估以太坊网络上的 gas 价格:
分析以太坊当前的 gas 价格。现在是 时机 进行交易吗?
克劳德将:
- 拨打
eth_gasPrice用于从 Quicknode 获取当前 gas 价格的工具 - 参见
gas-reference您提供的资源,其中包含了各条链上低、中、高及极高 gas 价格的阈值 - 将实时天然气数据与这些参考点进行对比
- 根据上下文返回响应,表明当前是否适合进行交易

恭喜!您已经成功构建了自己的基于大型语言模型(LLM)的区块链数据分析工具。现在,您可以使用 Claude 来分析和处理区块链数据,从而开发智能应用程序并实现流程自动化。
接下来会怎样?
一旦您的 EVM MCP 服务器投入运行,就有多种方法可以扩展其功能,并将其更深入地集成到 AI 工作流中。以下是几个值得探索的领域:
扩展 EVM 功能
添加更多原生 EVM 方法,以扩展服务器的功能:
eth_getLogs: 监控合约事件,例如代币转账或 DAO 投票eth_call: 读取智能合约数据(例如:代币余额、配置)eth_blockNumber: 获取最新区块,用于追踪区块链健康状况/状态eth_getTransactionByHash: 分析特定交易
构建面向人工智能的增强功能
当LLM代理在特定领域的推理和上下文指导下工作时,其实用性会得到提升。试想:
- 专项提示:针对 DeFi 分析、合约审计、钱包分析等任务,设计相应的操作指南。
- ENS 支持: 决心
.eth域名,以提升用户体验 - ERC20 代币和 NFT 数据探索:使用Token 和 NFT API v2 组合包来获取代币余额、NFT 元数据等信息
- 实时价格数据:使用 Quicknode Marketplace 插件(例如DEX Aggregator 交易 API)集成代币价格
- 交易功能:如果您希望超越只读查询,请参阅我们的《在 Base 上构建 Telegram 交易机器人》指南。试想一下,将 MCP 提示与交易操作相结合,从而创建自主交易代理。
- 自定义智能体:将 MCP 与 LangChain、AutoGen 或 CrewAI 结合,创建具备记忆、规划能力和区块链访问权限的完全自主智能体
- 探索多链扩展:有兴趣在支持 EVM 链的同时支持 Solana 吗?请参考我们的《如何构建用于 LLM 集成的 Solana MCP 服务器》指南,让您的代理在各个生态系统中拓展影响力。
添加缓存和性能优化
对于频繁查询的数据,缓存可以降低延迟并避免重复的 RPC 调用:
- 使用 Redis, SQLite,或者用于
eth_getBalance以及eth_gasPrice - 为每个链/方法设置TTL(生存时间)值,以确保数据的新鲜度
- 使用备忘录模式或自定义封装类,以避免每次运行时重复调用 Viem
跟踪分析和使用情况
了解您的工具是如何被使用的:
- 记录传入的工具调用并提示使用方法
- 监控哪些链被查询得最多
- 添加基本使用指标(例如,每条链的处理量、每种工具的延迟)
这些数据有助于指导未来的改进工作,例如优化提示词模板或扩展基础设施。
加强安全与稳定
由于 MCP 服务器会接受来自代理的输入,因此确保其攻击面安全至关重要:
- 使用Zod 模式对所有输入进行严格验证和清理
- 请阅读《MCP 安全注意事项》,以防止提示注入或滥用
- 如果将 MCP 服务器对外公开,请考虑实施速率限制或添加身份验证层
结论
EVM MCP 服务器在大型语言模型(LLM)代理与区块链数据之间架起了一座强大的桥梁。通过实现模型上下文协议(Model Context Protocol),我们创建了一个标准化接口,使人工智能模型能够访问并分析多个 EVM 兼容网络上的链上信息。
这一技术基础为人工智能驱动的区块链应用开辟了无数可能性,从自动化监控到智能分析和推荐系统。无论您是开发面向分析师的智能代理、去中心化应用(dApp),还是内部自动化系统,这都是您的基础——只需构建一次,即可无处不在地扩展应用。
如果您有任何疑问或需要帮助,欢迎通过我们的Discord或Twitter 联系我们。
其他资源
- 模型上下文协议文档
- Viem 文档
- Quicknode 多链指南
- EVM JSON-RPC 规范
- Claude 桌面版文档
- MCP Inspector——一款用于调试 MCP 服务器的实用工具
- MCP 安全注意事项——构建 MCP 服务器时需注意的重要安全事项
我们 ❤️ 您的反馈!
如果您有任何反馈或对新主题的建议,请告诉我们。我们非常期待您的来信。
