MCP、Tool Calling、Function Calling 到底什么关系?我用自己接的几个 MCP 把它讲清楚

MCP、Tool Calling、Function Calling 到底什么关系

哈喽,我是飞飞。

前阵子我写过一篇《一文看懂 MCP》,讲的是它为什么会成为整个 AI 世界的标准、为什么 OpenAI、Cursor 都跟着支持。那篇聊的是「它为什么火」。今天这篇换个角度,专门拆一件后台问得最多、也最容易绕晕的事:MCP、Tool Calling、Function Calling,这三个词到底什么关系,差在哪。

说真的,很多人是这状态:天天在用 Agent,知道它能调外部工具,可你要是问一句「MCP 跟 function calling 是不是一回事」,多半答不上来。不怪你。这三个词在各种文章里混着用,有的当同义词,有的又说谁替代谁,越看越糊。

我自己的 Claude Code 上实打实接了好几个 MCP server,包括给文章生封面的、把稿子一键发到知乎掘金 CSDN 公众号的。说句你可能没想到的,你现在看到的这篇文章,最后多平台分发那一步,就是其中一个 MCP 干的。所以这事我没法隔空讲概念,全是拿天天在跑的活线讲。咱们一层层拆。

Function Calling 其实只干了一半的活

先说最里面那层,Function Calling。

你可以把大模型想成一个特别能聊、但被锁在屋里、手够不着外面任何东西的人。它脑子好使,可它没法上网、没法读你硬盘上的文件、没法查你的数据库。你问它「我数据库里上周有多少订单」,它只能说「我不知道,我连不上你的库」。

Function Calling 就是给这个人开了一扇窗。具体怎么开?你提前告诉模型:我这儿有个工具叫 query_orders,它能查订单,要传一个时间参数。模型听懂之后,下次你问订单的事,它不会瞎编,而是回你一段结构化的东西,大意是「我要调 query_orders 这个工具,参数是上周」。

这里有个关键,很多人没意识到:模型到这一步就停了。它只是「说」它想调哪个工具、传什么参数,吐出来一个 JSON。它本身并不会真去查你的数据库。真正动手那一步,得你自己写代码接住这个 JSON,把查询跑起来,再把结果喂回给模型。

Prefect 那篇技术博客把这事说得很准:Function Calling 负责的是 schema(也就是工具的声明),执行那部分得你自己补。所以你看,它干的其实只有一半的活,模型出意图,你出力气。

至于 Tool Calling,别被它绕进去。它跟 Function Calling 基本是一回事,只是叫法不同。OpenAI 官方管这个叫 function calling,Anthropic 管它叫 tool use,更口语的场合大家就叫 tool calling。Descope 的文章里写得很直白:每家厂商都有自己的版本,名字各取各的,干的是同一件事。所以你下回看到这俩词,心里清楚它们是同层的同义词就行,不用纠结。

那这套现成的,为啥还要再造一个 MCP

如果 Function Calling 已经能让模型调工具了,那 MCP 又是来解决什么的?

问题出在「不通用」上。每家大模型定义工具的格式都不一样。你给 OpenAI 写的那套工具声明,结构叫 tool_calls;同样的工具搬到 Claude 上,格式变成 tool_use,连字段名都对不上,Anthropic 这边叫 input_schema,到 OpenAI 那儿就成了套在 function 里的 parameters

这意味着什么?你辛辛苦苦给一个模型接了二十个工具,哪天想换个模型试试,这二十个工具的声明、解析、错误处理,基本得照着新格式重写一遍。工具还死死焊在你这一个应用里。别人想用你这套,没法直接拿走,得自己再撸一遍。

这就是 MCP 要解决的。它不是来替代 Function Calling 的,这点我得重点强调,网上一堆文章把它俩说成对立关系,全错了。Portkey 那篇讲得最清楚:MCP 不替代 Function Calling,它俩在不同层。Function Calling 还是那个 Function Calling,模型该怎么表达调用意图还怎么表达。MCP 是架在上面的一层标准协议,把「工具怎么被发现、怎么被调用、结果怎么回来」这套执行的活,定成了一个跟厂商无关的统一规矩。

