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:
- Scans
tools/*.pyfor functions decorated with@tool - Scans
events/*.yamlfor AsyncAPI operations withx-agent-toolextension - Merges these with any mod-provided tools
- Exposes everything via the MCP transport
Creating Custom Tools
Step 1: Create the Tools Folder
mkdir -p my_network/toolsStep 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 * bStep 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:
| Field | Type | Required | Description |
|---|---|---|---|
enabled | boolean | Yes | Set to true to expose as tool |
name | string | No | Tool name (defaults to operation ID) |
description | string | No | Tool description (defaults to summary) |
Best Practices
Tool Design
- Clear names: Use descriptive, action-oriented names (
search_documents, notdocs) - Comprehensive docstrings: Include Args, Returns, and Raises sections
- Type hints everywhere: Enable automatic schema generation
- Proper error handling: Raise meaningful exceptions with clear messages
- Async for I/O: Use async functions for network/file operations
Event Design
- Meaningful channel addresses: Use hierarchical naming (
task.delegate,user.created) - Complete schemas: Define all properties with types and descriptions
- Required vs optional: Mark essential fields as required
- 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__.pyis skipped) - Verify
@tooldecorator is imported fromopenagents.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: trueis 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_toolsandexcluded_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!