翻了翻 2026 年的招聘信息,AI Agent 相关岗位里 LangChain、LangGraph 基本成了标配,MCP 出现的频率也越来越高。它和传统的 Function Calling 到底差在哪?我直接用三段能跑的 Python 代码,把两种做法从头到尾对比一遍。


太长不看版(TL;DR)

  • 传统 Function Calling:工具列表写在应用代码里,LLM 只是帮你"点菜",工具本体的定义、分发、生命周期全部耦合在应用内部
  • MCP(Model Context Protocol):Anthropic 于 2024 年 11 月开源的开放协议,2025 年先后移交 Linux 基金会并成立独立治理项目;工具通常以独立进程(MCP Server)运行,任何支持 MCP 的客户端(Claude、Cursor、你自己的 Agent)即插即用
  • 核心区别:Function Calling 绑定的是"函数",MCP 标准化的是"协议"
  • 2026 年为什么必学:主流 Agent 客户端和框架都原生支持 MCP,官方 + 社区维护的 Server 也越来越多,数据库、浏览器、GitHub、Slack 等场景直接拿来用
  • 实战要点:10 行代码写一个 MCP Server,20 行代码在 Client 里动态发现并调用它的工具——全程不需要写死工具 Schema

一、引言:为什么 2026 年突然都提 MCP?

都说 2026 年是 Agent 落地的爆发年,但有个点容易被忽略:Agent 的差距往往不在模型,而在工具链。只会聊天的 Agent 就是个陪聊机器人,能查库、能发邮件、能操作浏览器的 Agent 才是真正的生产力。

我自己折腾 Agent 的过程中发现,每个团队都在做同一件重复劳动:

  1. 用 JSON Schema 定义工具参数
  2. 把工具清单塞进 LLM 请求
  3. 解析返回的 tool_calls
  4. 自己实现一个"分发器"(dispatch)去调用真实函数
  5. 换一个客户端、换一种语言,全部重来

传统 Function Calling 的痛点也在这:工具被锁死在某个应用、某种语言里。2026 年的诉求是"一套工具,到处都能用",MCP 就是冲着这个来的。2025 年内 OpenAI、Google、微软、AWS 先后宣布支持,它从 Anthropic 的私有规范变成了行业公共协议(依据见文末参考资料)。

打个比方:Function Calling 像打印机自带的驱动,MCP 像 USB 接口。打印机插上 USB,什么电脑都能用,现在行业正在把打印机统一换成 USB 口。

这篇文章适合三类人:刚开始学 Agent 开发的(MCP 是简历加分项)、用 LangChain/LangGraph 做工程的、以及想搞清楚工具调用接下来往哪走的人。


二、先看老办法:传统 Function Calling 是怎么工作的

2.1 原理

传统 Function Calling 是 LLM API(OpenAI、DeepSeek、通义等)内置的能力,流程是一个闭环:

用户问题 → LLM 判断"需要调工具" → 返回结构化参数(tool_calls)
        → 应用代码执行真实函数 → 把结果回填给 LLM → LLM 生成最终回答

关键在最后一步:工具的定义(Schema)、执行(函数本体)、分发(dispatch)全都写在应用代码里。换一个应用,这些就得复制粘贴一遍。

2.2 完整代码示例(OpenAI API 风格)

import json
from openai import OpenAI

client = OpenAI(api_key="sk-xxx")  # 换成你的 key

# 1. 在代码里手写工具 Schema
tools = [
    {
        "type": "function",
        "function": {
            "name": "get_weather",
            "description": "查询指定城市的实时天气",
            "parameters": {
                "type": "object",
                "properties": {
                    "city": {"type": "string", "description": "城市名称,如北京"},
                },
                "required": ["city"],
            },
        },
    },
    {
        "type": "function",
        "function": {
            "name": "get_news",
            "description": "获取指定领域的新闻头条",
            "parameters": {
                "type": "object",
                "properties": {
                    "topic": {"type": "string", "description": "新闻领域,如科技"},
                },
                "required": ["topic"],
            },
        },
    },
]

# 2. 工具本体:真实业务逻辑
def get_weather(city: str) -> str:
    # 实际项目中这里调用天气 API / 数据库
    return f"{city} 今天晴,气温 26℃,微风"

def get_news(topic: str) -> str:
    return f"今日{topic}头条:MCP 生态持续扩张,更多企业接入"

# 3. 分发器:根据工具名手动路由
def dispatch(name: str, arguments: dict) -> str:
    if name == "get_weather":
        return get_weather(arguments["city"])
    if name == "get_news":
        return get_news(arguments["topic"])
    raise ValueError(f"未知工具: {name}")

