MCP协议开发实战:从零搭建AI Agent工具链
1. 引言:为什么需要MCP?
在AI Agent(智能体)开发领域,工具调用(Tool Calling)是连接大语言模型与现实世界的关键桥梁。然而,传统的工具集成方式往往面临以下挑战:
- 厂商锁定:不同AI平台(如OpenAI、Anthropic、Google)的工具调用API互不兼容。
- 开发复杂:为每个Agent重复定义工具接口、编写适配代码。
- 部署困难:工具与Agent强耦合,难以独立更新和扩展。
Model Context Protocol(MCP)正是为解决这些问题而生。它是由Anthropic主导的开源协议,旨在为AI模型提供标准化的工具调用和上下文管理接口。通过MCP,开发者可以:
- 一次定义工具,多处使用(跨平台、跨模型)。
- 将工具作为独立服务运行,实现解耦和弹性扩展。
- 利用丰富的开源工具生态,快速构建功能强大的Agent。
本文将带你从零开始,通过实战项目搭建一个基于MCP的完整AI Agent工具链。
2. MCP核心概念与架构
2.1 协议三层架构
MCP协议采用清晰的三层架构:
- 客户端(Client):通常是AI模型或应用(如Claude Desktop、Cursor),负责发起工具调用请求。
- 服务器(Server):工具提供方,实现具体的工具逻辑并通过MCP协议暴露接口。
- 传输层(Transport):支持Stdio(标准输入输出)和SSE(Server-Sent Events)两种通信方式。
这种架构使得工具开发与AI应用完全解耦。
2.2 核心资源类型
MCP定义了四种核心资源类型:
- 工具(Tools):可执行的操作,如查询天气、发送邮件、执行代码。
- 提示词模板(Prompts):预定义的提示词片段,支持参数化。
- 资源(Resources):只读数据源,如文档、API文档、数据库schema。
- 采样器(Samplers):用于控制模型生成行为的配置。
3. 环境准备与项目初始化
3.1 开发环境要求
- Node.js 18+ 或 Python 3.9+
- npm/pip 包管理器
- 代码编辑器(推荐VS Code)
- Claude Desktop(用于测试MCP工具)
3.2 初始化Node.js MCP服务器项目
# 创建项目目录
mkdir mcp-weather-server
cd mcp-weather-server
初始化npm项目
npm init -y
安装MCP SDK
npm install @modelcontextprotocol/sdk
安装依赖
npm install axios dotenv
3.3 项目结构规划
mcp-weather-server/
├── src/
│ ├── server.js # MCP服务器主文件
│ ├── tools/ # 工具实现
│ │ └── weather.js # 天气查询工具
│ └── config.js # 配置文件
├── package.json
├── .env.example # 环境变量示例
└── README.md
4. 实战一:构建天气查询MCP工具
4.1 创建MCP服务器
在src/server.js中创建基础MCP服务器:
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import {
CallToolRequestSchema,
ListToolsRequestSchema
} from "@modelcontextprotocol/sdk/types.js";
// 创建MCP服务器实例
const server = new Server(
{
name: "weather-mcp-server",
version: "1.0.0",
},
{
capabilities: {
tools: {}, // 声明支持工具功能
},
}
);
// 注册工具列表处理器
server.setRequestHandler(ListToolsRequestSchema, async () => {
return {
tools: [
{
name: "get_weather",
description: "获取指定城市的当前天气信息",
inputSchema: {
type: "object",
properties: {
city: {
type: "string",
description: "城市名称,如:北京、上海、New York"
},
units: {
type: "string",
enum: ["metric", "imperial"],
description: "温度单位:metric(摄氏度) 或 imperial(华氏度)",
default: "metric"
}
},
required: ["city"]
}
}
]
};
});
// 启动服务器(使用Stdio传输)
const transport = new StdioServerTransport();
await server.connect(transport);
console.error("Weather MCP Server started");
4.2 实现天气查询工具逻辑
创建src/tools/weather.js:
import axios from "axios";
import dotenv from "dotenv";
dotenv.config();
// 使用OpenWeatherMap API(需要注册获取API Key)
const OPENWEATHER_API_KEY = process.env.OPENWEATHER_API_KEY;
const BASE_URL = "https://api.openweathermap.org/data/2.5/weather";
export async function getWeather(city, units = "metric") {
try {
const response = await axios.get(BASE_URL, {
params: {
q: city,
appid: OPENWEATHER_API_KEY,
units: units,
lang: "zh_cn"
}
});
const data = response.data;
return {
city: data.name,
country: data.sys.country,
temperature: data.main.temp,
feels_like: data.main.feels_like,
humidity: data.main.humidity,
pressure: data.main.pressure,
weather: data.weather[0].description,
wind_speed: data.wind.speed,
wind_deg: data.wind.deg,
icon: data.weather[0].icon,
units: units === "metric" ? "°C" : "°F"
};
} catch (error) {
if (error.response?.status === 404) {
throw new Error(城市 "${city}" 未找到,请检查城市名称拼写);
}
if (error.response?.status === 401) {
throw new Error("API密钥无效,请检查OPENWEATHER_API_KEY配置");
}
throw new Error(天气查询失败: ${error.message});
}
}
4.3 注册工具调用处理器
在server.js中添加工具调用处理:
import { getWeather } from "./tools/weather.js";
// 注册工具调用处理器
server.setRequestHandler(CallToolRequestSchema, async (request) => {
const { name, arguments: args } = request.params;
if (name === "get_weather") {
try {
const { city, units = "metric" } = args;
const weatherData = await getWeather(city, units);
return {
content: [
{
type: "text",
text: `## ${weatherData.city}, ${weatherData.country} 天气\n` +
`- **温度**: ${weatherData.temperature}${weatherData.units} (体感 ${weatherData.feels_like}${weatherData.units})\n` +
`- **天气状况**: ${weatherData.weather}\n` +
`- **湿度**: ${weatherData.humidity}%\n` +
`- **气压**: ${weatherData.pressure} hPa\n` +
`- **风速**: ${weatherData.wind_speed} m/s, 风向 ${weatherData.wind_deg}°`
}
]
};
} catch (error) {
return {
content: [
{
type: "text",
text: `❌ 天气查询失败: ${error.message}`
}
],
isError: true
};
}
}
return {
content: [
{
type: "text",
text: 未知工具: ${name}
}
],
isError: true
};
});
5. 实战二:配置与测试MCP工具
5.1 配置Claude Desktop使用MCP工具
创建Claude Desktop配置文件(macOS路径:~/Library/Application Support/Claude/claude_desktop_config.json):
{
"mcpServers": {
"weather": {
"command": "node",
"args": ["/path/to/your/mcp-weather-server/src/server.js"],
"env": {
"OPENWEATHER_API_KEY": "your_api_key_here"
}
}
}
}
5.2 启动与验证
# 1. 启动MCP服务器(开发模式)
node src/server.js
2. 重启Claude Desktop
3. 在Claude中测试工具调用:
"查询北京今天的天气"
5.3 测试结果示例
成功调用后,Claude会返回格式化的天气信息:
Claude回复:我使用天气查询工具获取了北京的天气信息:
## 北京, CN 天气
- 温度: 15°C (体感 14°C)
- 天气状况: 晴
- 湿度: 45%
- 气压: 1015 hPa
- 风速: 3.2 m/s, 风向 180°
6. 进阶:构建工具链与管理多个MCP服务器
6.1 创建工具链管理器
对于需要多个MCP服务器的复杂场景,可以创建统一的管理器:
// mcp-manager.js
import { spawn } from 'child_process';
import fs from 'fs';
import path from 'path';
class MCPManager {
constructor(configPath) {
this.config = JSON.parse(fs.readFileSync(configPath, 'utf-8'));
this.servers = new Map();
}
async startAll() {
for (const [name, serverConfig] of Object.entries(this.config.mcpServers)) {
await this.startServer(name, serverConfig);
}
}
async startServer(name, config) {
return new Promise((resolve, reject) => {
const env = { ...process.env, ...config.env };
const serverProcess = spawn(config.command, config.args, { env });
this.servers.set(name, serverProcess);
serverProcess.stderr.on('data', (data) => {
console.log([${name}] ${data.toString()});
});
serverProcess.on('close', (code) => {
console.log([${name}] 进程退出,代码: ${code});
this.servers.delete(name);
});
// 等待服务器就绪信号
setTimeout(() => {
console.log(✅ MCP服务器 "${name}" 已启动);
resolve();
}, 1000);
});
}
}
// 使用示例
const manager = new MCPManager('./mcp-config.json');
await manager.startAll();
6.2 常用MCP服务器推荐
| 服务器 | 功能 | 语言 | GitHub仓库 |
|---|---|---|---|
| filesystem | 文件系统操作 | TypeScript | modelcontextprotocol/servers |
| postgres | PostgreSQL数据库操作 | TypeScript | modelcontextprotocol/servers |
| github | GitHub API集成 | TypeScript | modelcontextprotocol/servers |
| brave-search | Brave搜索 | Python | modelcontextprotocol/servers |
7. 生产环境部署与优化
7.1 安全性考虑
- API密钥管理:使用环境变量或密钥管理服务,避免硬编码。
- 输入验证:对所有工具参数进行严格的验证和清理。
- 速率限制:实现请求限流,防止滥用。
- 错误处理:避免泄露敏感信息在错误消息中。
7.2 性能优化
- 连接池:对于数据库类工具,使用连接池减少开销。
- 缓存策略:对频繁查询的数据添加缓存层。
- 异步处理:耗时的操作使用异步模式,不阻塞主线程。
- 健康检查:实现
/health端点供监控系统使用。
7.3 容器化部署
创建Dockerfile:
FROM node:18-alpine
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production
COPY src/ ./src/
USER node
EXPOSE 3000
CMD ["node", "src/server.js"]
8. 总结与展望
8.1 核心收获
通过本实战项目,我们掌握了:
- MCP协议的基本架构和工作原理
- 如何从零开发一个MCP服务器
- 在Claude Desktop中集成和使用自定义工具
- 构建可扩展的MCP工具链
8.2 MCP生态展望
MCP协议正在快速发展,未来可能的方向包括:
- 更丰富的工具市场:像npm、PyPI一样的MCP工具仓库
- 可视化工具编排:拖拽式配置复杂的工作流
- 跨平台标准化:成为所有AI助手的事实标准工具协议
- 企业级特性:审计日志、权限管理、SLA保障
8.3 下一步学习建议
MCP协议为AI Agent开发带来了真正的标准化和模块化。通过将工具开发与AI应用解耦,它让开发者能够专注于构建有价值的工具,而不必担心平台兼容性问题。随着生态的成熟,我们有望看到一个更加开放、互操作的AI工具未来。
更多推荐
所有评论(0)