「Agent Tool」MCP 和 Function Calling 有什么区别?有没有实际跑过 MCP?
0 前言
本文内容整理自公众号「小林面试笔记」的文章 6. MCP 和 Function Calling 有什么区别?有没有实际跑过 MCP?,用于记录与总结 AI Agent 工具调用相关的核心面试知识点。
「MCP 和 Function Calling 有什么区别?有没有实际跑过 MCP?」,可以这样作答:
MCP 和 Function Calling 解决的不是同一层面的问题,两者是上下层的配合关系,不是竞争或替代关系。Function Calling 是「调用语言」,定义的是单次调用怎么表达——工具定义用什么格式传给模型、模型怎么输出「我要调哪个函数、参数是什么」、执行结果怎么喂回对话;MCP 是「工具生态协议」,定义的是工具怎么标准化打包、注册被 AI 客户端自动发现、跨项目复用。
打个比方:Function Calling 像 HTTP 请求格式,MCP 像 REST API 的设计规范加服务注册发现机制——一个管「怎么传」,一个管「怎么组织和管理」。少了谁这套机制都运转不起来。
最关键的是:MCP 底层依然靠 Function Calling 驱动。MCP Client 连上 Server 后自动拉取工具定义(
list_tools接口),转成模型原生的 Function Calling 格式传给模型;模型照常输出tool_calls,Client 再路由到对应 Server 执行,结果以 tool 消息回填对话。整个过程模型完全感知不到 MCP 的存在,工具发现、schema 转换、调用路由全发生在宿主程序层——所以模型如果不支持 Function Calling,MCP 就完全不可用。实际跑过的经验:在 Claude Desktop 的配置文件里给文件系统、GitHub 各加几行 JSON,重启后客户端自动启动 Server 进程、自动发现工具,全程不用写一行对接代码;自己写一个 MCP Server(Python)核心也就三步,不超过 30 行代码。
如今 Claude Desktop、Cursor 等主流 AI 客户端都已内置 MCP 支持,GitHub、文件系统、数据库、浏览器自动化都有现成的官方或社区 Server——配置几行 JSON、重启即可用;而对大多数直接调模型 API 的产品来说,临时接一两个工具时仍是直接写 Function Calling 最省事。两种方式各归其位、互不取代,这恰好印证了它们不是竞争关系。
1 先破除误区:MCP 不是 Function Calling 的升级版
很多人第一次见到 MCP 时的第一反应:MCP 是 Function Calling 的升级版,MCP 出来之后 Function Calling 就该被淘汰了。这个直觉错在层次上——两个概念根本不在一个层面。
先给两个概念定位:Function Calling 是「调用语言」,定义的是模型怎么表达「我要调哪个函数、参数是什么」;MCP 是「工具生态协议」,定义的是工具怎么标准化打包、注册、被 AI 客户端发现。
有一个非常贴切的类比:HTTP 协议出来之后,我们在网络上传数据已经不成问题了,为什么还需要 REST API 规范?

因为 HTTP 解决的是「怎么传」——一次请求长什么样、用什么方法、怎么编码;REST 解决的是「怎么组织和管理」——资源怎么命名、端点怎么设计、状态怎么表达、多个服务之间怎么复用同一套约定。两个不同层次的事。
Function Calling 和 MCP 正是同样的关系:FC 管「一次函数调用请求长什么样」,MCP 管「一堆工具怎么被组织、发现、跨项目复用」。前者是格式,后者是规范加生态约定——前者负责「说清楚」,后者负责「管起来」。
2 Function Calling 解决的是「一次调用」的格式问题
从开发者视角看,Function Calling 回答的是这几个问题:工具定义用什么格式传给模型?模型想调工具时怎么表达「我要调哪个函数、参数是什么」?工具执行结果怎么喂回对话?
它定义的是单次调用的消息格式,仅此而已。每次使用,开发者都要手动写工具的 schema 定义,手动写调用逻辑,手动处理执行结果。Function Calling 本身没有任何工具管理、工具发现、跨项目复用的概念——它完完全全只管「这一次调用长什么样」。(运行时怎么闭环的,我们在第 1 篇里完整讲过:schema 传入、模型输出 tool_calls、代码执行回填。)
这就是边界:FC 把「一次调用」做到了极致,但一次调用之外的世界,它一概不管。
3 Function Calling 的痛点:每次对接都是一次性手工活
「每次都要手动」到底有多痛?你可能觉得复制一份 schema 没什么工作量,但工具一多、项目一多,问题就暴露出来了。
假设你在 A 项目里定义了 10 个工具的 schema 和对接逻辑,现在 B 项目也要用这些工具,怎么办?把那 10 个 schema 复制过来、对接逻辑重写一遍。写完还没完——A 项目用的是 Claude API,B 项目换成了 GPT-4,两边 Function Calling 的格式不完全一样,又得各自维护一套适配代码。这还不算完,如果某个工具的接口变了呢?你得去每个用到它的项目里逐一更新,漏改一处就是 bug。
把这个账算一下就明白痛点规模了:假设团队有 5 个应用、每个应用要接 8 个工具,那就是 40 份工具对接代码在维护。某天 GitHub API 的某个字段变了,你要在 5 个地方同步改,只要漏掉一个,那个应用凌晨就要报警;再假设要从 Claude 迁到 GPT-4,这 40 份代码里的 Function Calling 格式全部重新适配一遍,整个组的季度就交代进去了。