打个我自己琢磨出来的比方。Function Calling 像是你家墙里直接焊死的几个电器,台灯、风扇,焊在哪就只能在哪用,换房子带不走。MCP 像是墙上装了标准插座,任何电器,只要插头是这个标准的,插上就能用,换台电脑、换个模型,插座还在那儿。你的工具从此不绑死在某一个模型身上了。

技术上它怎么实现的?底层用的是一个叫 JSON-RPC 的老协议,结构是 client 和 server。你的 Agent 这边是 client,每个外部工具包成一个 server。Agent 一连上某个 server,先问它一句「你有哪些工具」(这步叫 discovery),server 把工具清单连描述带参数格式一并报上来;模型看完描述自己挑该用哪个,再带着参数去调。整个流程标准化了,所以同一个 MCP server,插到任何支持 MCP 的客户端上都能用,不用为每家模型各写一遍。

一个 Claude Code,同时挂着好几个 MCP

光说协议有点干,落到我自己的活上你就懂了。

我的 Claude Code 现在同时挂着好几个 MCP server。一个叫 banana-image,专门生图,我写文章配封面这事是自动的,在对话里说一句「给这篇配张封面」,背后就是这个 server 去调 Nano Banana 生图、再传到我自己的图床,我这头只管说话,回头图就在那儿了。还有一个叫 sync-assistant,管多平台分发,一篇稿子写完,它能帮我推到知乎、掘金、CSDN、公众号。前面说的,这篇文章发出去那一步,就是它干的。

除了这俩,还挂着查资料用的搜索 server、抓网页内容的 fetch、查最新技术文档的 context7。它们各管各的事,互不打架。这就是 MCP 架构最实在的好处:一个 host(我的 Claude Code)底下能同时连一串 server,每个 server 是一个独立的能力包。官方文档里也是这么说的,Claude Desktop 同时连三个 server,它就维护三个独立的 client,一对一,谁出问题不牵连别人。

你把这套放回前面那个比方再看一遍就通了。我的 Claude Code 是那面装满插座的墙,banana-image、sync-assistant 是各自插上来的电器,搜索、抓网页、查文档又是另外几个。我哪天想加个新能力,比如让它直接读写我的数据库,再插一个数据库 server 上去就行,不用动其他任何一个。这种「随插随用、各自独立」的体感,是单纯靠 Function Calling 焊在一个应用里给不了我的。

也正因为这套链路全自动,我前阵子还踩过一个隐蔽的坑。我整条博客发布是 GitHub Actions 自动化的,结果有个部署用的令牌悄悄过期了,构建明明成功,只有最后一步推送失败,红了一整天没人发现,我隔天主动去查才看到。这事跟 MCP 没直接关系,但它提醒我一件事:能力越自动、链路越长,你越得给「失败」本身配个能看见的告警。MCP 让接外部工具变得轻松,可工具接得越多,哪个 server 哑了你也得心里有数,不能全甩给它跑。

三个词,一句话各自归位

绕了一圈,我把这三个词给你各自归个位,记这一段就够了。

Function Calling,是模型「说」它想调哪个工具、传什么参数,只出一个意图,不负责执行。Tool Calling,是它的口语别名,同一层东西,不同厂商不同叫法而已。MCP,是架在上面的一层标准协议,把工具怎么被发现、怎么被调用、结果怎么回来,统一成一套跟模型无关的规矩,让你的工具不绑死在某一个模型上。

所以 Agent 那身「能调外部工具」的本事,底层就是从这儿来的:模型靠 Function Calling 表达意图,MCP 把这意图标准化地接到真实世界的工具上去执行。理解了这层,你再看任何一个号称能「接数据库、连搜索、读文件」的 Agent,心里就有底了,知道它那点能耐是怎么搭起来的,也知道该怎么自己搭一套。

回到开头那个问题,MCP 跟 Function Calling 是不是一回事。现在你应该能干脆地回一句:不是替代,是上下两层,一个出意图,一个管执行,各干各的还配合得好好的。

你自己有没有给 AI 接过外部工具?是停在用现成 Function Calling 这一步,还是已经动手挂过 MCP server 了,挂的是哪个,欢迎在评论区聊聊。