专栏第6篇:第五篇我们讲了工具调用的四层防御机制,以及 Function Calling 如何让 LLM 输出结构化的工具调用意图。但 Function Calling 有一个局限:它是模型厂商的私有协议——OpenAI 的格式、Anthropic 的格式、Google 的格式各不相同。如果我想让同一个工具被不同模型调用,难道要为每个模型写一套适配代码?今天我们要聊的 MCP(Model Context Protocol),正是为了解决这个"N 个模型 × M 个工具"的碎片化问题。


目录


一、Function Calling 的局限性:N 个模型 × M 个工具

第五篇我们讲了 Function Calling:LLM 根据工具描述,输出结构化的 JSON,表示"需要调用哪个工具、传什么参数"。这套机制在单个模型内部工作得很好,但当你需要对接多个模型时,问题就来了。

1.1 每个模型的 Function Calling 格式都不一样

OpenAI 的格式:
  {"name": "get_weather", "arguments": {"city": "北京"}}

Anthropic 的格式:
  {"tool": "get_weather", "input": {"city": "北京"}}

Google 的格式:
  {"function": {"name": "get_weather"}, "parameters": {"city": "北京"}}

同样的工具、同样的参数,三个模型输出三种不同的 JSON 结构。这意味着:

  • 每对接一个新模型,就要重写一套解析逻辑
  • 工具开发者要为每个模型维护不同的描述格式
  • 切换模型时,工具代码要跟着改

1.2 工具的"碎片化"

假设你开发了一个"查天气"工具:

给 OpenAI 用 → 按 OpenAI 的 Schema 格式写描述
给 Claude 用 → 按 Anthropic 的格式写描述
给本地模型用 → 可能根本不支持 Function Calling,得用 ReAct 文本解析

结果:同一个工具,写了 3 套不同的"说明书"

这就是 Function Calling 的核心痛点:它是模型厂商的私有协议,不是跨模型的通用标准


二、MCP 是什么?

MCP(Model Context Protocol) 是 Anthropic 于 2024 年底推出的开放协议,目标是标准化 LLM 与外部系统(工具、数据、提示词)的交互方式

💡 一句话理解:Function Calling 是"某个模型怎么表达调用意图",MCP 是"外部系统怎么向模型暴露能力"的通用标准。

2.1 为什么叫"Model Context Protocol"?

拆解一下这个名字:

  • Model(模型):指 LLM,是协议的"消费者"
  • Context(上下文):指模型需要的外部信息——不只是工具,还包括数据、提示词等
  • Protocol(协议):标准化的交互规则

"Context"这个词是关键。MCP 的原始设计意图不只是"工具调用协议",而是要让外部系统能向模型提供各种形式的"上下文":

MCP 能力类型 说明 示例
Tools(工具) 可执行的函数,模型可以调用 天气查询、计算器、文件操作
Resources(资源) 只读的数据,模型可以读取 数据库记录、知识库内容、文件内容
Prompts(提示词) 预定义的 Prompt 模板 代码审查模板、翻译模板、总结模板

也就是说,MCP 最初想解决的是一个更宏大的问题:如何让外部系统(数据源、工具集、模板库)以标准化的方式,成为 LLM 的"上下文提供者"

2.2 为什么现在主要被当作"工具调用协议"?

虽然 MCP 设计了三类能力,但目前生态中90% 的使用场景都是 Tools。原因很简单:

  • Tools 是最刚性的需求:Agent 必须能执行操作,否则只是聊天机器人
  • Resources 部分被 RAG 替代:很多数据检索场景直接用向量数据库 + RAG 实现
  • Prompts 部分被系统提示词替代:预定义模板通常直接写在代码里

💡 现状:MCP 的协议框架支持三种能力,但生态发展不均衡,Tools 一枝独秀。不过随着生态成熟,Resources 和 Prompts 的使用也在增长。

2.3 MCP 的核心思想:解耦

  • 工具开发者:只按 MCP 标准写一次能力描述和实现
  • 模型/Agent 开发者:只按 MCP 标准对接一次协议
  • 结果:任何支持 MCP 的模型,都能使用任何支持 MCP 的外部系统

没有MCP的碎片化世界

私有格式

私有格式

ReAct文本

OpenAI

天气工具A

Claude

天气工具B

本地模型

天气工具C

有MCP的统一世界

MCP标准

MCP标准

MCP标准

OpenAI

天气工具

Claude

本地模型


三、MCP 的三层架构:Host / Client / Server

MCP 采用三层架构,但需要先明确一点:这三者是逻辑角色,不是三个独立的物理进程。一个应用可以同时承担多个角色。

Host 宿主应用
如 Agent 平台、IDE

Client
MCP 客户端
Host 内部的连接模块

Server
MCP 服务端
独立进程

工具/数据/能力

