> ## Documentation Index
> Fetch the complete documentation index at: https://docs.xpander.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Tools Repository

> Discover, register, and invoke tools (both backend-managed and locally registered).

`ToolsRepository` is the registry that holds every tool an agent can call. There are two kinds:

* **Backend tools**: connectors and OpenAPI imports configured in the Workbench. Loaded automatically when you `agents.aget(...)` an agent.
* **Local tools**: Python functions you decorate with [`@register_tool`](/developers/sdk-reference/tools/register-tool). Registered in-process and merged into the agent's tool list.

You don't usually instantiate `ToolsRepository` directly: accessing `agent.tools` gives you the configured instance for that agent.

```python theme={"dark"}
agent = await agents.aget("agent-123")

# All tools (backend + local) merged into one list
for tool in agent.tools.list:
    print(tool.id, tool.name, tool.is_local)

# Look up by id or name
weather = agent.tools.get_tool_by_id("get_weather")
weather2 = agent.tools.get_tool_by_name("Weather")

# Framework-ready callables (used internally by Backend.aget_args)
fns = agent.tools.functions
```

## Class layout

| Type                       | Reference                                                       |
| -------------------------- | --------------------------------------------------------------- |
| `ToolsRepository`          | This page                                                       |
| `Tool`                     | [Tool class](/developers/sdk-reference/tools/tool)              |
| `@register_tool` decorator | [register\_tool](/developers/sdk-reference/tools/register-tool) |
| MCP types                  | [MCP](/developers/sdk-reference/tools/mcp)                      |
| Tool lifecycle hooks       | [`@on_tool_*`](/developers/sdk-reference/decorators/on-tool)    |

## Constructor

```python theme={"dark"}
ToolsRepository(
    configuration: Optional[Configuration] = None,
    tools: List[Tool] = [],
    agent_graph: Optional[AgentGraph] = None,
    is_async: bool = True,
)
```

| Parameter       | Type            | Default           | Description                                          |
| --------------- | --------------- | ----------------- | ---------------------------------------------------- |
| `configuration` | `Configuration` | `Configuration()` | SDK configuration.                                   |
| `tools`         | `list[Tool]`    | `[]`              | Backend-managed tools to seed the repository.        |
| `agent_graph`   | `AgentGraph`    | `None`            | Owning agent's graph (for schema overrides).         |
| `is_async`      | `bool`          | `True`            | Whether `.functions` should produce async callables. |

In practice, `agents.aget(...)` constructs a `ToolsRepository` for you with all four arguments populated.

## Properties

### `list`

```python theme={"dark"}
agent.tools.list -> list[Tool]
```

A merged list of backend tools and locally-registered tools (de-duplicated by `id`). Each tool has its `Configuration` set and any agent-graph schema overrides applied.

### `functions`

```python theme={"dark"}
agent.tools.functions -> list[Callable[..., Any]]
```

Framework-ready callables for every tool in `.list`. Each callable accepts a single `payload` argument validated against the tool's auto-generated Pydantic schema. The callable's `__name__` is the tool id and its `__doc__` includes a usage example.

This is what `Backend.aget_args` injects into your framework agent's `tools=...` parameter: you rarely need it directly. Useful when binding tools to a custom framework manually.

## Methods

### `get_tool_by_id`

```python theme={"dark"}
agent.tools.get_tool_by_id("get_weather") -> Tool | None
```

Returns the tool with the matching `id`, or `None`.

### `get_tool_by_name`

```python theme={"dark"}
agent.tools.get_tool_by_name("Weather") -> Tool | None
```

Returns the tool with the matching `name` (display name), or `None`.

### `register_tool` (classmethod)

```python theme={"dark"}
ToolsRepository.register_tool(tool: Tool)
```

Adds a tool to the global local registry. Used by the `@register_tool` decorator: you don't usually call this directly.

### `should_sync_local_tools`

```python theme={"dark"}
agent.tools.should_sync_local_tools() -> bool
```

Returns `True` when at least one local tool is marked `should_add_to_graph=True` and hasn't been synced yet.

### `get_local_tools_for_sync`

```python theme={"dark"}
agent.tools.get_local_tools_for_sync() -> list[Tool]
```

Returns local tools awaiting sync (used internally during `agent.aload`).

### `aload_tool_by_id`

```python theme={"dark"}
await agent.tools.aload_tool_by_id("connector_operation_id") -> None
```

Standalone tool loading: looks up a tool by its `connector_id_operation_id` form (e.g. `"slack_postMessage"`) and seeds it into the repository. Useful when you want to invoke a single tool without loading an agent.

The sync sibling is `load_tool_by_id`.

## Patterns

### Iterate every tool

```python theme={"dark"}
agent = await agents.aget("agent-123")

for tool in agent.tools.list:
    print(f"- {tool.id}: {tool.description[:60]}")
```

### Bind tools to a custom framework

```python theme={"dark"}
fns = agent.tools.functions   # list of callables, each accepts `payload`

# Pass directly to a framework that expects callables:
my_framework_agent = MyAgent(tools=fns)
```

### Standalone invocation (no agent context)

```python theme={"dark"}
from xpander_sdk import ToolsRepository

repo = ToolsRepository()
await repo.aload_tool_by_id("slack_post_message")
tool = repo.list[0]

invoke = tool.get_invocation_function(is_async=True)
result = await invoke({"channel": "#general", "text": "Hello"})
```

This pattern is how you call a single platform connector without going through an agent.
