New to Claude Skills? Learn how to install them →

Tmims-harvard on GitHub

ToolUniverse Tool Creator

Free

Efficiently create scientific tools for the ToolUniverse framework.

Get this skill

Free · Opens the source repo

What ToolUniverse Tool Creator does

The ToolUniverse Tool Creator is designed for developers looking to create new scientific tools within the ToolUniverse framework. This skill provides a structured approach to tool creation, ensuring that tools are implemented with proper validation, error handling, and testing. It guides users through the process of adding tools, implementing API integrations, and creating tool wrappers for scientific databases or services. By following established patterns, users can avoid common pitfalls that lead to tool failures.

This skill emphasizes the importance of adhering to the ToolUniverse contribution guidelines. It includes critical information on the two-stage architecture required for tool registration and operation. Users will learn how to define tool classes and automatically generate wrappers for various operations, ensuring that their tools are both functional and compliant with the framework's requirements. The comprehensive implementation guide outlines the necessary files to create, from the tool class to JSON configurations and testing scripts.

The ToolUniverse Tool Creator also highlights the top mistakes that lead to tool failures, such as misconfigured parameters and inadequate testing. By providing a checklist and detailed instructions, it helps users build robust tools that meet the framework's standards. This skill is particularly useful for developers and researchers who are looking to expand the capabilities of ToolUniverse with new tools that integrate seamlessly into the existing ecosystem.

When to use it

Use this skill when you need to develop new scientific tools or integrate APIs into the ToolUniverse framework.

When not to use it

This skill is not suitable for general-purpose programming tasks outside of the ToolUniverse framework.

What you can build with it

Creating a New API Tool

Use this skill to develop a new tool that integrates with a scientific API, following the provided templates and guidelines.

Validating Existing Tools

Leverage the validation and testing features of this skill to ensure your existing tools comply with ToolUniverse standards.

Expanding ToolUniverse Capabilities

Implement new functionalities or services within the ToolUniverse framework by creating and registering new tools.

How to install ToolUniverse Tool Creator

View source

1. Install with the skills CLI

npx skills add mims-harvard/tooluniverse/devtu-create-tool --agent claude-code

2. Or install it manually

Download the skill folder and drop it into ~/.claude/skills/ for all projects, or .claude/skills/ to scope it to one repo. Restart Claude Code so it picks up the new skill.

Anthropic's agentic coding CLI, and the reference implementation of Agent Skills. Drop a skill folder into ~/.claude/skills and Claude Code loads it automatically whenever a task matches the skill's description. Claude Code docs

Inside SKILL.md

Written by mims-harvard

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:

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)

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

[
  {
    "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:

{
  "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):

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


Testing (MANDATORY)

Full guide: 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

# 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

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

Frequently asked questions about ToolUniverse Tool Creator

Similar skills