乐于分享
好东西不私藏

MCP 深度解析:AI 时代的工具协议革命

MCP 深度解析:AI 时代的工具协议革命

MCP 深度解析:AI 时代的工具协议革命


一、背景:大模型的「最后一公里」困境

1.1 能力边界的结构性矛盾

大语言模型(LLM)的核心能力是语义理解和推理生成,但它天然是一个封闭的静态系统:训练数据有截止日期,无法感知实时状态,无法主动操作外部系统。这个矛盾在早期以”幻觉问题”的面貌出现,但随着 LLM 被推向更复杂的业务场景,问题的本质逐渐清晰——

LLM 缺少的不是智能,而是与现实世界的连接通道。

最直观的数据:一个企业级 AI 助手,可能需要对接内部知识库、代码仓库、工单系统、监控平台、日历服务……每一个系统都是独立的数据孤岛。模型本身再强,没有数据和操作能力,也只能在真空中推理。

1.2 工具调用的野蛮生长期

2023 年前后,各家 LLM 厂商几乎同步推出了”工具调用”能力——OpenAI 的 Function Calling、Anthropic 的 Tool Use、Google 的 Function Declarations。思路相似:给模型一份工具描述的 JSON,模型决定何时调用哪个工具,返回结构化参数,由调用方执行并将结果回填。

这个机制解决了”模型能不能调用工具”的问题,但随即暴露出更深层的工程问题:

问题一:N×M 集成爆炸

假设你有 N 个 AI 应用(内部 Copilot、客服机器人、数据分析助手……),M 个工具系统(CRM、代码库、知识库、监控系统……),理论上需要维护 N×M 个适配层。不同 LLM 的工具描述格式不同,相同工具在不同模型里需要重写一遍 schema。这是纯粹的工程税。

问题二:上下文注入无标准

除了工具调用,另一个高频需求是”把数据喂给模型”——把文档内容、数据库查询结果、用户历史记录注入到上下文窗口。但怎么注入?截多长?谁来管理生命周期?每个项目都有一套私有解法,完全没有复用性。

问题三:会话状态与工具状态失配

LLM 的 session 是有状态的(对话历史),但工具系统通常是无状态的 API。当一个复杂任务需要跨多步工具调用时,谁负责维护中间状态?调用方需要手工拼接上下文,极易出错,且难以调试。

1.3 抽象层的缺失

回顾软件工程史,每当出现 N×M 集成爆炸时,解法通常是引入一个标准抽象层

  • • TCP/IP 解决了异构网络互联
  • • POSIX 解决了操作系统 API 碎片化
  • • USB 解决了外设连接的硬件混乱

2024 年底,Anthropic 开源了 Model Context Protocol(MCP),试图扮演这个角色——成为 AI 应用与工具世界之间的标准连接协议。


二、MCP 是什么:协议层的统一解

2.1 核心定位

MCP 的官方定位是:一个开放协议,用于标准化 LLM 应用与外部数据源及工具之间的连接方式。

但这句话太抽象。更准确的说法是:

MCP 定义了一套语言,用于描述”一个系统能为 AI 提供哪些能力”,以及 AI 与这个系统交互的完整生命周期。它不依赖任何特定的 LLM,也不依赖任何特定的编程语言或框架。

2.2 三类能力原语

MCP 将 AI 可以使用的外部能力抽象为三类原语:

Resources(资源)
类比文件系统中的”文件”。Resources 是只读的、可被 LLM 消费的数据单元,每个 Resource 有一个 URI 标识。典型例子:一个文档的内容、一段代码、一条数据库记录。LLM 通过读取 Resource 来获取上下文,而不是通过工具调用。

关键设计:Resources 可以是静态内容(text/blob),也可以是动态内容(通过 URI 参数化)。Server 可以通知 Client 某个 Resource 发生了变化(Resource Changed Notification),这使得”订阅式上下文更新”成为可能。

Tools(工具)
类比函数调用。Tools 是有副作用的操作,LLM 通过决策何时调用来执行真实世界的动作。每个 Tool 有名称、描述(自然语言,供模型理解意图)、输入 Schema(JSON Schema,供模型生成合法参数)、以及执行结果。

Tools 是 MCP 中最类似传统”function calling”的部分,但有重要区别:工具描述与执行逻辑完全在 Server 侧,Client 不需要知道工具的实现细节。

Prompts(提示)
这个原语常被忽视,却非常有价值。Prompts 是预定义的、可复用的提示模板,由 Server 提供,可以包含参数化插槽。例如,一个代码审查系统可以提供”code_review”提示模板,Client 只需传入代码片段,Server 返回一个结构良好的 prompt,直接送入 LLM。

Prompts 解决的是”提示工程”的复用和标准化问题——将领域专家的提示经验封装到 Server 侧,避免每个调用方重复发明轮子。

2.3 传输层设计

MCP 在传输层支持两种模式:

stdio 模式(本地):Host 进程启动 Server 子进程,通过标准输入输出通信。适合本地工具(文件系统操作、本地命令执行)。延迟极低,无网络开销,安全边界清晰。

SSE over HTTP 模式(远程):Server 是独立的 HTTP 服务,通过 Server-Sent Events 实现服务端推送,通过 HTTP POST 实现客户端发送。适合云端服务、多 Client 共享场景。

协议本身是传输无关的——相同的 JSON-RPC 2.0 消息格式,在两种传输层上完全一致。这个设计决策使得本地开发和生产部署可以无缝切换。


三、技术架构深解

3.1 三层角色模型

MCP 定义了三种角色,理解它们的职责边界是理解整个协议的关键:

┌─────────────────────────────────────────┐
│              Host(宿主)                 │
│  ┌─────────────┐   ┌─────────────┐      │
│  │   Client A  │   │   Client B  │      │
│  └──────┬──────┘   └──────┬──────┘      │
└─────────┼────────────────┼─────────────┘
          │                │
    ┌─────▼──────┐   ┌──────▼─────┐
    │  Server 1  │   │  Server 2  │
    │ (文件系统)  │   │  (代码库)   │
    └────────────┘   └────────────┘

