[GH-ISSUE #21770] issue: OpenAPI tool server calls delegated to frontend via event_caller — execution always fails #58230

Closed
opened 2026-05-05 22:36:42 -05:00 by GiteaMirror · 1 comment
Owner

Originally created by @antonioromero-pm on GitHub (Feb 23, 2026).
Original GitHub issue: https://github.com/open-webui/open-webui/issues/21770

Check Existing Issues

  • I have searched for any existing and/or related issues.
  • I have searched for any existing and/or related discussions.
  • I have also searched in the CLOSED issues AND CLOSED discussions and found no related items (your issue might already be addressed on the development branch!).
  • I am using the latest version of Open WebUI.

Installation Method

Docker

Open WebUI Version

v0.8.3 (Docker, ghcr.io/open-webui/open-webui:v0.8.3)

Ollama Version (if applicable)

No response

Operating System

Windows 11 + WSL2

Browser (if applicable)

Chrome

Confirmation

  • I have read and followed all instructions in README.md.
  • I am using the latest version of both Open WebUI and Ollama.
  • I have included the browser console logs.
  • I have included the Docker container logs.
  • I have provided every relevant configuration, setting, and environment variable used in my setup.
  • I have clearly listed every relevant configuration, custom setting, environment variable, and command-line option that influences my setup (such as Docker Compose overrides, .env values, browser settings, authentication configurations, etc).
  • I have documented step-by-step reproduction instructions that are precise, sequential, and leave nothing to interpretation. My steps:
  • Start with the initial platform/version/OS and dependencies used,
  • Specify exact install/launch/configure commands,
  • List URLs visited, user input (incl. example values/emails/passwords if needed),
  • Describe all options and toggles enabled or changed,
  • Include any files or environmental changes,
  • Identify the expected and actual result at each stage,
  • Ensure any reasonably skilled user can follow and hit the same issue.

Expected Behavior

When the model generates a tool call for an OpenAPI tool server, the backend should make the HTTP request to that tool server directly and return the result to the model.

Actual Behavior

The backend sends a execute:tool event to the frontend via event_caller:

# middleware.py ~line 4054
if direct_tool:
    tool_result = await event_caller({
        "type": "execute:tool",
        "data": {
            "id": str(uuid4()),
            "name": tool_function_name,
            "params": tool_function_params,
            "server": tool.get("server", {}),
            "session_id": metadata.get("session_id", None),
        },
    })

The frontend receives this event but has no server state (it never fetched the tool server specs) and cannot execute the HTTP call. The tool result is None or {"error": "Tool Server Not Found"}.

Steps to Reproduce

Requires the schema injection issue (Bug 1) to be resolved first, OR testable by manually ensuring tool_servers is populated in the request.

  1. Configure an OpenAPI tool server and enable it for a model (same steps as Bug 1)
  2. Ensure the model receives tool schemas (either via a fix to Bug 1 or by manually sending a populated tool_servers payload)
  3. Send a message that causes the model to generate a tool call
  4. Observe the result returned to the model

Logs & Screenshots

No logs to share.

Additional Information

#21760 -- these are two halves of the same problem.

Root Cause

response_handler in middleware.py distinguishes between two tool types via the direct flag:

  • direct=False — workspace Python tools: executed server-side via tool["callable"]()
  • direct=True — OpenAPI tool server tools: execution delegated to frontend via event_caller

The frontend-delegation path assumes the frontend fetched and cached the tool server URL and credentials when it embedded specs into the request payload. Since the frontend never does this for admin-configured OpenAPI servers (Bug 1), it also has no state to execute the call.

The backend already has everything needed to execute the call directly: the server URL, auth headers, and the full OpenAPI spec are all available in tool["server"] within tools_dict. The utility function execute_tool_server() in open_webui/utils/tools.py is already capable of making this call and is used by the MCP execution path.


Suggested Fix

Replace the event_caller delegation in the direct_tool branch with a direct backend call using the already-available execute_tool_server utility:

if direct_tool:
    _server = tool.get("server", {})
    _url = _server.get("url", "")
    _token = _server.get("key", "") or ""
    _auth_type = _server.get("auth_type", "bearer")
    _headers = {}
    if _auth_type == "bearer" and _token:
        _headers["Authorization"] = f"Bearer {_token}"
    try:
        from open_webui.utils.tools import execute_tool_server
        tool_result, _ = await execute_tool_server(
            url=_url,
            headers=_headers,
            cookies={},
            name=tool_function_name,
            params=tool_function_params,
            server_data=_server,
        )
    except Exception as e:
        tool_result = {"error": str(e)}

Verification

With both this fix and the schema injection fix (Bug 1) applied, the full tool-calling chain works end-to-end:

  1. Startup: Initialized 3 tool server(s) — specs cached server-side ✓
  2. Request: Patch1: resolved 1 OpenAPI tool server(s) from server-side cache — schemas injected ✓
  3. Model generates tool call: tool_weather_forecast_post with lat/lon params ✓
  4. Execution: Patch2: executed tool_weather_forecast_post server-side
  5. Real API response returned to model, correct weather answer generated ✓

Confirmed working against Open-Meteo API via MCPO with Qwen3 80B using native function calling.


Additional Notes

  • MCP-type tool servers are unaffected — they use a completely separate execution path that is fully server-side
  • If the frontend-delegation path is intentional for a future use case (e.g. browser-local tool servers), it should at minimum fall back to server-side execution when the frontend returns no result, rather than silently failing
  • A Dockerfile patch implementing both fixes is available if useful for the maintainers
Originally created by @antonioromero-pm on GitHub (Feb 23, 2026). Original GitHub issue: https://github.com/open-webui/open-webui/issues/21770 ### Check Existing Issues - [x] I have searched for any existing and/or related issues. - [x] I have searched for any existing and/or related discussions. - [x] I have also searched in the CLOSED issues AND CLOSED discussions and found no related items (your issue might already be addressed on the development branch!). - [x] I am using the latest version of Open WebUI. ### Installation Method Docker ### Open WebUI Version v0.8.3 (Docker, `ghcr.io/open-webui/open-webui:v0.8.3`) ### Ollama Version (if applicable) _No response_ ### Operating System Windows 11 + WSL2 ### Browser (if applicable) Chrome ### Confirmation - [x] I have read and followed all instructions in `README.md`. - [x] I am using the latest version of **both** Open WebUI and Ollama. - [x] I have included the browser console logs. - [x] I have included the Docker container logs. - [x] I have **provided every relevant configuration, setting, and environment variable used in my setup.** - [x] I have clearly **listed every relevant configuration, custom setting, environment variable, and command-line option that influences my setup** (such as Docker Compose overrides, .env values, browser settings, authentication configurations, etc). - [x] I have documented **step-by-step reproduction instructions that are precise, sequential, and leave nothing to interpretation**. My steps: - Start with the initial platform/version/OS and dependencies used, - Specify exact install/launch/configure commands, - List URLs visited, user input (incl. example values/emails/passwords if needed), - Describe all options and toggles enabled or changed, - Include any files or environmental changes, - Identify the expected and actual result at each stage, - Ensure any reasonably skilled user can follow and hit the same issue. ### Expected Behavior When the model generates a tool call for an OpenAPI tool server, the backend should make the HTTP request to that tool server directly and return the result to the model. ### Actual Behavior The backend sends a `execute:tool` event to the frontend via `event_caller`: ```python # middleware.py ~line 4054 if direct_tool: tool_result = await event_caller({ "type": "execute:tool", "data": { "id": str(uuid4()), "name": tool_function_name, "params": tool_function_params, "server": tool.get("server", {}), "session_id": metadata.get("session_id", None), }, }) ``` The frontend receives this event but has no server state (it never fetched the tool server specs) and cannot execute the HTTP call. The tool result is `None` or `{"error": "Tool Server Not Found"}`. ### Steps to Reproduce Requires the schema injection issue (Bug 1) to be resolved first, OR testable by manually ensuring `tool_servers` is populated in the request. 1. Configure an OpenAPI tool server and enable it for a model (same steps as Bug 1) 2. Ensure the model receives tool schemas (either via a fix to Bug 1 or by manually sending a populated `tool_servers` payload) 3. Send a message that causes the model to generate a tool call 4. Observe the result returned to the model ### Logs & Screenshots No logs to share. ### Additional Information ## Related issue #21760 -- these are two halves of the same problem. ## Root Cause `response_handler` in `middleware.py` distinguishes between two tool types via the `direct` flag: - `direct=False` — workspace Python tools: executed server-side via `tool["callable"]()` - `direct=True` — OpenAPI tool server tools: execution delegated to frontend via `event_caller` The frontend-delegation path assumes the frontend fetched and cached the tool server URL and credentials when it embedded specs into the request payload. Since the frontend never does this for admin-configured OpenAPI servers (Bug 1), it also has no state to execute the call. The backend already has everything needed to execute the call directly: the server URL, auth headers, and the full OpenAPI spec are all available in `tool["server"]` within `tools_dict`. The utility function `execute_tool_server()` in `open_webui/utils/tools.py` is already capable of making this call and is used by the MCP execution path. --- ## Suggested Fix Replace the `event_caller` delegation in the `direct_tool` branch with a direct backend call using the already-available `execute_tool_server` utility: ```python if direct_tool: _server = tool.get("server", {}) _url = _server.get("url", "") _token = _server.get("key", "") or "" _auth_type = _server.get("auth_type", "bearer") _headers = {} if _auth_type == "bearer" and _token: _headers["Authorization"] = f"Bearer {_token}" try: from open_webui.utils.tools import execute_tool_server tool_result, _ = await execute_tool_server( url=_url, headers=_headers, cookies={}, name=tool_function_name, params=tool_function_params, server_data=_server, ) except Exception as e: tool_result = {"error": str(e)} ``` --- ## Verification With both this fix and the schema injection fix (Bug 1) applied, the full tool-calling chain works end-to-end: 1. Startup: `Initialized 3 tool server(s)` — specs cached server-side ✓ 2. Request: `Patch1: resolved 1 OpenAPI tool server(s) from server-side cache` — schemas injected ✓ 3. Model generates tool call: `tool_weather_forecast_post` with lat/lon params ✓ 4. Execution: `Patch2: executed tool_weather_forecast_post server-side` ✓ 5. Real API response returned to model, correct weather answer generated ✓ Confirmed working against Open-Meteo API via MCPO with Qwen3 80B using native function calling. --- ## Additional Notes - MCP-type tool servers are unaffected — they use a completely separate execution path that is fully server-side - If the frontend-delegation path is intentional for a future use case (e.g. browser-local tool servers), it should at minimum fall back to server-side execution when the frontend returns no result, rather than silently failing - A Dockerfile patch implementing both fixes is available if useful for the maintainers
GiteaMirror added the bug label 2026-05-05 22:36:42 -05:00
Author
Owner

@tjbck commented on GitHub (Feb 23, 2026):

Intended behaviour, if you require backend to call the server you should be using admin level connections.

<!-- gh-comment-id:3947695648 --> @tjbck commented on GitHub (Feb 23, 2026): Intended behaviour, if you require backend to call the server you should be using admin level connections.
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: github-starred/open-webui#58230