内容
# Deferred Tools for Open WebUI
A single Open WebUI filter that hides every MCP and builtin tool from the model
until the model asks for it by name. The model sees one tool, `load_tools`, plus
the names of every hidden tool grouped by server. Passing a name to `load_tools` puts that tool's real schema into the next
model call, and the model then calls it directly.
With Anchor's 17 tools and Open WebUI's 35 builtins enabled, an unfiltered request
carried about 29k prompt tokens on every model call. With the filter, the first
call carried about 600.
## Install
1. In Open WebUI go to **Admin Panel → Functions** and click **Create**.
2. Paste the contents of `deferred_tools.py` and click **Save**.
3. Turn the function on, then open its **⋯** menu and turn on **Global** so it
applies to every model.
Requirements: Open WebUI 0.11.2 or newer, models set to **Native** function
calling, and plugins enabled on the server (`ENABLE_PLUGINS=true`). Give each MCP
connection a readable id such as `anchor` or `linear`; tool names become
`<id>_<tool>`, and the model reads those names.
## Prompt caching
Loading a tool changes the request, so it is worth being precise about what that
costs. The paragraph appended to the system prompt names **every** hidden tool,
not just the ones still unloaded, and it is built from sorted input. It is
therefore byte-identical on every hop of the tool loop and on every later turn:
the hint itself never churns the cacheable prefix.
What does change is the tool array, once, at the moment a tool is loaded. The
loaded set only ever grows within a chat, so it re-stabilises immediately and a
chat pays at most one cache miss per distinct tool it actually needs. This is the
opposite of deciding the tool set per turn, which rewrites the prefix on every
turn and cannot be cached at all.
## What this does not do
It is not a permission boundary. Hiding a schema only changes what the model is
shown; Open WebUI resolves a tool call against its catalog, so a hidden tool is
still callable if the model names it. Use Open WebUI's own access controls to
decide what a user may reach.
It also needs models set to **Native** function calling; in Legacy mode Open WebUI
never builds the tool array this filter rewrites.
## Tests
```sh
cd tests
python3 -m venv .venv && .venv/bin/pip install -r requirements.txt
.venv/bin/pytest -q
```
The tests drive the filter the way Open WebUI's middleware does: the request
hook before each model call and on each hop of the tool loop, and `load_tools`
called with the arguments the model produced.
## License
[Apache License 2.0](LICENSE). Copyright 2026 Anchor Technologies, Inc.; see [NOTICE](NOTICE).