ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

MCP协议白话解析:AI应用连接数据与工具的标准方式

MCP协议白话解析:AI应用连接数据与工具的标准方式

还记得第一次做AI应用集成的那一周吗?光是让模型能查数据库、读文件、调API,我就折腾了两天——不是模型不给力,而是每个AI应用都有一套自己的工具对接方式:有的把工具描述塞进Prompt,有的要用私有格式写解析器,有的干脆只认自家生态。那时候我就想,这一行迟早需要一个“标准插座”。

现在,这个“标准插座”已经有了,就是MCP,全称Model Context Protocol,模型上下文协议。很多人第一次听到这名字,会本能地问一句:它到底是个协议还是个框架?其实它既不神秘也不复杂——本质上就是一套让大模型、AI应用和外部数据/工具之间“按规矩说话”的公共语言。你可以把它理解成AI世界的USB-C口:一头连着大模型和AI应用,另一头连着数据库、文件系统、Web服务、企业内部系统,插上就能通电干活。

这篇文章我用最白话的方式,把MCP的原理和作用从头到尾捋一遍。不堆术语,不背书,主要面向两类读者:正在做AI应用集成、天天和各种接口打交道的开发者;以及知道MCP很火、但始终没想明白它到底解决什么问题的产品经理和技术负责人。看完这篇文章,你会知道MCP里有哪几个角色、消息是怎么流转的、一次工具调用的完整过程、它和Function Calling到底有什么区别,还有实际落地时常见的坑。

1. MCP为什么会出现:AI应用连不上“外部世界”的痛

1.1 一个让人头疼的接入现场

先还原一个场景。假设要做一个智能客服助手,用户问“我的订单发货了吗”,AI得先查出订单状态,再组织语言回答。这个过程中,AI需要做三件事:理解用户问题、调取外部系统中的订单数据、把结果转化成自然语言。

调取外部数据这一步,就是接缝所在。订单数据存在哪?可能在MySQL里,可能在某个内部管理系统的API里,也可能在SAP这类企业软件里。最开始的做法是:给模型写一个工具函数,把工具的名字、功能、参数格式用JSON描述出来,告诉模型“当用户问订单状态时,调用这个工具”。模型分析完用户意图之后,生成了参数,代码再拿着参数去调数据库、调API。

听起来还行?那再想想,这个“工具描述”应该用什么格式?是OpenAI风格的JSON Schema,还是别的什么风格?每个大模型平台的标准都不一样。今天接的是A平台的模型,明天换成B平台的模型,那套工具描述基本得重写。同时,模型厂商自己也会不断更新工具调用格式,升级一次,你的接入代码就得跟着改一次。这种碎片化的接入方式,对于只有一两个工具的小应用来说还能忍;工具一多、系统一复杂,维护成本就直线上升。

1.2 AI应用的三大刚需:数据、工具、记忆

抛开具体技术不谈,任何一个稍微复杂一点的AI应用,都有三个绕不开的需求。

第一,它需要访问数据。模型自身的训练数据是有截止时间点的,而且大部分是企业私有数据。AI要真正回答具体问题,必须能查数据库、读文件、看网页。

第二,它需要操作工具。AI不能只“知道”订单状态,用户还希望它“修改订单备注”“发起退货流程”“给客户发一封邮件”。这些动作都需要调用外部系统完成。

第三,它需要上下文。一个有效回答,依赖完整上下文——用户当前说了什么、之前聊过什么、相关的业务数据是什么。这个“上下文”不仅仅指对话历史,也包括AI从外部系统里取回、拼进推理过程的信息。

这三个需求,每个都值得一套专门方案:数据访问需要连接器,工具调用需要协议,记忆管理需要存储机制。在没有统一标准的时候,每个AI应用都要自己发明一套轮子。这就是MCP出现前,应用开发者的真实状态。

1.3 碎片化接口的代价

碎片化带来了几笔很现实的开销。

开发成本上,同一个工具要与不同的AI应用分别对接。一个数据库查询功能给应用A写一套实现,给应用B再写一套,代码重复率极高。维护成本上,模型升级、接口变化、系统迁移都会引发连锁修改。最要命的是生态成本:一个开发者为某个AI应用写好的工具,另一个应用完全没法复用;工具提供商也无从下手,因为不知道要为多少个平台各做一份适配。

