# reload_tools — Manual

## What it does
Reloads the things that can be changed without restarting the server: tool files from `tools/`, context providers from `context_providers/`, and every configured MCP server (reconnected, its tools re-registered). Call it after writing or editing any of them.

It takes **no parameters**.

```json
{}
```

## Reading the report

The output is one line per fact, and the call's `success` is `false` if any of them reported an error:

```
Tools (4): get_current_datetime, gmail, weather, my_tool.
Tool errors (1):
  broken.py: SyntaxError: invalid syntax (broken.py, line 3)
Context providers (2): hostname, server_status.
MCP tools (37): mcp__tgclient__..., mcp__navi-web__...
```

- **`Tool errors` / `Context provider errors`** — file by file. Errors are isolated: a broken file does not stop the others from loading, and does not stop the call from being useful. Fix the named file and reload again.
- **`Warning: enabled.json names N tool(s) that do not exist...`** — `tools/enabled.json` lists a name no tool answers to. Those names are silently dropped from every profile, so the tool you thought you enabled is simply absent. Check the name matches the tool's `name` exactly.
- **`MCP reload error`** — the MCP leg failed as a whole; the tools above it were still reloaded.

## Writing a tool for it to load

Put a `.py` file in `tools/`. Files starting with `_` are ignored (`_template.py` is a scaffold, not a tool).

**Module style** — the simple form:

```python
name = "notes"
description = "Save and retrieve short text notes by key. Actions: save, get, list."
parameters = {
    "type": "object",
    "properties": {
        "action": {"type": "string", "enum": ["save", "get", "list"]},
        "key": {"type": "string", "description": "Note identifier"},
        "value": {"type": "string", "description": "Note content (for save)"},
    },
    "required": ["action"],
}

async def execute(params: dict) -> str:
    if params["action"] == "list":
        return "No notes saved yet."
    return f"Saved: {params['key']}"
```

All four names are required (`name`, `description`, `parameters`, `execute`), `execute` must be `async`, it takes `params` only, and it returns **a string** — a dict or `None` becomes `str(...)`. Raise an exception to signal failure: it surfaces as a failed tool result with the exception type. `description` is what the model reads when deciding whether to call the tool, so write it for that decision, not as a title.

**Class style** — a subclass of `Tool` needs class-level `name`, `description`, `parameters`, and `execute(self, params)` or `execute(self, params, ctx=None)`. Other signatures are rejected with a "wrong signature" error, and the class must be instantiable with no arguments.

To make the tool visible to a profile, its `name` must be declared — in the profile config, or in `tools/enabled.json`. A file that loads but is named nowhere is registered and still uncallable; `list_tools` is where that shows up.

## Rules

- Reload **after** the file is complete. A half-written file loads as a `Tool errors` line, and the report is then partly about your editor.
- Reloading MCP servers reconnects them — an in-flight MCP call is not something to reload through. Do it between steps, not mid-call.
- Context providers inject text into **every** system prompt. Reload after editing one, but change them deliberately: a bad provider costs tokens on every call, not just one.
- Do not call it in a loop. One reload after a batch of edits is enough.
- A reload is not needed for MCP tool *arguments* or for data files a tool reads — only for tool/provider/server definitions.