问题一目了然:同一个工具,换个项目就要重新对接一遍,每次都是一次性的手工活。这就是 Function Calling 解决不了的核心问题——工具的管理、复用和跨平台兼容。
4 MCP 的思路:把工具变成标准化服务
痛点既然「每个应用各自维护一套工具定义」,解决思路也就自然了:把工具做成独立的标准化服务,谁要用就来连,不用每次都重写一遍。这就是 MCP 的核心思路。
工具提供方实现一个 MCP Server:它是一个独立运行的进程,对外暴露标准接口,告诉外界「我有哪些工具、每个工具怎么调用」。任何支持 MCP 的 AI 客户端连上来,就能自动发现并使用里面的工具,完全不需要手写对接代码。

这带来的改变是质的:工具只实现一次,所有 AI 客户端都能用。GitHub 的官方 MCP Server 写好之后,不管你是用 Claude Desktop、Cursor 还是自己写的 Agent,连上去就能用,不需要各自维护一份 GitHub API 的调用代码——这才是 MCP 的真正价值。

5 最关键的连接:MCP 底层依然靠 Function Calling 驱动
这是很多人没想清楚的一点:MCP 不是 Function Calling 的替代品,而是建立在 Function Calling 之上。
看一条完整的调用链路就懂了:
- MCP Client 连上 Server,自动向它拉取所有工具的定义(调用
list_tools接口); - Client 把这些定义转换成模型原生的 Function Calling 格式传给模型;
- 模型照常输出
tool_calls来表达「我要调哪个工具」——它根本不知道背后有 Server; - Client 把调用请求路由到对应的 Server 去执行;
- 拿到结果后以 tool 消息的形式喂回对话。

从模型的视角来看,它完全感知不到 MCP 的存在,以为自己只是在做普通的 Function Calling。MCP 的所有「魔法」都发生在宿主程序层:工具的自动发现、schema 的格式转换、调用请求的路由、执行结果的返回,全在这一层默默完成。
这也推出一个硬结论:如果模型本身不支持 Function Calling,MCP 就完全没办法用——因为这个「翻译层」失效了。MCP 是站在 FC 肩膀上盖的楼,不是把 FC 拆掉的拆迁队。
6 实际跑一遍 MCP
接入一个现成 Server:配置几行 JSON
以 Claude Desktop 接入文件系统 MCP 为例,只需要编辑 claude_desktop_config.json,加入如下配置:
1 | |
这几行配置告诉 MCP Client:用 npx 这个命令启动文件系统 Server,把 /Users/yourname/Documents 目录作为允许访问的范围。command 和 args 组合起来就是启动 Server 进程的命令行——MCP Client 会把它作为子进程启动,通过标准输入输出和它通信。
配好之后重启 Claude Desktop,它会自动启动这个 Server 进程、自动发现里面提供的工具。然后你直接问「帮我读一下 Documents 里的 report.md」,Claude 会自动调用文件系统工具完成任务——全程你没写一行对接代码。
自己写一个 MCP Server:三步 30 行
如果不想用现成的,自己写一个 Server 也极其简单,核心就三步:用 @app.list_tools() 声明这个 Server 提供哪些工具及参数格式,用 @app.call_tool() 实现每个工具的真实执行逻辑,最后用 stdio 方式运行,让 Client 能通过管道和它通信:
1 | |
整个 Server 加起来不超过 30 行——Anthropic 开源的 MCP SDK 已经把底层的协议通信都封装好了,你只需要关心「工具有哪些、每个工具怎么执行」。
然后编辑 claude_desktop_config.json,把这个 Python 服务注册进去:
1 | |
注意路径要改成你自己实际存放文件的绝对路径,如果你的系统里 Python 命令是 python3,command 也要对应改过来。
重启 Claude Desktop 后直接输入「帮我算一下 25 加 17 等于多少」,Claude 就会自动调用你写的 add_numbers 工具并返回结果。整个流程里你只写了工具逻辑本身,通信、发现、调用路由全部由 MCP 框架搞定——这就是「模型负责决策、框架负责执行」的典型体验。
7 怎么选:用 FC 还是上 MCP
选型没有绝对答案,看场景:
临时给应用接一两个工具——Function Calling 就够用了。简单直接,不需要引入额外的进程和协议,一个 schema 一个回调就完事。
工具多了、需要跨项目复用、或者想直接用社区里已有的成熟 Server(GitHub、数据库、浏览器自动化都有现成的)——MCP 就值得上。接一个新工具就是在配置文件里加几行、重启后自动生效,比手写对接代码省事得多。
做 Agent 系统的话,更优先考虑 MCP。Agent 的工具来源杂、数量多,如果全靠手写 Function Calling 维护,工具定义代码会散落在各处,极难管理。MCP 的自动发现和统一管理能让架构干净很多:新增工具不需要改主程序逻辑,接上 Server 就行。