# 4. 完整 Agent 循环
def agent_loop(user_input: str, max_rounds: int = 5) -> str:
    messages = [{"role": "user", "content": user_input}]

    for _ in range(max_rounds):
        resp = client.chat.completions.create(
            model="gpt-4o",
            messages=messages,
            tools=tools,          # 每轮都要把工具清单塞进去
        )
        msg = resp.choices[0].message
        messages.append(msg)

        if msg.tool_calls:        # LLM 要求调用工具
            for tc in msg.tool_calls:
                result = dispatch(tc.function.name, json.loads(tc.function.arguments))
                messages.append({
                    "role": "tool",
                    "tool_call_id": tc.id,   # 必须回填这个 ID 才能对应上
                    "content": result,
                })
        else:
            return msg.content     # LLM 直接回答了,结束

    raise RuntimeError("超出最大轮数")

if __name__ == "__main__":
    print(agent_loop("北京今天天气怎么样?顺便看看科技新闻"))

这段代码有三个绕不开的问题:

  1. Schema 写死在应用里:工具多一个、少一个,都要改客户端代码并重新发版
  2. 分发逻辑要自己维护dispatch 里的 if-else 会随工具数量爆炸
  3. 不可复用:这套 get_weather 换个项目、换种语言(Java/TS)就得重写,且无法被 Cursor、Claude 等现成工具直接使用

三、MCP 是什么:协议的核心概念

MCP(Model Context Protocol,模型上下文协议)是一套开放标准,规定了"AI 应用(Host)"和"工具提供方(Server)"之间怎么通信。

┌─────────────────────────────┐
│  Host(AI 应用 / Agent)      │   ← Claude Desktop、Cursor、VS Code、
│  ┌──────────┐               │      你自己的 Python/JS 应用
│  │ MCP Client │             │
│  └──────────┘               │
└──────────┬──────────────────┘
           │  MCP 协议(stdio / HTTP)
     ┌─────┴─────┬─────────┐
┌────▼───┐ ┌─────▼───┐ ┌───▼────┐
│Server A│ │Server B │ │Server C│   ← 独立的工具服务进程
│数据库   │ │浏览器    │ │GitHub |
└────────┘ └─────────┘ └────────┘

3.1 三个核心角色

角色 作用 类比
Host 运行 Agent 的应用(Claude Desktop、Cursor、你的程序) 电脑主机
Client Host 内部的连接器,负责与 Server 通信 USB 控制器
Server 独立部署的工具服务(通常为独立进程),暴露工具/资源,只认 MCP 协议,不关心谁来调用 打印机

3.2 三个核心原语(Primitives)

原语 是什么 对应 Function Calling 的什么
Tools(工具) 可被 LLM 调用的函数,参数由 JSON Schema 描述 就是 Function Calling 里的 function
Resources(资源) 可被读取的数据(文档、配置、数据库查询结果),以 URI 标识 Function Calling 没有对应物
Prompts(提示词) 可复用的提示词模板 类似 system prompt 模板

一个关键差异:传统 Function Calling 只有"函数"这一个维度,MCP 多了 Resources 这一层——Agent 可以先读资源,再决定要不要调工具。RAG、配置注入这些场景就多了条标准通道。

3.3 通信方式

  • stdio:Client 以子进程方式拉起 Server,通过标准输入输出通信(本地开发最常用)
  • HTTP(Streamable HTTP):跨机器、跨语言部署,支持 OAuth 认证,生产环境首选

四、MCP vs 传统 Function Calling:一张表看懂

对比维度 传统 Function Calling MCP
本质 LLM API 内置的参数约定 独立于模型的开放协议(Linux 基金会治理)
工具定义位置 写死在应用代码里 由独立 MCP Server 提供,动态发现
Schema 维护 每加一个工具就改一次客户端代码 Server 自描述,Client 调用 list_tools() 自动获取
跨语言复用 每个项目、每种语言各写一份 一套 Server,Python/TS/Java 客户端通用
可被谁使用 只有你自己的应用 Claude、Cursor、Zed、VS Code、你的 Agent 全都能接
能力维度 只有函数调用 Tools + Resources + Prompts
认证与安全 自己设计,各自为政 标准化的 OAuth 2.1、授权范围(scopes)
生态 官方 + 社区维护的上千个 Server(Postgres、GitHub、Slack、浏览器…)
学习成本 低(会调 API 就行) 中(理解协议模型,但代码量更少)

简单说:Function Calling 解决"让 LLM 调我的函数",MCP 解决"让所有 Agent 调所有工具"——一个是应用内的事,一个是行业级的事。


五、实战:跑通你的第一个 MCP

5.1 环境准备

