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

# Tool Use

> Structured tool calls, executable tools, MCP Toolkits, and structured output.

<Note>
  *The model proposes. HeavenBase can execute — or just hand you the JSON and step back.*
</Note>

Tool use is where chat stops being text-only. Pass tools to `chat`, `stream`, or `LLMSession`, and HeavenBase normalizes schemas, runs executable callables, and projects the full turn through `include`.

## 1. What You Can Pass

The `tools` list accepts:

* OpenAI-compatible function schema dictionaries.
* Plain Python callables with type annotations and docstrings.
* HeavenBase `Tool` objects.
* HeavenBase `Toolkit` objects, including MCP servers imported with `Toolkit.from_fastmcp(...)`.

Schema-only tools are sent to the provider and returned as `tool_calls`. Executable tools run automatically, and their `role="tool"` result messages appear in `delta` and `messages`.

Tool execution errors serialize as structured tool-result content:

```json theme={"theme":{"light":"github-light","dark":"github-dark"}}
{"ok": false, "error": {"type": "ValueError", "message": "bad input"}}
```

<br />

## 2. Schema-Only Tools

Use schema-only tools when another process will execute the calls:

```python theme={"theme":{"light":"github-light","dark":"github-dark"}}
import heavenbase as hb

llm = hb.LLM(preset="chat")

tools = [
    {
        "type": "function",
        "function": {
            "name": "lookup_user",
            "description": "Look up a user by id",
            "parameters": {
                "type": "object",
                "properties": {"user_id": {"type": "string"}},
                "required": ["user_id"],
            },
        },
    }
]

calls = llm.chat("Find user 42", tools=tools, include="tool_calls")
```

Tool calls are collected from streaming deltas and returned in the standard OpenAI `tool_calls` shape.

<br />

## 3. Executable Tools

Use functions or Toolkits when HeavenBase should run the tools for the model:

```python theme={"theme":{"light":"github-light","dark":"github-dark"}}
import heavenbase as hb


def add(left: int, right: int) -> int:
    """Add two numbers."""
    return left + right


llm = hb.LLM(preset="chat")
result = llm.chat(
    "Use the add tool to calculate 42 + 73.",
    tools=[add],
    include=["text", "delta"],
    reduce=False,
)

print(result["text"])
print([message["role"] for message in result["delta"]])
```

When the model calls `add`, HeavenBase appends the assistant tool-call message, a tool-result message, then asks the model for the final answer. A typical `delta` looks like:

```python theme={"theme":{"light":"github-light","dark":"github-dark"}}
[
    {"role": "assistant", "tool_calls": [...]},
    {"role": "tool", "tool_call_id": "...", "name": "add", "content": "115"},
    {"role": "assistant", "content": "42 + 73 = 115."},
]
```

Control how many assistant iterations run with `max_tool_turns` (default `8` in Python, mapped from `--max-steps` in the CLI):

```python theme={"theme":{"light":"github-light","dark":"github-dark"}}
llm.chat("Plan a three-step fix.", tools=[...], max_tool_turns=12)
```

Async callables require `achat` instead of `chat`.

<br />

## 4. MCP as Toolkit

MCP servers become normal tools by importing them as a HeavenBase Toolkit:

```python theme={"theme":{"light":"github-light","dark":"github-dark"}}
import heavenbase as hb

workspace = hb.HeavenBase("demo", backends={"main": {"type": "inmem"}})
server_toolkit = workspace.to_mcp(name="demo-heavenbase")
mcp_tools = hb.Toolkit.from_fastmcp(server_toolkit.to_fastmcp())

answer = hb.LLM(preset="chat").chat(
    "List entities in the workspace.",
    tools=[mcp_tools],
)
```

The same pattern works with HTTP/SSE MCP URLs accepted by FastMCP clients.

The CLI exposes the same execution path:

```bash theme={"theme":{"light":"github-light","dark":"github-dark"}}
hb llm chat --mcp quickstart.math-tools:-1 "Use the math tools for 42 * 73."
hb llm chat --mcp quickstart.math-tools:-1 --max-steps 20 "Use the math tools for 42 * 73."
hb llm session --mcp http://127.0.0.1:7001/mcp
```

Inside a session, add another MCP source with `/mcp SOURCE`. `hb llm chat --max-steps` caps assistant iterations in a tool loop; the default is 20.

<br />

## 5. Structured Output

Pass OpenAI-compatible `response_format` arguments directly:

```python theme={"theme":{"light":"github-light","dark":"github-dark"}}
import heavenbase as hb

llm = hb.LLM(preset="chat")

data = llm.chat(
    "Return JSON with keys name and score.",
    response_format={"type": "json_object"},
    include="structured",
)
```

Most providers stream structured output through the normal path. When a model is known to be unreliable for streaming structured JSON, its model defaults can set `structured_stream: false`.

Force a non-streaming structured call when you need a single reliable payload:

```python theme={"theme":{"light":"github-light","dark":"github-dark"}}
data = llm.chat(
    "Return JSON with key ok=true.",
    response_format={"type": "json_object"},
    include="structured",
    enforce_non_stream_structured=True,
)
```

For `stream(..., enforce_non_stream_structured=True)`, HeavenBase performs one non-streaming request and yields a single projected chunk.

<br />

## 6. Tool-Call Repair

Some providers return malformed JSON in `tool_calls[].function.arguments`. HeavenBase can repair common mistakes — fenced code blocks, unbalanced braces, missing required fields — before execution.

Repair is off by default. Enable it globally:

```bash theme={"theme":{"light":"github-light","dark":"github-dark"}}
hb cfg set heavenbase.llm.tool_call_repair.enabled true
```

Or per instance:

```python theme={"theme":{"light":"github-light","dark":"github-dark"}}
llm = hb.LLM(preset="chat", tool_call_repair={"enabled": True})
result = llm.chat("Use the tool.", tools=[add], repair_tool_calls=True)
```

Set `strict: true` in config to raise when repair fails instead of returning the original arguments. See [Advanced LLM](/features/llm/advanced) for repair behavior details.

<br />

## Further Exploration

<Tip>
  **Related resources:**

  * [Sessions](/features/llm/sessions) — multi-turn tool use with `LLMSession` and `hb llm session`.
  * [LLM Chat](/features/llm/chat) — CLI `--mcp` for single-turn agentic calls.
  * [First MCP](/quickstart/first-mcp) — attach a math Toolkit from the quickstart.
</Tip>

<br />
