Open WebUI Tools Not Working: Check Native Mode, Tool Search, and Model Compatibility

A reproducible four-condition test that separates Open WebUI visibility, Native Mode, Tool Search, model-backend compatibility, and external tool-server failures without deleting the original connection.

Contents
Open WebUI Tools Not Working: Check Native Mode, Tool Search, and Model Compatibility

A tool is enabled, the model says it will use it, and the final answer even sounds plausible—yet no real tool call appears. That is not enough evidence to blame either the model or Open WebUI. The fastest way to isolate the fault is to establish a clean baseline with one harmless reverse_string tool, then change Native Mode, Tool Search, and the model connection one variable at a time.

This guide keeps the original connection intact. By the end, you will have a four-condition test matrix backed by actual call and execution records, so you can choose the smallest fix: turn Tool Search off, put critical tools in Always Loaded, or route tool-heavy work through a connection that has passed the same test.

Treat tool use as a five-layer pipeline

“Enabled” in the interface is only the beginning. A successful tool run crosses at least five layers.

LayerWhat must be trueMisleading symptom
1. Visibility and accessThe current user can see and read the toolAn admin can use it, but another user silently receives no tool
2. Chat, mode, and capabilityFunction Calling is Native; the tool is enabled for this chat; a built-in system tool also has Workspace → Models → Capabilities → Builtin Tools and its relevant category enabledBuiltin Tools is off, or a Workspace/MCP/OpenAPI tool is incorrectly treated as controlled by that switch
3. Request payloadThe backend receives the required tool definition or the supported deferred-tool helpersTool Search defers the schema while the UI still shows the tool as enabled
4. Model backendThe backend returns the intended structured tool call with valid argumentsThe model writes “I called it,” chooses another operation, or emits bad arguments
5. ExecutionOpen WebUI, MCP, or the OpenAPI server runs the correct call and returns a resultA correct call exists, but authentication, routing, protocol, or server execution fails

Work from the top down. Rebuilding an MCP server before checking user access and the actual call evidence wastes time and can destroy useful evidence.

Preserve the original state before changing anything

Record the baseline first:

  • Open WebUI version and deployment method;
  • connection name, exact model ID, actual provider or gateway route, and the model name shown in the UI;
  • the effective Model Settings → Advanced Params → Function Calling value;
  • for a built-in system tool, the model’s Workspace → Models → Capabilities → Builtin Tools value and relevant category switches;
  • tools enabled through Integrations → Tools in the current chat and the testing user’s read access;
  • the four effective values shown under Settings → Admin → Interface → Chat: Tool Search, Defer Built-in Tools, Deferral Threshold (characters), and Always Loaded Tools;
  • the corresponding configuration names: ENABLE_TOOL_SEARCH, TOOL_SEARCH_DEFER_BUILTIN_TOOLS, TOOL_SEARCH_DEFER_THRESHOLD, and TOOL_SEARCH_ALWAYS_LOADED;
  • whether the failing capability is a built-in system tool, Workspace Tool, MCP tool, or OpenAPI tool;
  • one failed prompt, its timestamp, a chat export or screenshot, and Open WebUI/tool-server logs from the same window.

A connection can be disabled with its toggle without deleting its configuration. When you need a comparison, add a separately named connection such as control-tool-test; do not overwrite the production entry.

Keep these two statements separate:

  1. Normal chat works. This proves that a basic text request can complete.
  2. Tool calling works. This requires the intended structured call, valid arguments, an execution record, and a returned result.

A sentence such as “I have used reverse_string” is not proof.

Confirm that the current chat is actually using Native Mode

Open WebUI documents Native as the current default and supported tool-calling mode. Legacy remains as an unsupported compatibility opt-out. Check all scopes that can override the setting:

  1. global model defaults;
  2. the selected model’s Advanced Params;
  3. Chat Controls for the current conversation.

Use the value that is effective in this chat. Pin it to Native for the test. Do not mix a Legacy-mode experiment with a Tool Search diagnosis: Tool Search applies to Native Mode.

If the missing capability is one of Open WebUI’s built-in system tools, open Workspace → Models, edit the selected model, and inspect Capabilities. Builtin Tools must be enabled, as must the relevant category in the Builtin Tools row. This switch controls injection of built-in system tools in Native Mode. It is not a master switch for a Workspace Tool such as reverse_string, or for MCP/OpenAPI tools.

