当一个AI助手能解释报错、整理文档之后,我们很容易继续提出要求:帮我查一下最新订单状态,再结合知识库说明应该怎么处理。
这时,模型需要面对应用外部的数据与操作。订单来自业务系统,知识来自文档,查询还受用户权限约束。每接入一个系统,都需要描述能力、组织参数、执行调用,再把结果送回助手。
**MCP(Model Context Protocol,模型上下文协议)**把其中一部分接入约定标准化。对于后端开发者,值得关注的是它如何把已有服务的能力组织成AI应用可以发现和调用的接口,以及接入后还剩哪些工程问题。
本文以2025-11-25版MCP规范为讨论基线,资料核对日期为2026年9月19日。这里的"新兴"指AI应用工具生态的发展方向,不代表协议刚在今天发布;草案中的变化不当作本文基线能力。
一、从一个订单查询场景开始
假设我们要做一个售后助手,用户问:"订单DEMO-1024到哪里了?"
一个合理的实现可以分为几步:助手识别查询意图,获得可用的订单查询工具定义,生成参数;应用在权限范围内调用工具;服务端查询业务系统;助手根据返回结果组织答复。
在这个流程里,模型可以帮助选择工具与整理语言,订单状态仍然由业务系统提供。它没有因为接入MCP就拥有数据库的全部权限,也没有自动获得业务事实的正确性保证。
我的理解是:当团队已经有一批接口,又希望它们被不同AI应用复用时,统一工具接入方式才开始体现价值。单个小脚本直接调用函数也能工作,是否引入协议层,应根据接入规模与维护成本判断。
二、Host、Client与Server分别负责什么
依据该版本的架构规范,可以把三个角色放在下面的位置:
| 角色 | 本文场景中的位置 | 核心责任 |
|---|---|---|
| Host | 用户使用的AI助手应用 | 组织交互、模型调用与连接权限 |
| Client | Host内部的协议连接组件 | 与某个Server协商能力并交换消息 |
| Server | 订单工具服务 | 暴露并执行明确的工具能力 |
一个Host可以管理多个Client;在这套架构中,一个Client与一个Server建立对应关系。Server可以是本地进程,也可以是远程服务。
为了便于理解,可以把Client看成Host里负责这一路连接的接口适配组件。模型本身不等同于Client,Server也不一定是另一个大模型。一个只查询订单状态的普通后端服务,就可以提供MCP能力。