这个格局像什么?像早年各种电子产品都有自己的充电接口:这款手机用A口,那款设备用B口,出门得带好几根线。后来USB-C逐渐统一了充电和数据传输接口,大家才终于松了一口气。MCP要解决的就是AI应用场景里的“接口统一”问题。

2. MCP到底是个什么:三个角色一台戏

2.1 官方定义翻译成人话

MCP的官方定义是:一种开放协议,用于标准化AI应用与外部数据源、工具之间的通信方式。听起来有点绕,用人话翻译就是:AI应用通过MCP,可以像插U盘一样,随时连接到外部服务,而不需要知道这个服务的内部实现细节。

从协议栈的角度看,MCP并不算复杂。它建立在JSON-RPC 2.0之上,这是一个成熟、轻量的远程调用协议,规定了客户端怎么发起请求、服务端怎么返回响应。MCP在里面新增了一些面向AI场景的方法,比如列出工具、调用工具、读取资源、获取提示词。所以学习MCP不需要什么高深的基础,只要理解JSON-RPC的基本套路,再看MCP的方法定义就八九不离十了。

2.2 三个角色搞清楚:Host、Client、Server

MCP架构里一共三个角色,理解了这个三层结构,就理解了MCP的一半。

Host(主机):用户所面对的那个AI应用。它可以是聊天机器人、IDE编辑器、自动化工作流平台、智能终端应用等。Host是整个交互的中枢,负责接收用户输入、调用大模型、向用户展示最终结果。

Client(客户端):每个Host内部或者旁边会运行一个或多个MCP Client,它是Host与外部MCP Server之间的连接器。一个Host可以同时对接多个Client,每个Client连接一个Server。Client负责发起协议握手、转发调用请求、接收结果,并把这些数据交还给Host。

Server(服务端):真正“干活”的一方。MCP Server负责把外部世界的能力和数据,暴露成标准化的接口给AI应用使用。比如一个“订单系统MCP Server”,背后连的是订单数据库和业务API,但对Host只暴露几个标准的MCP方法:读取订单、更新订单、查找物流等。

这三者的关系,很像“操作系统-驱动的匹配关系”:Host是操作系统,Server是打印机,Client就是操作系统里安装的打印机驱动。内核不需要知道打印机内部结构,只要驱动遵守统一标准,就能把文档打印出来。

2.3 一种核心抽象:MCP Server内部有什么

一个MCP Server对外提供的能力,正式地讲,被抽象成了三种类型:Tools、Resources、Prompts。

Tools是“动作型”能力。它对应具体操作,比如“运行一段SQL”“发送一封邮件”“创建一条工单”。Tools和模型直接打交道,模型判断需要执行某个操作时,就会让Host调用对应的Tool。这是最常用、最核心的能力类型。

Resources是“数据型”能力。它向AI提供可读取的上下文内容,比如一个文件的内容、一张表的结构、一份配置信息。Resources通过类似文件系统的URI来标识,例如file:///project/readme.md、database://orders/schema。

Prompts是“模板型”能力。它是一段可复用的提示词模板。用户选中模板后,Host会把它转换成具体的对话上下文。有点像一个“快捷指令”库,把那些每次都要写一遍的提示词封装成可复用的模板。

把视角拉高一点,这三种能力其实对应了AI应用的基本诉求:Tools管“干”,Resources管“读”,Prompts管“怎么组织思路”。MCP的设计者用这三种抽象,把外部世界的能力都收拾得井井有条。

3. 白话拆解MCP的核心机制:请求、发现与上下文注入

3.1 通信协议:一切从JSON-RPC 2.0说起

MCP的底层传输,采用的就是JSON-RPC 2.0。这个协议本身很简单:客户端向服务器发送一个JSON格式的请求,带上方法名和参数;服务端处理完,返回一个JSON格式的响应,带上结果或错误信息;两边通过一个递增的id来匹配请求和响应。

MCP的请求消息长这样:

{ "jsonrpc": "2.0", "id": 1, "method": "tools/call", "params": { "name": "query_orders", "arguments": { "customer_id": "C10086", "status": "shipped" } } }

响应则长这样:

{ "jsonrpc": "2.0", "id": 1, "result": { "content": [ { "type": "text", "text": "查询到3条已发货订单,最近一条发货时间是2025年1月10日。" } ], "isError": false } }

“tools/call”是MCP定义的一组方法名中的一个。看到这个格式,你会发现MCP并不发明新的RPC机制,而是在成熟协议上约定了一套面向AI场景的方法。这有什么好处?最大的好处是生态兼容性好:任何支持JSON-RPC的工具和库,都能无缝支持MCP,降低了接入门槛。

3.2 能力发现:MCP的自我介绍环节

MCP里有一个非常关键的环节,叫能力发现,官方叫Capability Discovery。简单来说,就是Client连接上Server之后,Server得先进行一次自我介绍:我这儿有哪些工具?每个工具是干什么的?参数怎么传?

具体流程是:Client向Server发送initialize请求做握手,交换协议版本和能力信息;然后Client发送tools/list请求,获取服务器支持的工具列表;Server返回一个JSON数组,每个工具都附带了名称、描述和参数Schema。这一步做完,Client才真正知道该怎样去调用这个Server。

为什么能力发现这么重要?因为大模型是不知道外部系统内部结构的。它必须通过工具列表来理解自己能做什么,就像一个人进入新工作环境,得先看一遍岗位说明书,才知道自己能干哪些活儿。没有这个步骤,模型就只能瞎猜,效果自然很差。

工具列表里,每个工具大概长这样:

{ "name": "query_orders", "description": "根据客户ID查询订单列表,支持按状态筛选", "inputSchema": { "type": "object", "properties": { "customer_id": { "type": "string", "description": "客户编号" }, "status": { "type": "string", "enum": ["pending", "shipped", "done"] } }, "required": ["customer_id"] } }

模型看到这个定义之后,会在回答用户问题时,自动判断“用户意图对应哪个工具”,从而生成合适的调用参数。

3.3 上下文注入:把外部信息塞进推理管线

MCP的另一个核心作用,就藏在它名字里的“Context”这个单词里——上下文注入。

大模型的每一次回答,本质上是在一个上下文窗口里进行推理。上下文里有什么,模型就知道什么。所以,要做AI应用,一项核心能力就是:把用户问题相关的、来自外部系统的信息,在恰当的时机注入到上下文里。

MCP把这件事标准化了。比如用户问“我的订单到哪了?”Host收到这个问题后,通过Client向订单系统的MCP Server发起调用,拿到物流信息;物流信息作为新增的上下文,被拼接到对话中;模型基于“用户问题+新增的物流上下文”生成最终回答。

关键点在于,这个拼接流程在MCP的标准下是可以复用的。无论是接订单系统,还是一个Wiki系统,流程都一样:发现问题对应工具,调用工具,把结果注入上下文。你不需要为每个新系统设计一套新的上下文拼接逻辑,框架已经帮你在协议层解决了。

3.4 消息编排:一组常用的MCP方法

能力发现和上下文注入,是通过一系列标准方法实现的。常用的MCP方法可以整理成一张表:

方法名作用调用时机
initialize协议握手,交换能力和版本建立连接时
tools/list获取服务端支持的工具清单模型需要了解可用能力时
tools/call执行工具调用模型决定调用外部工具时
resources/list获取可用资源的列表Client初始化或定期同步
resources/read读取指定URI指向的资源内容需要将资源注入上下文时
prompts/list获取可用的提示词模板列表用户选择模板或自动匹配时
prompts/get根据模板ID获取渲染后的提示词需要模板展开成上下文时

这套方法设计有一个共通特点:每类操作都分“列表”和“读写”两步。先列清单,再操作具体项。这样做的好处是,Client可以始终保持对Server能力的了解,而不用在每次调用之前重新发现。

4. 一次工具调用的完整流转过程

4.1 从用户问一句“订单到哪了”说起

语言层面讲了那么多,我们把它串成一个完整的例子走一遍。用户在某应用里发了一句:“帮我看看订单C10086现在到哪了?”接下来,MCP协议栈里会发生一连串事件。

