· 4 Min read

Building Custom Tools and Events in Your Network Workspace

One of the most powerful features of OpenAgents is the ability to extend your network with custom tools and events without writing any infrastructure code. Simply drop Python files in the tools/ folder or AsyncAPI definitions in the events/ folder, and they're automatically discovered and exposed via MCP.

This guide walks you through creating custom tools and events from scratch.

The Workspace Folder Structure

Every OpenAgents network has a workspace folder that contains your configuration, tools, events, and other resources:

my_network/
├── network.yaml           # Network configuration
├── tools/                 # Custom Python tools
│   ├── calculator.py
│   ├── file_operations.py
│   └── search.py
├── events/                # AsyncAPI event definitions
│   ├── task_events.yaml
│   └── notifications.yaml
└── data/                  # Optional data directory

When the network starts, OpenAgents automatically:

  1. Scans tools/*.py for functions decorated with @tool
  2. Scans events/*.yaml for AsyncAPI operations with x-agent-tool extension
  3. Merges these with any mod-provided tools
  4. Exposes everything via the MCP transport

Creating Custom Tools

Step 1: Create the Tools Folder

mkdir -p my_network/tools

Step 2: Write Your First Tool

Create a Python file with one or more functions decorated with @tool:

# my_network/tools/calculator.py
from openagents.core.tool_decorator import tool
 
@tool
async def add(a: float, b: float) -> float:
    """Add two numbers together.
 
    Args:
        a: First number
        b: Second number
 
    Returns:
        The sum of a and b
    """
    return a + b
 
@tool
async def multiply(a: float, b: float) -> float:
    """Multiply two numbers.
 
    Args:
        a: First number
        b: Second number
 
    Returns:
        The product of a and b
    """
    return a * b

Step 3: Customize Tool Names and Descriptions

Use decorator parameters to override defaults:

# my_network/tools/search.py
from openagents.core.tool_decorator import tool
 
@tool(
    name="web_search",
    description="Search the internet for information on any topic"
)
async def search(query: str, max_results: int = 10) -> str:
    """Internal implementation - decorator overrides this docstring."""
    # Your search implementation
    return f"Found {max_results} results for: {query}"

Type Hints and Schema Generation

The @tool decorator automatically generates JSON Schema from your type hints:

from typing import List, Optional, Dict
from openagents.core.tool_decorator import tool
 
@tool
async def create_task(
    title: str,                          # Required string
    priority: int = 1,                   # Optional integer with default
    tags: Optional[List[str]] = None,    # Optional array of strings
    metadata: Optional[Dict] = None      # Optional object
) -> dict:
    """Create a new task with the given parameters."""
    return {
        "title": title,
        "priority": priority,
        "tags": tags or [],
        "metadata": metadata or {}
    }

Creating Custom Events

Custom events let external agents trigger internal workflows. Events are defined using AsyncAPI 3.0 format with the x-agent-tool extension.

Define Your Events

Create an AsyncAPI 3.0 YAML file:

# my_network/events/task_events.yaml
asyncapi: '3.0.0'
info:
  title: Task Management Events
  version: '1.0.0'
 
operations:
  delegateTask:
    action: send
    channel:
      $ref: '#/channels/task~1delegate'
    summary: Delegate a task to a worker agent
    x-agent-tool:
      enabled: true
      name: delegate_task
      description: "Delegate a task to a specific agent for execution"

Understanding x-agent-tool

The x-agent-tool extension controls which operations become MCP tools:

FieldTypeRequiredDescription
enabledbooleanYesSet to true to expose as tool
namestringNoTool name (defaults to operation ID)
descriptionstringNoTool description (defaults to summary)

Best Practices

Tool Design

  1. Clear names: Use descriptive, action-oriented names (search_documents, not docs)
  2. Comprehensive docstrings: Include Args, Returns, and Raises sections
  3. Type hints everywhere: Enable automatic schema generation
  4. Proper error handling: Raise meaningful exceptions with clear messages
  5. Async for I/O: Use async functions for network/file operations

Event Design

  1. Meaningful channel addresses: Use hierarchical naming (task.delegate, user.created)
  2. Complete schemas: Define all properties with types and descriptions
  3. Required vs optional: Mark essential fields as required
  4. Enums for controlled values: Use enums for status fields and types

Troubleshooting

Tools Not Discovered

  • Check the file is in {workspace}/tools/ (not nested)
  • Ensure file doesn't start with _ (e.g., __init__.py is skipped)
  • Verify @tool decorator is imported from openagents.core.tool_decorator
  • Check for Python syntax errors in the file

Events Not Exposed

  • Verify asyncapi: '3.0.0' version
  • Check x-agent-tool.enabled: true is set
  • Ensure operation has a valid channel reference
  • Look for YAML syntax errors

What's Next

Now that you know how to create custom tools and events, explore:

  • Tool filtering: Control which tools are visible with exposed_tools and excluded_tools
  • Authentication: Secure your MCP endpoint with bearer tokens
  • Agent groups: Assign different permissions to different agent groups
  • Network mods: Build reusable tool packages as mods

Happy building!