--- title: "Tool Implementation Guide" task: "" lineage_type: import upstream_source: https://github.com/mims-harvard/ToolUniverse/blob/e2520a96/skills/devtu-create-tool/references/implementation-guide.md upstream_sha: e2520a96 imported_at: 2026-06-26 prompt_class: prompt upstream_changes: accepted author: upstream validated: false --- # Tool Implementation Guide Complete guidelines for adding and maintaining tools in ToolUniverse. This is the authoritative reference for tool structure, configuration conventions, and the development checklist. ## Guidelines for Adding Tools Based on `docs/expand_tooluniverse/contributing/local_tools.rst` and the current codebase structure. ### File Structure & Location - **Source Code**: `src/tooluniverse/xxx_tool.py` - **Configuration**: `src/tooluniverse/data/xxx_tools.json` - **Tests**: `tests/unit/test_xxx_tool.py` - **DO NOT** manually create files in `src/tooluniverse/tools/` — these are auto-generated wrappers. ### Implementation Pattern 1. **Inheritance**: Tool class must inherit from `BaseTool`. 2. **Registration**: Use `@register_tool` decorator with the class name. ```python from typing import Dict, Any from .base_tool import BaseTool from .tool_registry import register_tool @register_tool("MyNewTool") class MyNewTool(BaseTool): """My new tool description.""" def run(self, arguments: Dict[str, Any]) -> Dict[str, Any]: return {"result": "success"} ``` 3. **Configuration**: Use external JSON file (do NOT embed large configs in the decorator). ```json [ { "name": "my_new_tool", "type": "MyNewTool", "description": "Convert text to uppercase", "parameter": { "type": "object", "properties": { "input": { "type": "string", "description": "Text to convert" } }, "required": ["input"] }, "return_schema": { "type": "object", "properties": { "result": { "type": "string", "description": "The converted text" } } }, "test_examples": [ { "input": "hello" } ] } ] ``` ### JSON Configuration Conventions - The `"type"` field must match the Python class name registered with `@register_tool` - Include `return_schema` to define tool output structure - Put example inputs in `test_examples` (and optionally short examples in `description`) - **Avoid** adding JSON Schema `examples` blocks inside `parameter`/`return_schema` — they bloat configs and drift from reality - For large allow-lists, prefer listing values in the tool `description` and enforcing in Python at runtime (instead of a huge schema `enum`) ### Auto-Discovery Modern ToolUniverse uses automated discovery. You generally **do not** need to modify `src/tooluniverse/__init__.py` if you place your file correctly in `src/tooluniverse/`. ### Tool Naming Guidelines - **Recommended**: ≤ 55 characters (fits in MCP with `mcp__tu__` prefix) - **Maximum**: 64 characters (MCP hard limit without prefix) - **Automatic shortening**: Long names are automatically shortened for MCP exposure - **Best practice**: `FDA_get_drug_info` not `FDA_get_detailed_information_about_drug` If your tool name exceeds 55 characters, it will be automatically shortened when exposed via MCP. See `docs/mcp_name_shortening.md` for details. ### Development Checklist 1. [ ] Create `src/tooluniverse/xxx_tool.py` with `@register_tool` 2. [ ] Create `src/tooluniverse/data/xxx_tools.json` including `return_schema` 3. [ ] Ensure tool names are ≤ 55 characters 4. [ ] Implement `run(arguments)` method 5. [ ] Implement `validate_parameters` (optional but recommended) 6. [ ] Write unit tests in `tests/unit/` 7. [ ] Verify tool load with `tu.load_tools()` 8. [ ] Run `python scripts/check_tool_name_lengths.py --test-shortening` to validate 9. [ ] Run `python scripts/test_new_tools.py your_tool -v` (MANDATORY) --- ## Tool Improvement and Maintenance Checklist Systematic approach to improving and maintaining existing tools. ### Phase 1: Initial Assessment #### Step 1.1: Identify Tool Files - [ ] Locate tool class file: `src/tooluniverse/{category}_tool.py` - [ ] Locate JSON config file: `src/tooluniverse/data/{category}_tools.json` - [ ] List all tool function files: `src/tooluniverse/tools/{category}_*.py` (auto-generated wrappers) - [ ] Check `default_config.py` for category registration - [ ] Check `tools/__init__.py` for imports (auto-generated) #### Step 1.2: Verify Basic Structure - [ ] Tool class registration exists (`@register_tool`) - [ ] Class name matches JSON config `"type"` field - [ ] JSON file is valid - [ ] Tool loads without errors - [ ] Python syntax is valid ### Phase 2: Functionality Testing #### Step 2.1: Test Tool Execution - [ ] Load tools and test each tool with sample arguments - [ ] Verify results contain data (not empty) - [ ] Check response structure matches return_schema - [ ] Test error handling with invalid inputs #### Step 2.2: Test API Endpoints Directly - [ ] Test REST/GraphQL endpoints respond correctly - [ ] Verify status codes are 200 OK (not 404/502/503) - [ ] Check response format matches tool expectations ### Phase 3: Description Improvement #### Step 3.1: Review Tool Descriptions - [ ] Description includes: purpose, input, output, use cases - [ ] Description is clear to users unfamiliar with API - [ ] Add usage guidance and example inputs (prefer `test_examples`; optionally include short examples in `description`, not in JSON Schema) #### Step 3.2: Review Parameter Descriptions For each parameter: - [ ] Has clear description (include example values in the description text if helpful) - [ ] Has default value if optional - [ ] Has constraints (min/max/enum) if applicable - [ ] Type is correct #### Step 3.3: Review Return Schema - [ ] `return_schema` field exists - [ ] Schema matches actual tool output (test live responses; do not rely on docs alone) - [ ] Schema is **meaningful** (avoid `data: { additionalProperties: true }` as the only definition) - [ ] Model the common response shapes explicitly: - [ ] Paginated lists: `count`, `next`, `previous`, `results[]` - [ ] Detail objects: required identifiers + key domain fields - [ ] For nested structures, type the important subfields but allow extra fields with `additionalProperties: true` - [ ] Handle real-world type variability (e.g., values sometimes returned as string vs number): use union types like `["string","number","null"]` - [ ] If the tool wraps upstream responses (e.g., adds `status`, `url`, `error`), ensure `return_schema` reflects the wrapper shape consistently ### Phase 4: Error Handling Improvement #### Step 4.1: Review Current Error Handling - [ ] Test error messages with invalid inputs - [ ] Test HTTP error handling (404, 502, 503) - [ ] Verify try/except blocks exist - [ ] Errors return dict with "error" key #### Step 4.2: Improve Error Messages - [ ] Error messages are specific (not generic) - [ ] Errors suggest actionable solutions - [ ] Errors include context (status_code, endpoint) - [ ] Errors are user-friendly - [ ] If introducing a standardized error envelope, apply it consistently within that tool family #### Step 4.3: Add Retry Logic (if needed) - [ ] Identify transient failures (ConnectionError, Timeout) - [ ] Implement retry with exponential backoff - [ ] Set max retries (typically 2-3) - [ ] Handle final failure appropriately - [ ] Prefer using a shared retry helper if one exists in the codebase ### Phase 5: Finding Missing Tools #### Step 5.1: Research API Capabilities - [ ] **Read API Docs**: Check official documentation for all endpoints/operations - [ ] **GraphQL Introspection**: Use schema introspection to find all queries - [ ] **Test Endpoints**: Try different endpoint patterns - [ ] **Check Related Packages**: Look at R/Bioconductor or Python packages - [ ] **Web Search**: Search for "{API_NAME} API documentation" #### Step 5.2: Create Gap Analysis Matrix - [ ] List current tools from JSON config - [ ] List all API capabilities - [ ] Create comparison table (implemented vs available) - [ ] Prioritize missing tools (HIGH/MEDIUM/LOW) - [ ] Document findings #### Step 5.3: Identify Subset Extraction Opportunities - [ ] **Check Data Size**: If full response is large/complex - [ ] **Identify Subsets**: Common fields users need (diseases, pathways, etc.) - [ ] **Add Subset Tools**: Create tools that extract specific data types - [ ] **Implement Method**: Create `_extract_subset()` helper if needed - [ ] **Add field selection / projection** when supported upstream - [ ] If projection fields are many: document the allowed values in `description` and enforce in code (avoid giant schema enums) ### Phase 6: Fix Common Issues #### Issue 6.1: Tool Class Name Mismatch - Check: Python class name matches `@register_tool("ClassName")` - Check: JSON config `"type"` field matches class name exactly - Fix: Ensure exact match (case-sensitive) #### Issue 6.2: Response Format Mismatch - Check: Test API response format directly (list vs dict) - Fix: Check API response format and convert if needed #### Issue 6.3: Endpoint URL Issues - Check: Test endpoint directly, verify URL pattern in API documentation - Fix: Verify URL building logic and placeholder replacement #### Issue 6.4: Missing Error Handling - Check: Test with invalid inputs and network failures - Fix: Add try/except blocks with specific error handling ### Phase 7: Final Verification #### Step 7.1: Comprehensive Testing - [ ] Test all tools with valid inputs - [ ] Test error cases with invalid inputs - [ ] Test edge cases (empty results, null values) - [ ] Verify results contain meaningful data - [ ] Check performance is reasonable #### Step 7.2: Validation Checks - [ ] JSON files are valid - [ ] Python syntax is valid - [ ] No linting errors - [ ] All tools load without errors - [ ] Tool functions imported in `tools/__init__.py` (auto-generated, verify they exist) - [ ] Category registered in `default_config.py` ```bash python3 -m json.tool src/tooluniverse/data/{category}_tools.json python3 -m py_compile src/tooluniverse/{category}_tool.py ``` #### Step 7.3: Documentation - [ ] Tool descriptions are clear and complete - [ ] Parameter descriptions include examples - [ ] Return schemas match actual output - [ ] Create example script in `examples/` - [ ] Document findings and fixes ### Guidance for Large API Expansions When covering many endpoints in one category: - [ ] Use a generic REST tool + JSON configs to cover multiple endpoints - [ ] Verify real API behavior with live requests (prefer working patterns over docs) - [ ] Make `return_schema` match the tool's wrapper and validate upstream payload structure at a useful depth - [ ] Use real IDs from search/list endpoints in `test_examples` - [ ] Remove tools for endpoints that have no working or replacement API - [ ] Design "research-first": include discovery tools (search/list), detail tools (get by ID), and version/release tools for reproducibility - [ ] Keep schemas and parameter surfaces LLM-friendly: avoid enormous enums; keep descriptions explicit; enforce strict validation in code --- ## Quick Reference: Common Commands ### Validation ```bash python3 -m json.tool src/tooluniverse/data/{category}_tools.json python3 -m py_compile src/tooluniverse/{category}_tool.py ``` ### Testing ```bash python3 examples/{category}_tools_example.py python scripts/test_new_tools.py {tool_name} -v ``` ### Finding Tools ```bash ls src/tooluniverse/tools/{category}_*.py grep -c "\"name\":" src/tooluniverse/data/{category}_tools.json grep "@register_tool" src/tooluniverse/{category}_tool.py ```