Host(宿主应用):用户直接交互的应用层,如 Claude Desktop、Cursor IDE、自研 AI Copilot。Host 负责管理整体用户体验,创建和管理多个 Client 实例,协调 LLM 与 MCP 能力的交互,以及执行安全策略和用户授权。Host 是整个系统中唯一真正”知道用户意图”的角色。

Client(协议客户端):Host 内部的协议实现层,每个 Client 对应一个 Server 连接。Client 负责维护与 Server 的会话状态,执行能力协商,转发工具调用请求并接收响应。一个 Host 可以同时维护多个 Client,每个 Client 与一个 Server 保持独立的有状态连接。

Server(能力提供者):独立运行的进程或服务,封装具体的工具和数据能力。Server 可以无状态(每次请求独立处理),也可以有状态(维护会话上下文)。关键约束:Server 不应直接访问对话历史,也不应知道自己在哪个应用里被使用。 这个隔离是 MCP 安全模型的基础。

3.2 会话生命周期

MCP 的连接生命周期分为四个阶段,每个阶段都有精确的协议定义:

阶段一:Initialize(初始化)

Client 发送 initialize 请求,携带自身的协议版本和能力声明。Server 响应自身支持的协议版本和能力集合。这个握手不仅是版本协商,更是能力边界的划定——双方明确告知对方”我支持哪些特性”。

// Client → Server
{
"method":"initialize",
"params":{
"protocolVersion":"2024-11-05",
"capabilities":{
"roots":{"listChanged":true},
"sampling":{}
},
"clientInfo":{"name":"ExampleClient","version":"1.0.0"}
}
}

// Server → Client
{
"result":{
"protocolVersion":"2024-11-05",
"capabilities":{
"tools":{"listChanged":true},
"resources":{"subscribe":true,"listChanged":true},
"prompts":{"listChanged":true}
},
"serverInfo":{"name":"FileSystemServer","version":"2.1.0"}
}
}

阶段二:Capability Discovery(能力发现)

初始化完成后,Client 通过 tools/listresources/listprompts/list 枚举 Server 提供的全部能力。这些描述信息最终会被注入到 LLM 的系统提示中,成为模型”感知”外部能力的方式。

阶段三:Operation(操作阶段)

