devtu-create-tool by mims-harvard/tooluniverse
npx skills add https://github.com/mims-harvard/tooluniverse --skill devtu-create-tool遵循既定模式创建新的科学工具。
default_config.py 条目 — 工具将静默加载失败test_new_tools.py — 遗漏模式/API问题Stage 1: Tool Class Stage 2: Wrappers (Auto-Generated)
@register_tool("MyTool") MyAPI_list_items()
class MyTool(BaseTool): MyAPI_search()
def run(arguments): MyAPI_get_details()
一个类处理多个操作。JSON 定义独立的包装器。两者都需要。
步骤 1:通过 @register_tool("MyAPITool") 进行类注册
广告位招租
在这里展示您的产品或服务
触达数万 AI 开发者,精准高效
步骤 2(最常被遗漏):在 default_config.py 中进行配置注册:
TOOLS_CONFIGS = {
"my_category": os.path.join(current_dir, "data", "my_category_tools.json"),
}
步骤 3:在 tu.load_tools() 时自动生成包装器
src/tooluniverse/my_api_tool.py — 实现src/tooluniverse/data/my_api_tools.json — 工具定义tests/tools/test_my_api_tool.py — 测试from typing import Dict, Any
from tooluniverse.tool import BaseTool
from tooluniverse.tool_utils import register_tool
import requests
@register_tool("MyAPITool")
class MyAPITool(BaseTool):
BASE_URL = "https://api.example.com/v1"
def __init__(self, tool_config):
super().__init__(tool_config)
self.parameter = tool_config.get("parameter", {})
self.required = self.parameter.get("required", [])
def run(self, arguments: Dict[str, Any]) -> Dict[str, Any]:
operation = arguments.get("operation")
if not operation:
return {"status": "error", "error": "Missing: operation"}
if operation == "search":
return self._search(arguments)
return {"status": "error", "error": f"Unknown: {operation}"}
def _search(self, arguments: Dict[str, Any]) -> Dict[str, Any]:
query = arguments.get("query")
if not query:
return {"status": "error", "error": "Missing: query"}
try:
response = requests.get(
f"{self.BASE_URL}/search",
params={"q": query}, timeout=30
)
response.raise_for_status()
data = response.json()
return {"status": "success", "data": data.get("results", [])}
except requests.exceptions.Timeout:
return {"status": "error", "error": "Timeout after 30s"}
except requests.exceptions.HTTPError as e:
return {"status": "error", "error": f"HTTP {e.response.status_code}"}
except Exception as e:
return {"status": "error", "error": str(e)}
[
{
"name": "MyAPI_search",
"class": "MyAPITool",
"description": "搜索项目。返回结果数组。支持布尔运算符。示例:'protein AND membrane'。",
"parameter": {
"type": "object",
"required": ["operation", "query"],
"properties": {
"operation": {"const": "search", "description": "操作(固定)"},
"query": {"type": "string", "description": "搜索词"},
"limit": {"type": ["integer", "null"], "description": "最大结果数 (1-100)"}
}
},
"return_schema": {
"oneOf": [
{"type": "object", "properties": {"data": {"type": "array"}}},
{"type": "object", "properties": {"error": {"type": "string"}}, "required": ["error"]}
]
},
"test_examples": [{"operation": "search", "query": "protein", "limit": 10}]
}
]
{API}_{action}_{target} 模板{"status": "error", "error": "..."}{"status": "success|error", "data": {...}}当工具接受 id 或 name 时,两者都必须可为空:
{
"id": {"type": ["integer", "null"], "description": "数字 ID"},
"name": {"type": ["string", "null"], "description": "名称(id 的替代项)"}
}
如果没有 "null",当用户只提供一个参数时,验证会失败。
常见情况:id 或 name、gene_id 或 gene_symbol、任何可选过滤器。
可选密钥(没有也能工作,有则更好):
{"optional_api_keys": ["NCBI_API_KEY"]}
self.api_key = os.environ.get("NCBI_API_KEY", "") # 仅从环境变量读取
必需密钥(没有则无法工作):
{"required_api_keys": ["NVIDIA_API_KEY"]}
规则:对于可选密钥,切勿将 api_key 作为工具参数添加。仅使用环境变量。
run(),检查响应tu.tools.YourTool_op1(...),检查注册python scripts/test_new_tools.py your_tool -v → 0 失败# Check all 3 registration steps
python3 -c "
import sys; sys.path.insert(0, 'src')
from tooluniverse.tool_registry import get_tool_registry
import tooluniverse.your_tool_module
assert 'YourToolClass' in get_tool_registry(), 'Step 1 FAILED'
from tooluniverse.default_config import TOOLS_CONFIGS
assert 'your_category' in TOOLS_CONFIGS, 'Step 2 FAILED'
from tooluniverse import ToolUniverse
tu = ToolUniverse(); tu.load_tools()
assert hasattr(tu.tools, 'YourCategory_op1'), 'Step 3 FAILED'
print('All 3 steps verified!')
"
python3 -m json.tool src/tooluniverse/data/your_tools.json # 验证 JSON
python3 -m py_compile src/tooluniverse/your_tool.py # 检查语法
grep "your_category" src/tooluniverse/default_config.py # 验证配置
python scripts/test_new_tools.py your_tool -v # 强制测试
每周安装次数
152
代码仓库
GitHub 星标数
1.2K
首次出现
2026年2月4日
安全审计
安装于
codex147
opencode146
gemini-cli142
github-copilot140
amp135
kimi-cli134
Create new scientific tools following established patterns.
default_config.py Entry — tools silently won't loadtest_new_tools.py — misses schema/API issuesStage 1: Tool Class Stage 2: Wrappers (Auto-Generated)
@register_tool("MyTool") MyAPI_list_items()
class MyTool(BaseTool): MyAPI_search()
def run(arguments): MyAPI_get_details()
One class handles multiple operations. JSON defines individual wrappers. Need BOTH.
Step 1 : Class registration via @register_tool("MyAPITool")
Step 2 (MOST COMMONLY MISSED): Config registration in default_config.py:
TOOLS_CONFIGS = {
"my_category": os.path.join(current_dir, "data", "my_category_tools.json"),
}
Step 3 : Automatic wrapper generation on tu.load_tools()
src/tooluniverse/my_api_tool.py — implementationsrc/tooluniverse/data/my_api_tools.json — tool definitionstests/tools/test_my_api_tool.py — testsfrom typing import Dict, Any
from tooluniverse.tool import BaseTool
from tooluniverse.tool_utils import register_tool
import requests
@register_tool("MyAPITool")
class MyAPITool(BaseTool):
BASE_URL = "https://api.example.com/v1"
def __init__(self, tool_config):
super().__init__(tool_config)
self.parameter = tool_config.get("parameter", {})
self.required = self.parameter.get("required", [])
def run(self, arguments: Dict[str, Any]) -> Dict[str, Any]:
operation = arguments.get("operation")
if not operation:
return {"status": "error", "error": "Missing: operation"}
if operation == "search":
return self._search(arguments)
return {"status": "error", "error": f"Unknown: {operation}"}
def _search(self, arguments: Dict[str, Any]) -> Dict[str, Any]:
query = arguments.get("query")
if not query:
return {"status": "error", "error": "Missing: query"}
try:
response = requests.get(
f"{self.BASE_URL}/search",
params={"q": query}, timeout=30
)
response.raise_for_status()
data = response.json()
return {"status": "success", "data": data.get("results", [])}
except requests.exceptions.Timeout:
return {"status": "error", "error": "Timeout after 30s"}
except requests.exceptions.HTTPError as e:
return {"status": "error", "error": f"HTTP {e.response.status_code}"}
except Exception as e:
return {"status": "error", "error": str(e)}
[
{
"name": "MyAPI_search",
"class": "MyAPITool",
"description": "Search items. Returns array of results. Supports Boolean operators. Example: 'protein AND membrane'.",
"parameter": {
"type": "object",
"required": ["operation", "query"],
"properties": {
"operation": {"const": "search", "description": "Operation (fixed)"},
"query": {"type": "string", "description": "Search term"},
"limit": {"type": ["integer", "null"], "description": "Max results (1-100)"}
}
},
"return_schema": {
"oneOf": [
{"type": "object", "properties": {"data": {"type": "array"}}},
{"type": "object", "properties": {"error": {"type": "string"}}, "required": ["error"]}
]
},
"test_examples": [{"operation": "search", "query": "protein", "limit": 10}]
}
]
{API}_{action}_{target} template{"status": "error", "error": "..."}{"status": "success|error", "data": {...}}When tool accepts EITHER id OR name, BOTH must be nullable:
{
"id": {"type": ["integer", "null"], "description": "Numeric ID"},
"name": {"type": ["string", "null"], "description": "Name (alternative to id)"}
}
Without "null", validation fails when user provides only one parameter.
Common cases: id OR name, gene_id OR gene_symbol, any optional filters.
Optional keys (tool works without, better with):
{"optional_api_keys": ["NCBI_API_KEY"]}
self.api_key = os.environ.get("NCBI_API_KEY", "") # Read from env only
Required keys (tool won't work without):
{"required_api_keys": ["NVIDIA_API_KEY"]}
Rules: Never add api_key as tool parameter for optional keys. Use env vars only.
Full guide: references/testing-guide.md
run(), check responsetu.tools.YourTool_op1(...), check registrationpython scripts/test_new_tools.py your_tool -v → 0 failures# Check all 3 registration steps
python3 -c "
import sys; sys.path.insert(0, 'src')
from tooluniverse.tool_registry import get_tool_registry
import tooluniverse.your_tool_module
assert 'YourToolClass' in get_tool_registry(), 'Step 1 FAILED'
from tooluniverse.default_config import TOOLS_CONFIGS
assert 'your_category' in TOOLS_CONFIGS, 'Step 2 FAILED'
from tooluniverse import ToolUniverse
tu = ToolUniverse(); tu.load_tools()
assert hasattr(tu.tools, 'YourCategory_op1'), 'Step 3 FAILED'
print('All 3 steps verified!')
"
python3 -m json.tool src/tooluniverse/data/your_tools.json # Validate JSON
python3 -m py_compile src/tooluniverse/your_tool.py # Check syntax
grep "your_category" src/tooluniverse/default_config.py # Verify config
python scripts/test_new_tools.py your_tool -v # MANDATORY test
Weekly Installs
152
Repository
GitHub Stars
1.2K
First Seen
Feb 4, 2026
Security Audits
Gen Agent Trust HubFailSocketPassSnykWarn
Installed on
codex147
opencode146
gemini-cli142
github-copilot140
amp135
kimi-cli134
agent-browser 浏览器自动化工具 - Vercel Labs 命令行网页操作与测试
152,900 周安装
Gemini CLI 文档撰写规范 | 技术文档写作指南与标准
1,900 周安装
微信公众号文章提取器 - 高效解析微信文章元数据与内容,支持多种文章类型
1,900 周安装
bb-browser:浏览器自动化与信息获取工具,支持36+平台命令行API
1,900 周安装
agent-device 移动端自动化测试工具 | 跨平台UI测试与调试解决方案
2,000 周安装
内容差距分析工具 - 识别SEO内容机会,提升网站排名与流量
2,000 周安装
Claude Code 安全扫描工具 - 使用 AgentShield 审计配置,发现并修复安全问题
1,900 周安装