💡 关键理解:Client 不是独立于 Host 的第三方应用,而是Host 内部负责连接 Server 的模块。就像浏览器(Host)内部有 HTTP 客户端(Client)用来连接 Web 服务器。

3.1 Host(宿主应用)

Host 是最终用户直接交互的终端应用,比如:

  • 一个 Agent 平台(如 Claude Desktop、Cursor、openclaw、QoderWork等)
  • 一个用 LangChain 搭建的聊天机器人 Web 服务
  • 一个 IDE 插件或桌面客户端

💡 区分框架和 Host:LangChain、LlamaIndex 是框架(用来构建 Agent 的工具库),不是 Host。用 LangChain 写出来的那个"能跟用户聊天的应用"才是 Host。

Host 负责:

  • 提供用户交互界面
  • 管理内部 MCP Client 的生命周期
  • 协调不同 Server 之间的工具调用
  • 向用户展示最终答案

Host 本身也包含 Client:一个 Agent 平台作为 Host,其内部必然有 Client 模块来连接外部 Server。两者是"整体与部分"的关系,不是并列关系。

3.2 Client(MCP 客户端)

Client 是 Host 内部负责与 Server 通信的模块,每个 Client 实例对应一个 Server。

💡 关系澄清:一个 Host 内部可以有多个 Client(连接不同的 Server),一个 Server 也可以被多个 Client 连接(比如一个公共的天气查询 Server 被多个用户的 Agent 平台同时调用)。标准实现是一个 Client 实例只连接一个 Server

Client 负责:

  • 与 Server 建立连接(stdio 或 HTTP)
  • 将 Host 的请求转换为 MCP 标准消息
  • 将 Server 的响应返回给 Host
# Client 的核心职责:协议转换
class MCPClient:
    def __init__(self, server_command: str):
        # 启动 Server 进程,建立连接
        self.server = subprocess.Popen(server_command, ...)
    
    def list_tools(self):
        # 向 Server 请求工具列表
        return self.send_request("tools/list")
    
    def call_tool(self, tool_name: str, arguments: dict):
        # 调用 Server 上的某个工具
        return self.send_request("tools/call", {"name": tool_name, "arguments": arguments})

3.3 Server(MCP 服务端)

Server 是实际提供能力的"供应商",每个 Server 专注一类能力:

Server 类型 提供的能力 示例
工具 Server 可执行的函数 天气查询、计算器、文件操作
资源 Server 只读的数据访问 数据库查询、知识库检索
提示词 Server 预定义的 Prompt 模板 代码审查模板、翻译模板

Server 的核心职责:

  • 按 MCP 标准暴露自己的能力列表
  • 接收 Client 的请求并执行
  • 返回标准化的响应

四、MCP 与 Function Calling 的本质区别

⚠️ 限定范围:以下对比仅针对**工具调用(Tools)**这一交集领域。MCP 还支持 Resources(资源读取)和 Prompts(提示词模板),Function Calling 则不涉及这两类能力。

维度 Function Calling MCP
协议层级 模型输出层(LLM 怎么表达意图) 工具描述层(工具怎么定义自己)
标准归属 各模型厂商私有 Anthropic 主导的开放标准
工具位置 工具代码在 Agent 内部 工具代码在独立的 Server 进程中
工具发现 启动时静态注册 运行时动态发现(Server 随时可增删)
跨模型 每模型一套适配 一次适配,多模型通用
隔离性 工具和 Agent 同进程 工具和 Agent 隔离(Server 独立运行)

4.1 最关键的区别:协议层级

Function Calling 解决的是"LLM 怎么告诉系统它需要调用工具"——这是模型输出格式的问题。

MCP 解决的是"工具怎么描述自己、系统怎么发现工具、怎么调用工具"——这是工具接口标准的问题。

两者不是替代关系,而是互补关系

用户提问

LLM 推理

Function Calling
LLM输出JSON表示
需要调用天气工具

MCP Client
按MCP协议调用Server

MCP Server
实际执行天气查询

结果返回LLM

LLM生成最终回答

实际流程

  1. LLM 通过 Function Calling 输出"需要调用天气工具"
  2. Agent 框架(Host)把这个意图交给 MCP Client
  3. MCP Client 按 MCP 协议调用对应的 MCP Server
  4. MCP Server 执行实际的天气查询
  5. 结果返回,LLM 生成最终回答

4.2 多模型兼容性:谁来处理 Function Calling 的差异?

不同厂商的 Function Calling 输出格式确实不同(字段名、嵌套结构有差异),但这个差异不需要 Agent 平台自己处理——Agent 框架(如 LangChain)已经内部屏蔽了。

Function Calling 的结果不需要转换成 MCP 格式。因为两者在数据层面是一致的(都是工具名 + 参数),Agent 框架解析出工具名和参数后,直接传给 MCP Client 的 call_tool 方法即可。

