MCP协议开发实战:从零搭建AI Agent工具链
1. 引言:为什么需要MCP协议?
- AI Agent的“工具困境”:传统Agent开发中,工具集成繁琐、协议不统一、扩展性差。
- MCP(Model Context Protocol)的诞生:由Anthropic提出,旨在标准化AI模型与外部工具/数据源之间的通信。
- 本文目标:带领读者从零开始,基于MCP协议搭建一个可扩展、易维护的AI Agent工具链。
2. MCP协议核心概念解析
- 2.1 协议定位:连接AI模型(客户端)与工具/数据源(服务器)的标准化桥梁。
- 2.2 核心组件
- Server(服务器):封装具体能力(如搜索、数据库查询、API调用),向客户端宣告可用工具(Tools)和资源(Resources)。
- Client(客户端):通常是AI模型或应用,发现并调用服务器提供的工具和资源。
- Transport(传输层):支持Stdio(标准输入输出)和SSE(Server-Sent Events)两种通信方式。
- 2.3 关键能力
- Tools(工具):可执行的操作,包含名称、描述、参数schema。
- Resources(资源):可读取的静态或动态数据源(如文件、数据库表视图)。
- Prompts(提示词模板):可复用的提示词片段,供客户端组合使用。
3. 开发环境与工具准备
- 3.1 环境要求:Node.js (>=18) / Python 3.10+,代码编辑器。
- 3.2 核心工具库
- 官方SDK:
@modelcontextprotocol/sdk(Node.js) /mcp(Python)。 - 开发辅助:MCP Inspector(调试工具)、Claude Desktop(客户端测试环境)。
- 官方SDK:
- 3.3 项目初始化:创建项目目录,安装依赖。
4. 实战一:构建你的第一个MCP服务器(天气查询)
-
4.1 项目结构设计
-
4.2 实现Server基类:初始化、能力声明、请求路由。
-
4.3 定义并实现Tool:创建一个
get_weather工具,定义输入参数(城市名),集成第三方天气API。下面是一个完整的 Node.js 版
get_weather工具实现示例:// weatherTool.js const { Tool } = require('@modelcontextprotocol/sdk/server/tools'); const { z } = require('zod'); // 用于参数验证 /** * 天气查询工具 * 该工具模拟调用第三方天气API,返回指定城市的天气信息 */ class GetWeatherTool extends Tool { constructor() { super({ 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'], }, }); } /** * 执行天气查询 * @param {Object} params - 工具参数 * @param {string} params.city - 城市名称 * @param {string} [params.units='metric'] - 温度单位 * @returns {Promise<Object>} 天气信息 */ async execute(params) { const { city, units = 'metric' } = params; // 1. 参数验证 if (!city || typeof city !== 'string') { throw new Error('城市名称不能为空且必须是字符串'); } // 2. 模拟调用天气API(实际项目中替换为真实的API调用) // 这里使用模拟数据,实际开发中可集成OpenWeatherMap、和风天气等API const mockWeatherData = { '北京': { temp: 22, condition: '晴朗', humidity: 45 }, '上海': { temp: 25, condition: '多云', humidity: 65 }, '广州': { temp: 28, condition: '阵雨', humidity: 80 }, 'New York': { temp: 68, condition: 'Partly Cloudy', humidity: 60 }, }; // 3. 查找城市天气数据 const cityKey = Object.keys(mockWeatherData).find( key => key.toLowerCase() === city.toLowerCase() ); if (!cityKey) { throw new Error(`未找到城市 "${city}" 的天气数据`); } const weather = mockWeatherData[cityKey]; // 4. 单位转换(模拟) let temperature = weather.temp; let unitSymbol = '°C'; if (units === 'imperial') { temperature = Math.round((temperature * 9/5) + 32); unitSymbol = '°F'; } // 5. 返回结构化结果 return { city: cityKey, temperature: { value: temperature, unit: unitSymbol, original_unit: units === 'metric' ? 'celsius' : 'fahrenheit', }, condition: weather.condition, humidity: `${weather.humidity}%`, last_updated: new Date().toISOString(), source: 'mock-weather-api', units: units, // 附加建议信息 recommendations: this._generateRecommendations(weather.condition, temperature), }; } /** * 根据天气条件生成建议 * @private */ _generateRecommendations(condition, temperature) { const recommendations = []; if (condition.includes('雨')) { recommendations.push('建议携带雨具'); } if (temperature > 30) { recommendations.push('天气炎热,注意防暑降温'); } else if (temperature < 10) { recommendations.push('天气寒冷,注意保暖'); } if (condition.includes('晴朗') || condition.includes('Sunny')) { recommendations.push('适合户外活动,请注意防晒'); } return recommendations.length > 0 ? recommendations : ['天气适宜,享受美好的一天']; } } // 导出工具实例 module.exports = new GetWeatherTool();代码说明:
- 工具类定义:继承自
Tool基类,定义工具名称、描述和参数schema - 参数验证:使用Zod schema定义参数类型和约束,确保输入安全
- API集成:示例中使用模拟数据,实际项目可替换为真实天气API调用
- 错误处理:对无效城市名、参数错误等情况进行友好提示
- 结构化返回:返回包含温度、天气状况、湿度等信息的结构化JSON
- 单位转换:支持公制(摄氏度)和英制(华氏度)单位
- 附加建议:根据天气条件自动生成实用建议
在MCP服务器中注册该工具:
// server.js const { Server } = require('@modelcontextprotocol/sdk/server'); const weatherTool = require('./weatherTool'); const server = new Server( 'weather-server', { version: '1.0.0' } ); // 注册天气查询工具 server.setRequestHandler('tools/list', async () => ({ tools: [weatherTool.getDefinition()], })); server.setRequestHandler('tools/call', async (request) => { if (request.params.name === 'get_weather') { return await weatherTool.execute(request.params.arguments); } throw new Error(`Unknown tool: ${request.params.name}`); }); // 启动服务器 server.start().catch(console.error); - 工具类定义:继承自
-
4.4 运行与测试:通过Stdio启动服务器,使用MCP Inspector或Claude Desktop进行工具调用测试。
5. 实战二:扩展服务器能力(资源与提示词)
-
5.1 添加Resource:暴露一个本地配置文件或API文档作为可读资源。
下面是一个读取本地配置文件(config.json)并暴露为MCP资源的完整示例:
// configResource.js const { Resource } = require('@modelcontextprotocol/sdk/server/resources'); const fs = require('fs').promises; const path = require('path'); /** * 配置文件资源 * 将本地配置文件暴露为只读资源,客户端可以读取配置信息 */ class ConfigResource extends Resource { constructor(configPath) { super({ uri: 'file:///config.json', name: 'server-config', description: '服务器配置文件,包含API密钥、服务端点等设置', mimeType: 'application/json', }); this.configPath = configPath; } /** * 读取配置文件内容 * @returns {Promise<Object>} 配置对象 */ async read() { try { const configContent = await fs.readFile(this.configPath, 'utf-8'); const config = JSON.parse(configContent); return { content: [ { type: 'text', text: JSON.stringify(config, null, 2), }, ], metadata: { lastModified: new Date().toISOString(), fileSize: Buffer.byteLength(configContent), format: 'json', }, }; } catch (error) { throw new Error(`读取配置文件失败: ${error.message}`); } } /** * 获取资源定义(用于注册到服务器) */ getDefinition() { return { uri: this.uri, name: this.name, description: this.description, mimeType: this.mimeType, }; } } // 示例配置文件 config.json const exampleConfig = { "server": { "name": "weather-mcp-server", "version": "1.0.0", "port": 3000 }, "weatherApi": { "provider": "openweathermap", "apiKey": "YOUR_API_KEY_HERE", "baseUrl": "https://api.openweathermap.org/data/2.5", "cacheDuration": 300 // 缓存时间(秒) }, "logging": { "level": "info", "file": "logs/server.log" }, "features": { "enableCaching": true, "enableMetrics": true, "maxConcurrentRequests": 10 } }; // 创建配置文件(开发环境) async function createExampleConfig() { const configPath = path.join(__dirname, 'config.json'); await fs.writeFile(configPath, JSON.stringify(exampleConfig, null, 2)); console.log(`示例配置文件已创建: ${configPath}`); return configPath; } // 导出资源实例 module.exports = { ConfigResource, createExampleConfig, exampleConfig, };在MCP服务器中注册资源:
// server.js - 资源注册部分 const { ConfigResource, createExampleConfig } = require('./configResource'); // 创建配置文件(首次运行) const configPath = await createExampleConfig(); // 创建资源实例 const configResource = new ConfigResource(configPath); // 注册资源到服务器 server.setRequestHandler('resources/list', async () => ({ resources: [configResource.getDefinition()], })); server.setRequestHandler('resources/read', async (request) => { if (request.params.uri === configResource.uri) { return await configResource.read(); } throw new Error(`资源不存在: ${request.params.uri}`); });资源使用场景:
- 客户端可以读取服务器配置,了解可用功能和限制
- 暴露API文档、使用说明等静态内容
- 提供动态数据源(如数据库查询结果、实时监控数据)
-
5.2 添加Prompt:创建一个用于优化天气查询结果的提示词模板。
下面是一个优化天气查询结果的提示词模板示例,包含变量占位符和用法说明:
// weatherPrompt.js const { Prompt } = require('@modelcontextprotocol/sdk/server/prompts'); /** * 天气查询优化提示词 * 该提示词模板帮助客户端更好地理解和展示天气查询结果 */ class WeatherOptimizationPrompt extends Prompt { constructor() { super({ name: 'weather_result_optimizer', description: '优化天气查询结果的提示词模板,生成更友好的天气报告', arguments: [ { name: 'city', description: '城市名称', required: true, }, { name: 'temperature', description: '温度数值', required: true, }, { name: 'unit', description: '温度单位(°C或°F)', required: true, }, { name: 'condition', description: '天气状况(如晴朗、多云、下雨等)', required: true, }, { name: 'humidity', description: '湿度百分比', required: true, }, { name: 'recommendations', description: '天气建议数组', required: false, }, { name: 'time_of_day', description: '查询时间(早晨、中午、傍晚、夜晚)', required: false, }, ], }); } /** * 生成优化后的提示词 * @param {Object} args - 提示词参数 * @returns {string} 格式化后的提示词 */ generate(args) { const { city, temperature, unit, condition, humidity, recommendations = [], time_of_day = '当前', } = args; // 构建基础提示词 let prompt = `## ${city}天气报告\n\n`; prompt += `**查询时间**:${time_of_day}\n\n`; prompt += `### 天气概况\n`; prompt += `- **温度**:${temperature}${unit}\n`; prompt += `- **天气状况**:${condition}\n`; prompt += `- **湿度**:${humidity}\n\n`; // 添加天气解读 prompt += `### 天气解读\n`; // 根据温度给出解读 const tempNum = parseFloat(temperature); if (unit === '°C') { if (tempNum < 0) { prompt += `❄️ 气温极低,请注意防寒保暖,路面可能结冰。\n`; } else if (tempNum < 10) { prompt += `🧥 天气较冷,建议穿着外套。\n`; } else if (tempNum < 25) { prompt += `😊 气温舒适,适合户外活动。\n`; } else if (tempNum < 35) { prompt += `☀️ 天气较热,注意补充水分。\n`; } else { prompt += `🔥 高温天气,避免长时间户外活动。\n`; } } // 根据天气状况给出解读 if (condition.includes('雨')) { prompt += `🌧️ 有降雨,出行请携带雨具。\n`; } else if (condition.includes('雪')) { prompt += `❄️ 有降雪,注意道路安全。\n`; } else if (condition.includes('晴') || condition.includes('Sunny')) { prompt += `☀️ 天气晴朗,适合户外活动,请注意防晒。\n`; } else if (condition.includes('云') || condition.includes('Cloudy')) { prompt += `☁️ 多云天气,紫外线较弱。\n`; } else if (condition.includes('雾')) { prompt += `🌫️ 有雾,能见度较低,出行请注意安全。\n`; } // 添加湿度解读 const humidityNum = parseInt(humidity); if (humidityNum > 80) { prompt += `💦 湿度较高,体感可能闷热。\n`; } else if (humidityNum < 30) { prompt += `🏜️ 湿度较低,注意皮肤保湿。\n`; } // 添加自定义建议 if (recommendations.length > 0) { prompt += `\n### 出行建议\n`; recommendations.forEach((rec, index) => { prompt += `${index + 1}. ${rec}\n`; }); } // 添加穿衣建议 prompt += `\n### 穿衣指南\n`; if (tempNum < 5) { prompt += `👕 内搭保暖内衣 + 毛衣 + 羽绒服/厚外套\n`; prompt += `👖 加厚裤子 + 保暖鞋袜\n`; } else if (tempNum < 15) { prompt += `👕 长袖T恤 + 外套/夹克\n`; prompt += `👖 长裤 + 普通鞋袜\n`; } else if (tempNum < 25) { prompt += `👕 短袖/长袖T恤 + 薄外套\n`; prompt += `👖 长裤/休闲裤\n`; } else { prompt += `👕 短袖/背心\n`; prompt += `👖 短裤/薄长裤\n`; } // 添加活动建议 prompt += `\n### 活动推荐\n`; if (condition.includes('雨') || condition.includes('雪')) { prompt += `🏠 室内活动:阅读、看电影、室内健身\n`; prompt += `☕ 适合去咖啡馆、图书馆等室内场所\n`; } else { prompt += `🚶 户外活动:散步、慢跑、骑行\n`; prompt += `🌳 适合公园游玩、郊游、户外运动\n`; } prompt += `\n---\n*数据更新时间:{{current_time}}*\n`; prompt += `*提示:天气数据仅供参考,实际天气可能有所变化。*`; return prompt; } /** * 获取提示词定义(用于注册到服务器) */ getDefinition() { return { name: this.name, description: this.description, arguments: this.arguments, }; } } // 导出提示词实例 module.exports = new WeatherOptimizationPrompt();在MCP服务器中注册提示词:
// server.js - 提示词注册部分 const weatherPrompt = require('./weatherPrompt'); // 注册提示词到服务器 server.setRequestHandler('prompts/list', async () => ({ prompts: [weatherPrompt.getDefinition()], })); server.setRequestHandler('prompts/get', async (request) => { if (request.params.name === 'weather_result_optimizer') { const args = request.params.arguments || {}; // 添加当前时间变量 args.current_time = new Date().toLocaleString('zh-CN'); const promptText = weatherPrompt.generate(args); return { prompt: { messages: [ { role: 'user', content: promptText, }, ], }, }; } throw new Error(`提示词不存在: ${request.params.name}`); });提示词使用示例(客户端调用):
// 客户端调用提示词 async function useWeatherPrompt(client, weatherData) { const promptArgs = { city: weatherData.city, temperature: weatherData.temperature.value, unit: weatherData.temperature.unit, condition: weatherData.condition, humidity: weatherData.humidity, recommendations: weatherData.recommendations, time_of_day: '下午', }; const promptResult = await client.request('prompts/get', { name: 'weather_result_optimizer', arguments: promptArgs, }); console.log('优化后的天气报告:'); console.log(promptResult.prompt.messages[0].content); // 可以将优化后的报告发送给AI模型进一步处理 return promptResult; }提示词模板特点:
- 结构化参数:定义清晰的输入参数和类型约束
- 动态生成:根据天气数据动态生成个性化的天气报告
- 多维度解读:从温度、湿度、天气状况等多个维度提供解读
- 实用建议:包含穿衣指南、活动推荐等实用信息
- 可扩展性:可以轻松添加更多解读维度和建议类型
-
5.3 能力组合演示:展示Client如何联合使用Tool、Resource和Prompt完成复杂任务。
// 客户端组合使用示例 async function completeWeatherTask(client) { // 1. 读取服务器配置资源 const config = await client.request('resources/read', { uri: 'file:///config.json', }); console.log('服务器配置:', config.content[0].text); // 2. 调用天气查询工具 const weatherResult = await client.request('tools/call', { name: 'get_weather', arguments: { city: '北京', units: 'metric' }, }); // 3. 使用提示词优化天气结果 const optimizedReport = await client.request('prompts/get', { name: 'weather_result_optimizer', arguments: { city: weatherResult.city, temperature: weatherResult.temperature.value, unit: weatherResult.temperature.unit, condition: weatherResult.condition, humidity: weatherResult.humidity, recommendations: weatherResult.recommendations, time_of_day: '当前', }, }); // 4. 将优化后的报告发送给AI模型进行进一步处理 const finalResponse = await aiModel.generateResponse( `基于以下天气报告,为用户提供出行建议:\n\n${optimizedReport.prompt.messages[0].content}` ); return { rawWeather: weatherResult, optimizedReport: optimizedReport.prompt.messages[0].content, finalAdvice: finalResponse, }; }组合使用优势:
- 资源提供上下文:客户端先读取配置,了解服务器能力
- 工具执行操作:调用具体的天气查询功能
- 提示词优化展示:将原始数据转化为用户友好的报告
- 端到端自动化:整个流程可以完全自动化,无需人工干预
6. 实战三:打造自定义MCP客户端(Agent核心)
- 6.1 客户端职责:服务发现、工具列表获取、调用决策与执行。
- 6.2 连接多个服务器:实现一个客户端同时连接天气、日历、邮件等多个MCP服务器。
- 6.3 工具调用逻辑:解析模型请求,匹配并调用正确的工具,处理返回结果。
- 6.4 错误处理与降级:网络异常、工具调用
7. 实战四:集成与构建完整Agent工具链
-
7.1 架构设计:绘制基于MCP的AI Agent系统架构图(Mermaid)。
下面是一个基于 MCP 协议的 AI Agent 系统架构图,展示了客户端、多个 MCP 服务器以及外部数据源之间的交互关系:
架构图说明:
-
用户界面/应用层:用户通过自然语言与系统交互,提出需求如"明天北京天气如何?安排会议并邮件通知"。
-
AI Agent 层(MCP 客户端):
- MCP 客户端:作为 Agent 核心,负责连接和管理多个 MCP 服务器。
- 决策与编排引擎:
- 意图理解:解析用户请求,识别需要调用的工具和服务。
- 工具选择:根据意图从可用工具中选择最合适的组合。
- 流程编排:确定工具调用顺序和依赖关系。
-
MCP 服务器层:
- 天气查询服务器:提供天气查询工具、配置资源和天气报告优化提示词。
- 日历管理服务器:提供日历事件创建、查询工具和日历数据资源。
- 邮件通知服务器:提供邮件发送工具、邮件模板资源和内容生成提示词。
- 其他服务服务器:可扩展的其他 MCP 服务器,如文件操作、数据库查询等。
-
外部 API/数据源层:
- 天气 API:如 OpenWeatherMap、和风天气等第三方服务。
- 日历 API:如 Google Calendar、Outlook 等日历服务。
- 邮件服务 API:如 SMTP、SendGrid、AWS SES 等邮件发送服务。
- 数据库/文件系统:本地或远程的数据存储,用于配置、模板等资源。
-
数据流向:
- 请求流:用户请求 → Agent → MCP 服务器 → 外部 API。
- 响应流:外部 API → MCP 服务器 → Agent → 用户。
- 协议:Agent 与 MCP 服务器之间使用 MCP 协议(Stdio/SSE),服务器与外部 API 之间使用相应的 API 协议(HTTP/REST 等)。
-
关键设计特点:
- 松耦合架构:每个 MCP 服务器独立开发、部署和扩展。
- 标准化接口:所有服务器通过统一的 MCP 协议暴露能力。
- 能力组合:Agent 可以灵活组合不同服务器的工具、资源和提示词。
- 可扩展性:新增服务器只需实现 MCP 协议,即可被现有 Agent 发现和使用。
-
-
7.2 工具链编排:如何将多个独立的MCP服务器(数据查询、代码执行、内容生成)通过一个智能客户端(Agent)协同工作。
-
7.3 实战案例:旅行规划Agent
- 服务器1:航班/酒店查询工具。
- 服务器2:本地景点与天气资源。
- 服务器3:邮件/DingTalk消息发送工具。
- 客户端(Agent):理解用户需求,按顺序调用工具,生成旅行计划并通知。
序调用工具,生成旅行计划并通知。
8. 高级主题与最佳实践
- 8.1 性能优化:工具调用的异步处理、结果缓存、连接池管理。
- 8.2 安全考量:工具权限控制、输入验证、敏感信息过滤。
- 8.3 测试策略:单元测试(工具逻辑)、集成测试(客户端-服务器通信)、E2E测试(完整工作流)。
- 8.4 部署与监控:容器化部署、日志记录、健康检查与指标收集。
9. 总结与展望
- MCP协议的价值总结:标准化带来的开发效率提升、生态互操作性。
- 当前生态与工具:介绍社区中优秀的开源MCP服务器(如文件系统、数据库、Git)。
- 未来展望:协议演进方向、在AI应用开发中的更广泛应用。
更多推荐



所有评论(0)