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' 表示用户 ID,'email' 表示邮箱地址"
},
"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 层面形成双重保障。
更多推荐


所有评论(0)