For the Workspace, MCP, and OpenAPI paths, confirm their separate controls:

  • open Integrations beside the message box;
  • select Tools and enable the diagnostic or external tool for this chat;
  • if a tool is attached at model level, verify that this user also has read access.

Attaching a Workspace Tool to a model does not bypass access control. A tool that the current user cannot read may be skipped without giving the model anything to call.

Create one safe tool with an exact expected result

Workspace Tools execute Python inside the Open WebUI environment, so only trusted administrators should create or import them. For diagnosis, use a function that touches no files, network services, databases, or system commands.

Create a tool under Workspace → Tools with this code:

"""
title: Read-only Tool Check
description: Reverses a string for tool-call diagnostics
version: 1.0.0
"""

class Tools:
    async def reverse_string(self, string: str) -> str:
        """
        Reverse the supplied text without reading or changing external data.

        :param string: Text that must be reversed exactly.
        :return: The reversed text.
        """
        return string[::-1]

Save it, grant the testing user access, and enable it through Integrations → Tools.

Use one fixed prompt in a fresh chat:

You must use the reverse_string tool on the string tool-check-7.
Do not reverse it yourself and do not guess.
After the tool returns, output only the tool result.

The expected value is:

7-kcehc-loot

Matching text alone is still not a pass. Require all four signals:

  • a structured reverse_string call is visible in the request trace or tool activity;
  • the argument contains tool-check-7;
  • Open WebUI or server logs show the corresponding execution;
  • the tool returns 7-kcehc-loot, and the final answer uses that result.

Save the chat record, call details, and matching log lines. Run every later condition in a new chat with the same tool and prompt so previous context cannot influence the outcome.

Run four controlled conditions

Change one variable at a time, using the existing Admin UI rather than treating environment-variable names as the switch itself:

  1. Open Settings → Admin → Interface → Chat.
  2. Set Tool Search, Defer Built-in Tools, Deferral Threshold (characters), and Always Loaded Tools for the condition below.
  3. Save, reopen that page, and record the values actually shown.
  4. Start a new chat and run the same fixed prompt.

The four settings map to ENABLE_TOOL_SEARCH, TOOL_SEARCH_DEFER_BUILTIN_TOOLS, TOOL_SEARCH_DEFER_THRESHOLD, and TOOL_SEARCH_ALWAYS_LOADED. They are ConfigVar settings. With the default ENABLE_PERSISTENT_CONFIG=True, values saved in the Admin UI/database take precedence over environment variables, so editing .env and restarting does not guarantee that a condition changed. If your deployment deliberately uses ENABLE_PERSISTENT_CONFIG=False, record that fact: environment values take precedence after startup, while UI edits apply only to the running session and are lost on restart.

ConditionNativeTool SearchDefer Built-in ToolsThresholdAlways LoadedPurpose
AOnOffRecord current value; not used by this Workspace ToolNot applicableNot applicableBaseline with the full reverse_string definition sent directly
BOnOnOn and recorded; it affects built-in tools, not reverse_string0Exact visible name of the test toolCheck the always-loaded path while Tool Search is enabled
COnOnOn and recorded0EmptyForce the test tool into the deferred path and observe search_tools plus the target call
DOnSame as CSame as C0EmptyAfter qualifying a second connection with A (and B if needed), repeat C without changing anything else

A threshold of 0 matters because the normal rule only defers definitions longer than the configured number of characters. A tiny function such as reverse_string can remain fully loaded under the default threshold, which would make condition C test the wrong path. Restore your intended production values after the diagnosis.

Condition A: prove the basic Native tool path first

In Settings → Admin → Interface → Chat, set Tool Search to Off, save, reopen the page to verify the effective value, then use a fresh chat and the fixed prompt. Do not use a restart alone as proof that the setting changed.

Interpret the result:

  • A passes: user access, Native calling, this model route, and Workspace execution work for the minimal case.
  • A fails with no structured call: recheck chat tool selection, tool read access, effective Function Calling mode, and whether the actual backend supports native structured tool calls.
  • A produces the intended call but execution fails: inspect Open WebUI execution logs, the arguments, and the function schema.

Do not troubleshoot Tool Search until A works.

Condition B: prove that Always Loaded can keep a critical tool callable

In the same UI section, turn Tool Search On, keep Defer Built-in Tools On and recorded, set Deferral Threshold (characters) to 0, and put the exact model-visible test-tool name in Always Loaded Tools. Save, reopen, verify all four values, and run the prompt in a new chat.

