devtu-create-tool

$npx mdskill add mims-harvard/ToolUniverse/devtu-create-tool

Creates new scientific tools for ToolUniverse framework following established patterns and guidelines

  • Automatically registers new tools via decorators for seamless integration into ToolUniverse.
  • Deploys tool classes alongside auto-generated wrappers to ensure comprehensive API coverage.
  • Enforces validation, error handling, and test examples to maintain high-quality tool reliability.
  • Ensures compatibility with MCP (Microcontroller Protocol) by adhering to character limits and best practices.

SKILL.md

.github/skills/devtu-create-toolView on GitHub ↗
---
name: devtu-create-tool
description: Create new scientific tools for ToolUniverse framework with proper structure, validation, and testing. Use when users need to add tools to ToolUniverse, implement new API integrations, create tool wrappers for scientific databases/services, expand ToolUniverse capabilities, or follow ToolUniverse contribution guidelines. Supports creating tool classes, JSON configurations, validation, error handling, and test examples.
---

# ToolUniverse Tool Creator

Create new scientific tools following established patterns.

## Top 7 Mistakes (90% of Failures)

1. **Missing `default_config.py` Entry** — tools silently won't load
2. **Non-nullable Mutually Exclusive Parameters** — validation errors (#1 issue in 2026)
3. **Fake test_examples** — tests fail, agents get bad examples
4. **Single-level Testing** — misses registration bugs
5. **Skipping `test_new_tools.py`** — misses schema/API issues
6. **Tool Names > 55 chars** — breaks MCP compatibility
7. **Raising Exceptions** — should return error dicts instead

---

## Two-Stage Architecture

```
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()
```

One class handles multiple operations. JSON defines individual wrappers. Need BOTH.

## Three-Step Registration

**Step 1**: Class registration via `@register_tool("MyAPITool")`

**Step 2** (MOST COMMONLY MISSED): Config registration in `default_config.py`:
```python
TOOLS_CONFIGS = {
    "my_category": os.path.join(current_dir, "data", "my_category_tools.json"),
}
```

**Step 3**: Automatic wrapper generation on `tu.load_tools()`

---

## Implementation Guide

### Files to Create
- `src/tooluniverse/my_api_tool.py` — implementation
- `src/tooluniverse/data/my_api_tools.json` — tool definitions
- `tests/tools/test_my_api_tool.py` — tests

### Python Tool Class (Multi-Operation Pattern)

```python
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)}
```

### JSON Configuration

```json
[
  {
    "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}]
  }
]
```

### Critical Requirements

- **return_schema MUST have oneOf**: success + error schemas
- **test_examples MUST use real IDs**: NO "TEST", "DUMMY", "PLACEHOLDER"
- **Tool name <= 55 chars**: `{API}_{action}_{target}` template
- **Description 150-250 chars**: what, format, example, notes
- **NEVER raise in run()**: return `{"status": "error", "error": "..."}`
- **Set timeout** on all HTTP requests (30s)
- **Standard response**: `{"status": "success|error", "data": {...}}`

---

## Parameter Design

### Mutually Exclusive Parameters (CRITICAL — #1 issue)

When tool accepts EITHER `id` OR `name`, BOTH must be nullable:

```json
{
  "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.

### API Key Configuration

**Optional keys** (tool works without, better with):
```json
{"optional_api_keys": ["NCBI_API_KEY"]}
```
```python
self.api_key = os.environ.get("NCBI_API_KEY", "")  # Read from env only
```

**Required keys** (tool won't work without):
```json
{"required_api_keys": ["NVIDIA_API_KEY"]}
```

Rules: Never add `api_key` as tool parameter for optional keys. Use env vars only.

---

## Testing (MANDATORY)

Full guide: [references/testing-guide.md](references/testing-guide.md)

### Quick Testing Checklist

1. **Level 1** — Direct class test: import class, call `run()`, check response
2. **Level 2** — ToolUniverse test: `tu.tools.YourTool_op1(...)`, check registration
3. **Level 3** — Real API test: use real IDs, verify actual responses
4. **MANDATORY** — Run `python scripts/test_new_tools.py your_tool -v` → 0 failures

### Verification Script

```bash
# 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!')
"
```

---

## Quick Commands

```bash
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
```

## References

- **Testing guide**: [references/testing-guide.md](references/testing-guide.md)
- **Advanced patterns** (async, SOAP, pagination): [references/advanced-patterns.md](references/advanced-patterns.md)
- **Implementation guide** (full checklist): [references/implementation-guide.md](references/implementation-guide.md)
- **Tool improvement checklist**: [references/tool-improvement-checklist.md](references/tool-improvement-checklist.md)

More from mims-harvard/ToolUniverse

SkillDescription
create-tooluniverse-skillCreate high-quality ToolUniverse skills following test-driven, implementation-agnostic methodology.
devtu-auto-discover-apisAutomatically discover life science APIs online, create ToolUniverse tools, validate them, and prepare integration PRs. Performs gap analysis to identify missing tool categories, web searches for APIs, automated tool creation using devtu-create-tool patterns, validation with devtu-fix-tool, and git workflow management. Use when expanding ToolUniverse coverage, adding new API integrations, or systematically discovering scientific resources.
devtu-benchmark-harnessContinuous improvement system for ToolUniverse tools, skills, and plugin. Run benchmarks, diagnose failures, route fixes to devtu skills, retest. Use after skill optimization, tool additions, or as regression check.
devtu-code-optimization>
devtu-docs-qualityTOP PRIORITY skill — find and immediately fix or remove every piece of wrong, outdated, or redundant information in ToolUniverse docs. Wrong code, broken links, incorrect counts, and overlapping instructions must be fixed or removed — never left in place. Runs five phases: (D) static method scan, (C) live code execution, (A) automated validation, (B) ToolUniverse audit, (E) less-is-more simplification. Core philosophy: each concept appears exactly once; remove don't add; no emojis; single setup entry point. Use when reviewing docs, before releases, after API changes, or when asked to audit, fix, or simplify documentation.
devtu-fix-toolFix failing ToolUniverse tools by diagnosing test failures, identifying root causes, implementing fixes, and validating solutions. Use when ToolUniverse tools fail tests, return errors, have schema validation issues, or when asked to debug or fix tools in the ToolUniverse framework.
devtu-githubGitHub workflow for ToolUniverse - push code safely by moving temp files, activating pre-commit hooks, running tests, and cleaning staged files. Use when pushing to GitHub, fixing CI failures, or cleaning up before commits.
devtu-optimize-descriptionsOptimize tool descriptions in ToolUniverse JSON configs for clarity and usability. Reviews descriptions for missing prerequisites, unexpanded abbreviations, unclear parameters, and missing usage guidance. Use when reviewing tool descriptions, improving API documentation, or when user asks to check if tools are easy to understand.
devtu-optimize-skillsOptimize ToolUniverse skills for better report quality, evidence handling, and user experience. Apply patterns like tool verification, foundation data layers, disambiguation-first, evidence grading, quantified completeness, and report-only output. Use when reviewing skills, improving existing skills, or creating new ToolUniverse research skills.
devtu-self-evolve>