Releases
TinySearch: Open-Source MCP Web Research for Local LLMs
Most MCP servers that add “web search” to an agent do one of two things. They wrap a search API and hand back a list of links, leaving the model to fetch and read each one itself. Or they wrap a hosted research API that already runs its own model over the results, so the agent gets an answer it did not write and cannot fully verify.
TinySearch is the first tool in the TinySuite family, and it takes a third path: search, crawl, chunk, and rerank the web on infrastructure you run, then hand your agent’s own model a compact, cited prompt instead of a pile of links or somebody else’s answer.
What TinySearch actually does
The pipeline is short on purpose:
search -> crawl -> chunk -> rerank -> grounded promptTwo MCP tools cover the current recommended flow. search(query) does fast, top-level discovery: it returns backend-ordered titles, URLs, previews, and upstream dates, without crawling anything yet. scrape_urls(items) takes one to five URLs, already known or picked from a search call, and does the rest: crawl, chunk, hybrid-rank against an optional per-item query, and return focused evidence with each passage tied to its source. A third tool, get_current_datetime(), orients time-sensitive questions before either runs, so the agent has a concrete UTC timestamp instead of guessing what “latest” or “this week” means. An older all-in-one research(query) tool that combined search and crawling into one call still works for compatibility, but new integrations should compose search with scrape_urls instead.
The crawling and extraction underneath is handled by Crawl4AI, the open-source crawler that turns a webpage into clean, LLM-ready markdown. TinySearch adds the parts Crawl4AI doesn’t do: the search step that finds URLs in the first place, embedding-based chunk ranking on top of Crawl4AI’s own BM25 content filter, and an MCP interface that a client can call without touching Python.
Search itself comes from DDGS by default, with a bundled SearXNG instance available for the Docker deployment and Brave’s Web Search API as an optional keyed fallback. None of that requires an account to get started.
Three ways to run it
| Setup | Command | Default search backend |
|---|---|---|
| MCP client over stdio | uvx --from "tinysuite-search[server]" tinysearch |
DDGS |
| Python library | pip install tinysuite-search |
DDGS |
| Self-hosted HTTP stack | Docker Compose | Bundled SearXNG |
The stdio path is the fast one. Any MCP client that can launch a process can start TinySearch with a single command, and there’s nothing to provision first: no repository clone, no database, no API key. Fast search calls don’t touch Chromium or the embedding model at all; the first scrape_urls call is what initializes both, which can add a minute or two of one-time delay. Running tinysearch setup ahead of time pre-downloads Chromium and the configured embedding model so that delay doesn’t land on a real request, and tinysearch doctor checks an existing install (config location, browser, model bundle, writable config directory) without downloading anything.
The Docker path trades that simplicity for a shared, network-reachable endpoint with its own SearXNG instance, reachable over Streamable HTTP at /mcp, which matters once more than one client needs to hit the same research layer. The quick-start Compose file bundles the MCP server, a SearXNG instance with JSON output already enabled, and a persistent volume for downloaded embedding models so restarts don’t re-trigger the first-use download.
The Python library sits underneath both. search() and scrape_urls() return schema-v1 dictionaries rather than a finished prompt, which is what you want if your application needs to inspect, store, or render the retrieved chunks itself instead of handing them straight to a model. Per-call configuration is passed directly as a TinySearchConfig or partial mapping, and it deliberately ignores server environment variables, so a library call behaves the same regardless of how the surrounding process is configured.
Why the model doesn’t write the answer
TinySearch stops one step before most hosted research APIs do. Tools like Tavily’s Research mode or Perplexity’s Sonar API fold a model call into the response, so what you get back is already a written answer. That’s convenient, but it means the citations point at a summary of the evidence, not the evidence itself, and the model doing the summarizing isn’t the one your agent is built around.
search and scrape_urls return ranked, chunked passages with their source URLs still attached. Your client’s own model reads that context and writes the final answer, so the citations trace back to the actual text that supports them, and the reasoning happens in the model you already trust and are already paying for.
That also keeps TinySearch’s job narrow. There’s no shared crawling budget across other people’s requests, no hosted rate limit, and no dependency on a vendor staying up. The tradeoff is that you’re the one running the pipeline, including Crawl4AI’s browser and the embedding model’s warm-up time. For a deeper look at how that compares to hosted alternatives, see TinySearch vs. Tavily, Exa, Perplexity, and Brave.
How much comes back, and how that’s controlled
The MCP interface deliberately keeps its own parameters small rather than asking a client model to choose limits on every call. search_max_results (default 10) sets how many backend-ordered results an MCP search call returns, and scrape_max_tokens (default 2000) caps the content budget for each scrape_urls item. Both are server-side configuration, not tool arguments, which keeps the tool surface predictable no matter which client is calling it. Underneath those MCP-facing limits sit the pipeline’s own knobs: how many pages crawl in parallel, how large a candidate chunk is before ranking, how much overlap sits between adjacent chunks, and a near-duplicate cutoff that drops chunks too similar to ones already kept. The defaults are tuned to stay small; they’re all adjustable in the JSON configuration file for anyone who wants a different tradeoff between recall and prompt size.
Where it fits in the rest of TinySuite
TinySearch answers “what does the web say right now.” It doesn’t try to remember anything between calls, which is a deliberate boundary: memory is a different problem with a different shape, and TinySuite’s second tool, TinyContext, is built specifically for it. The two are meant to be used together: TinySearch brings in fresh, cited evidence; TinyContext stores the facts worth keeping and recalls them later inside the same kind of token budget.
Both projects start from the same premise: the best context for a model is usually smaller than the easiest context to produce, and it’s worth running the extra pipeline steps locally to get there. Install TinySearch or read the source on GitHub.