Matching is case-sensitive and accepts exact names or glob patterns. For MCP tools, the visible name is generally assembled as <server ID>_<tool name>. Copy the name from the actual tool list or request trace rather than guessing from the MCP server’s internal method name.

  • B passes: sending this tool in full works while Tool Search is enabled.
  • B fails while A passes: verify the saved UI value, exact visible name and case. Do not assume that an environment edit or restart overrode a persisted Admin UI value.

Condition C: force the deferred-tool path

Keep Tool Search On, Defer Built-in Tools On, and the threshold at 0; clear Always Loaded Tools. Save, reopen the page to verify the empty field and other effective values, then use a new chat and the same prompt.

Record each transition separately:

  • Was search_tools called?
  • Did it return the reverse_string definition?
  • Did the model produce the target structured invocation? On Open WebUI v0.12.2 and later, expect call_tool with tool_name set to the exact reverse_string name and JSON-encoded arguments.
  • Did Open WebUI then execute reverse_string with tool-check-7 and return 7-kcehc-loot?
  • Did the model instead choose the wrong tool, emit bad arguments, leak a tool name into prose, or continue without a call?

If search_tools never appears, first check whether the UI values really took effect, whether anything was actually deferred, and whether the model/route can select the helper. If search succeeds but no target structured invocation follows, keep model quality, schema/name clarity, route behavior, and deferred-tool compatibility in the diagnosis. If the correct target call appears but execution does not, move to the execution layer.

The current Open WebUI documentation says v0.12.2 and later use the declared call_tool helper, so each provider-facing call remains in the request’s tool list and listed-tools-only backends are supported. Earlier versions called a deferred tool by name, which strict backends could reject. Record the installed version before applying an old issue report to a current deployment. A public issue documented that older failure shape in one deployment and one strict backend family; it is a user report, not a universal result.

Condition D: change only the model connection

Do not accept a Native label as proof that the second connection is a valid deferred-tool control. First record its exact model ID, provider/gateway, Base URL or route, and run the same read-only A baseline with Tool Search Off. If necessary, run B as well. Only after the second connection passes the ordinary and always-loaded paths should you repeat C as condition D, keeping the tool, prompt, UI values, threshold, and empty Always Loaded field unchanged.

  • D passes while C fails: the original model route is the differentiator. Preserve it for ordinary chat if useful, and use the verified route for deferred-tool work.
  • The second connection fails A (or B): it is not a valid deferred compatibility control; fix or replace that baseline before comparing C and D.
  • A/B pass on both connections, but C and D both fail: keep the branch that both actual backends or routes may not support the deferred flow used by the installed version. Two different model names can still share one strict provider, gateway, or router. Check the real route and version, then branch on whether search_tools succeeded and whether the target structured invocation appeared; do not collapse this result into “Open WebUI configuration” alone.
  • C and D both pass: the original failure is more likely tied to the production tool’s visibility, schema, operation choice, arguments, permissions, or server.

Choose the smallest repair from the matrix

EvidenceBest next move
A fails and there is no structured callFix access, chat tool selection, Native mode, or use a backend with real function-calling support
A and B pass; C has no search_tools callVerify the effective UI values, threshold, installed version, and whether the model/route can select the Tool Search helper
search_tools succeeds, but no target structured invocation followsCheck model capability, visible name/schema, actual provider route, installed version, and deferred-tool compatibility; use Always Loaded or disable Tool Search as the minimal fallback
The target call appears, but reverse_string is not executedInspect Open WebUI execution logs and the call_tool target/arguments
A, B, and C pass, but a production tool failsInspect that tool’s model-visible definition, chosen operation, arguments, Tool Search treatment, route, access, and server evidence
Only one qualified model connection failsPreserve it for normal chat; use a connection that passed the same A/B/C evidence
Both qualified connections fail C/DKeep both-backends/one-shared-route deferred incompatibility as a live branch; compare search_tools, target-call, route, and version evidence

If you have only a modest number of tools, disabling experimental Tool Search is usually the simplest reliable configuration. If you have many large schemas, keep Tool Search but always-load a small set of frequently used, low-risk tools, then qualify every model connection independently.

After the Workspace baseline passes, inspect MCP or OpenAPI

A successful reverse_string call proves that one simple, single-string Workspace schema can work on that route. It does not prove that the same model will choose a complex production tool, select the correct operation, supply valid arguments, or finish a multi-step external workflow. Open WebUI’s MCP and OpenAPI documentation explicitly preserves those model limitations even when the connection itself works.

