MCP 和 Function Calling 是什么关系?有了 Function Calling 为什么还要 MCP?
简化版
两者管的是不同的两段,是上下游关系,不是二选一。Function Calling 管「模型和应用之间」:应用在请求里带上工具定义(名称、说明、参数的 JSON Schema),模型在回复里说「我要调哪个工具、传什么参数」,真正执行的是应用。MCP 管「应用和工具提供方之间」:应用通过 MCP 客户端连接各个 MCP Server,用 tools/list 发现工具、用 tools/call 调用工具。一次完整调用里两者串在一起:应用从 MCP Server 拿到工具列表,转换成模型能理解的工具定义放进请求;模型通过 Function Calling 选中某个工具;应用再通过 MCP 把调用转给对应的 Server,把结果交回模型。有了 Function Calling 还要 MCP,是因为 Function Calling 只规定了模型怎么「说」要调工具,没规定工具从哪来、怎么接入;每个应用都自己写一遍工具接入,工具就没法跨应用复用,MCP 把这一段标准化了。
详细版
┌──────── 应用(MCP Host)────────┐
│ │ MCP:tools/list、tools/call
│ 模型 ⇄ Function Calling ⇄ 编排 ─┼──────────────────────────▶ MCP Server A(文件)
│ │──────────────────────────▶ MCP Server B(数据库)
└──────────────────────────────────┘
模型只看到工具定义, 应用负责把模型的调用意图
说出要调哪个工具 转成对某个 Server 的协议请求
| 维度 | Function Calling | MCP |
|---|---|---|
| 连接的两端 | 模型 ↔ 应用 | 应用(客户端)↔ 工具提供方(服务端) |
| 定义的内容 | 请求里怎么描述工具、回复里怎么表达调用 | 怎么建立会话、发现工具、调用工具、传输消息 |
| 格式 | 各家模型接口略有不同 | 统一的 JSON-RPC 2.0 消息 |
| 谁执行工具 | 应用自己 | 工具所在的 MCP Server |
| 解决的问题 | 让模型能表达「要用什么工具」 | 让工具能被不同应用发现和复用 |
完整版教学
一、Function Calling 只解决了一半
Function Calling 是模型接口层面的能力:请求里带上 tools,模型可以在回复里返回工具调用意图,而不是直接生成文本。它规定了三件事:工具怎么描述(名称、说明、参数 Schema),模型怎么表达调用(工具名 + 参数 JSON),结果怎么回传(作为工具消息放回对话)。
它没规定的是:这些工具从哪来。在只用 Function Calling 的应用里,工具通常写死在应用代码中:
应用 A:自己写「查天气」「查订单」「读文件」三个工具
应用 B:又写一遍「查天气」「读文件」
应用 C:再写一遍……
每个应用都在重复实现工具接入,工具提供方也没法「写一次、到处用」。这就是 MCP 要补的另一半。Function Calling 的协议往返本身见「大模型工具调用的基本原理是什么?为什么需要函数调用格式?」。
二、MCP 补上的那一半
MCP 让工具以独立服务的形式存在,应用通过统一的协议去发现和调用:
1. 初始化:客户端与 Server 建立会话,协商协议版本和双方能力
2. 发现: 客户端请求 tools/list,得到每个工具的名称、说明、输入 Schema
3. 调用: 客户端请求 tools/call,带上工具名和参数,得到结果内容
注意 MCP 工具的定义(名称、说明、inputSchema)和 Function Calling 的工具定义几乎同构,这不是巧合:MCP 工具最终就是要交给模型通过 Function Calling 去选的。MCP 本身和具体用哪家模型无关,同一个 Server 可以被接入不同模型的应用使用。
记忆钩子:Function Calling 让模型能「开口点菜」,MCP 让厨房能「标准化上菜」。一个管模型怎么说,一个管工具怎么接。
三、一次调用里两者怎么串起来
以「帮我读一下项目里的 README 并总结」为例:
启动时:应用的 MCP 客户端连接文件系统 Server → tools/list 得到 read_file 等工具
请求时:应用把 read_file 的名称、说明、inputSchema 转成模型的工具定义,随请求发出
模型: 返回工具调用 read_file({"path": "README.md"}) ← Function Calling
应用: 找到 read_file 属于文件系统 Server,发送 tools/call ← MCP
Server:读取文件,返回内容
应用: 把内容作为工具消息放回对话,再请求模型
模型: 基于文件内容写出总结
模型从头到尾不知道 MCP 的存在,它只看到普通的工具定义;把模型的调用意图路由到正确的 Server,是应用(MCP 客户端这一层)的事。工具只在一个应用里用时,进程内的工具中心就够了,两者的区别见「本地工具中心和 MCP Server 有什么区别?什么时候值得拆成独立的 MCP 服务?」。
四、有了 MCP,还需要 Function Calling 吗
需要。MCP 解决的是工具怎么接入,模型要「决定调用哪个工具」,仍然依赖模型的工具调用能力。如果模型不支持 Function Calling,应用也可以让模型按约定格式输出文本再解析,但那就回到了不可靠的自由文本解析。现实中的组合是:
| 场景 | 用什么 |
|---|---|
| 工具只在一个应用里用,和应用同一技术栈 | 只用 Function Calling + 本地工具就够 |
| 工具要被多个应用复用,或来自第三方 | MCP 接入 + Function Calling 交给模型 |
| 不需要模型选择,流程固定调用某个服务 | 直接调接口,两者都不需要 |
五、工具多了之后的新问题
接入 MCP 后,应用很容易一下子连上好几个 Server、拿到几十个工具。每个工具定义都要放进请求,占用上下文,也会让模型选错。用一组示意数字估算:
3 个 Server × 每个 15 个工具 = 45 个工具
每个工具定义(名称 + 说明 + 参数 Schema)约 200 token
仅工具定义就占 45 × 200 = 9000 token,而且每一轮请求都要带
所以接入 MCP 之后,按任务只启用需要的 Server 和工具、工具说明写清楚什么时候该用,仍然是应用自己的职责,协议不会替你收窄。
六、名字冲突与路由
不同的 Server 可能提供同名工具,比如两个 Server 都有 search。模型只看工具名,应用要保证交给模型的名字唯一,并能从名字反查到属于哪个 Server。常见做法是给工具名加上 Server 前缀,或者在应用侧维护「工具名 → Server」的映射表,出现重名时拒绝加载或重命名。这一层映射也是记录调用日志、做权限控制的地方:每次调用都要能说清是哪个 Server 的哪个工具。
七、常见误区与追问
- 误区:MCP 取代了 Function Calling。 两者管不同的两段,MCP 接入的工具最终仍通过模型的工具调用能力被选择。
- 误区:模型直接和 MCP Server 通信。 模型只看到工具定义并表达调用意图,和 Server 通信的是应用里的 MCP 客户端。
- 误区:用了 MCP 就不用管工具数量。 工具定义仍要进上下文,工具太多会占用 token、降低选择准确率。
- 误区:MCP 只能配合某一家模型使用。 MCP 与模型无关,同一个 Server 可以被接入不同模型的应用使用。
- 误区:只要支持 Function Calling,工具就能跨应用复用。 Function Calling 不规定工具从哪来,复用要靠 MCP 这类接入协议。
- 追问:MCP 工具定义和 Function Calling 工具定义怎么转换? 名称、说明、输入 Schema 基本一一对应,应用读出
tools/list的结果,按目标模型接口的格式包装即可。 - 追问:两个 Server 有同名工具怎么办? 应用侧保证交给模型的名字唯一,加前缀或维护映射,并能从名字路由回对应的 Server。
八、加强记忆
MCP 和 Function Calling 记「一个管模型怎么说,一个管工具怎么接」:Function Calling 连接模型和应用,规定工具怎么描述、模型怎么表达调用、结果怎么回传,但不规定工具从哪来;MCP 连接应用和工具提供方,用 JSON-RPC 完成初始化、tools/list 发现和 tools/call 调用,让工具写一次就能被多个应用复用,且与模型无关。一次调用里应用先从 Server 拿工具列表、转成模型的工具定义,模型用 Function Calling 选中工具,应用再用 MCP 把调用路由到对应 Server。接入 MCP 后仍要控制工具数量、保证工具名唯一、能反查到 Server。