这是协议的核心运行态。双向通信在这里展开:

  • • Client → Server:执行工具调用(tools/call)、读取资源(resources/read)、获取提示(prompts/get
  • • Server → Client:推送通知(能力列表变更、资源内容变更)、发起 Sampling 请求(见 3.3 节)

阶段四:Shutdown(关闭)

优雅关闭协议,确保进行中的操作有机会完成。

3.3 Sampling:被低估的反向通道

MCP 中最被忽视、但设计上最有深度的特性是 Sampling——Server 可以主动请求 Client(进而请求 LLM)执行推理。

这打破了传统的”模型调用工具”的单向模式,实现了工具调用 LLM 的反向通道:

传统模式:LLM → 决策 → 工具执行 → 结果回填 → LLM

MCP Sampling:LLM → 调用 Server → Server 内部需要 LLM 推理
              → Server 请求 Client Sampling
              → Client 调用 LLM(携带 Server 构建的 prompt)
              → LLM 响应返回 Server
              → Server 继续处理 → 最终结果返回 LLM

这有什么实际价值?考虑一个复杂场景:一个代码库 MCP Server,在处理”找到所有与 bug 相关的函数”这个工具调用时,需要对每个函数的代码语义进行判断——这本身就需要 LLM 的语义理解能力。通过 Sampling,Server 可以在执行过程中递归调用 LLM,而不需要 Host 应用做任何额外的协调逻辑。

但是Sampling 的安全边界设计同样值得关注:Server 不能自由地调用任何 LLM,而是通过 Client 发起请求,Host 有完整的控制权——包括是否允许 Sampling、使用哪个模型、是否需要用户确认。这保留了 Human-in-the-Loop 的核心约束。

3.4 安全模型与权限边界

MCP 的安全设计遵循几个核心原则:

最小权限原则:每个 Server 只暴露它需要暴露的能力。文件系统 Server 可以限制可访问的根目录(通过 roots 机制),数据库 Server 可以只暴露只读工具。

用户授权节点:敏感操作(写文件、发邮件、执行代码)应在 Host 层获得用户明确授权,而不是 Server 自行决定。MCP 规范将这个设计原则称为”Human-in-the-Loop”。

Server 隔离:不同 Server 之间不能直接通信,所有协调逻辑都在 Host/Client 层。这防止了一个被攻击的 Server 影响其他 Server。

Prompt Injection 防护:这是 MCP 生态目前最活跃的安全研究方向。当 Server 返回的内容中包含试图操控 LLM 的文本时(例如,一个恶意文档中嵌入了”忽略之前的指令”),Host 需要有明确的防护机制。MCP 规范要求 Server 返回的内容应明确标记来源,但实际的防护仍然主要依赖 Host 实现。

3.5 LLM 与 MCP 的交互机制:全链路拆解

这是理解 MCP 运转本质最关键的一节,也是最容易被文档略过的部分。很多人知道”LLM 可以调用 MCP 工具”,但不清楚这个过程在工程层面究竟发生了什么。

核心事实:LLM 本身不直接感知 MCP 协议。

LLM 只处理 token 序列。它看不到 JSON-RPC 消息,不知道 MCP Server 的存在,也不会主动发起任何网络请求。LLM 与 MCP 之间的交互,完全由 Host 层作为中介来编排。理解这一点,是理解后续所有机制的前提。

3.5.1 工具描述的注入机制

交互的起点是 Host 在向 LLM 发送请求之前,将 MCP Server 的工具能力翻译成 LLM 能理解的格式——通常是原生的 function calling schema(各家格式略有差异,但核心是 JSON Schema 描述的工具列表)。

以 Anthropic Claude 为例,Host 从 MCP Server 获取工具列表后,将其转换为如下格式,附加到 API 请求中:

{
"model":"claude-3-5-sonnet",
"tools":[
{
"name":"search_documents",
"description":"在内部知识库中搜索相关文档。当用户询问公司内部规范、流程或历史记录时使用此工具。",
"input_schema":{
"type":"object",
"properties":{
"query":{
"type":"string",
"description":"搜索关键词或自然语言问题"
},
"top_k":{
"type":"integer",
"description":"返回的最相关文档数量,默认 5",
"default":5
}
},
"required":["query"]
}
},
{
"name":"create_ticket",
"description":"在工单系统中创建新工单。需要用户明确表示要提交问题时才调用。",
"input_schema":{
"type":"object",
"properties":{
"title":{"type":"string","description":"工单标题"},
"description":{"type":"string","description":"问题描述"},
"priority":{
"type":"string",
"enum":["low","medium","high"],
"description":"优先级"
}
},
"required":["title","description"]
}
}
],
"messages":[
{"role":"user","content":"帮我找一下数据库慢查询的排查流程文档"}
]
}

注意 description 字段的写法——这是给 LLM 读的意图描述,直接影响模型是否会在合适的时机选择正确的工具。这是 MCP Server 开发者最需要精心设计的部分,远比参数 Schema 更重要。

3.5.2 LLM 的工具调用决策

LLM 接收到包含工具列表的请求后,在推理过程中会决定:

  1. 1. 是否需要调用工具:基于用户意图和工具描述,判断当前问题能否直接回答,还是需要外部信息
  2. 2. 调用哪个工具:根据工具描述的语义匹配程度做出选择
  3. 3. 填入什么参数:根据参数的 JSON Schema 和 description 生成合法的参数值

当 LLM 决定调用工具时,它不是”执行调用”,而是输出一个结构化的调用意图,以特殊的 stop reason 终止本次生成:

{
"stop_reason":"tool_use",
"content":[
{
"type":"text",
"text":"我来帮你查找相关文档。"
},
{
"type":"tool_use",
"id":"toolu_01XYZ",
"name":"search_documents",
"input":{
"query":"数据库慢查询排查流程",
"top_k":3
}
}
]
}

这是 LLM 与外部工具交互的本质:LLM 产出意图,Host 负责执行。 LLM 的工作在这里暂停,控制权交回 Host。

3.5.3 Host 的工具执行与结果回填

Host 收到 LLM 的工具调用意图后,经过三个步骤完成执行闭环:

Step 1:参数校验与权限检查

Host 在将调用转发给 MCP Server 之前,通常会做一轮校验:

  • • 参数是否符合 JSON Schema(防御模型生成非法参数)
  • • 是否需要用户确认(对于写操作、敏感操作)
  • • 调用频率是否超限

这个校验层是 Human-in-the-Loop 的核心实施点。

Step 2:向 MCP Server 发起工具调用

Host 通过 MCP Client 向对应的 Server 发送 tools/call 请求:

{
"method":"tools/call",
"params":{
"name":"search_documents",
"arguments":{
"query":"数据库慢查询排查流程",
"top_k":3
}
}
}

Server 执行真实的业务逻辑(查询 ES、调用内部 API 等),返回结构化结果:

{
"result":{
"content":[
{
"type":"text",
"text":"找到 3 篇相关文档:\n\n1. 《MySQL 慢查询分析指南》\n   - 路径:/wiki/db/slow-query-guide\n   - 摘要:介绍 slow_query_log 配置、EXPLAIN 分析方法...\n\n2. 《索引优化最佳实践》\n   ...\n\n3. 《DBA OnCall 手册 - 性能问题处理流程》\n   ..."
}
],
"isError":false
}
}

Step 3:将结果回填到 LLM 上下文

Host 将工具执行结果以 tool_result 的角色追加到对话历史,然后再次调用 LLM,让模型基于工具返回的真实数据继续生成回答:

{
"messages":[
{"role":"user","content":"帮我找一下数据库慢查询的排查流程文档"},
{
"role":"assistant",
"content":[
{"type":"text","text":"我来帮你查找相关文档。"},
{"type":"tool_use","id":"toolu_01XYZ","name":"search_documents",
"input":{"query":"数据库慢查询排查流程","top_k":3}}
]
},
{
"role":"user",
"content":[
{
"type":"tool_result",
"tool_use_id":"toolu_01XYZ",
"content":"找到 3 篇相关文档:\n\n1. 《MySQL 慢查询分析指南》..."
}
]
}
]
}

LLM 接收到包含工具结果的完整上下文后,生成最终回答。此时模型处理的已经是真实的、最新的业务数据,而非训练时的静态知识。

3.5.4 多工具串联调用

实际场景中,一个用户意图往往需要多次工具调用才能满足。整个链路可能经历多个”LLM 推理 → 工具调用 → 结果回填”的迭代:

用户: "分析一下最近三天的数据库告警,找出根因"

第 1 轮:
  LLM → 调用 get_alerts(time_range="3d")
  Host → MCP Server 返回告警列表 (15 条)
  结果回填 LLM

第 2 轮:
  LLM → 发现告警集中在某表,调用 get_metrics(table="orders", metric="slow_query_count")
  Host → MCP Server 返回时序指标数据
  结果回填 LLM

第 3 轮:
  LLM → 需要确认最近变更,调用 search_commits(keyword="orders table", days=3)
  Host → MCP Server 返回相关提交记录
  结果回填 LLM

最终:
  LLM 基于三次工具返回的真实数据,生成根因分析报告

每一轮迭代,LLM 都在动态决策下一步需要什么信息。这种推理驱动的工具编排是 MCP + LLM 组合最核心的能力——不是预定义工作流,而是模型根据中间结果动态调整调用策略。

3.5.5 Resources 的注入方式:与 Tools 的本质差异

Resources 与 Tools 的交互方式截然不同,容易混淆,值得单独澄清。

Tools 由 LLM 在推理过程中主动决策调用,是动态的、按需触发的。

Resources 通常由 Host 在对话开始前(或根据上下文判断时)主动注入到 LLM 的上下文窗口,LLM 并不知道这段内容来自 MCP Resource,它只是”上下文里有这段文字”。

典型 Resources 注入流程:

1. Host 根据用户消息判断需要哪些背景信息
   (如:用户问到了某个服务 → 注入该服务的架构文档 Resource)

2. Host 通过 Client 调用 resources/read 获取 Resource 内容

3. Host 将 Resource 内容以 system message 或 context block 形式
   注入到发送给 LLM 的请求中

4. LLM 在回答时天然利用这些背景信息,无需显式调用任何工具

这个机制的关键设计权衡:Resources 降低了调用延迟和 token 开销(不需要额外一轮工具调用来获取数据),但 Host 必须预判需要哪些 Resources,引入了主动预加载的逻辑复杂度。

实践中,对于大型文档库,通常先用 Tool 做语义检索(找到相关文档的 URI),再用 Resource 读取具体内容——Tool 和 Resource 的组合使用,才是最完整的 MCP 使用姿势。

3.5.6 交互模型的完整全景

综合以上各环节,LLM 与 MCP 的完整交互模型如下:

用户(User)、Host层(Host)、MCP Server;三者为独立交互主体,采用顺序交互模式,消息流向遵循时间顺序,具体交互过程如下:

  1. 1. 用户 → Host层:同步发送【用户消息】,触发整个交互流程,为初始交互触发点。
  2. 2. Host层 → MCP Server:Host层接收用户消息后,发起第一个交互消息【resources/read】,用于向MCP Server请求预加载资源。
  3. 3. MCP Server → Host层:同步响应Host层的资源请求,返回【Resource 内容】,完成资源预加载(对应原流程图①)。
  4. 4. Host层内部操作:基于接收的用户消息、预加载的Resource内容,注入工具列表,完成LLM请求的构建(对应原流程图②),此过程为Host层内部处理,不涉及与其他参与者的消息交互。
  5. 5. Host层内部操作:调用LLM,LLM输出【tool_use 意图】,明确需要执行的工具调用操作(对应原流程图③),此过程为Host层与LLM的内部交互,不涉及外部参与者。
  6. 6. Host层 → MCP Server:根据LLM输出的tool_use意图,发起第二个交互消息【tools/call】,请求MCP Server执行对应工具(对应原流程图④)。
  7. 7. MCP Server → Host层:同步响应工具调用请求,返回【工具执行结果】,完成工具调用的执行与结果反馈(对应原流程图④)。
  8. 8. Host层内部操作:将MCP Server返回的工具执行结果回填至上下文,再次调用LLM,LLM基于所有上下文(用户消息、Resource内容、工具执行结果)生成【最终回答】(对应原流程图⑤),此过程为Host层内部处理。
  9. 9. Host层 → 用户:同步发送【最终回答】,将交互结果反馈给用户,整个MCP交互流程结束。

理解这个全景图有一个重要推论:MCP 的性能瓶颈不在协议本身,而在这个编排循环的深度。 每一轮工具调用都意味着一次 LLM 推理 + 一次 Server 执行 + 一次上下文更新。对于需要 10+ 轮工具调用的复杂任务,端到端延迟可能达到数十秒。这是当前 MCP 架构在实时性要求高的场景下需要重点优化的工程问题。

3.5.7 以 LangChain 框架为例:MCP 接入的完整实现

前几节讲的是原理层面的交互机制。这里用 LangChain 框架做一次完整的工程落地示例,把抽象概念映射到真实代码,帮助你建立”能跑起来”的直觉。
LangChain 是目前使用最广泛的 LLM 应用开发框架,它本身有一套 Tool 抽象(BaseTool),但与 MCP 协议并没有直接绑定。当你想把 MCP Server 的能力接入 LangChain Agent 时,需要一层适配代码——这层适配正好清晰地展示了”Host 如何将 MCP 工具翻译给 LLM”的全过程。

整体架构

LangChain Agent(扮演 Host 角色)
    │
    ├── ChatOpenAI / ChatAnthropic(LLM)
    │
    ├── MCP Client(通过 langchain-mcp-adapters 或手写适配层)
    │       │
    │       ├── MCP Server A(stdio,本地文件系统)
    │       └── MCP Server B(SSE/HTTP,远程知识库)
    │
    └── AgentExecutor(编排循环:推理 → 工具调用 → 回填)

Step 1:启动 MCP Client,获取工具列表

使用 mcp Python SDK 连接 Server,获取工具描述并转换为 LangChain 的 Tool 对象:

from mcp import ClientSession, StdioServerParameters
from mcp.client.stdio import stdio_client
from langchain_core.tools import StructuredTool
import asyncio, json

asyncdefload_mcp_tools(server_script: str) -> list[StructuredTool]:
"""
    连接 MCP Server,将其暴露的 Tools 转换为 LangChain StructuredTool 列表
    """

    server_params = StdioServerParameters(
        command="python",
        args=[server_script],
    )

asyncwith stdio_client(server_params) as (read, write):
asyncwith ClientSession(read, write) as session:
# 协议握手:Initialize + Capability Negotiation
await session.initialize()

# 获取工具列表
            tools_result = await session.list_tools()

            langchain_tools = []
for mcp_tool in tools_result.tools:
# 将 MCP Tool 定义转换为 LangChain StructuredTool
                tool = _mcp_tool_to_langchain(session, mcp_tool)
                langchain_tools.append(tool)

return langchain_tools


def_mcp_tool_to_langchain(
    session: ClientSession, mcp_tool
) -> StructuredTool:
"""
    适配层核心:将单个 MCP Tool 描述映射为 LangChain StructuredTool
    关键点:description 直接使用 MCP 工具的 description,这段文字将被注入给 LLM
    """

# 从 MCP Tool 的 inputSchema 动态构建 Pydantic 模型(用于参数校验)
from pydantic import create_model
from typing importAny

    schema = mcp_tool.inputSchema
    fields = {}
for prop_name, prop_def in schema.get("properties", {}).items():
        field_type = _json_type_to_python(prop_def.get("type""string"))
        description = prop_def.get("description""")
        fields[prop_name] = (field_type, ... if prop_name in schema.get("required", []) elseNone)

    ArgsModel = create_model(f"{mcp_tool.name}_args", **fields)

# 构建实际调用函数:这是 LangChain 执行工具时真正触发的逻辑
# 内部通过 MCP Client 发起 tools/call 请求
asyncdef_run(**kwargs: Any) -> str:
        result = await session.call_tool(mcp_tool.name, arguments=kwargs)
# 将 MCP 返回的 content 列表拼接为字符串返回给 LLM
return"\n".join(
            item.text for item in result.content ifhasattr(item, "text")
        )

return StructuredTool(
        name=mcp_tool.name,
        description=mcp_tool.description,   # 直接透传给 LLM 的意图描述
        args_schema=ArgsModel,
        coroutine=_run,
    )


def_json_type_to_python(json_type: str):
return {"string"str"integer"int"number"float"boolean"bool}.get(
        json_type, str
    )

Step 2:构建 LangChain Agent,绑定 MCP 工具

from langchain_openai import ChatOpenAI
from langchain.agents import create_tool_calling_agent, AgentExecutor
from langchain_core.prompts import ChatPromptTemplate

asyncdefbuild_mcp_agent(server_script: str) -> AgentExecutor:
# 1. 加载 MCP 工具(已转换为 LangChain Tool)
    tools = await load_mcp_tools(server_script)

# 2. 初始化 LLM
#    LangChain 会在调用时自动将 tools 列表转换为对应 LLM 的 function calling 格式
#    OpenAI 格式 / Anthropic 格式 / Gemini 格式 由 LangChain 内部适配,无需手动处理
    llm = ChatOpenAI(model="gpt-4o", temperature=0)

# 3. 构建 Prompt 模板
    prompt = ChatPromptTemplate.from_messages([
        ("system""你是一个企业内部助手,可以使用以下工具查询内部知识库和工单系统。\n"
"优先使用工具获取准确信息,而不是依赖自身知识。"),
        ("human""{input}"),
        ("placeholder""{agent_scratchpad}"),  # 存储中间推理过程和工具调用记录
    ])

# 4. 创建 Agent
#    create_tool_calling_agent 封装了"推理 → 工具调用 → 结果回填"的编排循环
    agent = create_tool_calling_agent(llm, tools, prompt)

# 5. 包装为 AgentExecutor(负责实际运行循环,直到 LLM 不再发出工具调用意图)
return AgentExecutor(
        agent=agent,
        tools=tools,
        verbose=True,       # 开启后可以观察每一轮推理和工具调用的详细日志
        max_iterations=10,  # 防止无限循环,限制最大工具调用轮次
        return_intermediate_steps=True,  # 返回中间步骤,便于调试和审计
    )

Step 3:运行 Agent,观察完整交互链路

asyncdefmain():
    agent_executor = await build_mcp_agent("./knowledge_base_server.py")

    result = await agent_executor.ainvoke({
"input""帮我找一下数据库慢查询的排查流程,然后根据内容给我一个简洁的操作步骤清单"
    })

print("=== 最终回答 ===")
print(result["output"])

print("\n=== 中间步骤(工具调用链路) ===")
for i, (action, observation) inenumerate(result["intermediate_steps"]):
print(f"\n第 {i+1} 轮工具调用:")
print(f"  工具名: {action.tool}")
print(f"  输入参数: {json.dumps(action.tool_input, ensure_ascii=False, indent=2)}")
print(f"  返回结果(前 200 字): {str(observation)[:200]}...")

asyncio.run(main())

开启 verbose=True 后,你会在控制台看到如下输出,清晰展示了 §3.5.2 至 §3.5.4 中描述的完整推理-调用循环:

> Entering new AgentExecutor chain...

[推理轮次 1]
Invoking: `search_documents` with `{'query': '数据库慢查询排查流程', 'top_k': 3}`

[MCP tools/call 请求发出,Server 执行检索,返回结果]
文档搜索结果:找到 3 篇相关文档...

[推理轮次 2 - LLM 判断需要读取具体文档内容]
Invoking: `get_document_content` with `{'doc_id': 'wiki/db/slow-query-guide'}`

[MCP tools/call 请求发出,Server 返回文档全文]
文档内容:...

[推理轮次 3 - LLM 已有足够信息,直接生成最终回答]
以下是数据库慢查询排查的操作步骤清单:
1. 开启 slow_query_log,设置阈值为 1s ...
...

> Finished chain.

关键工程细节:LangChain 如何透明地处理工具格式差异

这里有一个值得关注的细节:上面代码中,仅仅切换 ChatOpenAI 为 ChatAnthropic,LangChain 就会自动将相同的 StructuredTool 列表转换为 Anthropic 的 tool schema 格式(input_schema 而非 parameters)。这正是”协议与模型解耦”在框架层面的体现——MCP Server 的工具定义不变,LLM 侧的格式差异由 LangChain 的 Chat Model 层统一抹平。

# 只需切换这一行,工具调用逻辑完全不变
# llm = ChatOpenAI(model="gpt-4o")
llm = ChatAnthropic(model="claude-3-5-sonnet-20241022")

多 MCP Server 的并行加载

实际项目中往往需要同时连接多个 MCP Server,工具来自不同的业务系统。在 LangChain 中,只需将多个 Server 的工具列表合并即可,AgentExecutor 会统一管理:

asyncdefbuild_multi_server_agent():
# 并行连接多个 MCP Server,提升初始化速度
    tools_lists = await asyncio.gather(
        load_mcp_tools("./knowledge_base_server.py"),   # 知识库 Server
        load_mcp_tools("./ticketing_server.py"),        # 工单系统 Server
        load_mcp_tools("./monitoring_server.py"),       # 监控系统 Server
    )

# 合并所有工具,统一注入给 LLM
    all_tools = [tool for tools in tools_lists for tool in tools]

    llm = ChatOpenAI(model="gpt-4o", temperature=0)
# ... 后续构建 Agent 同上

这里揭示了 MCP 生态最核心的工程价值:每个 Server 独立开发、独立部署,而在 Host 层(LangChain AgentExecutor)被无缝整合。新增一个业务系统的 AI 能力,只需:① 实现一个新 MCP Server ② 在 asyncio.gather 中加一行——这就是 N+M 优于 N×M 在工程层面最直观的体现。


四、行业落地:通用解决方案视角

MCP 的落地价值,不在于”又一个 AI 功能”,而在于重构了 AI 应用的集成架构。以下从四个通用场景展开分析。

4.1 企业知识管理:从数据孤岛到统一上下文层

场景描述:企业内部存在多套知识系统——内部 Wiki、技术文档平台、工单系统、代码仓库、邮件档案。每个系统都有自己的 API 和数据格式。AI 助手需要跨系统理解和检索信息。

传统做法的问题

  • • 每个 AI 应用各自对接各个系统,代码重复、维护成本高
  • • 检索结果的格式不统一,需要大量后处理才能注入上下文
  • • 系统权限管理分散,难以统一控制 AI 的数据访问范围

MCP 方案
将每个知识系统封装为独立的 MCP Server。Wiki Server 提供文档搜索和内容读取的 Resources;工单 Server 提供工单查询 Tools;代码库 Server 提供文件浏览 Resources 和代码搜索 Tools。

所有 AI 应用(不论是 Chat 助手、IDE Copilot 还是自动化 Agent)都通过标准 MCP Client 接入,权限控制统一在 Server 侧实现。当新增一个知识系统时,只需实现一个新的 MCP Server,所有 AI 应用立即获得这个能力,而不需要逐一修改。

核心价值:将 AI 与知识系统的集成从 N×M 降低到 N+M,且权限边界清晰、可审计。

4.2 研发效能:AI 深度嵌入工程工具链

场景描述:研发团队希望 AI 不只是”代码补全”,而是能够真正参与工程流程——理解 CI 状态、分析测试失败、触发部署、查询监控数据。

MCP 方案的关键优势

这个场景最能体现 MCP 的双向能力原语价值。以一个”智能 OnCall 助手”为例:

  1. 1. 监控系统 作为 MCP Server,提供告警查询 Tools(get_alertsget_metrics)和监控数据 Resources(时序数据、日志流)
  2. 2. 代码仓库 作为 MCP Server,提供最近提交记录、变更文件 Resources
  3. 3. 部署系统 作为 MCP Server,提供部署历史查询 Tools 和(在授权下的)回滚操作 Tools

当告警触发时,AI 助手可以:

  • • 读取告警详情(Resource)
  • • 查询关联的监控指标(Tool)
  • • 搜索最近的代码变更(Resource)
  • • 基于分析结果提出回滚建议,并在用户确认后执行(Tool + Human-in-the-Loop)

整个链路中,每个 MCP Server 独立维护,安全策略各自管理。核心 AI 逻辑与具体工程系统的耦合降到最低。

4.3 业务流程自动化:安全边界下的系统操作

场景描述:企业核心业务系统(CRM、ERP、财务系统)有大量重复性操作,希望 AI 辅助甚至自动完成。但这些系统的数据敏感,直接暴露数据库给 AI 是不可接受的。

MCP 的安全优势

MCP Server 充当了业务系统的安全适配层:

  • • Server 暴露的工具是业务语义层面的操作create_orderupdate_customer_status),而非底层 SQL
  • • 每个工具都有精确的 JSON Schema 约束,不可能执行超出 Schema 描述的操作
  • • 敏感字段可以在 Server 层过滤,不暴露给 LLM 的上下文
  • • 操作日志在 Server 层统一记录,可审计、可回溯

