
1. 先搞清楚MCP 和 Function Calling 到底在解决什么问题刚接触 Agent 开发的朋友大概率会在同一个下午撞上两个词Function Calling 和 MCP。文档里一个说“让模型调用工具”另一个说“模型上下文协议”看起来都在干同一件事于是很容易得出一个错误结论——MCP 就是 Function Calling 的升级版。这个结论会让你在选型时反复横跳。我试过在一个小项目里先用 Function Calling 接了两个 API后来想加本地文件读取发现要重写一遍参数描述和解析逻辑换成 MCP 之后文件系统这块直接用一个现成的 Server 接上了。两者的差别不在“新旧”而在职责边界。用一句话概括Function Calling 是模型输出层的能力它让 LLM 决定“要不要调工具、调哪个、传什么参数”MCP 是系统集成层的协议它规定“工具怎么被发现、怎么被连接、上下文怎么在会话里传递”。前者是模型的一次输出格式约定后者是一套客户端与服务端之间的通信标准。适合谁看这篇写过一两个 Agent demo、能跑通 OpenAI 或兼容接口的 chat completions、但对“工具怎么规模化接入”还没形成体系认知的开发者。下面我会先给一个可复制的 MCP 客户端配置骨架再给 Function Calling 的请求/响应验证步骤最后把两者放在同一个任务里对比行为差异。全程用 TaoToken 作为统一接入点省去你到处找 Key 的麻烦。2. 前置准备用 TaoToken 统一接入别在 Key 上耗时间不管你是要验证 Function Calling 还是跑 MCP 客户端第一步都是拿到一个能用的模型接口。很多教程卡在“注册—绑卡—找 base_url”这三步上其实可以合并成一步。TaoToken 的定位就是给开发者提供一个兼容 OpenAI 协议的入口你不需要为每个模型单独改代码。官网地址是 https://taotoken.net/?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content 注册后在控制台生成 API Key 即可。API 端点固定为 https://taotoken.net/api 注意这个地址后面不加任何 UTM 参数直接作为 base_url 使用。操作路径很直接进入控制台 → 找到 API Keys 页面 → 新建一个 Key → 复制保存。这个 Key 后面会同时用在 Function Calling 的 curl 请求和 MCP 客户端的配置里。如果你还没决定用哪个模型可以先到模型对话页面发一条消息确认账号和额度正常再去写代码。注意API Key 只显示一次复制后存到本地环境变量里不要直接硬编码进要提交到 Git 的配置文件。对于长期做编码和 Agent 调试的场景可以了解一下 Coding Plan它更适合高频调用如果只是临时验证协议行为按量使用就够了。接入文档在 https://taotoken.net/doc 可以查到完整的参数说明。3. 可复制配置MCP 客户端骨架与 settings.json / config.toml 示例MCP 的客户端配置本质上就是告诉 Host我要启动哪些 Server、每个 Server 用什么命令拉起、允许访问哪些资源。不同 Host 的配置文件格式不一样但结构高度相似。下面给两个最常见的骨架。3.1 settings.json 骨架类 Claude Desktop 风格这个格式适合大多数桌面类 Host核心是mcpServers对象每个键是一个 Server 的别名。{ mcpServers: { filesystem: { command: npx, args: [ -y, modelcontextprotocol/server-filesystem, /Users/yourname/projects ], env: { TAOTOKEN_API_KEY: sk-你的key } }, fetch: { command: uvx, args: [mcp-server-fetch], env: { TAOTOKEN_BASE_URL: https://taotoken.net/api } } } }几个参数的含义command是启动命令Node 生态用npxPython 生态用uvxargs里最后一个路径参数是允许访问的目录边界这是 MCP 安全模型里的 Roots 概念Server 只能在这个范围内操作文件env用来注入环境变量把 Key 和 base_url 传进去避免写死在代码里。改完配置必须重启 Host 才生效而且 JSON 不允许有尾逗号否则整个文件解析失败Host 会静默忽略所有 Server。3.2 config.toml 骨架类 Codex / 终端工具风格有些命令行 Agent 工具用 TOML 格式结构更扁平[mcp_servers.filesystem] command npx args [-y, modelcontextprotocol/server-filesystem, /Users/yourname/projects] [mcp_servers.filesystem.env] TAOTOKEN_API_KEY sk-你的key [mcp_servers.fetch] command uvx args [mcp-server-fetch] [mcp_servers.fetch.env] TAOTOKEN_BASE_URL https://taotoken.net/apiTOML 的好处是支持注释和多行字符串调试时可以把某个 Server 整段注释掉做隔离排查。注意[mcp_servers.xxx.env]是独立表不能写成内联对象混在上一段里。3.3 启动后发生了什么Host 读取配置后会为每个 Server 启动一个子进程通过 stdio 建立 JSON-RPC 2.0 连接。第一步是initialize请求客户端带上协议版本和自己的能力声明Server 返回它支持的tools、resources、prompts清单。协商成功后客户端发notifications/initialized连接进入就绪状态。此时客户端会主动调tools/list拉取工具列表这些工具描述会在需要时注入到 LLM 的上下文里。整个过程你不需要手写工具 schema这是 MCP 和 Function Calling 在体感上最大的区别。4. 验证请求Function Calling 的请求/响应结构与跑通步骤MCP 配好之后我们回头验证 Function Calling这样才能对比。Function Calling 的核心是你在请求体里显式声明tools数组模型返回tool_calls字段。4.1 请求结构用 curl 直接打 TaoToken 的接口curl https://taotoken.net/api/v1/chat/completions \ -H Content-Type: application/json \ -H Authorization: Bearer $TAOTOKEN_API_KEY \ -d { model: gpt-4o-mini, messages: [ {role: user, content: 北京现在天气怎么样} ], tools: [ { type: function, function: { name: get_weather, description: 查询指定城市的当前天气, parameters: { type: object, properties: { city: {type: string, description: 城市名称} }, required: [city] } } } ], tool_choice: auto }关键字段tools[].function.parameters是标准 JSON Schema模型靠它理解参数结构tool_choice设为auto让模型自己决定是否调用设成具体函数名则强制调用。4.2 响应结构模型判断需要调工具时返回的message里会多出tool_calls{ choices: [ { message: { role: assistant, content: null, tool_calls: [ { id: call_abc123, type: function, function: { name: get_weather, arguments: {\city\:\北京\} } } ] }, finish_reason: tool_calls } ] }注意arguments是字符串不是对象需要你自己JSON.parse。这是新手最容易踩的坑之一。4.3 回传工具结果拿到tool_calls后你在本地执行真实函数然后把结果以role: tool的消息追加回去并带上对应的tool_call_id{ role: tool, tool_call_id: call_abc123, content: {\temp\: 18, \condition\: \晴\} }再发一次请求模型才会基于工具结果生成自然语言回答。也就是说Function Calling 的完整链路是两轮请求中间的执行和回传逻辑全由你维护。5. 行为对比同一个任务下 MCP 与 Function Calling 的差异把上面两条路放在同一个任务里跑差异会非常直观。任务让 Agent 读取本地一个notes.md文件并总结。用 Function Calling 时你要自己写一个read_file函数定义path参数处理路径校验、编码、异常然后把函数描述塞进tools。每加一个新能力就重复一遍这套流程而且工具描述和真实实现容易脱节。用 MCP 时filesystemServer 已经暴露了read_file、list_directory等工具。客户端启动后自动tools/list把清单注入上下文。模型决定调用后客户端通过 JSON-RPC 把tools/call发给 ServerServer 执行完返回结果。你全程没写一行工具 schema。维度Function CallingMCP工具定义位置每次请求体里手写Server 启动时声明客户端自动发现上下文维护开发者手动拼接消息历史协议层维护 Session 与 Context传输方式HTTP 请求-响应stdio / Streamable HTTP支持双向新增工具成本改代码 改 schema改配置重启 Host适用场景少量、固定的工具调用多工具、需复用、需权限边界实测下来工具数量超过五个之后Function Calling 的请求体会变得很长维护成本陡增而 MCP 的配置是声明式的加一个 Server 就是加一段配置。6. 本篇常见错排查报错一Method not foundJSON-RPC -32601说明客户端调用了 Server 不支持的方法。常见于协议版本不匹配或者你手动发了resources/read但该 Server 只实现了tools。检查initialize响应里的capabilities字段只调用声明了的能力。报错二MCP Server 启动后立刻退出先看command是否在 PATH 里。npx和uvx需要对应运行时已安装。把args里的包名单独在终端跑一次确认能拉起。如果是路径参数确认目录真实存在且有读权限。报错三Function Calling 返回arguments解析失败arguments是字符串且模型可能返回不完整 JSON。加一层 try/catch解析失败时把原始字符串回传给模型让它修正而不是直接抛异常中断。报错四401 Unauthorized检查Authorization头是不是Bearer加 Key中间有空格。base_url 用 https://taotoken.net/api 不要多加/v1之外的路径。Key 失效就到 API Keys 页面重新生成。报错五改了配置不生效MCP 配置改动必须重启 Host 进程热加载不保证支持。TOML 和 JSON 的语法错误都会导致整份配置被忽略用在线校验器过一遍再重启。7. 接下来怎么走按场景选入口如果你现在的目标是排查接入问题、确认 Key 和端点是否正常直接去 API Keys 页面新建一个 Key再对照接入文档把 base_url 和请求头核对一遍这是最快定位问题的方式。如果你还在犹豫选哪个模型来跑 Agent先去模型对话页面手动发几轮带工具描述的消息观察模型对tool_calls的触发是否稳定再决定写代码。如果你打算长期做编码类 Agent、频繁调用工具链Coding Plan 比按量计费更省心配置一次就能持续用。MCP 的配置骨架你已经有了把它接到你的 Host 里先跑通filesystem这一个 Server再逐步加fetch、数据库等比一次性堆一堆 Server 更容易定位问题。