ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

给 AI 接了 100 个工具最后全乱了——MCP 协议焊死,从 JSON-RPC 到三大原语一篇打通 Agent 与外部世界的标准接口

给 AI 接了 100 个工具最后全乱了——MCP 协议焊死,从 JSON-RPC 到三大原语一篇打通 Agent 与外部世界的标准接口 1. 从 100 个工具全乱套说起Agent 工具接入的上下文膨胀与适配地狱如果你给 AI Agent 接过超过 10 个工具大概率经历过这个阶段每个工具单独测都正常一旦全部挂上去模型开始变傻——该调 A 工具的时候调了 B参数传错或者干脆不调工具直接编答案。更糟的是上下文窗口被工具定义吃掉一大半真正留给对话和推理的空间所剩无几。我试过最夸张的一次一个 Agent 挂了 23 个工具光工具 schema 就占了 6000 多 token。模型还没开始干活上下文已经用掉三分之一。后来排查发现问题不在模型而在工具接入方式本身——每个工具都是手写胶水代码schema 格式不统一调用逻辑散落在各处没有标准协议约束。这就是 MCPModel Context Protocol模型上下文协议要解决的核心问题。它用 JSON-RPC 2.0 作为通信底座把 Agent 与外部世界的交互抽象成 Resources、Tools、Prompts 三大原语让工具接入从手写胶水变成标准接口。你可以把它理解成 AI 时代的 USB-C外设只要符合协议就能即插即用不用管里面是什么芯片。这篇文章面向的是已经踩过工具越多越乱这个坑的开发者。我会从 JSON-RPC 消息格式讲起拆解三大原语的设计意图给出可复制的 MCP Server 配置片段最后演示一次从工具注册到调用的完整验证流程。全程基于 Python SDK 1.26FastMCP和 TypeScript SDK 1.x代码都经过实机验证。先说清楚 MCP 到底解决什么问题。传统 Function Calling 模式下你的工具是按某个模型的 schema 格式写的——OpenAI 一套、Claude 一套、DeepSeek 又一套。N 个模型乘 M 个工具就是 N×M 套适配代码。换模型等于重写工具层。MCP 把这个矩阵压成一条线工具实现一次任何支持 MCP 的 Host 都能接。Claude、ChatGPT、Cursor、VS Code、Cline、Windsurf 这些客户端原生支持 MCP你的 Server 写一次就能到处跑。另一个隐性收益是上下文管理。传统方式把所有工具定义一次性塞进 promptMCP 支持渐进发现——Client 先调tools/list拿到工具清单模型按需请求具体工具的 schema。工具多的时候这个差别非常明显。2. TaoToken 前置给 MCP Server 一个稳定的模型出口MCP Server 本身只负责暴露工具和资源真正调用大模型的是 Host。但在开发和调试阶段你往往需要一个能快速切换模型、验证工具调用链路的出口。TaoToken 在这里的角色是提供统一的模型接入层让你在验证 MCP 工具调用时不用来回改配置。具体来说当你的 MCP Server 通过 stdio 或 Streamable HTTP 跑起来后Host 需要调用 LLM 来决定该不该调工具、调哪个工具、传什么参数。这个 LLM 调用如果直连各家厂商切换模型时 Base URL、API Key、Model ID 三件套都要改。TaoToken 把这层统一了一个 Base URL、一个 Key模型通过 Model ID 区分。配置上你需要在 Host 侧比如 Cline、Cursor 或自建 Agent设置三个东西Base URLhttps://taotoken.net/apiAPI Key在控制台创建格式通常是sk-开头Model ID按需选择比如claude-sonnet-4-20250514或gpt-4o这三件套是 MCP 工具调用链路能跑通的前提。MCP Server 负责有什么工具Host 负责用哪个模型决定调工具TaoToken 负责模型从哪来。三者职责清晰调试时也容易定位问题——工具不显示是 Server 的事模型不响应是 Host 或模型出口的事。如果你用的是 Claude Code 这类工具接入方式略有不同。Claude Code 通过~/.claude/settings.json或项目级.mcp.json配置 MCP Server模型出口则在环境变量或配置文件里指定。下面第三节会给出完整的可复制片段。需要提醒一点MCP Server 的调试和模型出口的调试要分开做。先用tools/list确认工具注册成功再验证模型能不能正确选择工具。两个环节混在一起排查效率会很低。3. 可复制配置MCP Server 注册与 JSON-RPC 消息示例这一节给的是能直接复制粘贴的配置。先看 MCP Server 的注册配置再看 JSON-RPC 消息格式最后是 Host 侧的模型出口配置。3.1 MCP Server 注册配置.mcp.json以 Cline 或 Claude Code 为例项目根目录建.mcp.json{ mcpServers: { knowledge-base: { command: python, args: [-m, my_mcp_server], env: { MY_API_KEY: your-api-key-here, LOG_LEVEL: INFO } }, remote-tools: { url: http://localhost:8000/mcp, transport: streamable-http } } }stdio 模式的 Server 用commandargs启动环境变量通过env传入。Streamable HTTP 模式的 Server 用url指定端点。注意 stdio 模式下 Server 的日志必须走 stderr用print()会污染 JSON-RPC 通道导致 Client 解析失败。3.2 JSON-RPC 消息示例MCP 的所有通信都是 JSON-RPC 2.0 消息。初始化握手{ jsonrpc: 2.0, id: 1, method: initialize, params: { protocolVersion: 2025-11-25, capabilities: { roots: { listChanged: true }, sampling: {} }, clientInfo: { name: my-agent, version: 1.0.0 } } }Server 返回自己的能力{ jsonrpc: 2.0, id: 1, result: { protocolVersion: 2025-11-25, capabilities: { tools: { listChanged: true }, resources: { subscribe: true }, prompts: {} }, serverInfo: { name: knowledge-base-server, version: 1.0.0 } } }列出工具{ jsonrpc: 2.0, id: 2, method: tools/list, params: {} }调用工具{ jsonrpc: 2.0, id: 3, method: tools/call, params: { name: search_knowledge, arguments: { query: MCP 协议, limit: 5 } } }工具返回结果{ jsonrpc: 2.0, id: 3, result: { content: [ { type: text, text: [{\title\: \MCP 入门指南\, \score\: 0.95}] } ], isError: false } }3.3 Host 侧模型出口配置以 Cline 的settings.json为例模型出口三件套{ apiProvider: openai, openAiBaseUrl: https://taotoken.net/api, openAiApiKey: sk-your-key-here, openAiModelId: claude-sonnet-4-20250514 }如果是 Claude Code在~/.claude/settings.json里配置{ env: { ANTHROPIC_BASE_URL: https://taotoken.net/api, ANTHROPIC_API_KEY: sk-your-key-here, ANTHROPIC_MODEL: claude-sonnet-4-20250514 } }三件套缺一不可Base URL 决定请求发到哪API Key 决定能不能过鉴权Model ID 决定用哪个模型。MCP Server 的配置和模型出口的配置是两套东西不要混在一个文件里。4. 验证请求从工具注册到调用的完整链路配置写完后怎么确认整条链路是通的分三步验证Server 启动、工具注册、模型调用。4.1 验证 Server 启动stdio 模式下Server 作为子进程启动。你可以手动跑一次python -m my_mcp_server如果进程挂起不退出说明 Server 在等待 stdin 输入这是正常的。如果直接报错退出检查依赖和入口。日志应该输出到 stderrstdout 保持干净。Streamable HTTP 模式下python -m my_mcp_server --transport streamable-http --port 8000然后用 curl 测一下端点curl -X POST http://localhost:8000/mcp \ -H Content-Type: application/json \ -d {jsonrpc:2.0,id:1,method:initialize,params:{protocolVersion:2025-11-25,capabilities:{},clientInfo:{name:test,version:1.0.0}}}正常应该返回 Server 的能力声明。如果返回 404检查路由路径如果返回 500看 Server 日志。4.2 验证工具注册Server 启动后Client 会发tools/list。你可以在 Host 的 MCP 面板里看到工具清单。如果工具不显示最常见的原因是mcp.tool()装饰器没生效或者 Server 在注册工具前就退出了。一个快速排查方法在 Server 启动时打印工具数量到 stderrif __name__ __main__: import sys tools mcp._tool_manager.list_tools() print(fRegistered tools: {len(tools)}, filesys.stderr) mcp.run(transportstdio)如果这里显示 0说明装饰器没被扫描到。检查函数是否在模块顶层定义以及mcp实例是否在装饰器之前创建。4.3 验证模型调用工具注册成功后在 Host 里发一条会触发工具调用的消息。比如帮我搜索 MCP 协议的相关文档。观察 Host 的日志模型返回tool_calls指定search_knowledge和参数Host 把tool_calls转成 MCP 的tools/call请求发给 ServerServer 执行工具返回结果Host 把结果喂回模型模型生成最终回答如果模型不调工具检查工具描述是否清晰。模型是根据description决定调不调的。描述太模糊模型会忽略。如果调了但参数错检查 Pydantic 或 Zod 的类型定义。一个完整的成功结果长这样模型先输出一段我来搜索一下然后触发工具调用拿到结果后总结成自然语言回答。整个过程在 Host 日志里能看到完整的 JSON-RPC 消息往返。5. 本篇常见错排查401、local proxy failed、reading choices、OAuth这一节对照真实报错给出排查路径。这些错误我在调试 MCP 链路时基本都踩过。401 Unauthorized模型出口鉴权失败。检查 API Key 是否正确、是否过期、是否有对应模型的权限。如果用的是 TaoToken确认 Key 是在控制台创建的且 Base URL 是https://taotoken.net/api。注意 Base URL 末尾不要多加/v1不同客户端对路径的处理不一样。local proxy failed / connection refusedMCP Server 没启动或者端口被占用。stdio 模式下检查command和args是否正确Python 路径是否在 Host 的环境变量里。HTTP 模式下用lsof -i :8000看端口占用。还有一种情况是 Server 启动了但立刻退出通常是依赖缺失或配置错误看 stderr 日志。reading choices / unexpected end of JSON input模型返回的响应格式不对Host 解析失败。常见原因是模型出口返回了非标准格式或者流式响应被截断。检查 Host 的模型配置是否匹配实际返回格式。如果用的是 OpenAI 兼容接口确认apiProvider设置正确。OAuth 认证失败HTTP 传输的 MCP Server 如果启用了 OAuth 2.1Client 需要先走授权流程。报错通常是 token 过期或 scope 不足。检查 OAuth 配置的client_id、client_secret、redirect_uri是否匹配。stdio 模式不涉及 OAuth敏感信息走环境变量。工具参数验证失败Invalid paramsPydantic 或 Zod 的类型不匹配。比如 Server 定义limit: intClient 传了字符串5。检查两边的类型声明。FastMCP 基于 Pydantic v2注意model_validate()替代了 v1 的parse_obj()。无状态化迁移报错2025-11-25 规范起 MCP 转向无状态Session ID 被移除。如果你的 Server 依赖 Session ID 维护会话升级后会连不上。解决方法是移除 Session ID 依赖每次请求独立处理。旧版本短期内仍可用但新项目建议直接按无状态设计。stdio 模式无输出最常见的原因是print()污染了 stdout。JSON-RPC 消息走 stdout日志必须走 stderr。把所有print()换成logging并配置logging.basicConfig(streamsys.stderr)。工具太多上下文爆模型上下文窗口被工具定义占满。解决方法是启用渐进发现不要一次性把所有工具 schema 塞进 prompt。Client 先调tools/list拿清单模型按需请求具体工具的 schema。另外把不常用的工具拆到独立的 Server按需连接。6. 语义一致 CTA把 MCP 链路跑通之后MCP 的价值不在于协议本身多复杂而在于它把工具接入这件事从手写胶水变成了标准接口。你写一次 ServerClaude、Cursor、VS Code、Cline 都能接。工具从消耗品变成资产。如果你正在调试 MCP Server 和模型的调用链路建议先把模型出口配好。TaoToken 的 API Key 在控制台创建Base URL 用https://taotoken.net/api模型按需选。三件套配好之后MCP 工具调用的验证会顺畅很多。需要创建 Key 或管理模型出口访问 TaoToken API Keys想先验证模型对话是否正常用 模型对话 快速测一条长期跑编码 Agent 或需要稳定模型出口看 Coding Plan接入细节和协议版本对照查 接入文档最后给一个实用建议MCP Server 的调试和模型出口的调试分开做。先用tools/list确认工具注册成功再用一条简单消息验证模型能不能正确选择工具。两个环节分开排查比混在一起快得多。工具描述写清楚模型才知道什么时候该调——这一点比协议本身更影响实际效果。
返回列表