相比”给 AI 一个数据库连接”的粗暴方案,MCP Server 提供了接口即权限边界的架构。每个可暴露的操作都是有意识的设计决策,而不是默认开放所有能力。

4.4 数据分析:从 BI 工具到 AI 原生数据接口

场景描述:数据分析师和业务方希望通过自然语言查询数据,而不是学习复杂的 BI 工具操作。

MCP 方案

BI 平台作为 MCP Server 暴露两类能力:

  • • Resources:数据集元信息(表结构、字段说明、业务含义)
  • • Tools:结构化查询(限制在预定义的查询模板范围内)、图表生成

LLM 通过读取 Resources 理解数据结构,通过 Tools 执行查询。关键设计是将”任意 SQL”转化为”参数化查询模板”——LLM 填入参数而非生成完整 SQL,大幅降低 SQL 注入风险。

对于多租户 SaaS 场景,MCP Server 可以在初始化阶段基于用户身份动态返回不同的工具集和资源列表——同一个 Server,管理员看到的 Tools 和普通用户看到的 Tools 不同。这是传统 REST API 难以优雅处理的场景。


五、MCP vs Agent Skill:一场有价值的技术对话

这是本文最想认真讨论的部分。两者经常被放在一起比较,但大多数讨论停留在表层。让我们从架构本质出发做一次深入分析。

