1. 从李博杰 4.3 节说起工具多了Agent 反而变笨了如果你正在做 AI Agent大概率遇到过这个场景给 Agent 挂上七八个 MCP 服务器工具列表一下子膨胀到五六十个然后模型开始乱选工具——该查天气的时候去调文件读取该写数据库的时候去调搜索。这不是模型不行而是工具选择本身成了一个独立的技术问题。李博杰在《深入理解 AI Agent》4.3 节里把这件事讲得很透MCP 解决了工具能不能跨框架复用的问题但没有解决工具多了怎么选的问题。这两件事经常被混为一谈。MCPModel Context Protocol是 Anthropic 在 2024 年底推出的开放通信标准用统一的方式描述工具、资源和提示模板。它的核心价值是一次开发处处可用——你写一个 MCP 服务器Cursor、Claude Desktop、各种 Agent 框架都能调。但它的工具描述是基于 JSON Schema 的每个工具都要把名称、描述、参数结构完整塞进上下文。少量服务器就能吃掉几万 Token而且工具越多模型在扁平列表里做选择的准确率越低。这篇内容聚焦一个具体问题在 MCP 工具生态下怎么把工具注册进去、怎么控制工具描述的开销、怎么验证模型真的选对了工具。我会给出一套可复制的配置骨架包括settings.json和config.toml两种常见格式以及一套工具筛选和验证的动作。整个流程跑在 TaoToken 的统一 Key/API 通道上这样你不需要为每个模型单独配一套凭证切换模型时工具配置不用动。适合谁看已经在用或准备用 MCP 接工具的 Agent 开发者被工具选择准确率困扰、想搞清楚描述和 Schema 怎么影响决策的人以及想用一套 API 通道统一管理多模型工具调用的团队。下面从工具注册开始一步步来。2. 前置准备TaoToken 统一 Key 与 MCP 客户端环境在讲工具选择之前先把通道打通。MCP 本身是协议不绑定模型供应商但你的 Agent 客户端需要调用大模型来做工具选择决策。如果每个模型都配一套 Key工具配置和凭证管理会变成两套复杂度。TaoToken 的做法是提供一个统一的 API 入口模型对话、Coding Plan、API Keys 都在一个控制台里管理MCP 客户端只需要指向同一个 base URL。你需要准备三样东西。第一是 TaoToken 的 API Key在控制台的 API Keys 页面创建地址是 https://taotoken.net/api-keys?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content 。第二是确认你的 MCP 客户端支持自定义模型端点主流 Agent 框架和 IDE 插件基本都支持。第三是准备至少一个 MCP 服务器做测试本地 stdio 模式的最简单比如官方的 filesystem 服务器。关于模型选择如果你只是做工具选择的验证测试用模型对话通道就够了地址在 https://taotoken.net/models?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content 。如果你要长期跑编码类 Agent、需要稳定的工具调用和较长的上下文Coding Plan 更合适入口是 https://taotoken.net/coding-plan?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content 。两者的 Key 是同一套体系切换时不用改 MCP 配置。这里有个容易踩的坑MCP 服务器的工具描述是客户端在建立连接时拉取的和模型调用是两条独立的链路。也就是说工具注册在客户端侧模型选择在 API 侧。TaoToken 统一的是 API 侧客户端侧的 MCP 配置还是按各客户端的规范来写。理解这一点后面排查问题会清晰很多。3. 可复制配置settings.json 与 config.toml 工具注册骨架MCP 客户端的配置格式因工具而异但核心结构一致声明服务器、指定传输方式、传入启动命令或 URL。下面给两个最常见的格式你可以直接改成自己的路径和参数。3.1 settings.json 格式Claude Desktop / Cursor 类{ mcpServers: { filesystem: { command: npx, args: [ -y, modelcontextprotocol/server-filesystem, /Users/yourname/agent-workspace ], env: { TAOTOKEN_API_KEY: sk-your-taotoken-key, TAOTOKEN_BASE_URL: https://taotoken.net/api } }, sqlite-readonly: { command: uvx, args: [ mcp-server-sqlite, --db-path, /Users/yourname/agent-workspace/data.db, --readonly ] } } }注意sqlite-readonly这个例子里的--readonly参数。这是工具选择边界的一部分只读工具和可写工具应该分开注册不要让一个工具同时具备查询和修改能力。模型在扁平列表里看到sqlite一个工具时它不知道边界在哪看到sqlite-readonly和sqlite-write两个工具时选择意图会明确很多。3.2 config.toml 格式部分 Agent 框架 / CLI 工具[mcp.servers.filesystem] command npx args [-y, modelcontextprotocol/server-filesystem, ./workspace] transport stdio [mcp.servers.filesystem.env] TAOTOKEN_API_KEY sk-your-taotoken-key TAOTOKEN_BASE_URL https://taotoken.net/api [mcp.servers.web-search] url https://your-mcp-host/mcp transport streamable-http headers { Authorization Bearer sk-your-taotoken-key } [mcp.servers.web-search.tool_filter] include [search, fetch] exclude [browse_history]tool_filter这一段是控制工具描述开销的关键。MCP 服务器可能暴露十几个工具但你当前场景只需要两三个。通过 include/exclude 过滤客户端在拉取工具列表时就只保留需要的上下文里的工具定义 Token 直接降下来。这比事后在 prompt 里告诉模型别用某个工具有效得多因为后者仍然占用上下文。3.3 工具描述与参数 Schema 的写法要点工具选择准确率低很多时候不是模型的问题是描述写得含糊。JSON Schema 里的description字段是模型做决策的主要依据。几个实测有效的写法工具名用动词开头search_documents比documents好read_file比file_reader好。描述里写清楚什么时候用和什么时候不用比如用于在本地工作区搜索文本内容不用于网络搜索网络搜索请用 web_search。参数描述里给示例值format: {type: string, description: 输出格式可选 json 或 text默认 text}比只写类型有用。参数 Schema 尽量收紧。能用 enum 就不用自由字符串能标 required 就标上。模型看到unit: {enum: [celsius, fahrenheit]}时选错参数的概率明显低于unit: {type: string}。这不是玄学是约束空间变小了。4. 验证请求确认模型选对了工具配置写完怎么知道模型真的按预期选工具不能只看它最后输出了什么要看它中间调用了哪个工具、传了什么参数。下面是一段用 Python 发起的验证请求走 TaoToken 的 API 通道打印出工具调用详情。import json import urllib.request API_KEY sk-your-taotoken-key BASE_URL https://taotoken.net/api # 模拟客户端拉取到的工具列表实际由 MCP 客户端注入 tools [ { type: function, function: { name: search_documents, description: 在本地工作区搜索文本内容。不用于网络搜索。, parameters: { type: object, properties: { query: {type: string, description: 搜索关键词}, max_results: {type: integer, default: 5} }, required: [query] } } }, { type: function, function: { name: read_file, description: 读取指定路径的文件内容。仅用于已知路径的读取。, parameters: { type: object, properties: { path: {type: string, description: 文件绝对路径} }, required: [path] } } } ] payload { model: claude-sonnet-4-20250514, messages: [ {role: user, content: 帮我在工作区里找一下关于 MCP 配置的笔记} ], tools: tools, tool_choice: auto } req urllib.request.Request( f{BASE_URL}/v1/messages, datajson.dumps(payload).encode(), headers{ Content-Type: application/json, x-api-key: API_KEY, anthropic-version: 2023-06-01 } ) with urllib.request.urlopen(req) as resp: result json.loads(resp.read()) for block in result.get(content, []): if block.get(type) tool_use: print(f选中工具: {block[name]}) print(f参数: {json.dumps(block[input], ensure_asciiFalse)})跑这段代码预期输出是选中工具: search_documents参数里query是MCP 配置。如果模型选了read_file说明工具描述里的边界没写清楚或者两个工具的描述有重叠。这时候回去改描述而不是改 prompt。验证要覆盖三类场景明确该用 A 工具的请求、明确该用 B 工具的请求、以及不该调用任何工具的纯对话请求。第三类最容易被忽略但它是检验工具描述是否过度诱导的关键。如果模型在纯聊天时也去调工具说明工具描述写得太宽泛了。5. 本篇常见错排查工具注册和选择过程中报错和异常行为集中在几个地方。下面按现象列排查路径。工具列表为空模型说没有可用工具。先确认 MCP 客户端是否成功建立了连接。stdio 模式下服务器进程启动失败是最常见原因检查command和args里的路径是否存在、依赖是否安装。npx类命令首次运行需要下载包网络不通会静默失败。可以在终端手动执行一遍command args看有没有报错输出。Streamable HTTP 模式下检查 URL 是否可达、headers 里的认证是否有效。模型选了工具但参数格式错误。这是 Schema 定义的问题。检查required字段是否和模型实际传的对得上检查类型是否一致——模型传字符串但你定义的是 integer调用就会失败。另外注意默认值JSON Schema 里的default不一定会被模型遵守关键参数还是标成 required 更稳。工具选择准确率低经常选错。按这个顺序排查工具数量是否超过 20 个超过就做分层或过滤工具描述是否有重叠语义有就改描述明确边界工具名是否都是名词改成动词开头参数 Schema 是否太宽松收紧 enum 和 required。李博杰提到的动态工具发现思路在这里适用不要一次性把所有工具灌进去先给模型一个list_tools类的元工具让它按需检索再把选中的工具定义加载进来。上下文 Token 消耗异常高。用客户端的调试日志看工具定义占了多少 Token。如果单个服务器就占了几千 Token检查是否有工具的描述写得过长或者暴露了不必要的工具。tool_filter和懒加载是主要手段。另外注意有些 MCP 服务器会把资源resources也塞进上下文如果不需要就关掉。切换模型后工具调用行为变了。不同模型对工具描述的理解有差异这是正常的。TaoToken 统一了 API 通道但模型本身的工具调用能力不同。如果某个模型在工具选择上表现差换一个模型对话通道里的模型试试不用改 MCP 配置。长期跑 Agent 的话Coding Plan 里的模型在工具调用稳定性上更适合。6. 把工具选择当成一个独立问题来对待回到李博杰 4.3 节的核心观点MCP 解决的是互操作不是选择。工具生态越繁荣选择问题越突出。我自己的做法是把工具选择拆成三层来管——注册层控制有哪些工具描述层控制模型怎么理解工具验证层控制选得对不对。三层各自有配置手段不要混在一起调。注册层用tool_filter和分层分类把工具数量压到模型能处理的范围内。描述层用动词命名、边界说明、收紧 Schema让每个工具的意图无歧义。验证层用上面那段代码覆盖正例、反例和空例每次改完配置都跑一遍。这三层跑顺了Agent 的工具调用准确率会有明显提升。如果你还没开始接 MCP建议从单个 filesystem 服务器起步跑通注册和验证流程再逐步加服务器。每加一个都重新跑一遍验证。TaoToken 的 API 通道在这里的作用是让你不用为每个模型单独配 Key工具配置和模型切换解耦排查问题时变量更少。接入文档在 https://taotoken.net/doc?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content 里面有各语言 SDK 的调用示例。Claude Code 相关的接入配置在 https://taotoken.net/claudecode-anthropic?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content 如果你用 Claude Code 做 Agent 开发可以直接参考。