# Python 3.10+,安装官方 SDK(FastMCP 是官方 python-sdk 提供的高阶封装)与 OpenAI SDK
pip install "mcp[cli]" openai

5.2 写一个 MCP Server(10 行代码)

新建 weather_server.py

from mcp.server.fastmcp import FastMCP

# 创建一个 MCP Server
mcp = FastMCP("weather-server")

# 工具(Tool):可被 LLM 调用的函数
@mcp.tool()
def get_weather(city: str) -> str:
    """查询指定城市的实时天气"""
    # 实际项目中这里应调用真实天气 API / 数据库,此处用静态数据演示
    weather_map = {"北京": "晴,气温 26℃", "上海": "多云,气温 28℃", "深圳": "阵雨,气温 30℃"}
    desc = weather_map.get(city, "晴,气温 25℃")
    return f"{city} 今天{desc},微风"

@mcp.tool()
def get_news(topic: str) -> str:
    """获取指定领域的新闻头条"""
    return f"今日{topic}头条:MCP 已进入 Linux 基金会治理"

# 资源(Resource):可被读取的数据,以 URI 标识
# 注意:URI 需符合 RFC 3986,推荐使用纯 ASCII(如 city://beijing),避免中文导致的兼容性问题
@mcp.resource("city://beijing")
def beijing_weather() -> str:
    """北京天气的静态资源(可被 Agent 读取后再决定是否调工具)"""
    return "北京 今天晴,气温 26℃,微风"

if __name__ == "__main__":
    # 以 stdio 方式启动:作为子进程被 Client 拉起
    mcp.run(transport="stdio")

注意到没有:没有 JSON Schema,没有 dispatch,也没有 if-else。函数签名(city: str)就是 Schema,FastMCP 自动生成并暴露出去。这就是 MCP 的自描述能力。

5.3 写一个 MCP Client(20 行代码)

新建 weather_client.py

import asyncio
from mcp import ClientSession, StdioServerParameters
from mcp.client.stdio import stdio_client


async def main():
    # 1. 配置:以子进程方式启动 Server
    server_params = StdioServerParameters(
        command="python",
        args=["weather_server.py"],
    )

    # 2. 建立连接 + 握手
    async with stdio_client(server_params) as (read, write):
        async with ClientSession(read, write) as session:
            await session.initialize()   # MCP 协议握手

            # 3. 动态发现 Server 暴露的所有工具(无需手写 Schema!)
            tools = await session.list_tools()
            print("=== Server 暴露的工具 ===")
            for t in tools.tools:
                print(f"  - {t.name}: {t.description}")
                print(f"    schema: {t.inputSchema}")

            # 4. 直接调用工具
            result = await session.call_tool("get_weather", {"city": "北京"})
            print("\n=== 调用 get_weather 结果 ===")
            print(result.content[0].text)

            # 5. 读取资源
            resource = await session.read_resource("city://beijing")
            print("\n=== 读取资源 city://beijing ===")
            print(resource.contents[0].text)


if __name__ == "__main__":
    asyncio.run(main())

运行:

python weather_client.py

预期输出(schema 内容为示意,实际由 FastMCP 根据函数签名自动生成,可能包含 additionalPropertiesrequired 等字段):

=== Server 暴露的工具 ===
  - get_weather: 查询指定城市的实时天气
    schema: {'type': 'object', 'properties': {'city': {'type': 'string'}}}
  - get_news: 获取指定领域的新闻头条
    schema: {'type': 'object', 'properties': {'topic': {'type': 'string'}}}

=== 调用 get_weather 结果 ===
北京 今天晴,气温 26℃,微风

=== 读取资源 city://beijing ===
北京 今天晴,气温 26℃,微风

六、实战进阶:让 LLM 动态发现并调用 MCP 工具

这一节讲 MCP 最实用的一点:把 Server 的工具清单自动转成 LLM 认识的 function schema。Agent 每轮拿到的工具列表都是最新的,加工具只改 Server 那一行代码,客户端不用动。

import asyncio
import json
from openai import OpenAI
from mcp import ClientSession, StdioServerParameters
from mcp.client.stdio import stdio_client

llm = OpenAI(api_key="sk-xxx")  # 换成你的 key


def build_tools_schema(mcp_tools) -> list:
    """把 MCP 动态发现的工具,自动转成 LLM 认识的 function schema"""
    schemas = []
    for t in mcp_tools:
        schemas.append({
            "type": "function",
            "function": {
                "name": t.name,
                "description": t.description,
                "parameters": t.inputSchema,   # 直接复用 MCP 的 schema
            },
        })
    return schemas