5.1 各自解决什么问题

MCP 的核心问题域:异构系统集成与协议标准化

MCP 从一开始就是在回答一个互操作性问题:如何让任意 LLM 应用和任意工具系统之间能够”说上话”?它的本质是一个外部集成协议,关注点在边界——Host 和外部世界的边界如何定义、如何传递信息、如何协商能力。

MCP 解决的是横向集成问题:一个工具实现,所有 AI 应用受益。

Agent Skill 的核心问题域:能力模块化与快速组合

Agent Skill(以 OpenClaw Skills 为代表的实现形态)解决的是一个内部组织问题:如何将 Agent 的业务逻辑拆分成可独立开发、可快速组合、可按需加载的能力单元?它关注的是 Agent 内部的架构:SKILL.md 作为能力描述契约,脚本和工具作为执行载体,平台 Registry 作为发现机制。

Agent Skill 解决的是纵向组织问题:将复杂的 Agent 能力分而治之,保持内聚性。

5.2 架构层次的本质差异

从软件架构视角看,两者处于不同的抽象层次:

┌─────────────────────────────────────┐
│          用户 / 业务逻辑层            │
├─────────────────────────────────────┤
│        Agent / LLM 应用层            │  ← Agent Skill 在这一层发挥作用
├─────────────────────────────────────┤
│       能力集成与工具协议层             │  ← MCP 在这一层发挥作用
├─────────────────────────────────────┤
│       外部系统 / 数据源层              │
└─────────────────────────────────────┘

