ToolsRepository is the registry that holds every skill an agent can call. In the SDK a skill is a Tool; agent.tools lists them. There are two kinds:
- Backend skills: catalog skills and OpenAPI imports configured in Xpander Chat. Loaded automatically when you
agents.aget(...)an agent. - Local skills: Python functions you decorate with
@register_tool. Registered in-process and merged into the agent’s skill list.
ToolsRepository yourself. agent.tools returns the configured instance for that agent.
Class layout
Constructor
In practice,
agents.aget(...) constructs a ToolsRepository for you with all four arguments populated.
Properties
list
id). Each Tool has its Configuration set and any agent-graph schema overrides applied.
functions
.list. Each callable accepts a single payload argument validated against the skill’s auto-generated Pydantic schema. The callable’s __name__ is the skill id and its __doc__ includes a usage example.
This is what Backend.aget_args injects into your agent loop’s tools=... parameter: you rarely need it directly. Useful when binding skills to an agent loop the SDK has no integration for.
Methods
get_tool_by_id
Tool with the matching id, or None.
get_tool_by_name
Tool with the matching name (display name), or None.
register_tool (classmethod)
Tool to the global local registry. Used by the @register_tool decorator: you don’t usually call this directly.
should_sync_local_tools
True when at least one local skill is marked should_add_to_graph=True and hasn’t been synced yet.
get_local_tools_for_sync
agent.aload).
aload_tool_by_id
<connector_id>_<operation_id> form and seeds it into the repository. Useful when you want to invoke a single skill without loading an agent.
The id is the skill’s connector_id UUID and the operation’s catalog id joined by a single underscore, for example "07687ac7-d474-4d24-8ec6-6debac476b00_6a581606eaade0ae8b8f2c9c". Both halves come from List Skill Operations.
The sync sibling is load_tool_by_id.
Patterns
Iterate every skill
Bind skills to an agent loop by hand
Standalone invocation (no agent context)
@register_tool
@register_tool turns a Python function into a skill the agent can invoke. The SDK extracts type hints and the docstring to build a schema and description automatically: there’s no manual schema writing.
calculate_sum is available to every Agents().aget(...) call as a local skill with id "calculate_sum".
Decorator forms
What it does
- Inspects the function’s parameters and type hints.
- Builds a Pydantic model (
<FunctionName>Args) from the parameters: required if no default, optional otherwise. - Constructs a
Toolwith:id= function namename= function namedescription= function docstringparameters= generated JSON schemafn= the functionis_local = Trueshould_add_to_graph = add_to_graph
- Registers the
ToolinToolsRepository’s class-level_local_toolslist (process-wide singleton). - Returns the original function unchanged:
calculate_sum(2, 3)still works as plain Python.
Examples
Async functions are supported
Optional parameters
Push to the agent graph
add_to_graph=True registers the skill on the agent in Xpander Chat for the next agents.aget(...): the SDK sync runs in the background after aget returns.
Use the function directly
Visibility rules
The decorator registers skills at module-import time on a process-wide registry. That means:- Every agent loaded by
Agents().aget(...)in this process inherits the local skills. - Skills defined inside a function body register the first time the function runs, but stay registered for the rest of the process’s lifetime.
- If you
delor rename a function after decoration, the registeredToolkeeps its captured reference (thefnattribute): it doesn’t unregister itself.
Backend.aget_args(tools=[fn]) instead: that adds callables to one specific aget_args call without polluting the global registry.
Schema details
The generated schema uses Pydantic’smodel_json_schema(mode="serialization"). Parameter names, types, and defaults map directly:
Related
Toolclass: what the decorator creates.@on_tool_before/@on_tool_after/@on_tool_error: lifecycle hooks around any skill invocation.
Tool class
Tool represents a single skill an agent can invoke: a catalog skill operation, an OpenAPI endpoint, a skill served over MCP, or a local Python function registered with @register_tool. You normally get one from agent.tools.list or agent.tools.get_tool_by_id(...).
Attributes
Computed properties
schema
tool.parameters. The model’s name is {ToolIdPascalCase}PayloadSchema. If the agent has schema overrides for this skill, they’re applied here.
payload_schema
payload field whose type is tool.schema. Useful when an agent loop expects every skill call to be wrapped in {"payload": {...}}.
Methods
ainvoke / invoke
Invoke the skill. Validates the payload against tool.schema, executes locally (is_local=True) or remotely, and returns a ToolInvocationResult.
Returns a
ToolInvocationResult (see below). Sync sibling: tool.invoke(...).
ainvoke runs the configured skill call lifecycle hooks (@on_tool_before / @on_tool_after / @on_tool_error) around the call.
acall_remote_tool / call_remote_tool
Lower-level: makes the API call without local-skill fallback or hook execution. Used internally by ainvoke when is_local=False. Use directly only for advanced cases (preflight checks, custom invocation pipelines).
agraph_preflight_check / graph_preflight_check
Asks the runtime to validate a hypothetical skill invocation without executing it. Used internally for graph routing.
get_invocation_function
connector_id + configuration. Use for standalone invocation (no agent context):
connector_id_operation_id and returns the raw response wrapped in ToolInvocationResult. Use it after ToolsRepository.aload_tool_by_id(...) to call a single skill without an agent.
ToolInvocationResult
The shape returned by ainvoke and the standalone invocation function.
is_success and is_error are mutually exclusive in normal operation: check is_error first to branch on failure cases.
Examples
Inspect a skill’s schema
Per-call configuration override
Reporting activity for non-Agno callers
When invoking a skill outside an Agno-driven flow (e.g. from your own agent loop), setreport_activity=True so the call shows up in the task’s activity log:
False: the Agno hook reports the call automatically and you’d otherwise double-emit events.
MCP types
The Model Context Protocol (MCP) lets agents connect to skills served over MCP. The SDK exposesMCPServerDetails for declaring MCP endpoints per task, and a few enums for the supported transports and auth types.
Agent.acreate_task(mcp_servers=[...]) to attach MCP endpoints for a single run without registering them in Xpander Chat; endpoints already registered there are added automatically.
MCPServerDetails
Enums
MCPServerType
MCPServerTransport
MCPServerAuthType
Examples
Local server (stdio)
Remote with API key
Remote with OAuth2
auth_events during a run when end-user authorization is required. Register an @on_auth_event handler to route the OAuth URL to your UI.
Per-task server attachment
Limit which skills are exposed
search_repositories and get_issue will be exposed to the agent: every other skill the MCP endpoint offers is hidden.
OAuth response types (for @on_auth_event payloads)
When OAuth flows fire, event.data is shaped like one of these:
MCPOAuthResponseType values: not_supported, login_required, token_issue, token_ready.
Use these in your auth handler to display the right state to the end user (login URL vs. “we’re working on it” vs. success).
