Skip to main content

Engineering

Add Web Search to a Local LLM: Open WebUI and TinySearch

Published · Updated

To give a local LLM web search, connect its chat client to a search tool and use a model capable of calling tools. In this walkthrough, Open WebUI calls TinySearch over MCP; TinySearch finds and reads web pages; your selected model writes the answer from the returned evidence.

The steps below assume Open WebUI and TinySearch run as native processes on the same machine. A Docker address table follows for existing container installations. No paid search API key is required for TinySearch’s default DDGS backend. Web queries still go to external search providers, and reading a page contacts that website.

Before you start

You need:

MCP makes tools available; it does not teach an unsuitable model to use them. Start with a model that already handles tool calls reliably in your client.

1. Prepare TinySearch

Check that uv is available, then download TinySearch’s browser and local embedding dependencies:

Terminal window
uv --version
uvx --python 3.12 --from "tinysuite-search[server]" tinysearch setup

Check readiness using the same environment:

Terminal window
uvx --python 3.12 --from "tinysuite-search[server]" tinysearch doctor

Resolve missing dependencies reported by doctor before continuing. On Linux, the installation troubleshooting guide covers Chromium system libraries. Preloading avoids placing browser and model downloads on your first scrape request.

2. Start the HTTP MCP server

Run this in a terminal and leave it open:

Terminal window
uvx --python 3.12 --from "tinysuite-search[server]" tinysearch serve

TinySearch serves Streamable HTTP at /mcp on port 8000. For Open WebUI running natively on the same machine, the connection URL is:

http://localhost:8000/mcp

The command without serve starts a stdio server for clients that launch their own subprocesses. Open WebUI’s native MCP connection uses HTTP instead. A browser visit to /mcp is not an MCP handshake and is not a sufficient connection test.

If Open WebUI or TinySearch runs in Docker

Choose the address from the Open WebUI backend’s point of view:

Deployment TinySearch URL entered in Open WebUI
Both native on the same machine http://localhost:8000/mcp
Open WebUI in Docker, TinySearch on the host http://host.docker.internal:8000/mcp
Both on the same Docker network, service named tinysearch http://tinysearch:8000/mcp
Native Open WebUI, TinySearch container published on host port 8000 http://localhost:8000/mcp

On Linux, the host-address option requires the host.docker.internal:host-gateway mapping in the Open WebUI container. TinySearch must also listen on an interface reachable from that container. Keep the endpoint on a trusted local network; configure authentication at your gateway before exposing it beyond that network. For a complete TinySearch container setup, use the Docker quick start.

3. Add TinySearch in Open WebUI

Open Settings → Admin → Integrations, then add an External Tool Server. Set its type to MCP (Streamable HTTP) and use the address from the table. Name the connection TinySearch. For this local setup, select authentication None; use your actual credentials if you have placed the server behind an authenticated gateway.

Save the connection and follow any restart prompt. In a new chat, enable TinySearch under Integrations → Tools. Menu labels can differ between releases; the Open WebUI MCP guide documents the current connection flow.

Select your local model and use Native function calling. Check that the available tools include get_current_datetime, search and scrape_urls. TinySearch also exposes browser tools when its browser backend is enabled. This first check only needs search and page reading.

4. Verify a search and a page read

Send a question that requires reading a specific source:

Use TinySearch to find the official SearXNG Search API documentation. Read the page and explain how to request JSON results and what happens when that output format is disabled. Cite the documentation URL. If a tool fails, report the error instead of guessing.

Inspect the tool activity, not just the final prose. A successful run should include:

  1. A TinySearch search call returning a relevant documentation URL.
  2. A scrape_urls call reading that URL with a focused query.
  3. An answer grounded in the returned page, with a source link you can open.

For this question, the documentation describes format=json and a 403 response when the requested format is not enabled. Check that the retrieved text supports the model’s answer. A fluent answer without those tool calls does not demonstrate that the connection works.

For a second test, ask about a recent software release and have the model check the current date before searching. The answer should reflect retrieved release information, not only the model’s training data.

Troubleshooting

Problem What to check
No MCP connection type Use an admin account and an Open WebUI release supporting native MCP
Connection refused Keep tinysearch serve running; verify port 8000 and the backend’s network address
Connection hangs after setup Confirm the type is MCP, the path is /mcp, and local auth is None rather than an empty Bearer token
Tools are connected but unused Enable them for this chat and check Native tool calling and model support
First page read is slow Run setup, then doctor, in the same environment as the server
Search works but a page cannot be read Inspect the scrape error; a blocked or unavailable page is different from a broken MCP connection
Search returns backend errors Inspect DDGS availability or configure a SearXNG instance using the linked guide

Keep the evidence manageable

search finds candidate URLs without starting the browser or embedding model. scrape_urls reads selected pages; with a focused query, it ranks passages and returns evidence within configured budgets. Your client model still decides how to use and cite that evidence. See the MCP tool reference for the current arguments and output shapes.

Once the connection works, choose between DDGS and SearXNG for your search workload and tune the configuration limits. Keep inference and embeddings local if that is your goal, while accounting separately for the external requests required to search and read the web.