第一步,Host里的对话管理器接收用户消息,把它交给大模型处理。此时模型还不知道订单C10086是什么,它接到的只是用户的一句话。

第二步,模型处理到一半,意识到“要查物流状态,需要一个查询工具”。于是它查看当前可用的工具清单——这个清单是本次会话开始时,Host通过MCP Client从订单系统Server那里获取到的。工具描述里写了“根据客户ID和订单号查询物流轨迹”,模型判断这个工具正合适。

第三步,模型生成一个工具调用。这通常是一段结构化指令,包含工具名和参数。比如:

{ "type": "function_call", "name": "query_logistics", "arguments": { "order_id": "C10086" } }

4.2 Host侧触发MCP调用

模型生成了调用意图之后,Host不会直接把这段指令扔向远端系统。它会把这指令交给对应的MCP Client,由Client把它包装成JSON-RPC请求,通过配置好的传输通道发往MCP Server。

传输通道有两种常见形式。本地场景用stdio,即Client直接启动Server进程,通过标准输入输出流传递JSON消息;远程场景用HTTP+SSE,Client通过HTTP请求把JSON-RPC消息发给Server,Server通过SSE(Server-Sent Events)把结果推回来。这两种传输方式覆盖了“本地进程”和“远端服务”两大主流场景。

请求发到Server那一侧,Server收到tools/call请求,从params里解出工具名和参数,定位到内部对应的业务函数,开始查数据库、调API,把真实物流数据抓回来。

4.3 结果回传与二次生成

业务函数查到物流轨迹后,Server把结果包装成MCP响应返回给Client。响应内容通常包含一段或多段文本,每段文本可以标成text类型,也可以带一些结构化元数据。Client收到响应,把内容交回Host。

到这里,工具调用本身已经完成,但对一次AI交互来说,还差最后关键一步:模型得基于工具返回的结果,生成用户能看懂的话。Host会把工具返回值拼接进对话上下文,连同原始用户消息一起,再次交给大模型。

模型此时看到了物流信息:“2025年1月10日已从分拨中心发出,目前在运输途中。”它结合用户问题,生成一个自然、友好的回答:“您的订单C10086昨天已从上海分拨中心发出,预计1月13日送达,请保持电话畅通。”用户看到的是最终回复,但背后其实完成了两轮模型推理,中间隔了一次MCP工具调用。

4.4 失败怎么办:MCP的错误处理思维

工具调用不可能永远成功。后端系统可能超时,SQL可能报错,参数可能不合法。MCP对错误的处理方式很值得学习:它把错误当作正常结果返回,而不是让协议崩溃。

正常结果: { "result": { "content": [...], "isError": false } } 执行失败: { "result": { "content": [ { "type": "text", "text": "订单不存在或已被删除" } ], "isError": true } }

你注意,即使业务失败,它也会result正常返回,只是isError为true。这样做的原因很实际:大模型读到错误文本之后,可以生成“抱歉,我查不到这个订单”这样的回复,甚至自动换个工具重试。如果协议层面直接抛异常,交互就断掉了。把业务错误放在消息体里,交给模型去消化,正好符合AI应用的工作方式。

5. MCP和Function Calling到底差在哪

5.1 Function Calling本身解决什么问题

提到MCP,绕不开Function Calling(函数调用)。这是主流大模型早已具备的能力:模型在生成回答时,可以输出一个结构化指令,告诉宿主程序“去调用某个函数,并给它传这些参数”。宿主程序执行完后,再把结果返回给模型。

这个机制本身解决了一个关键问题:大模型终于可以“动手”而不只是“动嘴”了。它给所有的AI应用打开了一道大门,让模型能嵌进真实业务流程。

但Function Calling有一个很大的限制:它是个机制,不是个协议。每个模型平台的函数调用格式都有差异:有的用嵌套JSON,有的用数组,有的用特殊标记。而且调用规则、参数Schema的写法也不通用。你为A平台写的函数定义,拿到B平台上未必能跑。

5.2 MCP的升级之处:四大变化

MCP本质上是把Function Calling从“各家私有格式”变成了“开放标准协议”。两者的核心区别可以用一张表说清:

对比维度Function CallingMCP
标准化程度各平台私有格式,互不通用开放协议,统一JSON-RPC格式
工具发现由宿主硬编码注入模型上下文服务端自动“报菜单”,动态发现
复用性每个应用单独实现,难复用同一Server可被任意Host复用
连接方式代码内直接调用,通常进程内支持本地stdio和远程HTTP+SSE
工具范围主要是代码函数函数、资源、提示词模板,覆盖更广
生态角色模型厂商各自为政工具提供商一次开发、处处部署

可以这么理解:Function Calling是“单个模型内部的一种能力开关”,MCP则是“不同模型、不同应用之间的一种互操作标准”。MCP把函数调用从模型内部解耦出来,变成了应用和外部系统之间的通用契约。

5.3 两者关系:不是替代,是协同

很多人以为MCP会取代Function Calling,实际运行中更常见的形态是协同合作。

大模型内部依然有它的函数调用机制,这是模型理解工具的基础能力;MCP在外部把“工具是什么”“怎么调用”“结果怎么回”标准化。Host内部逻辑大致是:模型通过Function Calling机制输出调用意图,Host把意图翻译成MCP协议请求,发给Server执行,再把结果交回模型生成回复。

所以,MCP不是推翻模型已有的函数调用能力,而是在函数调用之后补上了一段“标准化传输通道”。对开发者来说,好处很实在:以后换模型、换应用,只要对方支持MCP,你自己的那套Server几乎不用动。

6. MCP实际能干什么:几个看得见摸得着的场景

6.1 让AI真正会“查库”和“读文件”

最基础的用途,就是给AI配上数据库和文件系统的访问能力。过去你想让AI帮你查一张业务表,必须专门为此写一个查询函数,还要按所在平台的格式描述给模型看。现在用MCP,只需要一个“数据库查询Server”,它对外暴露query工具,工具描述写明“输入SQL,返回查询结果”。

不同AI应用想接数据库,只要各自配置一个MCP Client指向这个Server就行。Server本身可以独立部署,支持多个应用共享。文件读取场景也一样,做一个文件系统Server,通过resources/read方法把文件内容暴露给模型,模型就能直接“看”到指定文件的内容,而不需要你手动把文件粘贴到对话窗口里。

6.2 把AI接入企业业务系统

企业场景里,MCP的价值更明显。想象一家公司内部有CRM、ERP、工单系统、知识库、文档中心——想让AI助手统一处理这些系统的事务性操作,按照传统做法,每个系统都要单独对接一次。

如果每个系统都提供一个MCP Server,统一暴露标准接口,那么AI助手只需要通过MCP Client与各个Server连接,就可以统一调度:用户问“帮我查一下A客户的合同进度”,AI转给CRM的MCP Server;用户说“把这份文档存入技术知识库”,AI转给文档中心的知识库Server。这种架构的最大好处是:系统间的耦合被协议层切断,任何一个系统的Server更新不影响AI应用本身。

6.3 上下文管理:从一次会话到“始终在线”

前面重点讲了请求-响应模型,其实MCP对上下文的管理不止于此。在协议层面,MCP定义了“上下文”在一段时间内的持续性:Client与Server可以维持长连接的会话,允许Server推送状态变化,Host实时感知外部系统的更新。

举个例子。一个项目管理AI助手,通过MCP Server连接着项目进度数据库。当数据库里的任务状态发生变化时,Server可以主动推送事件。Host收到事件后,可以决定是否把新状态注入上下文,并向用户发出提醒:“你负责的迭代开发任务状态更新为已上线。”这让AI应用从一个“人问它答”的被动工具,变成了一个“眼观六路”的主动助手。

6.4 开发工具与自动化流水线

MCP目前落地最活跃的场景之一,其实是开发工具领域。主流IDE和代码编辑器已经支持通过MCP连接外部工具,比如代码仓库管理、问题跟踪、CI/CD流水线等。

