MCP 和传统 Function Call 的对比:从 JSON-RPC 到 Client-Server 的 LLM 工具调用演进

发布时间:2026/10/10 20:17:36
MCP 和传统 Function Call 的对比:从 JSON-RPC 到 Client-Server 的 LLM 工具调用演进 1. 从一次“工具爆炸”的深夜排障说起MCP 和 Function Call 到底差在哪如果你正在做 LLM 工具调用大概率遇到过这种局面一开始只接了一个查天气的 Function Call代码清爽得像刚洗完的白衬衫。两周后产品说“再加个查订单、发邮件、读数据库、调内部工单系统”于是你的tools数组膨胀到二十几个每个模型供应商的 schema 写法还不一样OpenAI 的function字段、Anthropic 的tool_use块、国内某模型的tools结构改一处要动三处。这就是典型的“工具爆炸 接口碎片”。MCPModel Context Protocol和传统 Function Call 的核心差异用一句话概括Function Call 解决的是“模型怎么表达我要调哪个函数”MCP 解决的是“模型和工具之间怎么标准化地发现、协商、调用、维持会话”。前者是模型输出层的一个约定后者是一套 Client-Server 的通信协议底层用 JSON-RPC 2.0 承载。这篇文章面向三类人正在用 Function Call 做 Agent 但被多模型适配折磨的开发者、想引入 MCP 但不确定值不值得的架构同学、以及刚听说 MCP 想跑通第一条调用链的新手。我会把两种方式的配置、代码、验证命令都摊开你可以直接复制到本地跑。实测下来理解这两者的边界比盲目上 MCP 重要得多。先给一个直观对照后面每一节都会展开维度传统 Function CallMCP定位模型输出结构化调用意图模型与工具/资源的标准化协议通信应用侧自行解析执行JSON-RPC 2.0 over stdio / HTTPSSE角色模型 → 函数Host / Client / Server 三角色工具发现无靠代码硬编码注册tools/list动态发现会话一次性状态最小支持 session、多步调用链跨模型复用差各家 schema 不同好协议层统一2. 前置准备用 TaoToken 统一拿到模型入口与 API Key在对比两种调用方式之前得先有一个能稳定调模型的入口。我这边习惯用 TaoToken 做统一网关原因是它把模型对话、Coding Plan、API Key 管理放在一个控制台里切换模型不用改一堆环境变量。官网入口是 https://taotoken.net/?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content 注册后在控制台生成 Key。拿到 Key 之后你需要记下三个东西后面所有配置都围绕它们Base URL 用https://taotoken.net/api注意这个地址不加 UTM 参数直接写进配置API Key 形如sk-xxxxModel ID 比如claude-sonnet-4-5或gpt-4o之类具体以控制台模型列表为准。这三个要素就是所谓的“三件套”无论你是接 Claude Code、Cline、还是自己写脚本都逃不掉。如果你只是想先验证模型能不能通可以直接去模型对话页面发一条消息试试https://taotoken.net/models?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content 。这一步能排除掉后面 90% 的“到底是网络问题还是配置问题”。对于长期做编码和 Agent 的场景Coding Plan 会更划算入口在 https://taotoken.net/coding-plan?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content 。API Key 管理页在 https://taotoken.net/api-keys?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content 接入文档在 https://taotoken.net/doc?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content 。注意Base URL 一定要区分清楚https://taotoken.net/api是给 SDK 和工具用的接口地址不要和官网首页混用。很多 401 报错就是因为把首页地址填进了base_url。环境变量建议这样设后面 Python 和 Node 脚本都读它export TAOTOKEN_BASE_URLhttps://taotoken.net/api export TAOTOKEN_API_KEYsk-你的key export TAOTOKEN_MODELclaude-sonnet-4-5Windows PowerShell 用$env:TAOTOKEN_API_KEYsk-你的key。设完echo $TAOTOKEN_API_KEY确认一下别带着空值往下走。3. 可复制配置Function Call 示例与 MCP Server 配置对照这一节是全文的核心我把两种方式的完整配置都放出来你可以对照着改。3.1 传统 Function Call 的完整调用先看 Function Call。它的本质是你在请求里塞一个tools数组模型判断需要调用时返回一个tool_calls结构你的代码解析后执行本地函数再把结果作为tool角色消息塞回对话。下面是一个能跑的 Python 示例import os, json from openai import OpenAI client OpenAI( base_urlos.environ[TAOTOKEN_BASE_URL], api_keyos.environ[TAOTOKEN_API_KEY], ) tools [{ type: function, function: { name: get_weather, description: 查询指定城市某天的天气, parameters: { type: object, properties: { city: {type: string, description: 城市名如 Singapore}, date: {type: string, description: 日期如 2025-06-01} }, required: [city, date] } } }] def get_weather(city, date): # 真实场景替换为你的 API 调用 return {city: city, date: date, temp_c: 29, condition: sunny} messages [{role: user, content: 查一下新加坡明天的天气}] resp client.chat.completions.create( modelos.environ[TAOTOKEN_MODEL], messagesmessages, toolstools, tool_choiceauto, ) msg resp.choices[0].message if msg.tool_calls: call msg.tool_calls[0] args json.loads(call.function.arguments) result get_weather(**args) messages.append(msg) messages.append({ role: tool, tool_call_id: call.id, content: json.dumps(result, ensure_asciiFalse) }) final client.chat.completions.create( modelos.environ[TAOTOKEN_MODEL], messagesmessages, ) print(final.choices[0].message.content)这段代码里模型只负责“说要调get_weather参数是 city 和 date”真正的执行、结果回传、二次请求全是你手写的。工具一多这个if msg.tool_calls的分支就会变成一坨。3.2 MCP Server 的配置片段MCP 把上面那坨胶水代码抽到了协议层。一个 MCP Server 通常用 stdio 或 HTTPSSE 暴露工具Client 通过 JSON-RPC 调用。下面是一个最小 MCP Server 的配置以常见的mcpServers结构为例Claude Desktop / Cline 都认这个格式{ mcpServers: { weather: { command: python, args: [/Users/you/mcp_weather_server.py], env: { TAOTOKEN_BASE_URL: https://taotoken.net/api, TAOTOKEN_API_KEY: sk-你的key } } } }对应的 Server 端用官方 Python SDK 写核心是注册工具和启动 stdiofrom mcp.server.fastmcp import FastMCP mcp FastMCP(weather) mcp.tool() def weather_query(city: str, date: str) - dict: 查询指定城市某天的天气 return {city: city, date: date, temp_c: 29, condition: sunny} if __name__ __main__: mcp.run(transportstdio)注意这里的差别Function Call 里你要手写parameters的 JSON Schema而 MCP 里mcp.tool()装饰器会从函数签名和 docstring 自动生成 schemaClient 通过tools/list就能拿到。新增工具只要加一个函数不用改 Client 代码。如果你用的是 Claude Code 这类工具配置会落在~/.claude/settings.json或项目级.mcp.json结构类似。Cline 的 MCP 配置在插件设置里格式也是mcpServers。Codex 的auth.json则用于存凭证路径通常在~/.codex/auth.json里面放 API Key 和 Base URL。这三件套Base URL Key Model ID在任何一种工具里都要对齐缺一个就是 401 或 model not found。4. 本地验证跑通 Function Call 与 MCP 两条调用链路配置写完不算完得验证。我习惯分两步先验证模型入口通不通再验证工具调用链路通不通。4.1 验证模型入口用 curl 打一发最朴素的请求确认 Key 和 Base URL 没问题curl -s https://taotoken.net/api/v1/chat/completions \ -H Authorization: Bearer $TAOTOKEN_API_KEY \ -H Content-Type: application/json \ -d { model: $TAOTOKEN_MODEL, messages: [{role: user, content: 只回复 ok}] }返回里能看到choices[0].message.content就说明入口通了。如果这里就报 401别往下走先去 API Keys 页面确认 Key 有没有复制全、有没有多余空格。4.2 验证 Function Call 链路跑上面那段 Python观察输出。成功的话你会看到模型先返回tool_calls然后你的代码执行get_weather最后模型基于结果生成一句自然语言回答类似“新加坡明天晴29 度适合户外活动”。这个过程有两个网络往返token 消耗会翻倍这是 Function Call 的固有成本。4.3 验证 MCP 链路MCP 的验证稍微不同因为它是 Client-Server 结构。你可以用官方提供的 inspector 工具或者直接写一个最小 Clientimport asyncio from mcp import ClientSession, StdioServerParameters from mcp.client.stdio import stdio_client async def main(): params StdioServerParameters( commandpython, args[/Users/you/mcp_weather_server.py], ) async with stdio_client(params) as (read, write): async with ClientSession(read, write) as session: await session.initialize() tools await session.list_tools() print(发现工具:, [t.name for t in tools.tools]) result await session.call_tool( weather_query, {city: Singapore, date: 2025-06-01} ) print(调用结果:, result.content) asyncio.run(main())跑通后你会看到先打印“发现工具: [weather_query]”再打印调用结果。这一步的关键在于session.initialize()完成了能力协商list_tools完成了动态发现call_tool走的是 JSON-RPC 的tools/call方法。整个过程你一行解析tool_calls的代码都没写。对比下来Function Call 的验证是“看模型有没有吐出正确的 JSON”MCP 的验证是“看 Client 能不能发现并调用 Server 的工具”。前者验证的是模型能力后者验证的是协议链路。5. 常见报错排查401、local proxy failed、reading choices、OAuth这一节按真实报错来都是我踩过的坑。401 Unauthorized最常见。九成是 Key 错了或 Base URL 填成了首页。检查base_url是不是https://taotoken.net/apiKey 有没有sk-前缀环境变量有没有被 shell 覆盖。MCP 场景下还要检查mcpServers的env里有没有把 Key 传进去Server 进程读不到环境变量也会 401。local proxy failed / connection refused这个报错通常出现在 MCP 用 HTTPSSE 传输时Client 连不上 Server 的端口。先确认 Server 进程起来了curl http://localhost:端口/sse能不能通。如果是 stdio 传输检查command和args路径对不对Python 解释器路径建议写绝对路径。reading choices of undefined这是 Node/JS 侧解析响应时的经典错误说明返回体里没有choices字段。原因可能是请求根本没成功返回的是错误对象或者你用的 SDK 版本和 API 格式不匹配。打印完整response再解析别直接.choices[0]。OAuth 相关报错部分 MCP Server 或远程工具需要 OAuth 授权报错里会出现invalid_token或authorization required。检查 token 有没有过期scope 对不对。如果是 Codex 的auth.json确认文件权限和字段名auth.json里通常需要OPENAI_API_KEY和base_url两个字段对齐三件套。model not foundModel ID 写错了。去控制台模型列表复制准确的 ID别自己拼。不同工具对 Model ID 的格式要求可能不同有的要带前缀有的不带。排查顺序建议先 curl 验证入口 → 再验证单次 Function Call → 最后验证 MCP 链路。逐层排除别一上来就怀疑协议。6. 选型建议与下一步什么时候该从 Function Call 迁到 MCP回到最初的问题到底用哪个。我的经验是分三个阶段。工具少于 5 个、只用一个模型、调用流程是单步的Function Call 完全够用上手快调试直观没必要为了“先进”而引入 MCP 的复杂度。这个阶段你的瓶颈是产品逻辑不是协议。工具超过 10 个、开始接第二个模型、出现多步调用链比如“查天气 → 判断 → 预约活动”Function Call 的维护成本会陡增。每加一个工具要改 schema、改解析分支、改错误处理而且换模型时 schema 可能要重写。这时候 MCP 的价值就出来了工具注册一次所有支持 MCP 的 Client 都能发现和调用跨模型复用。再往上如果你要做的是平台级 Agent需要工具市场、权限治理、调用审计那 MCP 几乎是必选项。它的 session 管理、能力协商、transport 抽象都是为规模化准备的。迁移路径建议先把现有 Function Call 的工具抽成一个独立 MCP Server用 stdio 跑通Client 侧先用 inspector 验证。确认链路没问题后再把 Host 里的硬编码调用替换成 MCP Client。这样风险可控不会一次性推翻现有系统。想动手的话先去 https://taotoken.net/api-keys?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content 拿一个 Key然后照着第 3 节的配置把 MCP Server 跑起来。接入文档在 https://taotoken.net/doc?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content 里面有各工具的详细配置。如果你主要做编码 AgentCoding Plan 页面 https://taotoken.net/coding-plan?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content 有更省额度的方案。最后提醒一句MCP 的扩展性越强安全治理的要求越高工具权限和数据边界一定要在设计阶段就想清楚别等出事再补。

关于本文作者

来自尧图内容编辑团队

尧图内容编辑团队 内容团队

尧图内容编辑团队

本文由尧图网络内容编辑团队执笔。团队由资深项目经理、前端工程师与设计师组成,所有内容均来自亲手交付的真实项目,先讲清问题、再给出可落地的解法。尧图深耕北京网站建设十年,服务过京华建材集团、智造科技等各行业客户,把一线经验沉淀为可复用的行业观察。

  • 十年建站经验,覆盖建材、制造、服务、文创等
  • 项目经理把关选题与事实准确性
  • 工程师与设计师联合撰写专业细节
  • 统一编辑规范,保证文风与排版一致
  • 每月复盘转化数据,迭代选题方向

延伸阅读

相关资讯与近期热门内容

深度阅读推荐

建站决策前值得细读的三篇

网站改版的5个关键决策
2024-08-12

网站改版的5个关键决策

什么时候该改版、改到什么程度、如何避免流量掉光,京华建材集团改版复盘给出答案。

获取专属建站方案

看完文章,把您的行业与预算告诉我们,免费获取一份量身定制的官网建设方案与报价。

立即免费咨询