MCP 与 Function Calling 深度辨析——概念、关系与手写实现
开篇:一个常见的混淆
做 AI 应用开发时,”MCP” 和 “Function Calling” 这两个词经常被混用。有人觉得它们是同一个东西,有人说 MCP 就是 Function Calling 的升级版。
都不对。它们不是替代关系,而是分工关系。
先给一个一句话结论,然后我们再拆开细讲:
Function Calling 是 LLM 的”决策能力”(它决定要调哪个工具),MCP 是”通信协议”(定义了工具如何被发现和调用)。前者是脑力,后者是神经传导系统。
一、Function Calling:LLM 的”脑力”
1.1 它到底是什么?
Function Calling 是 LLM 的一项内置能力——模型在推理时,除了生成文本,还可以输出一个结构化的 “我想调这个函数” 的意图:
1 | { |
注意:LLM 只是说出了这个意图,它自己没有执行这个函数。 真正执行是调用方(你的代码)的事。
1.2 工作流程
1 | 用户:"帮我查一下三角函数的资料" |
关键认知:Function Calling 只是 LLM 给你了一个”指令”,至于你怎么执行这个指令,和 LLM 无关。
1.3 没有 MCP 也能用 Function Calling
以 LangChain4j 为例:
1 | // 纯 Function Calling,不经过 MCP |
这里的一切都在 同一个 JVM 进程 里——LLM 客户端持有工具对象的引用,Function Calling 的结果直接映射到 Java 方法调用。没有网络通信,没有 JSON-RPC,没有 /mcp 端点。
这在单体应用里完全够用。那为什么还需要 MCP?
二、MCP:标准化通信协议
2.1 MCP 的全称和定位
MCP = Model Context Protocol,由 Anthropic 于 2024 年底提出。
它解决的不是 “LLM 如何决定调工具”(那是 Function Calling 的事),而是 “工具提供方和工具调用方之间如何以标准方式通信”。
2.2 MCP 定义了三个角色
1 | ┌──────────────┐ JSON-RPC 2.0 ┌──────────────┐ |
- MCP Host:运行 LLM 的应用,发起工具调用请求
- MCP Client:Host 内部的协议客户端,负责与 Server 通信
- MCP Server:暴露工具的轻量服务,处理
tools/list和tools/call
2.3 MCP 协议规定的方法
| 方法 | 方向 | 作用 |
|---|---|---|
initialize |
Client → Server | 握手,交换能力和协议版本 |
notifications/initialized |
Client → Server | 通知握手完成 |
tools/list |
Client → Server | 自动发现所有可用工具 |
tools/call |
Client → Server | 调用指定工具,传入参数 |
每一步都是标准的 JSON-RPC 2.0 消息:
1 | // → 请求 tools/list |
1 | // → 请求 tools/call |
三、核心区别:十个维度的对照
| 维度 | Function Calling | MCP |
|---|---|---|
| 本质 | LLM 的能力(输出结构化调用意图) | 通信协议(定义 Client-Server 交互格式) |
| 谁做的 | LLM 内部推理 | 应用层协议实现 |
| 解决什么问题 | “LLM 如何表达它想调工具” | “工具提供方和调用方如何标准化对接” |
| 通信方式 | 无——只是 LLM 的输出格式 | JSON-RPC 2.0 over HTTP/SSE |
| 工具发现 | 取决于框架(手动注册或注解) | tools/list 标准化自动发现 |
| 跨进程 | 不涉及 | 核心价值:跨进程、跨语言、跨网络 |
| 标准化程度 | 各 LLM 提供商格式略有差异 | 统一规范 2024-11-05 |
| 安全边界 | 无独立边界 | /mcp 端点可统一鉴权、限流、日志 |
| 能否独立部署 | 不能,绑定在 LLM 调用链路里 | 能,Server 独立部署和扩缩 |
| 与 LLM 的关系 | 依赖 LLM | 无关——理论上可以不走 LLM,直接用 REST 调工具 |
四、实际协作流程:它们怎么配合
来看一个完整的调用链路——用户在 AI 对话框里问 “最近张三成绩怎么样?”:
1 | 用户输入 |
分工总结:
- Function Calling 做了 Step 1(决策)和 Step 4(整合)
- MCP 做了 Step 2(传输)和 Step 3(执行)
- 少了任何一个,流程都跑不通
五、为什么需要 MCP?三个不可替代的理由
5.1 跨进程解耦
这是 MCP 最核心的价值。如果你的 LLM 网关和业务服务是两个独立的进程(甚至是两台机器),Function Calling 的 “本地方法调用” 模式就失效了。
1 | ❌ 单体模式(LLM 和工具在同一进程): |
5.2 自动发现
你新增一个工具:
1 |
|
不需要改任何其他代码。Spring 自动注入所有 ToolDefinition 实现类,tools/list 自动发现。LLM 不需要重新配置 Prompt,自动感知新工具的存在。
而在硬编码模式中,每加一个工具,你都要去 Controller 加 if-else 判断逻辑。
5.3 统一安全边界
所有工具调用都经过 /mcp 这一个入口:
1 |
|
所有工具调用可审计、可限流、可监控。硬编码的函数调用散落在各个 Controller 里,很难统一管理。
六、什么时候不该用 MCP
如果一个技术方案你只能说它好,不能说它不适合什么场景,那这篇文章就不够诚实。
6.1 单体应用不需要 MCP
你的 Spring Boot 项目是单体部署,LLM 调用和工具执行在同一个 JVM 进程里,LangChain4j 可以直接持有 Tool 对象的引用:
1 | Assistant assistant = AiServices.builder(Assistant.class) |
这种情况下引入 MCP 是过度设计:
- 本来是一次方法调用,变成一次 HTTP 请求;本来是一个断点能调试的,变成跨网络追日志
- 多了一个需要监控、运维、保活的独立服务
判断标准:如果你的工具和 LLM Gateway 打包在同一个 jar 里部署,用 Function Calling 就够了。
6.2 工具数很少且不常变化
只有 1~3 个工具,而且半年不变一次。你用 if-else 或者简单 Map 分发的维护成本远低于引入一整套 MCP 协议栈。MCP 的自动发现优势在工具数量大、频繁增减时才会体现。
6.3 团队规模小、没有跨团队协作
MCP 解决的一个重要问题是:工具提供方和 LLM 应用方由不同团队维护。如果你的项目是个人或 2~3 人团队全栈负责,引入 MCP 带来的边界清晰化收益接近于零,反而增加了沟通成本——只不过这次沟通双方变成了你自己写的两个服务。
6.4 小结
1 | 需要 MCP: |
七、MCP 的代价——没有免费的午餐
每一层抽象都有它的账单。引入 MCP 不是零成本的:
7.1 网络延迟
纯 Function Calling 模式下,一次工具调用就是一次 Java 方法调用,耗时可以忽略。换成 MCP 之后:
1 | 本地方法调用: ~0.01ms |
你每次 tools/list 要发请求,每次 tools/call 也要发请求。在你需要连续调 3 个工具(比如先查知识库、再查学生成绩、再查提交记录),这个延迟会叠加。对于需要实时响应的对话场景,每一次额外的网络往返都是用户体验的损耗。
7.2 序列化开销
所有参数和返回值都要走 JSON-RPC 序列化/反序列化。对于简单的 String 参数还好,但如果你需要传复杂对象(比如一个多层嵌套的配置 Bean),你需要在 JSON 和 Java 对象之间来回转换,处理类型丢失、循环引用、特殊字符转义等一系列问题。
7.3 错误处理复杂度爆炸
本地函数调用失败,你 catch 一个异常就完事了。MCP 模式下可能的失败点:
1 | 调用方 MCP Server 工具本身 |
你需要为每一个失败点写降级逻辑——是重试?是返回默认值?是告诉用户”系统繁忙请稍后再试”?这些在本地调用里根本不用考虑的问题,在 MCP 下都需要单独处理。
7.4 排错成本
1 | ❌ 本地模式: |
跨进程意味着你需要分布式链路追踪才能高效定位问题。没有 traceId 串起来的 MCP 调用链,排错就是灾难。
7.5 运维负担
多了一个需要部署、监控、扩容、保活的服务。MCP Server 挂了,你的 AI 功能就会降级——LLM 拿到 Function Calling 的指令后,发现工具调不通,只能回复”抱歉我无法获取这个信息”。你需要为这个服务配置健康检查、告警、自动重启,跟你的核心业务服务一样对待。
7.6 代价总结
1 | 引入 MCP 的隐性成本: |
这些代价不是说不该付,而是你决定引入 MCP 之前,心里要有这笔账。 如果你的场景确实需要跨进程解耦、工具自动发现、统一安全边界(如 Section 5 所述),那这些代价是值得的。如果只是想做本地函数调用,那是拿大炮打蚊子。
八、MCP 的现状与格局(2026 年中)
写这篇文章时是 2026 年 6 月——MCP 已经从一个实验性协议变成了 AI 基础设施层的关键拼图。保持客观:以下是目前的事实和正在进行的博弈。
8.1 治理:不再是 Anthropic 一家的东西
2025 年 12 月,Anthropic 将 MCP 捐赠给了 Linux 基金会旗下的 Agentic AI Foundation(AAIF)。联合创始方包括 OpenAI 和 Block,白金成员有 AWS、Google、Microsoft、Cloudflare、GitHub、Bloomberg。
这意味着 MCP 的治理模型对标的是 Kubernetes 和 PyTorch——不再由任何一家公司单独控制。对开发者来说,你不用担心”万一 Anthropic 改方向了怎么办”,协议的演进由社区共识驱动。
8.2 生态规模:千倍增长
| 指标 | 2024 年底 | 2026 年中 | 增长 |
|---|---|---|---|
| 月均 SDK 下载 | ~10 万 | ~9,700 万 | ~970× |
| 公开 MCP Server | ~1,200 | 10,000~17,000+ | ~10×+ |
| 原生支持 MCP 的客户端 | Claude | Claude、ChatGPT、Gemini、Cursor、Windsurf、VS Code + Copilot | — |
| 企业生产部署 | 0 公开案例 | Uber、亚马逊、Nordstrom、Bloomberg、Duolingo、PwC、Block 等 | — |
Block(原 Square)旗下的 Goose——基于 MCP 的企业级 AI Agent——已经有数千名员工日常使用,连接 Snowflake、GitHub、Jira、Slack、Google Drive,报告称节省 50%-75% 的时间。Gartner 预测到 2026 年底,40% 的企业应用将包含任务专属的 AI Agent。
8.3 协议架构:向无状态演进
MCP 正在经历自发布以来最大的架构改动——从有状态会话转向无状态请求(2026-07-28 候选版本已锁定):
- 弃用
initialize握手和Mcp-Session-Id头 - 协议元数据通过
_meta字段随每次请求传递 - 支持标准 HTTP 负载均衡,不再需要 sticky routing
对你手写 MCP Server 的影响:目前基于 2024-11-05 的实现可以继续用——协议委员会承诺 12 个月的平滑过渡期。但长期看,如果你还没实现过 MCP Server,现在可以直接按无状态模式设计,跳过有状态的历史包袱。
8.4 MCP Apps:工具可以返回界面
2026 年 1 月,MCP 发布了第一个官方扩展 MCP Apps——工具不仅能返回文本,还能返回交互式的 HTML 界面,在对话中以沙箱 iframe 渲染。Figma 用它做内联组件编辑,Hex 用它做可交互的数据看板。Claude、ChatGPT、VS Code 首日即支持。
这是一个信号:MCP 的野心不只是”调工具”,而是成为 Agent 与用户交互界面的标准传输层。
8.5 MCP 和 A2A:分工已基本明确
Google 主导的 **A2A(Agent-to-Agent)**协议在 2026 年发布了 v1.0,IBM 的 ACP 也并入了 A2A。两者都在 AAIF 下治理,分工现在很清晰:
1 | MCP = Agent ←→ 工具/数据/服务 (纵向连接) |
互不替代,各管一层。你的 Spring Boot 服务暴露的是工具接口,属于 MCP 的范畴;如果你的服务需要和另一个 AI Agent 进行任务协商和结果传递,那才是 A2A 的问题。
8.6 安全:最大的现实挑战
2026 年初,社区披露了 30+ 个 MCP 相关 CVE,包括一个 CVSS 9.6 的远程代码执行漏洞。核心威胁模型不是传统网络攻击,而是 工具投毒(Tool Poisoning)——恶意 MCP Server 在工具描述中嵌入隐藏指令,通过 LLM 的 Function Calling 机制间接操控 Agent 行为。
这在企业落地中催生了新的安全实践:网关层策略执行、工具元数据清理、高权限工具隔离、禁用”始终允许”按钮。MCP 2026 年路线图已将企业安全列为首位优先级。
8.7 一句话:MCP 现在的阶段
MCP 不再让人兴奋——它变得重要了。17 个月前,部署 MCP 意味着你是一个 early adopter;现在,部署 MCP 意味着你在用一套已被广泛验证的基础设施。 但它同时面临着无状态改造、安全治理、企业就绪等规模化问题——这些问题,恰恰证明它已经被用在了真正重要的地方。
九、一个常见误解:MCP Tool 不用写描述?
不是的。描述照样要手写。
1 |
|
这段代码你用 Function Calling 本地调用也得写,用 MCP 也得写。MCP 不省描述,省的是通信标准化和工具发现自动化。
十、总结:一句话记住两个概念
| Function Calling | MCP | |
|---|---|---|
| 一句话 | LLM 决定了”要调什么” | MCP 规定了”怎么调” |
| 类比 | 你的大脑决定要拿起杯子 | 你的神经系统传递信号给肌肉 |
| 如果没有它 | LLM 无法表达工具调用意图 | LLM 和服务之间通信靠 ad-hoc 编码,不可扩展 |
最后的最后:它们不是竞争对手,是搭档。Function Calling 让你有东西可调,MCP 让你能调得到——尤其是当 LLM 和工具不在同一个进程里的时候。





