拓冰建站拓冰建站
首页 / 资讯中心 / 正文

MCP协议:统一AI工具调用,打破AI应用孤岛

1. 从“AI孤岛”到“工具互联”为什么我们需要MCP如果你最近在折腾AI应用开发尤其是想让大语言模型LLM去调用外部工具、查询实时数据或者操作你的本地文件那你大概率已经体会过什么叫“混乱”了。你可能试过LangChain发现它内置的工具调用Tool Calling功能虽然强大但一旦你想接入一个LangChain官方没支持的工具就得自己写一个适配器遵循它那套特定的BaseTool接口。或者你用了某个AI应用框架比如Dify或Flowise它们也有自己的工具定义方式。更别提各家云厂商的AI平台都有一套自己的“插件”或“工具”生态。这就导致了一个非常现实的问题你为ChatGPT写的一个工具函数没法直接拿到Claude的API里去用你在本地用LangGraph搭建的一个Agent工作流想换个框架跑工具层就得重写一遍。每一个AI应用框架、每一个模型服务提供商都像是一座“AI孤岛”它们各自定义了与外部世界交互的“方言”。开发者就成了在这些孤岛之间疲于奔命的“翻译官”。这不仅仅是开发效率的问题。它严重限制了AI能力的组合与进化。一个优秀的、能稳定查询天气的工具理应可以被任何需要天气信息的AI Agent轻松调用无论这个Agent是跑在OpenAI的平台上还是Anthropic的模型上抑或是你本地部署的Llama 3。但现在这几乎不可能。所以当Model Context ProtocolMCP出现时它瞄准的正是这个痛点。你可以把它理解为AI世界的“USB协议”或“HTTP协议”。它的核心目标非常简单定义一套统一的、与模型供应商无关的协议让任何AI应用客户端都能以同样的方式发现、描述并调用任何工具服务器。简单来说MCP想做的事是让工具开发者只写一次工具服务Server就能被所有支持MCP的AI应用Client使用让AI应用开发者无需关心工具的具体实现只需按照协议去“发现”和“调用”。这背后是对AI应用开发范式的一次根本性重构——从“为特定平台开发工具”转向“开发通用的工具服务”。2. MCP协议核心三要素资源、工具与提示词模板要理解MCP如何实现“统一”我们需要拆解它的核心组成部分。MCP协议主要围绕三个核心概念来构建资源Resources、工具Tools和提示词模板Prompts。这三者共同构成了AI与外部世界交互的完整上下文。2.1 资源Resources为AI提供可读的“数据文档”资源在MCP中指的是AI可以读取的静态或动态数据。它不是一个可执行的函数而是一个信息的载体。想象一下你有一个数据库或者一个不断更新的日志文件AI需要了解里面的内容才能做出决策。直接让AI去连数据库查SQL是不现实且危险的。MCP的“资源”提供了一种安全、可控的方式将这些数据以文本的形式暴露给AI。一个典型的资源示例服务器状态日志假设你有一个MCP服务器它提供了一个名为readme://server-status的资源。这个资源的URI统一资源标识符是readme://server-status它的内容可能是实时生成的当前服务器状态 - CPU使用率24% - 内存使用率62% - 磁盘空间剩余120GB - 最近一次错误日志[空] - 服务运行时间15天 6小时当AI客户端比如一个运维Agent需要检查服务器健康时它不需要知道如何执行top或df命令它只需要“读取”这个资源。MCP服务器负责以安全的、格式化的文本返回这些信息。资源的特性只读性AI只能读取资源内容不能通过资源直接修改系统状态。这构成了第一道安全屏障。结构化描述每个资源都有名称、描述和MIME类型如text/plain,text/markdown帮助AI理解其内容格式。动态性资源的内容可以是动态生成的。每次AI“读取”时MCP服务器都可以返回最新的数据。在AI工作流中资源常用于提供背景信息。例如在代码分析场景一个MCP服务器可以提供file:///project/README.md资源让AI在开始编码前了解项目概况。2.2 工具Tools赋予AI可执行的“双手”如果说资源是AI的“眼睛”那么工具就是AI的“双手”。工具代表了一个可以执行并可能产生副作用的操作。这是AI与真实世界进行交互、完成任务的关键。MCP中的工具定义非常清晰它严格遵循一个结构化的输入输出模式。每个工具都必须明确声明name: 工具的唯一标识符如get_weather。description: 工具功能的自然语言描述这对于LLM理解何时调用该工具至关重要。inputSchema: 一个符合JSON Schema规范的输入参数定义。这强制要求了调用的类型安全。工具调用深度解析以“发送邮件”为例让我们定义一个send_email工具。它的inputSchema可能如下所示{ type: object, properties: { recipient: { type: string, description: 收件人的邮箱地址 }, subject: { type: string, description: 邮件主题 }, body: { type: string, description: 邮件正文支持Markdown格式 } }, required: [recipient, subject, body] }当AI客户端决定要发送邮件时它会构造一个符合该Schema的JSON对象例如{recipient: userexample.com, subject: 项目周报, body: 本周进展顺利...}然后通过MCP协议调用该工具。MCP服务器收到调用请求后会执行真正的发信逻辑可能是调用SMTP API或发送请求到内部邮件服务然后将执行结果成功或失败信息返回给客户端客户端再呈现给用户或进行下一步决策。工具与资源的关键区别工具执行可能改变系统状态发邮件、写文件、创建订单而资源只是提供信息。这种区分让AI的行为意图更加清晰也便于实施更精细的权限控制。2.3 提示词模板Prompts预置的“对话剧本”这是MCP中一个非常巧妙的设计。提示词模板允许MCP服务器预定义一些复杂的、可复用的提示词Prompt客户端可以随时获取并填充变量后使用。为什么需要这个因为很多高级工具的使用需要精心设计的提示词来引导LLM。例如一个代码重构工具可能不仅需要调用一个refactor函数还需要在调用前给LLM一段特定的指令让它以“资深代码审查员”的身份思考。提示词模板工作流服务器定义模板MCP服务器声明一个名为code_review的提示词模板并描述其用途。客户端获取模板AI客户端如一个IDE插件可以列出所有可用的提示词模板。填充与使用当用户想进行代码审查时客户端向服务器请求code_review模板。服务器返回一个模板字符串其中包含占位符例如“请以{role}的身份审查以下{language}代码{code}”。客户端填充变量客户端将当前代码编辑器的语言、选中的代码片段填充到{language}和{code}中。发送给LLM客户端将填充后的完整提示词发送给LLM如GPT-4得到审查意见。这个过程将提示词工程的部分责任从客户端转移到了工具开发者服务器端。工具开发者最清楚如何使用自己的工具因此由他们来提供最优的提示词模板能极大提升AI使用工具的效果和一致性。3. MCP实战从零构建一个“待办事项”MCP服务器理解了核心概念我们通过一个完整的例子看看如何亲手构建一个MCP服务器。我们将创建一个简单的“待办事项”Todo List管理器。这个服务器将提供一个资源只读地查看所有待办事项。两个工具创建待办事项、标记待办事项为完成。一个提示词模板生成周报总结。我们将使用MCP的官方JavaScript SDKmodelcontextprotocol/sdk来实现。这是目前最流行的实现方式之一。3.1 环境搭建与项目初始化首先确保你安装了Node.js版本18或以上。然后创建一个新项目并安装依赖。mkdir mcp-todo-server cd mcp-todo-server npm init -y npm install modelcontextprotocol/sdk创建一个入口文件server.js。MCP服务器本质上是一个遵循特定标准的进程它通过标准输入输出stdin/stdout与客户端进行JSON-RPC通信。SDK帮我们处理了底层的通信协议。3.2 构建服务器骨架与资源我们从引入SDK和定义内存中的数据存储开始。// server.js import { Server } from modelcontextprotocol/sdk/server/index.js; import { StdioServerTransport } from modelcontextprotocol/sdk/server/stdio.js; import { CallToolRequestSchema, ListResourcesRequestSchema, ListToolsRequestSchema, ListPromptsRequestSchema, ReadResourceRequestSchema, GetPromptRequestSchema } from modelcontextprotocol/sdk/types.js; // 初始化服务器 const server new Server( { name: todo-list-server, version: 0.1.0, }, { capabilities: { resources: {}, // 声明支持资源 tools: {}, // 声明支持工具 prompts: {}, // 声明支持提示词模板 }, } ); // 内存中存储待办事项 let todos [ { id: 1, text: 学习MCP协议, completed: true }, { id: 2, text: 编写示例服务器, completed: false }, { id: 3, text: 测试工具调用, completed: false }, ]; // 1. 实现资源列表和读取 server.setRequestHandler(ListResourcesRequestSchema, async () { return { resources: [ { uri: todo:///list, name: 待办事项列表, description: 当前所有的待办事项, mimeType: text/plain, // 纯文本格式 }, ], }; }); server.setRequestHandler(ReadResourceRequestSchema, async (request) { if (request.params.uri todo:///list) { // 动态生成资源内容 const todoText todos.map(t - [${t.completed ? x : }] ${t.text} (ID: ${t.id})).join(\n); const content 当前待办事项\n${todoText}\n\n总计${todos.length} 项已完成${todos.filter(t t.completed).length} 项。; return { contents: [ { uri: request.params.uri, mimeType: text/plain, text: content, }, ], }; } throw new Error(Resource not found: ${request.params.uri}); });代码解读与注意事项StdioServerTransport是用于命令行交互的传输层这是运行MCP服务器的标准方式。capabilities中声明了服务器支持的功能这里是资源、工具和提示词模板。资源todo:///list的URI是自定义的只要符合URI格式即可。通常使用自定义协议如todo://。ReadResourceRequestSchema处理器中我们根据当前内存数据动态生成文本内容。这里返回的是纯文本但你也可以返回Markdowntext/markdown以获得更好的展示效果。关键点资源处理器必须是幂等的多次读取同一URI应返回相同或更新的内容但不应对系统状态产生副作用。3.3 实现工具创建与更新待办事项接下来我们添加两个工具并处理工具的调用请求。// 2. 实现工具列表和调用 server.setRequestHandler(ListToolsRequestSchema, async () { return { tools: [ { name: create_todo, description: 创建一个新的待办事项, inputSchema: { type: object, properties: { text: { type: string, description: 待办事项的内容描述, }, }, required: [text], }, }, { name: complete_todo, description: 根据ID标记一个待办事项为已完成, inputSchema: { type: object, properties: { id: { type: number, description: 待办事项的唯一ID, }, }, required: [id], }, }, ], }; }); server.setRequestHandler(CallToolRequestSchema, async (request) { const { name, arguments: args } request.params; if (name create_todo) { const { text } args; if (!text || text.trim() ) { throw new Error(待办事项内容不能为空); } const newId todos.length 0 ? Math.max(...todos.map(t t.id)) 1 : 1; const newTodo { id: newId, text: text.trim(), completed: false }; todos.push(newTodo); return { content: [ { type: text, text: ✅ 已创建待办事项 #${newId}: ${newTodo.text}, }, ], }; } if (name complete_todo) { const { id } args; const todoIndex todos.findIndex(t t.id Number(id)); if (todoIndex -1) { throw new Error(未找到ID为 ${id} 的待办事项); } if (todos[todoIndex].completed) { return { content: [ { type: text, text: ℹ️ 待办事项 #${id} 已经是完成状态。, }, ], }; } todos[todoIndex].completed true; return { content: [ { type: text, text: 已完成待办事项 #${id}: ${todos[todoIndex].text}, }, ], }; } throw new Error(未知工具: ${name}); });工具实现的要点与避坑指南输入验证在工具实现内部必须对args进行严格的验证。SDK会进行基础的JSON Schema校验但业务逻辑校验如ID是否存在、内容是否为空需要服务器自己完成。这是保证服务健壮性的关键。错误处理使用throw new Error()抛出错误客户端会收到清晰的错误信息。避免在工具内部崩溃导致整个服务器进程退出。返回格式工具调用必须返回content数组其中包含type为text的对象。这是MCP协议规定的标准响应格式确保客户端能正确解析和显示结果。副作用管理create_todo和complete_todo都修改了内存中的todos数组产生了副作用。在真实场景中这里应该连接数据库并进行事务操作。3.4 实现提示词模板生成周报最后我们添加一个提示词模板用于生成基于待办事项的周报总结。// 3. 实现提示词模板 server.setRequestHandler(ListPromptsRequestSchema, async () { return { prompts: [ { name: generate_weekly_summary, description: 根据当前待办事项生成一份周报总结, }, ], }; }); server.setRequestHandler(GetPromptRequestSchema, async (request) { if (request.params.name generate_weekly_summary) { // 这个模板不需要客户端提供参数但我们可以基于服务器状态动态生成提示词 const completedCount todos.filter(t t.completed).length; const totalCount todos.length; const completionRate totalCount 0 ? Math.round((completedCount / totalCount) * 100) : 0; const promptTemplate 你是一个高效的项目助理。请基于以下待办事项状态生成一份简洁的周报总结突出进展和后续重点。 【待办事项状态】 总计任务${totalCount} 项 已完成${completedCount} 项 完成率${completionRate}% 【任务列表】 ${todos.map(t - ${t.completed ? ✅ : ⏳} ${t.text}).join(\n)} 请生成一份包含以下部分的周报 1. 本周整体完成情况概览。 2. 主要成果列举已完成的重点任务。 3. 待推进事项列举未完成的任务并简要说明卡点或后续计划。 4. 下周初步建议。 要求语气专业、简洁使用分点陈述。; return { prompt: { messages: [ { role: user, content: { type: text, text: promptTemplate, }, }, ], }, }; } throw new Error(Prompt not found: ${request.params.name}); }); // 启动服务器 async function main() { const transport new StdioServerTransport(); await server.connect(transport); console.error(MCP Todo Server 已启动并运行在 stdio 上); } main().catch((error) { console.error(服务器启动失败:, error); process.exit(1); });提示词模板的设计心法动态化注意我们的提示词模板并不是一个静态字符串。它在被请求时会读取当前的todos状态并将数据如完成率、具体任务列表填充到模板中。这使得提示词能基于实时上下文生成更加智能。结构化引导模板中明确要求了周报的格式四个部分和语气专业、简洁。这能极大地提高LLM输出结果的质量和一致性避免了每次都需要在客户端编写复杂的提示词。角色设定模板开头的“你是一个高效的项目助理”设定了LLM的角色这对于生成符合预期的文本非常重要。3.5 运行与测试你的MCP服务器现在我们的服务器已经完成。为了运行它我们需要一个MCP客户端。最方便的测试方法是使用MCP的官方调试工具mcp-cli或者使用已经集成了MCP的AI应用如Claude Desktop。首先通过npm全局安装modelcontextprotocol/sdk的CLI工具如果可用或者更简单的方式是我们直接通过Node运行服务器并手动模拟一个客户端请求。但为了更真实我们介绍如何与Claude Desktop集成。步骤一运行服务器直接运行我们的脚本node server.js此时服务器会阻塞等待通过stdio接收客户端连接。你可能会看到我们打印的启动日志。步骤二配置Claude Desktop以Mac为例打开Claude Desktop应用。进入配置文件夹。通常位于~/Library/Application Support/Claude/claude_desktop_config.json。在配置文件中添加我们的MCP服务器配置{ mcpServers: { todo-list: { command: node, args: [/ABSOLUTE/PATH/TO/YOUR/mcp-todo-server/server.js] } } }注意必须使用Node.js的绝对路径和你server.js文件的绝对路径。重启Claude Desktop。步骤三在Claude中交互重启后在Claude的聊天界面你应该能看到一个“工具”的图标被点亮。你可以尝试以下对话“我有哪些待办事项” - Claude会调用todo:///list资源读取列表。“创建一个待办事项’写项目文档‘。” - Claude会调用create_todo工具。“把ID为2的待办事项标记为完成。” - Claude会调用complete_todo工具。“根据我的待办事项生成一份周报。” - Claude会获取generate_weekly_summary提示词模板填充后发送给模型并返回生成的周报。通过这个完整的例子你应该能清晰地感受到MCP的工作流程客户端Claude通过协议发现服务器我们的Node脚本提供了什么资源、工具和模板然后根据用户需求动态地调用它们。服务器则专注于实现业务逻辑无需关心客户端是Claude、ChatGPT还是其他任何AI应用。4. MCP生态现状、挑战与未来展望MCP的理念非常吸引人但作为一个新兴协议它的生态和应用现状如何在实际落地中又会遇到哪些挑战4.1 当前生态快速生长的早期花园目前MCP生态主要由两部分组成官方与社区开发的MCP服务器以及支持MCP的客户端应用。服务器端Servers官方示例Anthropic提供了一些基础示例如文件系统filesystem、SQLite数据库sqlite服务器展示了协议的基本用法。社区贡献这是生态中最活跃的部分。在GitHub上搜索“MCP”你可以找到大量社区开发的服务器例如搜索引擎类tavily-mcp,brave-search-mcp让AI能进行网络搜索。开发者工具类github-mcp操作GitHubfigma-mcp读取Figma设计稿chromedevtools-mcp浏览器调试playwright-mcp浏览器自动化。效率工具类notion-mcp读写Notion页面slack-mcp发送Slack消息。本地工具类很多开发者将本地脚本如数据处理、系统监控封装成MCP服务器。客户端端ClientsClaude Desktop目前对MCP支持最完善、体验最好的客户端。它原生集成了MCP配置简单交互流畅是体验MCP能力的首选。代码编辑器/IDE插件这是一个极具潜力的方向。想象一下在VS Code中你的AI编程助手能通过MCP直接读取项目文件结构、运行测试、调用构建工具。已有一些早期项目在探索。其他AI应用平台像Cursor、Windsurf等新一代AI原生编辑器也开始关注或集成MCP。一些开源的AI应用框架如ai-shell也正在添加MCP客户端支持。协议实现与SDK官方SDKAnthropic提供了TypeScript/JavaScript和Python的官方SDK大大降低了开发MCP服务器的门槛。我们上面的例子就基于此。第三方实现社区也出现了其他语言的实现如Go、Rust等虽然成熟度不一但显示了社区的广泛兴趣。4.2 核心挑战与开发者决策点尽管前景光明但在当前采用MCP时你需要面对几个现实的挑战1. 协议仍在演进中MCP协议本身尚未达到1.0稳定版本。这意味着未来的版本可能会引入不兼容的更改。对于生产环境这需要谨慎评估。不过目前的核心概念资源、工具、提示词已相对稳定主要变化可能在于性能优化和高级特性增加。2. 安全与权限模型的细化MCP协议定义了交互的“语法”但“语义”层面的安全很大程度上依赖于实现。例如工具调用的权限一个文件系统MCP服务器是允许AI删除任何文件还是只允许操作特定目录这需要在服务器实现时做严格的路径白名单校验。资源访问的控制哪些资源可以暴露给AI包含敏感信息的数据库表是否应该作为资源提供提示词模板的滥用一个设计不当的提示词模板可能会诱导LLM产生有害输出。目前这些安全策略都需要服务器开发者自行设计和实现。一个最佳实践是遵循最小权限原则。服务器默认只提供最安全、最必要的能力并通过配置项让最终用户或系统管理员来决定启用哪些高风险功能。3. 性能与通信开销MCP通信基于JSON-RPC over stdio/HTTP/SSE这对于频繁的、小型的工具调用如简单的计算、状态查询是合适的。但对于需要传输大量数据如上传/下载大文件、传输图片或需要低延迟流式响应的场景当前的协议可能不是最优选择。开发者可能需要考虑将大数据的传输通过资源提供下载链接或工具返回处理后的摘要的方式进行折中。4. 开发与调试体验调试一个通过stdio通信的MCP服务器有一定门槛。你需要查看标准错误输出或者实现更复杂的日志系统。社区正在开发更好的调试工具但在成熟之前这可能会增加开发周期。4.3 MCP vs. 其他方案并非替代而是互补很多人会问有了LangChain的Tool Calling为什么还需要MCP它们之间是什么关系我的理解是它们解决的是不同层面的问题并非互斥而是互补甚至未来可能融合。LangChain Tool Calling是一个应用框架层面的工具调用抽象。它主要解决的是“在一个Python或JS应用内部如何让LLM方便地调用我写好的函数”的问题。它的优势在于与LangChain生态深度集成如果你已经在用LangChain构建复杂的Agent工作流用它内置的工具调用非常方便。MCP是一个跨进程、跨平台、跨供应商的协议标准。它解决的是“如何让我写的工具服务能被世界上任何支持此协议的AI应用使用”的问题。它不关心你用什么语言实现服务器可以是Python、Node.js、Go也不关心客户端是什么Claude、VS Code插件、自定义AI前端。一个更形象的比喻LangChain Tool Calling像是你家里一套好用的瑞士军刀工具都在手边方便而MCP像是建立了一套全球通用的电源插头标准USB-C让你家的电器工具可以插到世界上任何一个符合标准的插座AI应用上使用。实际上我看到的发展趋势是融合。已经有项目在探索如何将LangChain Tools适配成MCP服务器或者让MCP服务器在LangChain中作为Tool被调用。未来开发者可能用LangGraph编排复杂的AI工作流客户端而工作流中的某些节点通过MCP协议去调用部署在远端或本地的专用工具服务服务器。这样既利用了LangChain在编排上的优势又获得了MCP在工具生态互通上的好处。4.4 未来展望AI时代的“应用商店”雏形MCP的终极愿景是成为AI原生时代的“协议层”。如果这个协议被广泛采纳我们可以预见工具市场的诞生会出现一个集中的“MCP服务器市场”或“工具商店”。开发者可以发布自己编写的通用工具服务器如高级数据分析、专业图像处理、特定API集成用户只需一键配置就能让自己使用的所有AI助手获得这些能力。专业化工具服务的兴起公司或社区可以开发和维护非常专业的MCP服务器比如“法律文书分析MCP”、“医疗影像初步解读MCP”。这些服务器封装了领域知识和安全边界通过标准的MCP协议为各种AI前端提供专业服务。客户端体验的统一用户不再需要为每个AI应用学习不同的插件系统。只要应用支持MCP用户就可以用同一套方式管理添加、删除、配置所有的工具。本地优先与隐私保护MCP服务器可以完全运行在本地。你可以有一个本地运行的“个人文件管理MCP”让AI助手帮你整理文档而所有数据都不会离开你的电脑。这为注重隐私的用户提供了强大的解决方案。5. 给你的实践建议现在该如何入手如果你是一名开发者被MCP的理念所吸引我建议你可以按以下路径开始探索第一步先做用户体验魔力去下载Claude Desktop找几个有趣的社区MCP服务器比如github-mcp,sqlite-mcp按照教程配置好。亲自体验一下AI如何通过统一的界面操作你的GitHub仓库或查询本地数据库。这种“开箱即用”的体验是理解MCP价值最快的方式。第二步从“包装”现有脚本开始不要一开始就想设计一个庞大的系统。找一个小而实用的本地脚本比如你有一个Python脚本用来压缩指定文件夹的图片或者一个Shell脚本用来清理下载目录。尝试用MCP SDK把它包装成一个服务器。这个过程会让你快速掌握MCP服务器的基础结构、工具定义和错误处理。第三步深入理解协议细节阅读MCP的官方协议文档。虽然SDK屏蔽了大部分通信细节但了解底层的JSON-RPC消息格式、连接初始化过程、错误码定义对你调试复杂问题和未来贡献社区非常有帮助。特别是理解initialize、tools/list、tools/call这几个核心请求/响应的数据结构。第四步参与社区关注演进在GitHub上关注modelcontextprotocol官方仓库以及一些高星的社区服务器项目。看看别人是如何设计工具接口、处理安全性和管理复杂状态的。社区是学习最佳实践和了解协议最新动态的最佳场所。第五步在具体项目中谨慎评估当你要为一个真实项目引入MCP时问自己几个问题工具是否需要被多种不同的AI前端使用如果是MCP的收益很大。工具逻辑是否足够复杂值得作为一个独立服务部署简单的工具可能用应用内函数更直接。团队是否有能力维护一个长期运行的服务器进程这涉及到部署、监控、升级等运维成本。协议稳定性是否可接受对于追求绝对稳定的企业级生产环境可能需要等待协议更加成熟。从我个人的实践来看MCP代表了AI应用架构中一个非常正确的方向——解耦与标准化。它可能不会完全取代现有的框架内工具调用方式但它为解决“AI工具生态碎片化”这个根本性问题提供了一条清晰且可行的路径。现在入手学习正是站在一个充满潜力的新生态的起点。
分享:

看完干货,该让你的企业上线了

免费需求沟通 · 48 小时内出具建站方案 · 河南本地可上门