Function Call 与 MCP:一个是"手",一个是"插座"
一句话总结 :Function Call 解决"模型怎么开口要工具" ------模型输出一段结构化 JSON,说"我要调
get_weather,参数是北京";MCP 解决"工具怎么被复用" ------它把工具、数据、提示词按统一协议暴露出来,让任何 AI 应用都能接任何 工具。两者不是替代关系,而是分层关系 :MCP 暴露的工具,最终还是通过 Function Call 交给模型去选 。一句话:Function Call 是模型的手,MCP 是墙上统一的插座。
📋 目录
- 先看一张图:它们根本不在同一层
- Function Call:模型如何"开口要工具"
- MCP:把 N×M 变成 N+M
- 关键澄清:MCP 不能替代 Function Call
- MCP 的三个核心概念 + 2026 年的重大变化
- 最小代码:一个工具,两种写法
- 三个最容易踩的坑
- 什么时候用哪个
- 总结
一、先看一张图:它们根本不在同一层
#mermaid-svg-NRBbuQdrGNzVD3MC{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-NRBbuQdrGNzVD3MC .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-NRBbuQdrGNzVD3MC .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-NRBbuQdrGNzVD3MC .error-icon{fill:#552222;}#mermaid-svg-NRBbuQdrGNzVD3MC .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-NRBbuQdrGNzVD3MC .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-NRBbuQdrGNzVD3MC .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-NRBbuQdrGNzVD3MC .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-NRBbuQdrGNzVD3MC .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-NRBbuQdrGNzVD3MC .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-NRBbuQdrGNzVD3MC .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-NRBbuQdrGNzVD3MC .marker{fill:#333333;stroke:#333333;}#mermaid-svg-NRBbuQdrGNzVD3MC .marker.cross{stroke:#333333;}#mermaid-svg-NRBbuQdrGNzVD3MC svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-NRBbuQdrGNzVD3MC p{margin:0;}#mermaid-svg-NRBbuQdrGNzVD3MC .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-NRBbuQdrGNzVD3MC .cluster-label text{fill:#333;}#mermaid-svg-NRBbuQdrGNzVD3MC .cluster-label span{color:#333;}#mermaid-svg-NRBbuQdrGNzVD3MC .cluster-label span p{background-color:transparent;}#mermaid-svg-NRBbuQdrGNzVD3MC .label text,#mermaid-svg-NRBbuQdrGNzVD3MC span{fill:#333;color:#333;}#mermaid-svg-NRBbuQdrGNzVD3MC .node rect,#mermaid-svg-NRBbuQdrGNzVD3MC .node circle,#mermaid-svg-NRBbuQdrGNzVD3MC .node ellipse,#mermaid-svg-NRBbuQdrGNzVD3MC .node polygon,#mermaid-svg-NRBbuQdrGNzVD3MC .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-NRBbuQdrGNzVD3MC .rough-node .label text,#mermaid-svg-NRBbuQdrGNzVD3MC .node .label text,#mermaid-svg-NRBbuQdrGNzVD3MC .image-shape .label,#mermaid-svg-NRBbuQdrGNzVD3MC .icon-shape .label{text-anchor:middle;}#mermaid-svg-NRBbuQdrGNzVD3MC .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-NRBbuQdrGNzVD3MC .rough-node .label,#mermaid-svg-NRBbuQdrGNzVD3MC .node .label,#mermaid-svg-NRBbuQdrGNzVD3MC .image-shape .label,#mermaid-svg-NRBbuQdrGNzVD3MC .icon-shape .label{text-align:center;}#mermaid-svg-NRBbuQdrGNzVD3MC .node.clickable{cursor:pointer;}#mermaid-svg-NRBbuQdrGNzVD3MC .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-NRBbuQdrGNzVD3MC .arrowheadPath{fill:#333333;}#mermaid-svg-NRBbuQdrGNzVD3MC .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-NRBbuQdrGNzVD3MC .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-NRBbuQdrGNzVD3MC .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-NRBbuQdrGNzVD3MC .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-NRBbuQdrGNzVD3MC .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-NRBbuQdrGNzVD3MC .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-NRBbuQdrGNzVD3MC .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-NRBbuQdrGNzVD3MC .cluster text{fill:#333;}#mermaid-svg-NRBbuQdrGNzVD3MC .cluster span{color:#333;}#mermaid-svg-NRBbuQdrGNzVD3MC div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-NRBbuQdrGNzVD3MC .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-NRBbuQdrGNzVD3MC rect.text{fill:none;stroke-width:0;}#mermaid-svg-NRBbuQdrGNzVD3MC .icon-shape,#mermaid-svg-NRBbuQdrGNzVD3MC .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-NRBbuQdrGNzVD3MC .icon-shape p,#mermaid-svg-NRBbuQdrGNzVD3MC .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-NRBbuQdrGNzVD3MC .icon-shape .label rect,#mermaid-svg-NRBbuQdrGNzVD3MC .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-NRBbuQdrGNzVD3MC .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-NRBbuQdrGNzVD3MC .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-NRBbuQdrGNzVD3MC :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} Function Call
输出 tool_calls
MCP 协议
tools/call
结果
tool 消息
👤 用户提问
🧠 大模型
(判断:要不要调工具、调哪个)
🖥️ Host 应用
(执行调度)
🔌 MCP Server
(真正干活的工具)
✅ 最终回答
看这张图就能明白:
| 管什么 | 在哪一层 | |
|---|---|---|
| Function Call | 模型**表达"我要调工具"**的语言 | 模型能力层 |
| MCP | 应用发现和调用工具的接口标准 | 工程集成层 |
它们解决的是完全不同的问题。 一个在"模型怎么说话",一个在"系统怎么接线"。
二、Function Call:模型如何"开口要工具"
2.1 一次完整的往返
Function Call 的本质是一个"三段式"循环 ,模型自己不执行任何东西:
真实函数 大模型 应用 真实函数 大模型 应用 #mermaid-svg-D2wM8SxIZ4wmktIv{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-D2wM8SxIZ4wmktIv .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-D2wM8SxIZ4wmktIv .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-D2wM8SxIZ4wmktIv .error-icon{fill:#552222;}#mermaid-svg-D2wM8SxIZ4wmktIv .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-D2wM8SxIZ4wmktIv .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-D2wM8SxIZ4wmktIv .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-D2wM8SxIZ4wmktIv .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-D2wM8SxIZ4wmktIv .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-D2wM8SxIZ4wmktIv .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-D2wM8SxIZ4wmktIv .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-D2wM8SxIZ4wmktIv .marker{fill:#333333;stroke:#333333;}#mermaid-svg-D2wM8SxIZ4wmktIv .marker.cross{stroke:#333333;}#mermaid-svg-D2wM8SxIZ4wmktIv svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-D2wM8SxIZ4wmktIv p{margin:0;}#mermaid-svg-D2wM8SxIZ4wmktIv .actor{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-D2wM8SxIZ4wmktIv text.actor>tspan{fill:black;stroke:none;}#mermaid-svg-D2wM8SxIZ4wmktIv .actor-line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-D2wM8SxIZ4wmktIv .innerArc{stroke-width:1.5;stroke-dasharray:none;}#mermaid-svg-D2wM8SxIZ4wmktIv .messageLine0{stroke-width:1.5;stroke-dasharray:none;stroke:#333;}#mermaid-svg-D2wM8SxIZ4wmktIv .messageLine1{stroke-width:1.5;stroke-dasharray:2,2;stroke:#333;}#mermaid-svg-D2wM8SxIZ4wmktIv #arrowhead path{fill:#333;stroke:#333;}#mermaid-svg-D2wM8SxIZ4wmktIv .sequenceNumber{fill:white;}#mermaid-svg-D2wM8SxIZ4wmktIv #sequencenumber{fill:#333;}#mermaid-svg-D2wM8SxIZ4wmktIv #crosshead path{fill:#333;stroke:#333;}#mermaid-svg-D2wM8SxIZ4wmktIv .messageText{fill:#333;stroke:none;}#mermaid-svg-D2wM8SxIZ4wmktIv .labelBox{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-D2wM8SxIZ4wmktIv .labelText,#mermaid-svg-D2wM8SxIZ4wmktIv .labelText>tspan{fill:black;stroke:none;}#mermaid-svg-D2wM8SxIZ4wmktIv .loopText,#mermaid-svg-D2wM8SxIZ4wmktIv .loopText>tspan{fill:black;stroke:none;}#mermaid-svg-D2wM8SxIZ4wmktIv .loopLine{stroke-width:2px;stroke-dasharray:2,2;stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-D2wM8SxIZ4wmktIv .note{stroke:#aaaa33;fill:#fff5ad;}#mermaid-svg-D2wM8SxIZ4wmktIv .noteText,#mermaid-svg-D2wM8SxIZ4wmktIv .noteText>tspan{fill:black;stroke:none;}#mermaid-svg-D2wM8SxIZ4wmktIv .activation0{fill:#f4f4f4;stroke:#666;}#mermaid-svg-D2wM8SxIZ4wmktIv .activation1{fill:#f4f4f4;stroke:#666;}#mermaid-svg-D2wM8SxIZ4wmktIv .activation2{fill:#f4f4f4;stroke:#666;}#mermaid-svg-D2wM8SxIZ4wmktIv .actorPopupMenu{position:absolute;}#mermaid-svg-D2wM8SxIZ4wmktIv .actorPopupMenuPanel{position:absolute;fill:#ECECFF;box-shadow:0px 8px 16px 0px rgba(0,0,0,0.2);filter:drop-shadow(3px 5px 2px rgb(0 0 0 / 0.4));}#mermaid-svg-D2wM8SxIZ4wmktIv .actor-man line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-D2wM8SxIZ4wmktIv .actor-man circle,#mermaid-svg-D2wM8SxIZ4wmktIv line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;stroke-width:2px;}#mermaid-svg-D2wM8SxIZ4wmktIv :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} ① 用户问题 + 可用工具列表 ② tool_calls: {name: "get_weather", args: {city: "北京"}} ③ 应用去执行(模型不执行) ④ "北京 晴 25℃" ⑤ 把结果作为 tool 消息回传 ⑥ 基于结果生成最终回答
关键点:模型只负责"决定"和"填参数",执行永远是应用的事。
2.2 协议长什么样
第一步,把工具描述给模型:
json
{
"model": "gpt-4o",
"messages": [{"role": "user", "content": "北京天气怎么样?"}],
"tools": [{
"type": "function",
"function": {
"name": "get_weather",
"description": "查询指定城市的实时天气",
"parameters": {
"type": "object",
"properties": {
"city": {"type": "string", "description": "城市名称,如 北京"}
},
"required": ["city"]
}
}
}]
}
第二步,模型回一个"调用意图":
json
{
"choices": [{
"finish_reason": "tool_calls",
"message": {
"role": "assistant",
"tool_calls": [{
"id": "call_abc123",
"type": "function",
"function": {
"name": "get_weather",
"arguments": "{\"city\": \"北京\"}"
}
}]
}
}]
}
第三步,应用执行完,把结果塞回去:
json
{
"role": "tool",
"tool_call_id": "call_abc123",
"content": "北京 晴,25℃"
}
模型拿到结果后继续生成,就得到了自然语言回答。
2.3 它有三个天然局限
| 局限 | 后果 |
|---|---|
| 工具定义要写在每次请求里 | 工具一变,所有应用的 prompt 都要改 |
| 各家格式不统一 | OpenAI / Claude / Gemini 的 schema 有差异,换模型要重写 |
| 工具和执行绑在应用里 | 你写的天气工具,别人的应用用不了 |
🎯 这三个局限,正好就是 MCP 要解决的问题。
三、MCP:把 N×M 变成 N+M
3.1 没有 MCP 的世界
假设你有 3 个 AI 应用 (IDE、客服机器人、个人助手)和 4 个工具(数据库、文件系统、GitHub、搜索)。
每一个应用都要为每一个工具写一遍适配代码:
#mermaid-svg-nbsOFgdHod05xbc4{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-nbsOFgdHod05xbc4 .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-nbsOFgdHod05xbc4 .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-nbsOFgdHod05xbc4 .error-icon{fill:#552222;}#mermaid-svg-nbsOFgdHod05xbc4 .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-nbsOFgdHod05xbc4 .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-nbsOFgdHod05xbc4 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-nbsOFgdHod05xbc4 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-nbsOFgdHod05xbc4 .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-nbsOFgdHod05xbc4 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-nbsOFgdHod05xbc4 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-nbsOFgdHod05xbc4 .marker{fill:#333333;stroke:#333333;}#mermaid-svg-nbsOFgdHod05xbc4 .marker.cross{stroke:#333333;}#mermaid-svg-nbsOFgdHod05xbc4 svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-nbsOFgdHod05xbc4 p{margin:0;}#mermaid-svg-nbsOFgdHod05xbc4 .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-nbsOFgdHod05xbc4 .cluster-label text{fill:#333;}#mermaid-svg-nbsOFgdHod05xbc4 .cluster-label span{color:#333;}#mermaid-svg-nbsOFgdHod05xbc4 .cluster-label span p{background-color:transparent;}#mermaid-svg-nbsOFgdHod05xbc4 .label text,#mermaid-svg-nbsOFgdHod05xbc4 span{fill:#333;color:#333;}#mermaid-svg-nbsOFgdHod05xbc4 .node rect,#mermaid-svg-nbsOFgdHod05xbc4 .node circle,#mermaid-svg-nbsOFgdHod05xbc4 .node ellipse,#mermaid-svg-nbsOFgdHod05xbc4 .node polygon,#mermaid-svg-nbsOFgdHod05xbc4 .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-nbsOFgdHod05xbc4 .rough-node .label text,#mermaid-svg-nbsOFgdHod05xbc4 .node .label text,#mermaid-svg-nbsOFgdHod05xbc4 .image-shape .label,#mermaid-svg-nbsOFgdHod05xbc4 .icon-shape .label{text-anchor:middle;}#mermaid-svg-nbsOFgdHod05xbc4 .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-nbsOFgdHod05xbc4 .rough-node .label,#mermaid-svg-nbsOFgdHod05xbc4 .node .label,#mermaid-svg-nbsOFgdHod05xbc4 .image-shape .label,#mermaid-svg-nbsOFgdHod05xbc4 .icon-shape .label{text-align:center;}#mermaid-svg-nbsOFgdHod05xbc4 .node.clickable{cursor:pointer;}#mermaid-svg-nbsOFgdHod05xbc4 .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-nbsOFgdHod05xbc4 .arrowheadPath{fill:#333333;}#mermaid-svg-nbsOFgdHod05xbc4 .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-nbsOFgdHod05xbc4 .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-nbsOFgdHod05xbc4 .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-nbsOFgdHod05xbc4 .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-nbsOFgdHod05xbc4 .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-nbsOFgdHod05xbc4 .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-nbsOFgdHod05xbc4 .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-nbsOFgdHod05xbc4 .cluster text{fill:#333;}#mermaid-svg-nbsOFgdHod05xbc4 .cluster span{color:#333;}#mermaid-svg-nbsOFgdHod05xbc4 div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-nbsOFgdHod05xbc4 .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-nbsOFgdHod05xbc4 rect.text{fill:none;stroke-width:0;}#mermaid-svg-nbsOFgdHod05xbc4 .icon-shape,#mermaid-svg-nbsOFgdHod05xbc4 .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-nbsOFgdHod05xbc4 .icon-shape p,#mermaid-svg-nbsOFgdHod05xbc4 .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-nbsOFgdHod05xbc4 .icon-shape .label rect,#mermaid-svg-nbsOFgdHod05xbc4 .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-nbsOFgdHod05xbc4 .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-nbsOFgdHod05xbc4 .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-nbsOFgdHod05xbc4 :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 应用1
工具1
工具2
工具3
应用2
应用3
3 × 4 = 12 份适配代码。 加一个应用就是 4 份新代码,加一个工具就是 3 份新代码。
3.2 有 MCP 的世界
工具只需要按 MCP 标准做成一个 Server,应用只需要实现一个 MCP Client:
#mermaid-svg-rsuvXibeJahCjzw8{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-rsuvXibeJahCjzw8 .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-rsuvXibeJahCjzw8 .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-rsuvXibeJahCjzw8 .error-icon{fill:#552222;}#mermaid-svg-rsuvXibeJahCjzw8 .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-rsuvXibeJahCjzw8 .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-rsuvXibeJahCjzw8 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-rsuvXibeJahCjzw8 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-rsuvXibeJahCjzw8 .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-rsuvXibeJahCjzw8 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-rsuvXibeJahCjzw8 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-rsuvXibeJahCjzw8 .marker{fill:#333333;stroke:#333333;}#mermaid-svg-rsuvXibeJahCjzw8 .marker.cross{stroke:#333333;}#mermaid-svg-rsuvXibeJahCjzw8 svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-rsuvXibeJahCjzw8 p{margin:0;}#mermaid-svg-rsuvXibeJahCjzw8 .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-rsuvXibeJahCjzw8 .cluster-label text{fill:#333;}#mermaid-svg-rsuvXibeJahCjzw8 .cluster-label span{color:#333;}#mermaid-svg-rsuvXibeJahCjzw8 .cluster-label span p{background-color:transparent;}#mermaid-svg-rsuvXibeJahCjzw8 .label text,#mermaid-svg-rsuvXibeJahCjzw8 span{fill:#333;color:#333;}#mermaid-svg-rsuvXibeJahCjzw8 .node rect,#mermaid-svg-rsuvXibeJahCjzw8 .node circle,#mermaid-svg-rsuvXibeJahCjzw8 .node ellipse,#mermaid-svg-rsuvXibeJahCjzw8 .node polygon,#mermaid-svg-rsuvXibeJahCjzw8 .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-rsuvXibeJahCjzw8 .rough-node .label text,#mermaid-svg-rsuvXibeJahCjzw8 .node .label text,#mermaid-svg-rsuvXibeJahCjzw8 .image-shape .label,#mermaid-svg-rsuvXibeJahCjzw8 .icon-shape .label{text-anchor:middle;}#mermaid-svg-rsuvXibeJahCjzw8 .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-rsuvXibeJahCjzw8 .rough-node .label,#mermaid-svg-rsuvXibeJahCjzw8 .node .label,#mermaid-svg-rsuvXibeJahCjzw8 .image-shape .label,#mermaid-svg-rsuvXibeJahCjzw8 .icon-shape .label{text-align:center;}#mermaid-svg-rsuvXibeJahCjzw8 .node.clickable{cursor:pointer;}#mermaid-svg-rsuvXibeJahCjzw8 .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-rsuvXibeJahCjzw8 .arrowheadPath{fill:#333333;}#mermaid-svg-rsuvXibeJahCjzw8 .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-rsuvXibeJahCjzw8 .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-rsuvXibeJahCjzw8 .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-rsuvXibeJahCjzw8 .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-rsuvXibeJahCjzw8 .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-rsuvXibeJahCjzw8 .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-rsuvXibeJahCjzw8 .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-rsuvXibeJahCjzw8 .cluster text{fill:#333;}#mermaid-svg-rsuvXibeJahCjzw8 .cluster span{color:#333;}#mermaid-svg-rsuvXibeJahCjzw8 div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-rsuvXibeJahCjzw8 .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-rsuvXibeJahCjzw8 rect.text{fill:none;stroke-width:0;}#mermaid-svg-rsuvXibeJahCjzw8 .icon-shape,#mermaid-svg-rsuvXibeJahCjzw8 .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-rsuvXibeJahCjzw8 .icon-shape p,#mermaid-svg-rsuvXibeJahCjzw8 .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-rsuvXibeJahCjzw8 .icon-shape .label rect,#mermaid-svg-rsuvXibeJahCjzw8 .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-rsuvXibeJahCjzw8 .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-rsuvXibeJahCjzw8 .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-rsuvXibeJahCjzw8 :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 应用1
🔌 MCP
应用2
应用3
Server: 工具1
Server: 工具2
Server: 工具3
3 + 4 = 7 份代码。 加一个应用只写 1 份 Client,加一个工具只写 1 个 Server。
💡 这就是 MCP 被叫做"AI 界的 USB-C"的原因 :它不是让你多一个选择,而是让接口形状统一。
3.3 三个角色
| 角色 | 是什么 | 例子 |
|---|---|---|
| Host | 用户直接用的 AI 应用 | Claude Desktop、Cursor、你的 Agent |
| Client | Host 内部与 Server 一一对应的连接器 | SDK 里的 ClientSession |
| Server | 真正暴露工具/数据的一方 | 你写的天气服务、GitHub 官方 Server |
关系:一个 Host 可以挂多个 Client,每个 Client 连一个 Server。
四、关键澄清:MCP 不能替代 Function Call
这是最容易搞混的一点,也是面试常问的。
很多人以为上了 MCP 就不需要 Function Call 了。错。
真实链路是这样的:
#mermaid-svg-kQXkS1KdjBp1K5WI{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-kQXkS1KdjBp1K5WI .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-kQXkS1KdjBp1K5WI .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-kQXkS1KdjBp1K5WI .error-icon{fill:#552222;}#mermaid-svg-kQXkS1KdjBp1K5WI .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-kQXkS1KdjBp1K5WI .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-kQXkS1KdjBp1K5WI .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-kQXkS1KdjBp1K5WI .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-kQXkS1KdjBp1K5WI .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-kQXkS1KdjBp1K5WI .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-kQXkS1KdjBp1K5WI .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-kQXkS1KdjBp1K5WI .marker{fill:#333333;stroke:#333333;}#mermaid-svg-kQXkS1KdjBp1K5WI .marker.cross{stroke:#333333;}#mermaid-svg-kQXkS1KdjBp1K5WI svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-kQXkS1KdjBp1K5WI p{margin:0;}#mermaid-svg-kQXkS1KdjBp1K5WI .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-kQXkS1KdjBp1K5WI .cluster-label text{fill:#333;}#mermaid-svg-kQXkS1KdjBp1K5WI .cluster-label span{color:#333;}#mermaid-svg-kQXkS1KdjBp1K5WI .cluster-label span p{background-color:transparent;}#mermaid-svg-kQXkS1KdjBp1K5WI .label text,#mermaid-svg-kQXkS1KdjBp1K5WI span{fill:#333;color:#333;}#mermaid-svg-kQXkS1KdjBp1K5WI .node rect,#mermaid-svg-kQXkS1KdjBp1K5WI .node circle,#mermaid-svg-kQXkS1KdjBp1K5WI .node ellipse,#mermaid-svg-kQXkS1KdjBp1K5WI .node polygon,#mermaid-svg-kQXkS1KdjBp1K5WI .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-kQXkS1KdjBp1K5WI .rough-node .label text,#mermaid-svg-kQXkS1KdjBp1K5WI .node .label text,#mermaid-svg-kQXkS1KdjBp1K5WI .image-shape .label,#mermaid-svg-kQXkS1KdjBp1K5WI .icon-shape .label{text-anchor:middle;}#mermaid-svg-kQXkS1KdjBp1K5WI .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-kQXkS1KdjBp1K5WI .rough-node .label,#mermaid-svg-kQXkS1KdjBp1K5WI .node .label,#mermaid-svg-kQXkS1KdjBp1K5WI .image-shape .label,#mermaid-svg-kQXkS1KdjBp1K5WI .icon-shape .label{text-align:center;}#mermaid-svg-kQXkS1KdjBp1K5WI .node.clickable{cursor:pointer;}#mermaid-svg-kQXkS1KdjBp1K5WI .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-kQXkS1KdjBp1K5WI .arrowheadPath{fill:#333333;}#mermaid-svg-kQXkS1KdjBp1K5WI .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-kQXkS1KdjBp1K5WI .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-kQXkS1KdjBp1K5WI .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-kQXkS1KdjBp1K5WI .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-kQXkS1KdjBp1K5WI .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-kQXkS1KdjBp1K5WI .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-kQXkS1KdjBp1K5WI .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-kQXkS1KdjBp1K5WI .cluster text{fill:#333;}#mermaid-svg-kQXkS1KdjBp1K5WI .cluster span{color:#333;}#mermaid-svg-kQXkS1KdjBp1K5WI div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-kQXkS1KdjBp1K5WI .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-kQXkS1KdjBp1K5WI rect.text{fill:none;stroke-width:0;}#mermaid-svg-kQXkS1KdjBp1K5WI .icon-shape,#mermaid-svg-kQXkS1KdjBp1K5WI .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-kQXkS1KdjBp1K5WI .icon-shape p,#mermaid-svg-kQXkS1KdjBp1K5WI .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-kQXkS1KdjBp1K5WI .icon-shape .label rect,#mermaid-svg-kQXkS1KdjBp1K5WI .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-kQXkS1KdjBp1K5WI .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-kQXkS1KdjBp1K5WI .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-kQXkS1KdjBp1K5WI :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} MCP Server 声明工具
Host 拉取 tools/list
Host 把 MCP 工具
转成模型的 tool schema
模型用 Function Call 选择
Host 用 tools/call 执行
结果回传给模型
拆开看:
| 环节 | 谁负责 |
|---|---|
| 工具有哪些、怎么调 | MCP |
| 模型选哪个、填什么参数 | Function Call |
| 真正执行 | MCP Server |
🎯 一句话 :MCP 是"工具的目录和插头",Function Call 是"模型点菜的动作"。
目录再标准,也得模型自己点。
一个反证:如果模型没有 function calling 能力,你接再多 MCP Server 也没用------它根本不会发起调用。
五、MCP 的三个核心概念 + 2026 年的重大变化
5.1 三个原语
| 原语 | 是什么 | 谁来决定 |
|---|---|---|
| Tools | 可执行的函数(查天气、发邮件) | 模型决定调用 |
| Resources | 可读取的数据(文件、数据库记录) | 应用/用户决定加载 |
| Prompts | 预置的提示词模板 | 用户主动选择 |
区别很关键:Tools 是"模型想用就用",Resources 是"应用决定给不给",Prompts 是"用户点了才用"。
📌 做 RAG 或工具集成,90% 的场景只用 Tools。
5.2 ⚠️ 2026-07-28 规范:一次大改
如果你的参考资料是 2025 年的,现在大概率已经过时了。 当前规范是 2026-07-28,最重要的变化:
| 变化 | 说明 |
|---|---|
| 协议变无状态 | initialize 握手被移除,Mcp-Session-Id 也被移除;协议版本、客户端信息改放在每次请求的 _meta 里 |
新增 server/discover |
客户端需要预先了解服务端能力时用它(非必需) |
| Streamable HTTP 必带两个头 | Mcp-Method 和 Mcp-Name,方便网关/限流器直接路由,不用解析 body |
| 列表可缓存 | tools/list 等结果带上 ttlMs 和 cacheScope |
| Roots / Sampling / Logging 已弃用 | 还能用,至少再撑 12 个月,但新项目别再用 |
| HTTP+SSE 传输已弃用 | 改用 Streamable HTTP |
为什么"无状态"是件大事?
以前:客户端要先 initialize 拿 Mcp-Session-Id,之后每个请求都要带这个 ID,被钉死在某一台服务器实例上------所以你需要 sticky session、共享 session 存储。
现在:每个请求自带全部上下文,任何一个实例都能处理。 直接扔到普通轮询负载均衡后面就行。
🎯 这一改动让 MCP Server 从"能跑"变成"能上生产"。
5.3 生态现状
- 官方 TypeScript / Python / Go / C# 四个一级 SDK 均已支持 2026-07-28
- 一级 SDK 月下载量接近数亿次,TS 与 Python 累计都过了 10 亿
- 2025 年起 OpenAI、Google、Microsoft 陆续宣布支持,已成事实标准
六、最小代码:一个工具,两种写法
6.1 纯 Function Call 写法
python
import json
from openai import OpenAI
client = OpenAI()
def get_weather(city: str) -> str:
"""查询指定城市的实时天气"""
return f"{city} 晴,25℃"
TOOLS = [{
"type": "function",
"function": {
"name": "get_weather",
"description": "查询指定城市的实时天气",
"parameters": {
"type": "object",
"properties": {
"city": {"type": "string", "description": "城市名称"}
},
"required": ["city"],
},
},
}]
messages = [{"role": "user", "content": "北京天气怎么样?"}]
resp = client.chat.completions.create(
model="gpt-4o", messages=messages, tools=TOOLS
)
msg = resp.choices[0].message
if msg.tool_calls:
messages.append(msg)
for call in msg.tool_calls:
args = json.loads(call.function.arguments)
result = get_weather(**args) # ← 应用自己执行
messages.append({
"role": "tool",
"tool_call_id": call.id,
"content": result,
})
final = client.chat.completions.create(model="gpt-4o", messages=messages)
print(final.choices[0].message.content)
注意 :get_weather 是写死在这个应用里的,别人拿不走。
6.2 MCP Server 写法
python
# 以官方 Python SDK 为例
# 注意:2026-07-28 规范下 SDK 有迁移,具体 API 以官方 README 为准
from mcp.server.fastmcp import FastMCP
mcp = FastMCP("weather")
@mcp.tool()
def get_weather(city: str) -> str:
"""查询指定城市的实时天气。这段 docstring 会成为工具描述。"""
return f"{city} 晴,25℃"
if __name__ == "__main__":
mcp.run()
区别在哪?
| Function Call 写法 | MCP Server 写法 | |
|---|---|---|
| 工具在哪 | 写死在应用里 | 独立进程/服务 |
| 谁能用 | 只有这个应用 | 任何 MCP Client |
| 换应用 | 重写一遍 | 不用改 |
| 换工具 | 改 prompt | 改 Server,应用不动 |
💡 一行总结 :Function Call 是"函数调用",MCP 是"函数即服务"。
七、三个最容易踩的坑
坑 1:以为 MCP 能替代 Function Call
不会。 MCP Server 暴露的工具,Host 仍然要转成模型的 tool schema,模型仍然用 function call 来选。
MCP 让工具"可复用",但没有让模型"会调用" ------那还是模型自身的能力。
坑 2:照抄 2025 年的 MCP 教程
2026-07-28 规范是破坏性变更。 如果你看到教程里出现这些,说明它过时了:
| 过时写法 | 现状 |
|---|---|
method: "initialize" 握手 |
❌ 已移除 |
Mcp-Session-Id 请求头 |
❌ 已移除 |
HTTP + SSE 传输 |
⚠️ 已弃用,用 Streamable HTTP |
用 Sampling / Roots / Logging |
⚠️ 已弃用,新项目别用 |
坑 3:工具描述写得太随意
这一点和 Function Call 完全一样:
工具名 + docstring + 参数说明,会直接变成模型提示词的一部分。
所以:
- ❌
def f(a, b): ... - ✅
def search_flights(origin, destination, date): """查询指定日期从出发地到目的地的航班。"""
另外:参数越少、越扁平越好。 嵌套三层对象,模型填错的概率会明显上升。
八、什么时候用哪个
| 你的场景 | 建议 |
|---|---|
| 就一个应用、几个内部函数 | Function Call 够了,别上 MCP |
| 工具要被多个应用/多个模型复用 | 上 MCP |
| 要做成给别人用的产品/插件 | 上 MCP |
| 需要标准化地接外部数据源 | 上 MCP |
| 只是本地跑个 demo | Function Call 更快 |
🎯 一个务实的判断 :
工具只有你自己用 → Function Call;工具要让别人也能用 → MCP。
不要因为 MCP 火,就给一个只有三个函数的小脚本套一层 Server。
九、总结
三句话记住区别
- Function Call 是模型的能力 :它学会"举手说我要调工具",并填对参数。
- MCP 是工程的协议 :它让工具只用写一次,任何 Host 都能接。
- 两者是叠在一起的:MCP 提供目录,Function Call 完成点菜,Server 负责上菜。
✅ 应该做的
- 记住 Host / Client / Server 三个角色
- 新项目按 2026-07-28 规范开发(无状态、Streamable HTTP)
- 工具描述当成 prompt 来写,名字要语义化
- 工具参数尽量少而扁平
- 先用 Function Call 跑通,再考虑抽成 MCP Server
❌ 不要做的
- ❌ 以为上了 MCP 就不需要 Function Call
- ❌ 照着 2025 年教程写
initialize+Mcp-Session-Id - ❌ 新项目继续用
Sampling/Roots/Logging - ❌ 给三个函数的小脚本套 MCP Server
- ❌ 把工具描述写成
def f(a, b)
🎯 最后一句
Function Call 让模型"能用手",MCP 让全世界的手"能插同一个插座"。
前者是模型能力的里程碑,后者是工程标准化的里程碑------它们不是一代淘汰一代,而是两层叠在一起。
📚 参考资料
- MCP 官方规范 :https://modelcontextprotocol.io/specification
- MCP 2026-07-28 发布说明 :https://blog.modelcontextprotocol.io/posts/2026-07-28
- Streamable HTTP 传输 :https://modelcontextprotocol.io/specification/draft/basic/transports/streamable-http
- MCP Python SDK :https://github.com/modelcontextprotocol/python-sdk
- OpenAI Function Calling 文档 :https://platform.openai.com/docs/guides/function-calling
版本说明 :本文 MCP 部分基于 2026-07-28 规范 (2026-10 核对)。该版本为破坏性变更 :移除 initialize 握手与 Mcp-Session-Id、新增 server/discover、Streamable HTTP 强制 Mcp-Method / Mcp-Name 头、Roots / Sampling / Logging 已弃用。如果你参考的是 2025 年的资料,请务必核对版本。SDK 的 Python API 在该版本下有迁移,示例代码以官方 README 为准。
如果这篇对你有帮助,欢迎点赞 + 收藏。下一篇可以写 怎么 10 分钟写一个自己的 MCP Server ,或者 MCP 的 Resources 和 Tools 到底怎么分工------评论区告诉我。