Agent Skill 是应用层的能力组织模式。它定义的是”这个 Agent 能做什么”以及”Agent 的各个能力模块如何协作”。SKILL.md 是给 LLM 读的契约,本质是 prompt engineering 的结构化表达。Skill 的执行可以是调用 shell 命令、调用本地 API、甚至调用 MCP Server。

MCP 是协议层的连接标准。它定义的是”Agent 如何与外部世界通信”的底层语言。它不关心 Agent 内部怎么组织,只关心 Agent 与 Server 之间的消息格式和交互契约。

这个层次差异意味着:两者不是竞争关系,而是天然的分层协作关系。

5.3 核心优劣势对比

维度
MCP
Agent Skill
标准化程度
跨厂商开放协议,已有 Claude/Cursor/Zed 等多方支持
平台约定,强绑定特定 Agent 框架
生态网络效应
强:一个 MCP Server,N 个应用受益
弱:Skill 通常只在特定平台内复用
开发复杂度
中等:需要实现协议握手、能力声明等样板代码
低:SKILL.md + 脚本即可,极其轻量
业务逻辑内聚性
弱:协议层不关心业务语义
强:Skill 天然是业务能力的封装单元
上下文感知
有限:Server 不应访问对话历史
强:Skill 在 Agent 上下文中执行,可读取完整对话历史
动态能力
支持:能力列表可动态变化,支持通知
有限:能力集在加载时确定
调试与可观测性
协议层透明,但跨进程调试复杂
直接在 Agent 运行时内,调试相对简单
安全隔离
Server 进程隔离,边界清晰
依赖平台沙箱,隔离程度取决于实现
适合场景
需要跨系统共享的通用工具
快速封装私有业务逻辑、内聚型任务

