Toolbox and Tools
Elemental provides an interface for defining tools that agents may use to perform actions against external systems. Tools are standalone functions that are wrapped in the common interface that makes them exposed are executable through a common interface. This mechanism of detecting the tools and making them available to agents is done through a ToolBox
object in Elemental.
Tool
Tools are defined in Elemental in toolbox
module. This module includes both the definition of Tool
and ToolBox
where the later is used to discover and run tools that agent can use.
Tools use following interface which includes four classes ToolParameters
, ToolInitParameters
, ToolResult
, and Tool
. The interface defines them as:
class ToolParameters(BaseModel):
class ToolInitParameters(BaseModel):
class ToolResult(BaseModel):
class Tool(ABC):
name: str = None
description: str = None
example: str = None
def __init__(
self,
init_params: Optional[ToolInitParameters] \
= None
) -> None:
self._init_params = init_params
Tools are defined as classes that inherit from the Tool
class. The Tool
class is an abstract base class that defines the interface for all tools. The Tool
class has three main components:
Tools are defined as classes that inherit from the Tool
class. The Tool
class is an abstract base class that defines the interface for all tools. The Tool
class has three main components:
ToolParameters
: This class is used to define the input parameters required by the tool. The input parameters are defined as a Pydantic model.ToolResult
: This class is used to define the output parameters returned by the tool. The output parameters are defined as a Pydantic model.Tool
: This class is the abstract base class for all tools. TheTool
class defines the interface for all tools and provides therun
method that is used to execute the tool.
The Tool
class has the following attributes:
name
: The name of the tool. This attribute is used to identify the tool in the toolbox.description
: The description of the tool. This attribute is used to provide a description of the tool in the toolbox.example
: The example of how to use the tool. This attribute is used to provide an example of how to use the tool in the toolbox.
The Tool
class has the following methods:
run
: The abstract method that is used to execute the tool. This method is used to run the tool with the specified parameters. The parameters are provided as a Pydantic model.@abstractmethod def run( self, parameters: ToolParameters ) -> ToolResult
get_name
: This method returns the name of the tool.@classmethod def get_name(cls) -> str
get_description
: This method returns the description of the tool.@classmethod def get_description(cls) -> str
get_example
: This method returns an example of how to use the tool.@classmethod def get_example(cls) -> str
Toolbox details
Tools are registered in the ToolBox
class. The ToolBox
class is responsible for managing the tools and providing an interface for the agent to use the tools.
ToolBox
is initialized as
def __init__(self) -> None:
self._tool_registry: Dict[str, Tuple[BaseModel, BaseModel, BaseModel]] = {}
self._mcp_client_registry: Dict[str, MCPClientToolbox] = {}
self._mcp_tool_registry: Dict[str, MCPTool] = {}
The ToolBox
class is initialized with an empty dictionary that will be used to store the tools. The dictionary is used to register the tools in the toolbox. The keys of the dictionary are the names of the tools and the values are tuples that contain the class of the tool, the class of the parameters and the class of the initialization parameters. The initialization parameters are optional and are used to initialize the tool before it is executed.
The ToolBox
class includes the following methods:
register_tool
- Register a tool in the toolbox. The tool is registered with the name and the class of the tool. The class of the tool is used to create an instance of the tool.def register_tool( self, tool_name: str, tool_class: BaseModel, param_model_class: BaseModel, init_model_class: Optional[BaseModel] = None, ) -> None
call_tool
- Call a tool with the specified parameters. The parameters are provided as a JSON string. Thecall_tool
method returns the result of the tool execution.def call_tool(self, tool_name: str, parameters_json: str ) -> ToolResult | MCPToolResult
describe
- Describe the tools in the toolbox. Thedescribe
method returns a dictionary with the name, description, arguments and example of use for the tools.def describe(self) -> Dict[str, str]
describe_short
- Describe the tools in the toolbox. Thedescribe_short
method returns a short version of the description as string with only tool name and their description.def describe_short(self) -> str
discover_tools
- Discover tools from multiple locations in the system and return a dictionary of tools. This method does not register the tool in the agents toolbox, it only returns the list of tools that are available in the system. Outside of the default module location, this method will check paths defined in two environmental variables i.e.ATTO_SYSTEM_TOOLS_DIR
andATTO_USER_TOOLS_DIR
. This allows to register tools from multiple locations without the need to modify the original code.def discover_tools(self) -> Dict[str, Tuple]
load_classes_from_file
- Load classes from Python files in a directory and return a dictionary of tools. This method is used to load tools from a directory. The directory should contain Python files with the tool classes.def load_classes_from_files( self, directory: Path ) -> Dict[str, tuple]
register_tool_by_name
- Register a tool by name. The tool is registered with the name and the class of the tool. This method will register the tool given only by its name in the toolbox.def register_tool_by_name( self, tool_name: str ) -> None
call_mcp_tool
- Call an MCP tool by name with the specified parameters provided as a JSON string. This function is used from within thecall_tool
method if the tools is provided by MCP server.def call_mcp_tool( self, tool_name: str, parameters_json: str ) -> ToolResult | MCPToolResult
register_mcp_tool_by_name
- Register an MCP tool by using MCP server. This method is called from theregister_tool_by_name
if the tool name is definedMCP|ServerName|ToolName
. This method sets the MCP server and registers the tool within the toolbox.def register_mcp_tool_by_name( self, tool_name: str ) -> None
ToolBox Example
box = ToolBox()
box.register_tool_by_name("PythonRunner")
box.register_tool_by_name("Calculator")
description = box.describe()
CALCULATOR_JSON = '{"expression": "2 + 3 * 4"}'
final_result = box.call_tool("Calculator", CALCULATOR_JSON)
In the example above, we show how to register tools in the toolbox and how to call them. The ToolBox
class is used to manage the tools and to provide an interface for the agent to use the tools.
Model Context Protocol Tools
Model Context Protocol Servers are external applications executed on your device. Be cautious about the selection of MCP servers and verify their origin. Using not verified servers may bride the security of your agents or your device.
Elemental provides an interface to bring tools provided by Model Context Protocol (MCP) server. The tools are registered in the toolbox and can be used by the agent. The tools are brought to the ToolBox
object with the same interface, however, definition of MCP servers must be present in the environment.
The MCP servers can be defined in the .env
file in the mcpServers
variable. Using Github MCP server as an example, the mcpServers
entry could be
mcpServers='{"Github": {"command": "npx", "args": ["-y","@modelcontextprotocol/server-github"], "env": {"GITHUB_PERSONAL_ACCESS_TOKEN": "<YOUR_TOKEN>"}}}'
The mcpServers
variable should be a JSON string with name of the server as a key and three variables command
, args
, and env
present for the key. More than one server may be defined.
The MCP tools in Elemental require following particular naming convention to bring them together with native tools. The name of the tool must be MCP|server_name|tool_name
, where MCP
indicates that the tool needs to come from an MCP server, server_name
will indicate the correct entry in the mcpServers
definition to use for this server, tool_name
is the name of the individual tool in the given server.
Example below illustrates how to bring MCP defined tools together with native tools
box = ToolBox()
box.register_tool_by_name("PythonRunner")
box.register_tool_by_name("Calculator")
box.register_tool_by_name("MCP|Github|list_issues")
box.register_tool_by_name("MCP|Github|search_repositories")
description = box.describe()
If you want to include all tools provided by a given MCP server, you may use MCP|server_name|*
instead of listing individual tools. The above toolbox specification would change to:
box = ToolBox()
box.register_tool_by_name("PythonRunner")
box.register_tool_by_name("Calculator")
box.register_tool_by_name("MCP|Github|*")
description = box.describe()
Tools are included in the description and called using the same mechanism as the native tools and may be used with any language model.