图中MCP标在通信连线上,表示协议约定;一个Host还可以管理更多Client连接。
现有REST接口可以继续保留,由MCP Server封装调用。这是本文建议的渐进接入方案:业务规则仍留在原系统,协议层负责将合适的能力暴露出来。
三、Tools、Resources与Prompts:三个入口
1. Tools:可以请求执行的能力
例如get_order_status,用订单编号查询状态。工具有名称、描述和输入结构,客户端通过tools/list发现工具,通过tools/call发起调用。
工具是否只读、会不会产生外部影响,应在设计时讲清楚。"查询物流"和"取消订单"虽然都可以包装成工具,它们的授权与交互要求显然不同。工具机制与消息字段见Tools规范。
2. Resources:可以读取的上下文
例如一份售后政策文档或数据库结构说明。资源通过URI标识,应用可以获取内容并决定如何把它加入上下文。
资源适合表达"这里有一份可读取的信息"。把哪些信息交给模型、读取多少、是否需要缓存,仍由具体应用安排。参见Resources规范。
3. Prompts:可以复用的交互模板
例如"根据订单信息整理一份售后处理摘要"的模板。Server可以提供模板及参数,由客户端获取相应消息。
模板帮助统一任务的输入组织方式。它不会替应用完成权限检查,也不保证模型一定遵循每一条描述。参见Prompts规范。
实践中不必为了覆盖全部概念而同时实现三类能力。一个边界清楚的只读查询工具,就足以验证接入流程。
四、看懂一次工具调用的消息
下面是教学用消息示例,工具名称和订单数据均为虚构,没有连接真实业务系统。这里只展示初始化完成后的工具发现与调用阶段,不是可以省略握手直接发送的完整会话。
客户端查询可用工具:
json
{"jsonrpc":"2.0","id":1,"method":"tools/list","params":{}}
服务端可以返回这样的工具定义:
json
{
"jsonrpc": "2.0",
"id": 1,
"result": {
"tools": [
{
"name": "get_order_status",
"description": "查询当前已认证用户有权查看的订单状态,只读。",
"inputSchema": {
"type": "object",
"properties": {
"orderId": { "type": "string" }
},
"required": ["orderId"],
"additionalProperties": false
}
}
]
}
}
客户端发起一次调用:
json
{
"jsonrpc": "2.0",
"id": 2,
"method": "tools/call",
"params": {
"name": "get_order_status",
"arguments": { "orderId": "DEMO-1024" }
}
}
示意响应:
json
{
"jsonrpc": "2.0",
"id": 2,
"result": {
"content": [
{ "type": "text", "text": "订单DEMO-1024已发货,物流状态为运输中。" }
],
"isError": false
}
}
inputSchema描述参数的形状,并不证明这位用户有权查询该订单。服务端应从可信的认证上下文取得身份,再检查订单归属;不应让模型传一个userId就决定访问权限。
同样,返回了JSON也不意味着数据已经足够可靠。业务结果还可能涉及数据更新时间、部分字段缺失、下游超时等情况。工具契约越具体,助手越容易解释"查到了什么"和"哪些信息还不确定"。
五、从本地试验走向服务接入
在本文基线版本中,标准传输包括stdio 和Streamable HTTP。
stdio通常由客户端启动本地子进程,标准输入输出承载协议消息。普通调试日志写到stderr,避免把stdout里的消息流污染掉。Streamable HTTP适合独立运行的服务,通过HTTP交换消息,并可结合SSE传送服务端消息;不能把它简单理解为每次请求都必须使用SSE。具体约定见传输规范。
正式交换业务消息之前还需要初始化、版本与能力协商,随后发送初始化完成通知。用SDK开发时也应理解这些步骤,排查"连上了却看不到工具"时才有方向。参见生命周期规范。
从Java后端的角度,我更倾向于从一个很小的服务能力开始验证:
- 选一个边界清楚的只读查询,明确输入、输出和错误。
- 复用原来的服务层,实现参数校验、身份鉴别和数据权限。
- 通过支持相应协议版本的Client连接,检查能力协商和工具发现。
- 分别测试正常查询、无权限、找不到数据和下游超时。
- 确认调用日志能追踪到工具名称、结果状态和耗时,再考虑增加写操作。
这里给出的是工程拆分思路,没有绑定某个SDK版本。落地时应以所选SDK的发布文档和客户端兼容情况为准,不把不同版本教程中的配置直接拼在一起。
六、MCP与RAG、Agent是什么关系
为了安排项目职责,可以从三个问题理解这些概念:
| 概念 | 关注的问题 | 在售后助手里的例子 |
|---|---|---|
| RAG | 如何检索并提供相关知识 | 找出适用的售后政策段落 |
| MCP | 如何发现和交换外部能力与上下文 | 发现并调用订单查询工具 |
| Agent | 如何围绕目标组织多步行动 | 先查询订单,再检索政策并整理答复 |
这是本文用于项目设计的划分方式。实际实现中它们可以组合:MCP Server可以封装一个检索工具,Agent可以调用该工具,检索结果再进入生成环节。MCP的接入并不会自动完成检索质量评估或多步任务规划。
因此,评估接入效果时,我会分别看三个层面:工具能否稳定调用、返回信息是否准确、最终答复是否忠实于结果。把这些问题拆开,比只看"助手似乎能用了"更容易找到改进方向。
七、值得提前想清楚的边界
**权限仍然属于应用与业务系统。**工具描述可以说明用途,服务端必须执行真实校验。对于会改变外部状态的动作,还应设计明确的确认、幂等和失败补偿机制。
**外部内容应按数据处理。**文档或工具返回值中如果夹带了"忽略原要求""把其他系统资料发出去"等文字,不应因此获得控制应用的权限。上下文来源与应用指令的边界需要持续保持。
**能力暴露要克制。**一个可任意执行SQL的工具看起来灵活,却让权限、审计和错误处理都变得困难。对于固定业务,几个输入输出清楚的查询工具通常更容易测试和维护。这是设计取舍,不能仅凭工具数量判断系统能力。
八、🧠 思维导图
#mermaid-svg-BpulQ9PK1XATcZPa{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-BpulQ9PK1XATcZPa .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-BpulQ9PK1XATcZPa .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-BpulQ9PK1XATcZPa .error-icon{fill:#552222;}#mermaid-svg-BpulQ9PK1XATcZPa .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-BpulQ9PK1XATcZPa .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-BpulQ9PK1XATcZPa .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-BpulQ9PK1XATcZPa .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-BpulQ9PK1XATcZPa .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-BpulQ9PK1XATcZPa .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-BpulQ9PK1XATcZPa .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-BpulQ9PK1XATcZPa .marker{fill:#333333;stroke:#333333;}#mermaid-svg-BpulQ9PK1XATcZPa .marker.cross{stroke:#333333;}#mermaid-svg-BpulQ9PK1XATcZPa svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-BpulQ9PK1XATcZPa p{margin:0;}#mermaid-svg-BpulQ9PK1XATcZPa .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-BpulQ9PK1XATcZPa .cluster-label text{fill:#333;}#mermaid-svg-BpulQ9PK1XATcZPa .cluster-label span{color:#333;}#mermaid-svg-BpulQ9PK1XATcZPa .cluster-label span p{background-color:transparent;}#mermaid-svg-BpulQ9PK1XATcZPa .label text,#mermaid-svg-BpulQ9PK1XATcZPa span{fill:#333;color:#333;}#mermaid-svg-BpulQ9PK1XATcZPa .node rect,#mermaid-svg-BpulQ9PK1XATcZPa .node circle,#mermaid-svg-BpulQ9PK1XATcZPa .node ellipse,#mermaid-svg-BpulQ9PK1XATcZPa .node polygon,#mermaid-svg-BpulQ9PK1XATcZPa .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-BpulQ9PK1XATcZPa .rough-node .label text,#mermaid-svg-BpulQ9PK1XATcZPa .node .label text,#mermaid-svg-BpulQ9PK1XATcZPa .image-shape .label,#mermaid-svg-BpulQ9PK1XATcZPa .icon-shape .label{text-anchor:middle;}#mermaid-svg-BpulQ9PK1XATcZPa .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-BpulQ9PK1XATcZPa .rough-node .label,#mermaid-svg-BpulQ9PK1XATcZPa .node .label,#mermaid-svg-BpulQ9PK1XATcZPa .image-shape .label,#mermaid-svg-BpulQ9PK1XATcZPa .icon-shape .label{text-align:center;}#mermaid-svg-BpulQ9PK1XATcZPa .node.clickable{cursor:pointer;}#mermaid-svg-BpulQ9PK1XATcZPa .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-BpulQ9PK1XATcZPa .arrowheadPath{fill:#333333;}#mermaid-svg-BpulQ9PK1XATcZPa .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-BpulQ9PK1XATcZPa .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-BpulQ9PK1XATcZPa .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-BpulQ9PK1XATcZPa .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-BpulQ9PK1XATcZPa .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-BpulQ9PK1XATcZPa .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-BpulQ9PK1XATcZPa .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-BpulQ9PK1XATcZPa .cluster text{fill:#333;}#mermaid-svg-BpulQ9PK1XATcZPa .cluster span{color:#333;}#mermaid-svg-BpulQ9PK1XATcZPa div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-BpulQ9PK1XATcZPa .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-BpulQ9PK1XATcZPa rect.text{fill:none;stroke-width:0;}#mermaid-svg-BpulQ9PK1XATcZPa .icon-shape,#mermaid-svg-BpulQ9PK1XATcZPa .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-BpulQ9PK1XATcZPa .icon-shape p,#mermaid-svg-BpulQ9PK1XATcZPa .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-BpulQ9PK1XATcZPa .icon-shape .label rect,#mermaid-svg-BpulQ9PK1XATcZPa .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-BpulQ9PK1XATcZPa .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-BpulQ9PK1XATcZPa .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-BpulQ9PK1XATcZPa :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} MCP与AI工具接入
架构:Host、Client、Server
能力:Tools、Resources、Prompts
流程:协商、发现、调用、返回
传输:stdio与Streamable HTTP
边界:权限、数据可信度、执行控制
九、总结
总结要点
**MCP提供了统一的能力接入约定。**它让AI应用与外部工具、资源之间的连接更容易复用,理解Host、Client和Server的分工是入门的第一步。
**协议接入只是工程工作的一部分。**认证、业务权限、参数校验、超时与错误反馈仍然需要认真设计。工具返回的数据也需要被准确解释。
**从一个小而完整的场景开始。**先把只读查询的发现、调用、结果展示和失败路径跑通,再逐步扩展,会比一开始暴露大量能力更容易积累可靠经验。
后续随笔继续关注AI应用中的检索与工具协作,Java进阶系列则按原有节奏推进。
👉 如果你觉得这篇文章对你有所帮助,欢迎点赞、收藏、分享!😊