5.4 融合路径:Skill 调用 MCP

最有价值的工程实践不是”选 MCP 还是选 Skill”,而是在 Skill 内部调用 MCP Server——用 Skill 提供业务语义层的组织,用 MCP 提供外部系统的集成能力。

具体形态:

  1. 1. 轻量场景:Skill 直接封装业务逻辑,使用 exec 或内置工具完成操作。适合私有、快速迭代的场景。
  2. 2. 集成场景:Skill 的实现中调用 MCP Client,连接到已有的 MCP Server(代码库、知识库等)。Skill 提供业务语义,MCP 提供数据和工具能力。
  3. 3. 服务化场景:将成熟的 Skill 逻辑封装为 MCP Server,对外提供标准接口,供其他 Agent 应用复用。这是 Skill 演进为 MCP Server 的自然路径。

这三种形态代表了能力封装从”内部工具”到”标准服务”的成熟度演进,而不是非此即彼的选择。

5.5 一个值得思考的深层问题

MCP 的 Prompts 原语和 Agent Skill 的 SKILL.md 在某种程度上解决了相似的问题:如何将领域专家的操作知识结构化地传递给 LLM?

MCP Prompts 的方式是:将提示模板封装在 Server 侧,通过协议动态获取,模板可以包含动态数据。

Agent Skill 的方式是:SKILL.md 是静态的能力说明,在加载时注入到 Agent 的系统提示中。

前者更动态、更灵活,但引入了额外的协议开销;后者更简单、更直接,但灵活性受限。这个设计权衡反映了两种哲学:MCP 倾向于将更多智能下沉到 Server 侧,Skill 倾向于保持 Agent 的中心性。


六、相关技术生态横向对比

6.1 vs OpenAI Function Calling / GPT Actions

Function Calling 是私有的、模型侧的特性,工具描述与调用约定由 OpenAI 定义,其他模型需要各自实现。GPT Actions 进一步将工具接入 ChatGPT 平台,但仍是封闭生态。

MCP 的根本区别在于协议开放性:任何 LLM、任何应用可以实现 MCP,不依赖特定厂商。当你的工具实现为 MCP Server,它可以被 Claude、Cursor、任何支持 MCP 的应用使用,而不需要为每个 LLM 各写一套。

6.2 vs LangChain / LlamaIndex Tools

LangChain 的 Tool 是一个框架层概念,解决的是”如何在 Python 代码中组织工具调用逻辑”。它是代码抽象,不是通信协议——工具的实现和调用发生在同一个进程中,不涉及跨进程或跨服务通信。

MCP 是进程间协议,Server 和 Client 是独立的进程(甚至独立的机器)。这使得 MCP Server 可以用任意语言实现,可以独立部署、独立扩缩容,可以在不同 Agent 框架之间共享。代价是引入了进程间通信的复杂度和延迟。