async def run_agent(prompt: str):
    server_params = StdioServerParameters(command="python", args=["weather_server.py"])

    async with stdio_client(server_params) as (read, write):
        async with ClientSession(read, write) as session:
            await session.initialize()

            # 1. 动态发现工具 → 自动生成 schema(传统写法里这段要手写)
            tools_result = await session.list_tools()
            tools_schema = build_tools_schema(tools_result.tools)

            # 2. 标准 Agent 循环(和第二节几乎一样,但 schema 是"发现"来的)
            messages = [{"role": "user", "content": prompt}]

            for _ in range(5):
                resp = llm.chat.completions.create(
                    model="gpt-4o",
                    messages=messages,
                    tools=tools_schema,
                )
                msg = resp.choices[0].message
                messages.append(msg)

                if not msg.tool_calls:
                    print("最终回答:", msg.content)
                    return

                # 3. 工具执行交给 MCP Server,而不是本地 dispatch
                for tc in msg.tool_calls:
                    args = json.loads(tc.function.arguments)
                    result = await session.call_tool(tc.function.name, args)
                    messages.append({
                        "role": "tool",
                        "tool_call_id": tc.id,
                        "content": result.content[0].text,
                    })


if __name__ == "__main__":
    asyncio.run(run_agent("北京和上海今天天气怎么样?"))

运行效果:

最终回答: 北京今天晴,气温 26℃,微风;上海今天多云,气温 28℃。

注:此输出与 5.2 节 get_weather 函数的静态数据一致;实际运行时,最终回答由模型根据工具返回内容生成,措辞可能略有差异。

跟第二节的代码一比,差别很明显:

传统 Function Calling MCP 版
工具 Schema 手写 JSON,写死在代码里 list_tools() 自动获取
工具执行 本地 dispatch() if-else session.call_tool() 一步到位
新增工具 改客户端代码 + 发版 只改 Server,客户端零改动
换客户端 全部重写 同一个 Server,Cursor/Claude 直接接

七、顺手的生态红利:现成 MCP Server 直接用

自己写 Server 是第一步,更省事的是直接用生态里现成的,比如:

  • @modelcontextprotocol/server-postgres:让 Agent 直接查数据库
  • @modelcontextprotocol/server-filesystem:读写本地文件
  • @modelcontextprotocol/server-github:操作 GitHub 仓库
  • playwright-mcp:让 Agent 控制浏览器
  • 各类官方 Server:Slack、Notion、Google Drive、Figma…

官方 CLI 一条命令就能注册到 Claude Desktop:

# 全局安装 MCP CLI
pip install "mcp[cli]"

# 用 Inspector 图形化调试你的 Server
mcp dev weather_server.py

# 安装到 Claude Desktop
mcp install weather_server.py

LangChain / LangGraph 也内置了 MCP 适配器,能把 MCP Server 包装成普通 Tool:

# 需要先安装:pip install langchain-mcp-adapters
from langchain_mcp_adapters.tools import load_mcp_tools
from mcp import ClientSession, StdioServerParameters
from mcp.client.stdio import stdio_client

async with stdio_client(server_params) as (read, write):
    async with ClientSession(read, write) as session:
        await session.initialize()
        tools = await load_mcp_tools(session)   # MCP Server → LangChain Tool
        # 然后就可以直接塞进 AgentExecutor / LangGraph 节点

八、什么场景该用哪个?选型建议

场景 推荐方案 原因
快速 Demo、单应用、工具就 2~3 个 传统 Function Calling 零额外架构,代码最少
工具会持续增加、团队多项目共享 MCP 一次开发,多处复用
工具要接入 Cursor / Claude / VS Code MCP 客户端原生支持,别无选择
企业跨部门、跨语言工具平台 MCP 标准协议 + OAuth,治理成本最低
Agent 需要读数据再决定行动(RAG 等) MCP Resources 原语天然支持

两者不是二选一,而是层级关系:一个是实现细节,一个是行业标准。现在的现实是,就算先用 Function Calling,后面接生态时多半也得包一层 MCP,不如一开始就按 MCP 设计。


九、总结

  1. 传统 Function Calling 是"应用内"技术:Schema 写死、分发靠自研、换项目就重来。但它简单直接,想搞懂工具调用还是得先学它
  2. MCP 是"行业级"协议:工具封装成独立 Server,靠 Tools / Resources / Prompts 三个原语和 stdio / HTTP 两种传输,实现"一套工具,所有 Agent 通用"
  3. 生态在涨、主流客户端和框架都原生支持、招聘市场认可度高,2026 年学 MCP 基本是稳的
  4. 上手路径:10 行代码写 Server → 20 行代码写 Client → 接入 LLM 动态调用 → 复用生态 Server → 用 LangGraph 编排成生产级 Agent

参考资料

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