8 面试总结
回答这道题,最大的雷就是把 MCP 当成 Function Calling 的「替代品」或「升级版」——这是很多人的第一反应,但完全搞反了两者的关系。先避开三个经典误区:
| 误区 | 正解 |
|---|---|
| MCP 是 FC 的升级版 / FC 将被淘汰 | 两个不同抽象层次:FC 管单次调用格式,MCP 管工具生态标准化,是上下层配合关系 |
| MCP 只是把 FC「换了个写法」 | 本质差异在标准化管理、自动发现、跨项目复用,不是写法问题 |
| MCP 和 FC 是竞争关系、二选一 | 缺了 FC,MCP 根本转不起来——MCP 底层由 FC 驱动 |
再按这张框架组织答案:
| 框架 | 要点 |
|---|---|
| FC 定位 | 「调用语言」:单次调用的消息格式(schema 怎么传、tool_calls 怎么表达、结果怎么回填),每次对接都是一次性手工活 |
| MCP 定位 | 「工具生态协议」:工具标准化打包、注册、自动发现、跨项目复用(HTTP vs REST 类比:一个管怎么传,一个管怎么组织管理) |
| 最关键联系 | MCP 底层由 FC 驱动:list_tools 拉定义 → 转原生 FC 格式 → 模型输出 tool_calls → Client 路由到 Server;模型感知不到 MCP,「魔法」全在宿主程序层 |
| 实际经验 | Claude Desktop 配置几行 JSON 接入 filesystem / GitHub,重启即自动发现;自研 Python Server 三步(list_tools / call_tool / stdio)30 行搞定 |
| 选型 | 临时接一两个工具用 FC;工具多、跨项目复用、做 Agent 系统上 MCP |
追问预案:
- 「MCP 和 Function Calling 到底是什么关系?」——不同层面的上下层配合:FC 管单次调用的消息格式,MCP 管工具生态的标准化管理;MCP 建立在 FC 之上,两者互补(FC 运行时机制详见第 1 篇,MCP 组成结构详见第 3 篇)。
- 「MCP 底层靠什么驱动工具调用?」——Function Calling。Client 把 Server 的工具定义转成模型原生的 FC 格式,模型输出
tool_calls表达调用意图;模型不支持 FC,MCP 的翻译层就失效。 - 「模型能感知到 MCP 的存在吗?」——不能。工具的自动发现、schema 转换、调用路由、结果回填全发生在宿主程序层,模型以为自己只是在做普通 Function Calling。
- 「接入一个 MCP Server 需要写多少代码?」——用现成的:配置文件里几行 JSON,重启自动生效;自己实现 Server:核心三步(
list_tools/call_tool/ stdio),30 行内。 - 「既然 MCP 这么好,Function Calling 会被淘汰吗?」——不会,MCP 恰恰离不开 FC;而且轻量场景下直接写 FC 更简单直接,两者各归其位。
参考
本文图片均来源于公众号「小林面试笔记」,版权归原作者所有。