Before moving to server diagnostics, capture the production tool definition as the model sees it and the actual target call evidence:

  • No target call, wrong operation, or invalid arguments: keep model capability, tool name/description/schema, Tool Search, and the actual model/provider route in the investigation.
  • The correct structured target call is emitted, but it never reaches the server or returns a transport/authentication error: move to URL, access control, authentication, protocol, proxy, TLS, and server diagnostics.
  • The server receives the correct operation but rejects arguments or returns an application error: compare the call with the exposed schema and inspect server handling.

MCP: check transport, access, and the visible name

Open WebUI’s native MCP connection uses MCP (Streamable HTTP). A local server that exposes only stdio is not a native HTTP MCP endpoint; it needs an appropriate bridge or proxy.

Verify:

  • the connection Type is MCP rather than OpenAPI;
  • the Streamable HTTP URL is reachable from the Open WebUI host or container;
  • authentication is valid for the current user;
  • access control includes the testing user;
  • the exact model-visible definition and name follow the expected <server ID>_<tool name> form;
  • the model selected that target and supplied valid arguments;
  • a correct call reaches the MCP server logs;
  • the server returns a protocol result rather than an HTTP, authorization, or application error.

If there is no correct target call, remain in the model/schema/Tool Search/route branch. If a correct structured call exists but the MCP server receives nothing, inspect URL routing, proxy rules, certificates, and network reachability. If the server receives the request but rejects its arguments, compare the call with the exposed schema.

OpenAPI: verify that operations are actually discovered

Open WebUI discovers operations from an OpenAPI 3.x path-item structure. Confirm that the specification exposes standard HTTP method operations, usable parameter definitions, and stable names and descriptions that let the model distinguish the intended operation.

Save:

  • the specification URL and the version you tested;
  • the tool names and definitions Open WebUI actually exposed to the model;
  • the operation the model selected and arguments from the structured call;
  • the tool server’s access log and response status;
  • the returned body that Open WebUI passed back to the model.

A saved tool-server or model connection is not an execution test. A failed /models verification also does not automatically prove that chat or tools are incompatible: some compatible providers do not implement a standard /models endpoint. In that case, enter the exact Model ID manually and judge the route through the A/B/C evidence and the real production-tool call.

Optional: add a BetterToken comparison connection

For a second model or protocol path, keep the original connection and add an OpenAI-compatible comparison connection. The BetterToken API Base URL is:

https://www.bettertoken.ai/v1

Choose an exact Model ID from the current catalog whose supported_endpoint_types includes openai, and use your own API key. Do not guess the ID from a display label. More importantly, do not promote “normal chat works” into “Tool Search is compatible.”

Run conditions A–D on that connection as well. BetterToken is only an optional alternate API path and a place to observe request usage here; it is not evidence that Open WebUI, a particular model, or Tool Search has been fixed.

References:

Save a reproducible diagnostic record

Replace “this model does not use tools” with a record another person can rerun:

Open WebUI version:
Deployment:
Connection:
Exact model ID:
Actual provider/gateway route:
Function Calling:
Builtin Tools capability/categories:
Tool Search UI value:
Defer Built-in Tools UI value:
Deferral Threshold UI value:
Always Loaded Tools UI value:
ENABLE_PERSISTENT_CONFIG mode:
ENABLE_TOOL_SEARCH:
TOOL_SEARCH_DEFER_BUILTIN_TOOLS:
TOOL_SEARCH_DEFER_THRESHOLD:
TOOL_SEARCH_ALWAYS_LOADED:
Tool visible name:
Prompt:
search_tools call observed:
target call_tool / structured invocation observed:
reverse_string execution log observed:
Returned value:
Timestamp:

This record also gives you a compact regression test after an Open WebUI upgrade, model change, or tool-server migration.

Start with one real call, not a redesign

The first action is simple: keep the original connection, set the current chat to Native, turn Tool Search off, and run reverse_string with tool-check-7. Only after you have a structured call, an execution record, and 7-kcehc-loot should you enable forced deferral and compare connections.

That evidence tells you whether the smallest safe fix is access, mode, Always Loaded, disabling Tool Search, or changing the model path—without trusting a model’s prose claim and without rebuilding the entire tool stack.

Ready to optimize your LLM workflow?

Join thousands of developers building faster, smarter, and more cost-effective AI applications with BetterToken.

Get Started for Free