OpenAI 输出 → LangChain 解析 → 提取{工具名, 参数} → 直接调用 MCP Server
Claude 输出 → LangChain 解析 → 提取{工具名, 参数} → 直接调用 MCP Server

Agent 平台只需要接入支持多模型的框架,框架会自动处理 Function Calling 的解析差异,然后直接调用 MCP Server。MCP 协议本身不规定 Function Calling 的格式,只负责工具和 Agent 之间的标准化通信。

4.3 为什么 MCP 需要独立的 Server 进程?

传统方式(无MCP):
  Agent 代码 ──直接调用──→ 天气API
  Agent 代码 ──直接调用──→ 数据库查询
  Agent 代码 ──直接调用──→ 文件操作
  
  问题:工具和 Agent 强耦合,代码混在一起

MCP 方式:
  Agent 代码 ──MCP协议──→ 天气Server(独立进程)
  Agent 代码 ──MCP协议──→ 数据库Server(独立进程)
  Agent 代码 ──MCP协议──→ 文件Server(独立进程)
  
  优势:
  1. 工具和 Agent 解耦,可以独立开发、独立部署
  2. 工具崩溃不影响 Agent
  3. 不同语言实现的工具可以共存(Python Agent + Node.js Server)

4.4 工具发现:LLM 怎么知道有哪些工具可用?

前面讲了 MCP 架构,但有一个关键问题没提:LLM 是怎么知道有哪些工具可以调用的?

答案是:Agent 平台通过 MCP 协议的 list_tools() 动态获取,然后注入到 LLM 的上下文(System Prompt)中。

MCP Server 启动
  ↓
Agent 平台连接 Server,调用 list_tools()
  ↓
获取工具列表:[{name, description, parameters}, ...]
  ↓
把这些信息注入 System Prompt
  ↓
LLM 根据工具描述做决策 → 输出 Function Calling

Skill 文件的作用

在实际项目中,你可能会看到类似这样的配置:

## 工具列表
- 工具名: weather-query
- 描述: 查询指定城市的天气
- 参数: {city: string}

但要注意:这个文件是给人看的开发文档,不是 LLM 获取工具信息的来源。 LLM 看到的工具信息来自 list_tools() 的实时返回,不是 Skill 文件里的静态配置。

对 LLM 完全透明

LLM 不知道也不关心工具是 MCP 的还是本地的、是 Python 的还是 Node.js 的。它看到的始终是统一格式的工具描述:

你有一个工具叫 weather-query,描述是 xxx,参数是 yyy。
你有一个工具叫 file-read,描述是 aaa,参数是 bbb。

决策逻辑完全一样:看描述 → 判断要不要用 → 输出 Function Calling。工具的实现细节对 LLM 是透明的。


五、传输类型:stdio vs HTTP

MCP 支持两种传输方式,适用于不同场景:

5.1 stdio(标准输入输出)

原理:Host 启动 Server 作为子进程,通过标准输入输出进行 JSON-RPC 通信。

Host 进程
  └── 启动 Server 子进程(如 python weather_server.py)
      └── 通过 stdin 发送请求
      └── 通过 stdout 接收响应

适用场景

  • 本地开发、调试
  • Server 和 Host 在同一台机器上
  • 需要进程隔离(Server 崩溃不影响 Host)
  • Agent 平台从 MCP 市场/广场安装的大部分插件(平台读取配置中的命令,在本地启动 Server 子进程)

优点

  • 简单,不需要网络配置
  • 天然进程隔离
  • 适合本地工具(文件操作、本地命令)

缺点

  • 只能本地通信
  • 每个 Server 占用一个进程

5.2 HTTP(Streamable HTTP)

原理:Server 作为独立的服务运行,Host 通过 HTTP 请求与其通信。

Host 进程 ──HTTP请求──→ MCP Server(独立服务)
                        可以是本地服务或远程服务

消息格式:HTTP 传输可以是普通的请求-响应模式(一次 POST 发请求,一次返回完整 JSON),也可以使用 SSE(Server-Sent Events)JSON Stream 进行流式通信(服务器实时推送增量数据)。具体用哪种取决于 Server 的实现和场景需求。

适用场景

  • Server 部署在远程服务器上
  • 多个 Host 共享同一个 Server
  • 需要高可用、负载均衡

优点

  • 支持远程部署
  • 多个 Host 可以共享 Server
  • 可以使用现有的 HTTP 基础设施(网关、鉴权等)

缺点

  • 需要网络配置
  • 增加了延迟
  • 需要处理连接管理和错误恢复

5.3 如何选择?

场景 推荐传输 原因
本地开发调试 stdio 简单,即开即用
本地文件/命令工具 stdio 本地资源访问,不需要网络
团队共享工具 HTTP 统一部署,多 Host 共享
云端服务 HTTP 远程访问,弹性伸缩
高安全要求 stdio 进程隔离,不暴露网络端口