一个很典型的场景:开发者在编辑器里和AI讨论代码时,AI可以通过MCP直接访问Git仓库的Issue列表,甚至可以创建Pull Request。整个过程在对话流里无缝完成,不需要切出工具去操作。对自动化流水线而言,MCP还能串起多步骤任务:AI拿到需求文档,通过MCP读取设计规范,再通过另一个MCP调用代码生成服务,最后把生成结果写入指定代码仓。整个流程的每个环节,都通过协议连接到不同的Server,组件化搭建,各干各的活。

7. 落地实践:部署MCP时容易踩的坑

7.1 传输方式怎么选:stdio还是远程

MCP Server的部署方式直接牵涉到传输选择。如果Server和应用部署在同一台机器上,用stdio最简单:Client启动Server进程,通过标准输入输出通信,不需要开网络端口,安全性和隔离性都更好。但stdio模式下,Client和Server的进程是一对一的,一个Server实例只能服务一个Client,如果多个应用想共享一个Server,就别用stdio。

跨机器、多租户的场景,用HTTP+SSE更合适。Server独立部署成Web服务,多个应用远程连接。这里有几个容易踩的坑:HTTP通道通常需要自己处理鉴权;SSE长连接如果中间经过反向代理,要配置好代理的超时时间,否则连接很容易断开;不建议随便暴露到公网,至少加上Token校验。

7.2 安全边界:别让AI乱闯数据库

MCP把外部系统的能力暴露给AI之后,安全问题就得跟着上心。我见过不少团队,为了图方便,把数据库查询Server的工具描述写得很宽,结果AI基于模糊的意图生成了全表扫描SQL,把一个生产库查得差点宕机。

建议的做法,是把权限边界做在Server内部。工具层面要细化,不要暴露“执行任意SQL”这种危险工具,而是暴露“按客户ID查询订单”“按订单号查询物流”这种语义明确的工具;数据库账号权限最小化,Server只用一个只读账号,需要写入操作时单独配置一个受控的写入工具;再就是对工具调用做审计,记录谁在什么时候调用了哪个工具、传了什么参数。安全问题的关键不在于AI是否“有意识作恶”,而在于工具是否被设计成可以被滥用,这个问题前置到Server端解决,性价比最高。

7.3 排错三板斧:查握手、查清单、查返回

MCP出问题的时候,先别急着看模型生成的回复。按照下面的顺序排查,大部分问题都能定位。

第一斧,查握手。Client和Server连接不上,先看initialize请求有没有成功。用调试工具或日志确认两边协议版本是否一致、传输通道是否连通。

第二斧,查工具清单。模型“乱调用工具”甚至“不知道有工具”,先看tools/list返回内容。工具描述写得是否清晰?参数Schema是不是有误?工具清单为空,模型就只能睁眼瞎。

第三斧,查返回体。工具调用报错,看返回内容里的isError标记和文本描述。很多错误信息就藏在返回文本里,比如“列名不存在”“订单号格式错误”,把这些文本原样抛给模型,模型反而能给出更合理的处理。

我实际调试中,最多的问题来自工具描述写得含糊。模型选错了工具,看起来是“模型不够聪明”,实际上是“工具说明写得不够清楚”。把工具描述当成写给一个聪明但没经验的新同事看的说明书,每一句话都要准确、无歧义。

7.4 我的选型建议

最后给一个实用建议。如果你的项目只有一个AI应用,配一个数据源,MCP带来的增量价值有限——直接用普通代码调用更轻量。但如果有多个AI应用要共享同一批工具、或者计划让外部团队为你的平台开发扩展能力,那就值得从一开始就把MCP架构搭起来。

围绕MCP的框架和SDK,目前在主流编程语言里都有比较成熟的实现,生态正在快速补齐。选择时优先关注框架对协议版本的兼容性和文档完善度,不要被某个大而全的框架绑架,尽量选择可替换的实现。这样等到协议更新或生态变化时,你还能保留换轮子的余地。

我个人的体会是:MCP最好的用法,不是一次性把所有的工具都暴露出来,而是从一两个核心工具开始——比如先接一个查询工具,把一个完整的请求-响应链路跑通,再逐步往外拓展。链路通了,后面的工具接入就是重复劳动;链路没通,工具做再多都是白搭。MCP的价值从来不在“多”,而在“通”,这条原则,适用于任何一个正在引入MCP的团队。

RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进