> ## 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.

# Tool class

> The Tool object (schema, invocation, and lifecycle).

`Tool` represents a single callable an agent can invoke: a connector operation, an OpenAPI endpoint, an MCP tool, or a local Python function registered with `@register_tool`. You normally get one from `agent.tools.list` or `agent.tools.get_tool_by_id(...)`.

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

print(tool.id, tool.name, tool.description)
print(tool.parameters)        # raw JSON schema
print(tool.schema)            # Pydantic model class generated from parameters
```

## Attributes

| Attribute             | Type                           | Description                                                                     |
| --------------------- | ------------------------------ | ------------------------------------------------------------------------------- |
| `id`                  | `str`                          | Tool identifier (used as the function name when invoked by the LLM).            |
| `name`                | `str`                          | Display name.                                                                   |
| `method`              | `str`                          | HTTP method for remote invocation (`"POST"`, `"GET"`, …).                       |
| `path`                | `str`                          | Endpoint path.                                                                  |
| `description`         | `str`                          | Human-readable description (used by the LLM to decide when to call).            |
| `parameters`          | `dict`                         | JSON schema for the input payload.                                              |
| `is_local`            | `bool`                         | `True` when the tool is a `@register_tool` Python function.                     |
| `is_synced`           | `bool`                         | For local tools: `True` after the tool has been pushed to the platform's graph. |
| `is_standalone`       | `bool`                         | `True` when loaded via `aload_tool_by_id` (no agent context).                   |
| `should_add_to_graph` | `bool`                         | Whether this tool should be added to agent execution graphs.                    |
| `connector_id`        | `str \| None`                  | For platform tools: the connector id.                                           |
| `operation_id`        | `str \| None`                  | For platform tools: the operation id.                                           |
| `schema_overrides`    | `AgentGraphItemSchema \| None` | Per-agent input/output schema overrides.                                        |
| `fn`                  | `Callable \| None`             | The Python function for local tools. Excluded from serialization.               |
| `configuration`       | `Configuration`                | SDK configuration.                                                              |

## Computed properties

### `schema`

```python theme={"dark"}
tool.schema -> type[BaseModel]
```

A dynamically-generated Pydantic model class derived from `tool.parameters`. The model's name is `{ToolIdPascalCase}PayloadSchema`. If the agent has schema overrides for this tool, they're applied here.

```python theme={"dark"}
WeatherSchema = tool.schema
WeatherSchema(city="NYC")          # validates input
```

### `payload_schema`

```python theme={"dark"}
tool.payload_schema -> type[BaseModel]
```

A wrapper schema with a single `payload` field whose type is `tool.schema`. Useful when a framework expects every tool call to be wrapped in `{"payload": {...}}`.

```python theme={"dark"}
PayloadModel = tool.payload_schema
PayloadModel(payload={"city": "NYC"})
```

## Methods

### `ainvoke` / `invoke`

Invoke the tool. Validates the payload against `tool.schema`, executes locally (`is_local=True`) or remotely, and returns a `ToolInvocationResult`.

```python theme={"dark"}
result = await tool.ainvoke(
    agent_id="agent-123",
    payload={"city": "Tokyo"},
)
print(result.result, result.is_success)
```

| Parameter           | Type            | Required | Default       | Description                                                                                                                                                            |
| ------------------- | --------------- | -------- | ------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `agent_id`          | `str`           | Yes      | –             | Agent invoking the tool.                                                                                                                                               |
| `payload`           | `Any`           | Yes      | –             | Tool input. Validated against `tool.schema`.                                                                                                                           |
| `agent_version`     | `str`           | No       | `None`        | Pin to a specific agent version.                                                                                                                                       |
| `payload_extension` | `dict`          | No       | `{}`          | Extra fields deep-merged into the payload (headers, auth, etc.).                                                                                                       |
| `configuration`     | `Configuration` | No       | Tool's config | Override SDK configuration.                                                                                                                                            |
| `task_id`           | `str`           | No       | `None`        | Associate with a task (for activity logging).                                                                                                                          |
| `tool_call_id`      | `str`           | No       | `None`        | Correlation id matching the LLM's tool-call id.                                                                                                                        |
| `report_activity`   | `bool`          | No       | `False`       | Push `ToolCallRequest` / `ToolCallResult` events to the task activity log. Set this when invoking outside the framework's tool hook (so events aren't double-emitted). |

Returns a `ToolInvocationResult` (see below). Sync sibling: `tool.invoke(...)`.

`ainvoke` runs the configured [tool lifecycle hooks](/developers/sdk-reference/decorators/on-tool) (`@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-tool fallback or hook execution. Used internally by `ainvoke` when `is_local=False`. Use directly only for advanced cases (preflight checks, custom invocation pipelines).

```python theme={"dark"}
result = await tool.acall_remote_tool(
    agent_id="agent-123",
    payload={"city": "Tokyo"},
)
```

### `agraph_preflight_check` / `graph_preflight_check`

Asks the platform to validate a hypothetical tool invocation without executing it. Used internally for graph routing.

### `get_invocation_function`

```python theme={"dark"}
tool.get_invocation_function(
    is_async: bool = False,
    configuration: Optional[Configuration] = None,
) -> Callable
```

Factory that returns a pre-configured invocation function bound to this tool's connector + configuration. Use for standalone invocation (no agent context):

```python theme={"dark"}
invoke = tool.get_invocation_function(is_async=True)
result = await invoke({"city": "NYC"})   # ToolInvocationResult
```

This skips agent-id and task-id binding: the underlying call hits the connector via `connector_id_operation_id` and returns the raw response wrapped in `ToolInvocationResult`. Use it after `ToolsRepository.aload_tool_by_id(...)` to call a single connector without an agent.

## `ToolInvocationResult`

The shape returned by `ainvoke` and the standalone invocation function.

| Field          | Type          | Description                    |
| -------------- | ------------- | ------------------------------ |
| `tool_id`      | `str`         | The tool's id.                 |
| `tool_call_id` | `str \| None` | The correlation id, if passed. |
| `task_id`      | `str \| None` | The task id, if passed.        |
| `payload`      | `Any`         | The payload that was sent.     |
| `status_code`  | `int`         | HTTP status (200 by default).  |
| `result`       | `Any`         | The tool's response.           |
| `is_success`   | `bool`        | `True` on 2xx.                 |
| `is_error`     | `bool`        | `True` on failure.             |
| `is_local`     | `bool`        | `True` for local tools.        |

`is_success` and `is_error` are mutually exclusive in normal operation: check `is_error` first to branch on failure cases.

## Examples

### Inspect tool schema

```python theme={"dark"}
tool = agent.tools.get_tool_by_id("get_weather")

# Pydantic schema (from parameters)
schema = tool.schema
print(schema.model_json_schema())

# Validate a payload before sending
schema.model_validate({"city": "NYC"})   # raises ValidationError on bad shape
```

### Per-call configuration override

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

custom_config = Configuration(api_key="other-key", organization_id="other-org")

result = await tool.ainvoke(
    agent_id="agent-123",
    payload={"city": "Berlin"},
    configuration=custom_config,
)
```

### Reporting activity for non-Agno callers

When invoking a tool outside an Agno-driven flow (e.g. from your own agent loop), set `report_activity=True` so the call shows up in the task's activity log:

```python theme={"dark"}
result = await tool.ainvoke(
    agent_id="agent-123",
    task_id=task.id,
    payload={...},
    report_activity=True,
)
```

Inside Agno-driven flows, leave it at `False`: the Agno hook reports the call automatically and you'd otherwise double-emit events.