六、开发一个 MCP Server

开发 MCP Server 的核心是:按 MCP 标准实现几个固定的接口。

6.1 Server 必须实现的接口

from mcp.server import Server
from mcp.types import Tool, TextContent

# 1. 创建 Server
server = Server("weather-server")

# 2. 注册工具列表接口(让 Client 知道你有什么工具)
@server.list_tools()
async def list_tools() -> list[Tool]:
    return [
        Tool(
            name="get_weather",
            description="查询指定城市的天气信息",
            inputSchema={
                "type": "object",
                "properties": {
                    "city": {"type": "string", "description": "城市名称"}
                },
                "required": ["city"]
            }
        )
    ]

# 3. 注册工具调用接口(实际执行工具)
@server.call_tool()
async def call_tool(name: str, arguments: dict) -> list[TextContent]:
    if name == "get_weather":
        city = arguments["city"]
        result = await query_weather_api(city)  # 实际的天气查询逻辑
        return [TextContent(type="text", text=result)]
    
    raise ValueError(f"未知工具: {name}")

# 4. 启动 Server(stdio 模式)
if __name__ == "__main__":
    server.run(transport="stdio")

6.2 Server 的"配置文件"

除了代码,MCP Server 还需要一个描述文件(通常是 package.jsonmcp.json),告诉 Host 怎么连接它。

stdio 模式的配置(Host 在本地启动 Server 子进程):

{
  "name": "weather-server",
  "version": "1.0.0",
  "command": "python",
  "args": ["weather_server.py"],
  "env": {
    "WEATHER_API_KEY": "your-api-key"
  }
}

HTTP 模式的配置(Host 连接一个已运行的远程/本地服务):

{
  "name": "weather-server",
  "version": "1.0.0",
  "url": "http://localhost:3000/mcp",
  "headers": {
    "Authorization": "Bearer token"
  }
}

如何区分两种配置?

特征 stdio 模式 HTTP 模式
配置中的关键字段 command + args url
Server 由谁启动 Host 启动子进程 已独立运行,Host 只负责连接
适用场景 本地工具、MCP 市场插件 远程服务、团队共享 Server

Host 读取配置后,根据有无 command 字段判断用 stdio 还是 HTTP 方式连接。

6.3 工具的发现与调用流程

调用执行

发现工具

初始化

stdio模式

HTTP模式

Host启动

读取配置

启动Server子进程

连接远程Server

Client建立连接

请求tools/list

返回工具列表

传给LLM

LLM决定调用

发送tools/call

Server执行

结果返回LLM

生成回答


七、MCP 在 Agent 生态中的定位

把 MCP 放在整个 Agent 技术栈中看,它的位置如下:

用户

Host Agent应用

LLM推理层
感知→规划→行动→反思

Function Calling
LLM输出调用意图

MCP Client

MCP Server A
天气查询

MCP Server B
数据库

MCP Server C
文件操作

外部API/本地资源

各层职责

层级 代表技术 职责
推理层 ReAct、Reflexion 决定做什么、怎么做
意图表达层 Function Calling LLM 表达"需要调用什么工具"
协议层 MCP 标准化工具的注册、发现、调用
执行层 MCP Server 实际执行工具逻辑
资源层 API、数据库、文件 最终的数据和操作对象

MCP 的价值

  1. 对工具开发者:写一次,到处用(任何支持 MCP 的 Agent 都能调用)
  2. 对 Agent 开发者:接一次,用所有工具(不需要为每个工具写适配代码)
  3. 对用户:Agent 的能力范围随 MCP Server 生态扩大而自动扩展

八、总结

本文从 Function Calling 的局限性出发,梳理了:

  1. 碎片化问题:N 个模型 × M 个工具,Function Calling 格式各不相同
  2. MCP 的定位:标准化的工具接口协议,解耦工具开发与 Agent 开发
  3. 三层架构:Host(应用)→ Client(Host 内部连接 Server 的模块)→ Server(能力提供)
  4. 与 Function Calling 的关系:互补而非替代——Function Calling 是 LLM 的"意图表达",MCP 是工具的"接口标准";多模型差异由 Agent 框架自动处理;LLM 对工具来源完全透明,不关心工具是 MCP 的还是本地的,需要调用时只输出 Function Calling
  5. 传输类型:stdio(本地、简单、隔离)vs HTTP(远程、共享、可扩展)
  6. Server 开发:实现 list_toolscall_tool 两个核心接口
  7. 生态价值:工具一次开发,多模型/多 Agent 复用

参考资源

  • Anthropic MCP Specification(官方协议文档)
  • MCP SDK Documentation(Python/TypeScript SDK)
  • 《Model Context Protocol: A Standard for Connecting AI Assistants to Data》(Anthropic, 2024)
Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