6.3 vs OpenAPI / REST

这个对比最能揭示 MCP 的本质创新。OpenAPI 描述的是”这个接口接受什么参数、返回什么数据”,面向人类开发者和代码生成工具设计。MCP 描述的是”这个工具做什么事情、在什么情况下应该被调用”,面向 LLM 的语义理解设计。

关键差异:

  • • 意图描述:MCP 工具的 description 字段是给 LLM 读的自然语言,不是给人读的文档注释
  • • 参数语义:JSON Schema 中的 description 同样面向 LLM,引导模型正确填充参数
  • • 双向通信:MCP 支持 Server 主动推送(通知)和 Sampling(反向 LLM 调用),REST 是纯请求-响应模式
  • • 会话状态:MCP 有明确的会话生命周期,REST 是无状态的

换句话说,OpenAPI 是数据接口的描述语言,MCP 是 AI 能力的描述语言

6.4 与 A2A(Agent-to-Agent Protocol)的关系

2025 年,Google 发布了 Agent-to-Agent Protocol(A2A),试图标准化 Agent 之间的通信协议。这引发了业界关于 MCP 和 A2A 关系的讨论。

两者解决的是互补的不同问题

  • • MCP:Agent 与工具/数据源的连接(Agent-Tool 层)
  • • A2A:Agent 与 Agent 之间的委托和协作(Agent-Agent 层)

在多 Agent 系统架构中,两者可以同时存在:一个 Orchestrator Agent 通过 A2A 将子任务委托给 Specialist Agent,每个 Specialist Agent 通过 MCP 访问自己需要的工具和数据。这是一个自洽的分层架构。


七、展望:协议演进与未来挑战

7.1 生态建设的关键缺口

MCP 目前最大的短板不是协议设计,而是生态基础设施

可发现性问题:目前没有官方的 MCP Server Registry。用户找到一个可用 Server 的方式主要是 GitHub 搜索和社区分享。一个标准化的、可信任的 Registry(类似 npm registry 或 Docker Hub)是生态爆发的前提。

信任与验证问题:如何确认一个 MCP Server 是可信的?恶意 Server 可以通过工具描述中的隐藏指令(Tool Poisoning)操控 LLM 行为。这需要 Registry 层面的签名验证和社区审核机制。

开发者体验:创建一个生产级 MCP Server 的工程成本仍然较高——需要处理协议握手、错误处理、日志、监控、授权。更好的 SDK、脚手架工具和最佳实践文档是近期最有价值的投入方向。

7.2 有状态工作流的支持

当前 MCP 的会话模型适合短时任务——发起一次工具调用,获取结果,继续对话。但企业级 Agent 越来越多需要长时工作流:任务可能持续几小时甚至几天,需要在中途暂停等待人工审批,需要断点续传能力。

这要求 MCP 在协议层面增强对有状态工作流的支持:

  • • 任务 ID 机制:为长时任务分配持久化的 ID,支持异步查询状态
  • • Checkpoint 协议:标准化任务状态的持久化和恢复接口
  • • Human-in-the-Loop 节点:将等待人工审批建模为一等公民的协议原语,而不是由 Host 应用自行处理

7.3 Multi-Agent 场景的协议栈融合

最值得关注的长期趋势是 MCP + A2A 的协议栈融合。当 Multi-Agent 系统成为主流架构,Agent 的角色会同时扮演多个身份:对 Orchestrator 而言是工具(MCP Server),对子 Agent 而言是调度者(A2A Client),对用户而言是 Host。

这个场景要求 Agent 框架能够无缝融合两种协议,并且统一处理权限、审计、上下文传递等横切关注点。未来的 Agent Runtime 可能会内置同时支持 MCP 和 A2A 的能力,让 Agent 开发者只关注业务逻辑,而不需要手工处理协议细节。

7.4 Agent Skill 的演进路径

对于 Agent Skill 生态,可以预见几个演进方向:

标准化增强:Skill 的 SKILL.md 约定会逐步形式化,从自然语言描述演进为包含结构化元数据的混合格式——类似 OpenAPI Spec,但面向 LLM 语义而非机器解析。

跨平台可移植性:随着 MCP 生态成熟,Skill 可以选择将自身对外暴露为 MCP Server,从而在不同 Agent 平台间复用。这是 Skill 从平台内工具演进为生态级能力的关键路径。

能力组合的协议化:当前 Skill 之间的组合调用(一个 Skill 内部调用另一个 Skill)是松散的。未来可能出现 Skill-to-Skill 的标准调用协议,将 Skill 编排从约定变为规范。

7.5 一个更大的图景:AI 原生软件架构

从更宏观的视角看,MCP 代表的是软件架构范式的一次转变尝试:从为人类工程师设计的接口(REST API、SDK)迈向为 AI Agent 设计的接口(语义描述、意图驱动、双向通信)。

这个转变还处于非常早期的阶段。MCP 解决了工具集成层的协议问题,但 AI 原生软件架构还需要在认证授权、数据隐私、可解释性、可审计性等多个维度上建立新的标准。

MCP 是第一块砖,不是终点。


结语

MCP 的出现,标志着 AI 工具集成从”每个团队造自己的轮子”走向”基于共识的协议互操作”。它没有解决所有问题,但它定义了一个值得投资的方向。

对于工程师和架构师而言,现在是一个好时机:

  • • 将现有的工具和数据接口封装为 MCP Server,为未来的多应用复用做准备
  • • 在 Agent 开发中同时拥抱 Skill 的敏捷性和 MCP 的互操作性,用分层架构而非非此即彼的选择
  • • 关注 Registry、安全、有状态工作流这三个近期最可能产生工程价值的演进方向

持续更新中,关注我获取更多干货
本站文章均为手工撰写未经允许谢绝转载:夜雨聆风 » MCP 深度解析:AI 时代的工具协议革命

猜你喜欢

  • 暂无文章