[GH-ISSUE #23749] perf: MCP tool server reconnects on every message causing 15-20s silent delay #90796

Closed
opened 2026-05-15 16:04:29 -05:00 by GiteaMirror · 1 comment
Owner

Originally created by @DSavaliya-gh on GitHub (Apr 15, 2026).
Original GitHub issue: https://github.com/open-webui/open-webui/issues/23749

Bug Description

When an MCP (Model Context Protocol) tool server is enabled in Open WebUI, every chat message triggers a full MCP connection lifecycle from scratch:

  1. MCPClient() — new instance
  2. connect() — TCP → TLS → HTTP session → MCP initialize() handshake (10 s timeout)
  3. list_tool_specs() — full list_tools() round-trip

This happens before the model is ever called, and no status event is emitted to the frontend during this phase. The user sees a blinking dot for 15–20 seconds with zero feedback, followed by the model thinking phase.

Steps to Reproduce

  1. Add any MCP tool server in Admin Panel → Settings → Tools
  2. Assign that server to a model
  3. Start a new chat with that model
  4. Send any message

Expected Behavior

  • The blinking dot phase should be ≤2 s for warm connections (subsequent messages)
  • The user should see a visible status message like "Connecting to [server]..." during any network wait

Actual Behavior

  • 15–20 second silent blinking dot on every message, including follow-ups where reconnecting is unnecessary
  • No user-visible feedback during the MCP handshake phase

Analysis

In backend/open_webui/utils/middleware.py, the block inside process_chat_payload that handles tool_ids starting with server:mcp: does:

mcp_clients[server_id] = MCPClient()          # fresh every message
await mcp_clients[server_id].connect(...)     # full handshake
tool_specs = await mcp_clients[server_id].list_tool_specs()  # list_tools() round-trip

No event_emitter call is made before this block. The two fixes needed are:

  1. Status events — emit type: 'status' with action: 'mcp_connect' before and after the handshake so the user sees progress
  2. Connection pooling — for static bearer-auth servers (whose credentials don't change per user), reuse the MCPClient session from a previous request instead of reconnecting every time

Environment

  • Open WebUI version: current dev
  • MCP transport: Streamable HTTP (/mcp)
  • Auth type: bearer (static key)

Linked PR

A fix is ready at: https://github.com/DSavaliya-gh/open-webui/tree/fix/mcp-connection-pool-status-events

Originally created by @DSavaliya-gh on GitHub (Apr 15, 2026). Original GitHub issue: https://github.com/open-webui/open-webui/issues/23749 ## Bug Description When an MCP (Model Context Protocol) tool server is enabled in Open WebUI, every chat message triggers a **full MCP connection lifecycle from scratch**: 1. `MCPClient()` — new instance 2. `connect()` — TCP → TLS → HTTP session → MCP `initialize()` handshake (10 s timeout) 3. `list_tool_specs()` — full `list_tools()` round-trip This happens **before** the model is ever called, and **no status event is emitted to the frontend** during this phase. The user sees a blinking dot for **15–20 seconds** with zero feedback, followed by the model thinking phase. ## Steps to Reproduce 1. Add any MCP tool server in **Admin Panel → Settings → Tools** 2. Assign that server to a model 3. Start a new chat with that model 4. Send any message ## Expected Behavior - The blinking dot phase should be ≤2 s for warm connections (subsequent messages) - The user should see a visible status message like *"Connecting to [server]..."* during any network wait ## Actual Behavior - 15–20 second silent blinking dot on **every** message, including follow-ups where reconnecting is unnecessary - No user-visible feedback during the MCP handshake phase ## Analysis In `backend/open_webui/utils/middleware.py`, the block inside `process_chat_payload` that handles `tool_ids` starting with `server:mcp:` does: ```python mcp_clients[server_id] = MCPClient() # fresh every message await mcp_clients[server_id].connect(...) # full handshake tool_specs = await mcp_clients[server_id].list_tool_specs() # list_tools() round-trip ``` No `event_emitter` call is made before this block. The two fixes needed are: 1. **Status events** — emit `type: 'status'` with `action: 'mcp_connect'` before and after the handshake so the user sees progress 2. **Connection pooling** — for static bearer-auth servers (whose credentials don't change per user), reuse the `MCPClient` session from a previous request instead of reconnecting every time ## Environment - Open WebUI version: current `dev` - MCP transport: Streamable HTTP (`/mcp`) - Auth type: bearer (static key) ## Linked PR A fix is ready at: https://github.com/DSavaliya-gh/open-webui/tree/fix/mcp-connection-pool-status-events
Author
Owner

@Classic298 commented on GitHub (Apr 15, 2026):

STOP OPENING / SPAMMING THE ISSUES SECTION

<!-- gh-comment-id:4253230822 --> @Classic298 commented on GitHub (Apr 15, 2026): STOP OPENING / SPAMMING THE ISSUES SECTION
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: github-starred/open-webui#90796