mcpField
D
devtu-fix-tool

devtu-fix-tool

github.com/mims-harvard开发1.8k380 次安装2 天前更新
代码仓库

关于 devtu-fix-tool

用于诊断和修复 ToolUniverse 工具故障的开发技能,面向维护工具配置、实现与测试的开发者。它强调先用命令行复现问题,再按错误类型修复根因并验证结果。

主要功能

  1. 01先用 CLI 验证故障是否复现
  2. 02按错误类型定位配置或实现
  3. 03检查 API 文档与参数定义
  4. 04更新工具配置和测试
  5. 05重新生成工具并运行验证

适用场景

  1. 01排查返回数据与 schema 不匹配
  2. 02修复参数校验或 API 端点问题
  3. 03验证修复后的集成与单元测试

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/mims-harvard/tooluniverse --skill devtu-fix-tool

安装后在 Claude Code 中输入/devtu-fix-tool确认已加载。

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

EXAMPLES.md
QUICK-REFERENCE.md
unit-tests-reference.md

详细介绍

修复 ToolUniverse 工具

通过系统性地识别错误、针对性修复和验证,诊断并修复失败的 ToolUniverse 工具。

修复 Bug 的基本原则

编写任何修复前,请先问:用户为什么会遇到这种失败情况?

  1. 预防,而非补救 — 修复根本原因,让故障无法发生,而不是在故障发生后添加提示文本
  2. 在输入时验证,而非在输出时验证 — 应尽早发现并拒绝错误参数、未知疾病名称和不受支持的药物,并提供清晰的指导,而不是等到静默调用 API 后才发现问题
  3. 不要掩盖静默变更 — 如果输入会被自动规范化(融合表示法、标题大小写),就原生支持两种形式,或者明确拒绝并给出指导;绝不能静默转换并将其隐藏
  4. 区分“没有数据”和“查询错误” — 过滤条件错误导致零结果,与数据不存在导致零结果并不相同;响应必须清楚地区分两者
  5. 修复抽象,而非个例 — 如果参数名称不一致,就修复接口;不要添加一个只会不断增长的别名列表

应避免的反模式:

  • 在零结果消息中添加提示文本,而不提前验证
  • 添加参数别名,而不修复命名一致性
  • 查询失败后再探测以挽救查询,而不提前验证

Bug 验证(重要)

实施任何 Bug 报告中的修复前,先通过 CLI 验证:

python3 -m tooluniverse.cli run <ToolName> '<json_args>'

许多由 Agent 报告的 Bug 都是由 MCP 接口混淆造成的误报。实施修复前,请务必确认该 Bug 可以复现。


说明

修复失败的工具时:

  1. 运行针对性测试以定位错误:
python scripts/test_new_tools.py <tool-pattern> -v
  1. 确认 API 正确 — 在线搜索官方 API 文档,确认端点、参数和模式均正确

  2. 识别错误类型(参见“错误类型”部分)

  3. 根据错误模式应用适当的修复

  4. 如果修改了 JSON 配置或工具类,请重新生成工具:

python -m tooluniverse.generate_tools
  1. 如果 tests/tools/ 中存在工具测试,请检查并更新:
ls tests/tools/test_<tool-name>_tool.py
  1. 重新运行集成测试和单元测试,验证修复

  2. 提供修复摘要,说明问题、根本原因、解决方案和测试结果

在何处修复

