Skip to main content

Web search, fetch, and research pipeline for LLMs — usable as a Python SDK, a standalone MCP server, and an Open WebUI plugin.

Project description

websearch-kit

Web search, fetch, and research pipeline for LLMs — one engine, three surfaces: a Python SDK, a standalone MCP server, and an Open WebUI plugin.

Query expansion → multi-provider search → SSRF-guarded concurrent fetching (40-UA browser profile, pinned-IP connect) → trafilatura extraction → BM25 rerank with adaptive context budgeting → numbered, citable context for your LLM.

No fail-silent: a call either raises a typed error or returns a result where every dropped, blocked, truncated, or substituted item is enumerated as a structured Degradation. On the live web that looks like:

ok        : True   partial: True
sources   : 10                       # 5 fetched pages + 5 relevance-filtered snippets
warnings  :
  - [fetch] https://cloud.google.com/...: response exceeded byte cap (1054971 > 1048576 bytes)
stats     : 10 raw -> 10 unique, 5 fetched, context 23471 chars,
            timings {'search': 854, 'fetch': 1662, 'extract': 878, 'rank': 3}

Status: 0.1.0. See SPEC.md, CHANGELOG.md.

Features

  • One engine, three surfaces — the SDK core is the only pipeline; the MCP server and Open WebUI adapters are thin translators over it, so behavior and config semantics never drift between surfaces.
  • Full research pipelineresearch() runs search → fetch → extract → rank → assemble in one call and returns a numbered [N] context block with 1:1 source citations, ready to drop into a prompt.
  • Multi-provider search — zero-key ddgs out of the box; keyed Tavily / Brave / Serper / Exa and self-hosted SearXNG via config; ordered fallback chains with per-provider circuit breakers.
  • Hardened fetching — SSRF guard (private / reserved / metadata IP ranges blocked at connect time with pinned-IP enforcement), per-response byte caps, rotating 40-UA browser profile, concurrent fetches with deadline budgeting.
  • Quality extraction & ranking — trafilatura article extraction, BM25 reranking (golden-tested math), adaptive context budgeting: the most relevant pages get more of the character budget, marginal ones shrink, noise is dropped.
  • No-fail-silent contract — every degradation (blocked URL, truncated page, provider fallback, budget cut) is a typed, enumerable warning; nothing disappears without a trace.
  • LLM query expansion (optional) — expand a question into multiple search queries via any OpenAI-compatible endpoint or an injected callback.
  • Caching — in-memory by default, sqlite persistence a config flag away.
  • Typed throughout — pyright-strict clean, structured results on every surface (Pydantic models in the SDK, JSON structured output over MCP).
  • 688+ tests including live-web smoke suites and hand-computed golden tests.

How to use

Python SDK

pip install "websearch-kit[ddgs]"   # ddgs = the zero-API-key search provider
import asyncio
from websearch_kit import SearchKit

async def main():
    async with SearchKit() as kit:          # zero-config: ddgs, no keys, no LLM
        report = await kit.research("RISC-V vs ARM datacenter adoption")
        print(report.context)               # numbered [N] block for your LLM
        for s in report.sources:
            print(f"[{s.n}] {s.title}{s.url}")
        print(report.warnings)              # everything the run degraded on

asyncio.run(main())

Beyond research(), the kit exposes the pipeline stages individually:

results = await kit.search("python 3.14 free threading", count=5)     # snippets only
pages   = await kit.fetch(["https://docs.python.org/3.14/whatsnew/"])  # URLs, extracted
status  = await kit.health()                                           # provider probe

Prefer blocking code? SyncSearchKit mirrors the async API 1:1. Keyed providers, fallback chains, sqlite caching, and LLM query expansion are all config away — see docs/deployment/sdk.md and examples/.

MCP server

Add to your MCP client config (Claude Code, Claude Desktop, or any MCP client):

{
  "mcpServers": {
    "websearch-kit": {
      "command": "uvx",
      "args": ["--from", "websearch-kit[mcp,ddgs]", "websearch-kit-mcp"]
    }
  }
}

Four read-only tools with typed structured output, over stdio or streamable HTTP:

Tool What it does
web_search Snippet-level results — context-economical
fetch_page Read one URL as markdown, cursor pagination for long pages
research Full pipeline → [N] context block + one resource link per citation
health Provider latency, circuit-breaker state, config checks

For HTTP transport, scaling, and hardening flags see docs/deployment/mcp.md and examples/mcp_config_examples.md.

Open WebUI

Install the single-file filter from adapters/owui/websearch_kit_filter.py (Admin Panel → Functions → Import). It pip-installs this SDK automatically via its frontmatter requirements: line and uses your instance's configured web search out of the box.

Toggle the pill to research every message, or trigger one-off:

?? quantum routers --count 12 --lang en --reply de --fresh week

A Tool variant for model-invoked (agentic) use ships alongside it. See docs/deployment/owui.md.

Documentation

License

MIT — with a CI-enforced permissive-only dependency policy (no GPL/AGPL; trafilatura>=1.8.0 pinned for its Apache-2.0 relicense).

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

websearch_kit-0.2.0.tar.gz (497.4 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

websearch_kit-0.2.0-py3-none-any.whl (182.6 kB view details)

Uploaded Python 3

File details

Details for the file websearch_kit-0.2.0.tar.gz.

File metadata

  • Download URL: websearch_kit-0.2.0.tar.gz
  • Upload date:
  • Size: 497.4 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for websearch_kit-0.2.0.tar.gz
Algorithm Hash digest
SHA256 25f8cfd0cafd89e636c955c46990e6059052099c290d8ebfa0060afa80bf3b5a
MD5 ca14ae38e4892ec3cf86d326207a6e65
BLAKE2b-256 b175342b8d0d57f3a5b95e61bd81c3a0070946ae5720c1fa22c28ec4eee2a4e9

See more details on using hashes here.

Provenance

The following attestation bundles were made for websearch_kit-0.2.0.tar.gz:

Publisher: publish.yml on rmarnold/websearch-kit

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file websearch_kit-0.2.0-py3-none-any.whl.

File metadata

  • Download URL: websearch_kit-0.2.0-py3-none-any.whl
  • Upload date:
  • Size: 182.6 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for websearch_kit-0.2.0-py3-none-any.whl
Algorithm Hash digest
SHA256 e43f4ab1173278391a4c2bb72f6be6c64540a39c20cd38ea4c733092abd7a6e8
MD5 82cedd5e6c2c7675fbf675571d42de45
BLAKE2b-256 efddc8ab58dd421e48c806fa36f984e9e92cfd1705d8385f100e24162e9cb26f

See more details on using hashes here.

Provenance

The following attestation bundles were made for websearch_kit-0.2.0-py3-none-any.whl:

Publisher: publish.yml on rmarnold/websearch-kit

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page