MCP 工具调用中的常见问题与实战解决方案
MCP 工具调用中的常见问题与实战解决方案这是 MCP 落地中非常典型的问题核心原因在于工具描述Tool Description和参数 Schema 的信息密度不够模型缺乏足够的上下文来做出正确决策。下面分两个维度系统性地拆解。一、模型分不清类似接口问题本质当多个工具功能相近时模型看到的 tool definition 可能长这样// 模型视角下的两个模糊工具{name:get_user,description:获取用户信息}{name:get_user_info,description:获取用户详细信息}模型无法判断该调哪个。解决方案1. 工具描述中写清「何时用」和「何时不用」{name:get_user_basic,description:根据用户 ID 获取用户的基本信息姓名、邮箱、手机号。仅需要用户基本信息时使用。如果需要用户的订单、权限或偏好设置请使用 get_user_profile。}关键原则描述不只是「这个工具做什么」而是「什么时候该用它什么时候不该用」。2. 用 MCP 的 annotations 字段做区分MCP 协议支持annotations可以给工具加元数据{name:search_products,description:搜索商品,annotations:{category:product,useCase:用户想要找某个具体商品时使用,contrastWith:list_products用于浏览商品列表非搜索场景}}3. 合并相似工具为一个用参数区分// 改造前两个容易混淆的工具// get_user_by_id / get_user_by_email// 改造后一个工具参数区分{name:get_user,description:根据 ID 或邮箱获取用户信息。必须且只能提供 identifier_type 和 identifier 两个参数。,inputSchema:{type:object,properties:{identifier_type:{type:string,enum:[id,email],description:查询方式id 表示用户 IDemail 表示邮箱地址},identifier:{type:string,description:对应的查询值需与 identifier_type 匹配}},required:[identifier_type,identifier]}}4. 工具命名用动词前缀做语义分组✅ 好的命名 user_get → 获取用户 user_update → 更新用户 order_list → 列出订单 order_get_detail → 获取订单详情 ❌ 差的命名 getUser getUserInfo getUserDetail getUserData二、参数传递问题问题 1不知道 type 传什么原因枚举值没有暴露给模型// 模糊的 Schema{type:{type:string,description:类型}}模型完全不知道type可以取什么值。解决方案用 enum 把所有合法值列出来{type:{type:string,enum:[personal,enterprise,government,education],description:账户类型。personal个人用户enterprise企业用户government政府机构education教育机构。如果用户没有明确指定默认为 personal。}}如果枚举值太多或动态变化在 description 中说明获取方式{category_id:{type:string,description:商品分类 ID。如果用户未指定分类请先调用 list_categories 获取可用分类列表及其 ID再从中选择。}}问题 2不知道 id 传什么这是实战中最高频的问题。模型不知道该传什么 ID或者从哪里获取。解决方案 A在参数描述中写清 ID 的来源和格式{order_id:{type:string,description:订单 ID格式为 ORD- 开头加 12 位数字如 ORD-202401010001。可通过 search_orders 或 get_user_orders 获取。}}解决方案 B设计「搜索 → 选择 → 操作」的工具链工具链设计 search_user(name/email) → 返回 user_id 列表 get_user(user_id) → 返回用户详情 update_user(user_id, …) → 更新用户在每个工具的描述中明确写出「上游依赖」{name:update_user,description:更新用户信息。user_id 必须来自 search_user 的返回结果不要猜测或编造 ID。,inputSchema:{properties:{user_id:{type:string,description:用户 ID必须通过 search_user 工具获取。格式示例usr_8a3b2c1d}}}}解决方案 C提供一个「万能查询」工具兜底{name:resolve_entity,description:当不确定某个实体用户/订单/商品的 ID 时用自然语言描述来查找对应的 ID。这是 ID 解析的兜底工具。,inputSchema:{properties:{entity_type:{type:string,enum:[user,order,product],description:要查找的实体类型},query:{type:string,description:自然语言描述如 张三的账号、上周的退货订单、iPhone 15}},required:[entity_type,query]}}三、系统性最佳实践总结┌─────────────────────────────────────────────────────────┐ │ MCP 工具设计检查清单 │ ├─────────────────────────────────────────────────────────┤ │ │ │ 1. 每个工具的 description 是否回答了 │ │ ✅ 它做什么 │ │ ✅ 什么时候该用它 │ │ ✅ 什么时候不该用它该用哪个替代工具 │ │ │ │ 2. 每个参数的 description 是否回答了 │ │ ✅ 取值范围是什么enum / format │ │ ✅ 从哪里获取哪个上游工具的返回值 │ │ ✅ 有没有默认值 │ │ ✅ 给出一个示例值 │ │ │ │ 3. 工具之间的调用关系是否清晰 │ │ ✅ 搜索类 → 获取类 → 操作类 的链路是否完整 │ │ ✅ 是否有兜底工具处理模糊查询 │ │ │ │ 4. 错误信息是否对模型友好 │ │ ✅ 参数不合法时返回可操作的错误提示 │ │ ✅ 不要只返回 error要返回 请提供 X格式为 Y │ │ │ └─────────────────────────────────────────────────────────┘最关键的一条经验把工具描述当作给一个「聪明但完全不了解你业务的新人」写的交接文档。模型的能力上限很大程度上取决于你给它的上下文质量。MCP 工具的 description 和 parameter schema本质上就是你和模型之间的「接口契约」——写得越精确模型调用得越准确。四、进阶用 System Prompt 补充业务上下文如果工具 Schema 空间有限可以在 MCP Server 的 instructions 或系统提示中补充你当前可以使用以下 MCP 工具。使用前请注意 - 所有 ID 参数必须通过搜索类工具获取禁止自行编造 - type 字段只能使用工具定义中 enum 列出的值 - 如果用户描述模糊优先调用 search/resolve 类工具缩小范围 - 如果不确定该调哪个工具先调用 help 工具查看工具使用指南这样在 Schema 层面和 Prompt 层面形成双重保障。