问题类型要修改的文件
二进制响应src/tooluniverse/*_tool.py + src/tooluniverse/data/*_tools.json
架构不匹配src/tooluniverse/data/*_tools.json (return_schema)
缺少数据包装器src/tooluniverse/*_tool.py (operation methods)
端点 URLsrc/tooluniverse/data/*_tools.json (endpoint field)
无效测试示例src/tooluniverse/data/*_tools.json (test_examples)
工具测试更新tests/tools/test_*_tool.py (if exists)
将 API 密钥用作参数src/tooluniverse/data/*_tools.json (remove param) + *_tool.py (use env var)
工具未加载(可选密钥)src/tooluniverse/data/*_tools.json (use optional_api_keys not required_api_keys)

错误类型

1. JSON 解析错误

症状:Expecting value: line 1 column 1 (char 0)

原因:工具需要 JSON,却收到了二进制数据(图像、PDF、文件)

修复:检查 Content-Type 标头。对于二进制响应,应返回描述字符串,而不是解析 JSON。将 return_schema 更新为 {"type": "string"}。

2. 架构验证错误

症状:Schema Mismatch: At root: ... is not of type 'object' 或 Data: None

原因:缺少 data 字段包装器,或架构类型错误

修复方法取决于错误:

  • 如果是 Data: None → 在所有操作方法中添加 data 包装器(参见下方的多操作模式)
  • 如果是类型不匹配 → 在 JSON 配置中更新 return_schema:
    • 数据是字符串:{"type": "string"}
    • 数据是数组:{"type": "array", "items": {...}}
    • 数据是对象:{"type": "object", "properties": {...}}

关键概念:架构验证的是 data 字段的内容,而不是完整响应。

3. 可空字段错误

症状:Schema Mismatch: At N->fieldName: None is not of type 'integer'

原因:API 对可选字段返回 None/null

修复:在 JSON 配置中使用 {"type": ["<base_type>", "null"]} 允许可空类型。此设置用于可选字段,不要用于必需标识符。

4. 互斥参数错误

症状:传入其他参数时出现 Parameter validation failed for 'param_name': None is not of type 'integer'

原因:工具接受参数 A 或参数 B(二者互斥),但两者都定义了固定类型。仅提供其中一个参数时,另一个参数为 None,导致验证失败。

示例:

{
  "neuron_id": {"type": "integer"},      // ❌ Fails when neuron_name is used
  "neuron_name": {"type": "string"}      // ❌ Fails when neuron_id is used
}

修复:将互斥参数设为可空:

{
  "neuron_id": {"type": ["integer", "null"]},      // ✅ Allows None
  "neuron_name": {"type": ["string", "null"]}      // ✅ Allows None
}

常见模式:

  • id 或 name 参数(按 ID 或名称获取)
  • acronym 或 name 参数(按符号或全名搜索)
  • 可能不提供的可选筛选参数

重要:即使参数不互斥,也要将真正可选的参数(如 filter_field、filter_value)设为可空。

5. 混合类型字段错误

症状:Schema Mismatch: At N->field: {object} is not of type 'string', 'null'

原因:字段会根据上下文返回不同结构

修复:对于具有多个不同架构的字段,在 JSON 配置中使用 oneOf。这不同于可空类型({"type": ["string", "null"]}),后者表示相同的基本类型加上 null。

6. 无效测试示例

症状:404 ERROR - Not found 或 400 Bad Request

原因:测试示例使用了无效或过时的 ID

修复:使用以下“列表 → 获取”或“搜索 → 详情”模式查找有效示例。

7. API 参数错误

症状:400 Bad Request 或参数验证错误

修复:在 JSON 配置中更新参数架构,确保类型、必填字段和枚举值正确。

8. API 密钥配置错误

症状:API 密钥为可选项时工具未加载,或 api_key 参数造成混淆

原因:对本应为可选项的密钥使用了 required_api_keys,或将 API 密钥作为工具参数公开

关键区别:

  • required_api_keys:缺少密钥时会跳过工具
  • optional_api_keys:没有密钥时工具仍会加载并运行(性能会降低)

修复:对于可匿名使用、但使用密钥时速率限制更宽松的 API,在 JSON 配置中使用 optional_api_keys。仅从环境变量读取 API 密钥(os.environ.get()),绝不要将其作为工具参数。

9. API 端点模式错误

症状:有效资源返回 404,或出现意外结果

修复:核对官方 API 文档,确认值应放在 URL 路径中还是查询参数中。

10. API 暂时性故障

症状:测试间歇性地因超时、连接错误或 5xx 错误而失败

修复:在单元测试中对暂时性错误使用 pytest.skip(),不要因外部 API 故障而导致测试失败。

常见修复模式

架构验证模式

架构验证的是 data 字段的内容,而不是完整响应。让 return_schema 类型与 data 中的内容(数组、对象或字符串)相匹配。

多操作工具模式

每个内部方法都必须返回 {"status": "...", "data": {...}}。不要在顶层使用其他字段名。

查找有效测试示例

当测试示例因 400/404 错误而失败时,可通过以下方式查找有效 ID:

  • 列表 → 获取:先调用列表端点,再从结果中提取 ID
  • 搜索 → 详情:搜索已知实体,并使用返回的 ID
  • 遍历版本:如果支持,可尝试不同的数据集版本

单元测试管理

检查是否存在单元测试

修复工具后,检查是否存在单元测试:

ls tests/tools/test_<tool-name>_tool.py
何时更新单元测试

在以下情况下更新单元测试:

  1. 更改返回结构:更新检查 result["data"] 结构的断言
  2. 添加/修改操作:为新操作添加测试用例
  3. 更改错误处理:更新错误断言
  4. 修改必需参数:更新参数验证测试
  5. 修复架构问题:确保测试验证正确的数据结构
  6. 添加二进制处理:为二进制响应添加测试
运行单元测试
# Run specific tool tests
pytest tests/tools/test_<tool-name>_tool.py -v

# Run all unit tests
pytest tests/tools/ -v
单元测试检查清单
  • 检查 tests/tools/test_<tool-name>_tool.py 是否存在
  • 在修复前后运行单元测试
  • 如果数据结构发生变化,更新断言
  • 确保直接测试和接口测试均通过

有关单元测试模式和示例的详细信息,请参阅 unit-tests-reference.md。

验证

运行集成测试
python scripts/test_new_tools.py <pattern> -v
运行单元测试(如果存在)
pytest tests/tools/test_<tool-name>_tool.py -v
重新生成工具

修改 JSON 配置或工具类后:

python -m tooluniverse.generate_tools

在以下情况下重新生成:

  • 更改 src/tooluniverse/data/*_tools.json 文件
  • 修改工具类实现

更改测试脚本时无需重新生成。

输出格式

修复后,提供以下摘要:

问题:[简要说明]

根本原因:[失败原因]

解决方案:[所做的更改]

所做更改:

  • 文件 1:[说明]
  • 文件 2:[说明]
  • 文件 3(如适用):[单元测试更新]

集成测试结果:

  • 修复前:X 项测试,Y 项通过(Z%),N 项失败,M 项架构无效
  • 修复后:X 项测试,X 项通过(100.0%),0 项失败,0 项架构无效

单元测试结果(如适用):

  • 修复前:X 项测试,Y 项通过,Z 项失败
  • 修复后:X 项测试,X 项通过,0 项失败

测试最佳实践

测试前确认参数名称

重要:始终阅读工具的 JSON 配置或生成的包装器,以获取正确的参数名称。不要猜测参数名称。

错误的测试示例:

# ❌ WRONG - assumed parameter name
AllenBrain_search_genes(query='Gad1')  # Fails: unexpected keyword 'query'

正确的方法:

# ✅ RIGHT - checked config first
# Config shows parameters: gene_acronym, gene_name
AllenBrain_search_genes(gene_acronym='Gad1')  # Works!

如何查找正确的参数名称:

  1. 阅读 JSON 配置:src/tooluniverse/data/*_tools.json
  2. 检查生成的包装器:src/tooluniverse/tools/<ToolName>.py
  3. 查看 JSON 配置中的 test_examples
系统化测试方法

测试多个工具时:

  1. 先抽样:每个 API 测试 1-2 个工具,以识别模式
  2. 错误分类:按错误类型分组(参数验证、API 错误、数据结构)
  3. 系统化修复:一次性修复所有存在相同问题的工具
  4. 只重新生成一次:完成所有 JSON 更改后,运行 python -m tooluniverse.generate_tools
  5. 全部验证:全面测试所有已修复的工具
了解数据结构

工具可以返回不同的数据结构:

  • 对象:{"data": {"id": 1, "name": "..."}} - 单个结果
  • 数组:{"data": [{"id": 1}, {"id": 2}]} - 多个结果
  • 字符串:{"data": "description text"} - 文本响应

相应地编写测试:

# For object data
result = tool()
data = result.get('data', {})
value = data.get('field_name')  # ✅

# For array data
result = tool()
items = result.get('data', [])
count = len(items)  # ✅
first = items[0] if items else {}  # ✅

常见陷阱

  1. 架构验证的是 data 字段,而不是完整响应
  2. 所有方法都需要 {"status": "...", "data": {...}} 包装结构
  3. 更改 JSON 配置后必须重新生成
  4. 对于无需密钥即可使用的 API,请使用 optional_api_keys
  5. 查阅官方 API 文档以确认正确的端点模式
  6. 遇到临时性 API 故障时,单元测试应跳过,而不是失败
  7. 互斥参数必须可为 null——这是新工具中最常见的问题
  8. 从配置中确认参数名称——不要假设或猜测
  9. 按照正确的数据结构预期进行测试——列表、字典还是字符串

调试

  • 检查 API 响应:检查状态码、Content-Type 标头和响应正文预览
  • 检查工具配置:加载 ToolUniverse 并检查工具的配置
  • 添加调试输出:在 run 方法中记录 URL、参数、状态和 Content-Type

快速参考

任务命令
运行集成测试python scripts/test_new_tools.py <pattern> -v
运行单元测试pytest tests/tools/test_<tool-name>_tool.py -v
检查是否存在单元测试ls tests/tools/test_<tool-name>_tool.py
重新生成工具python -m tooluniverse.generate_tools
检查状态git status --short | grep -E "(data|tools|.*_tool.py|tests/tools)"
错误类型修复位置
JSON 解析错误src/tooluniverse/*_tool.py 的 run() 方法
Schema 不匹配src/tooluniverse/data/*_tools.json 的 return_schema
404 错误src/tooluniverse/data/*_tools.json 的 test_examples 或 endpoint
参数错误src/tooluniverse/data/*_tools.json 的参数 schema
单元测试失败tests/tools/test_*_tool.py 中的断言
工具被跳过(可选密钥)src/tooluniverse/data/*_tools.json 中使用 optional_api_keys
API 密钥作为参数从 JSON 参数中移除,并在 Python 中使用 os.environ.get()

评论

支持 Markdown