Skip to main content

Cluefinch MCP

Cluefinch is a local-first, version-aware research navigation layer for agents. It provides SearXNG search, HTML reading, and source collection without a separate LLM or paid search API. The agent plans, evaluates evidence, and writes conclusions; the server supplies research capabilities.

Repository | Issues | Agent workflow

Install

Requires Python 3.12.4+. After the first PyPI release, use an activated virtual environment:

pip install cluefinch
cluefinch

This starts an MCP stdio server, not an interactive shell or web interface. Connect it to an MCP client. Search requires a separate SearXNG instance with JSON output enabled. Its default address is http://127.0.0.1:8081; override it with MCP_SEARCH_SEARXNG_URL. The package does not install SearXNG. These commands describe installation after publication, not a claim that the package is already published. Neither uv nor Docker is required to install it.

Do not install mcp-search and cluefinch in the same environment: both can own the mcp_search files. Prefer a new virtual environment. To reuse an existing one, run pip uninstall mcp-search before pip install cluefinch. The Python package remains mcp_search; python -m mcp_search and all MCP_SEARCH_ settings remain supported.

Install from source

From a checkout of this repository, with uv installed:

uv sync --locked
python scripts/init_env.py
docker compose up -d
uv run cluefinch

Docker is only needed for the supplied SearXNG deployment. Reuse an existing SearXNG instance if available. The sample binds to loopback port 8081. For a different port, set SEARXNG_PORT in .env and update the MCP client's MCP_SEARCH_SEARXNG_URL accordingly.

init_env.py creates a unique secret without overwriting an existing .env. Compose passes it as SEARXNG_SECRET. Never commit .env or your local searxng/settings.yml. SEARXNG_IMAGE accepts a tested tag or digest; the default searxng/searxng:latest is a development convenience, not a pinned release configuration. Upstream changes can affect search results.

Connect an MCP client

For clients using mcpServers, point to the interpreter in your environment:

{
  "mcpServers": {
    "cluefinch": {
      "command": "/absolute/path/.venv/bin/python",
      "args": ["-m", "mcp_search"],
      "env": {"MCP_SEARCH_SEARXNG_URL": "http://127.0.0.1:8081"}
    }
  }
}

On Windows, use a path such as C:\\path\\.venv\\Scripts\\python.exe. Client configuration formats vary. Alternatively configure the installed cluefinch executable with no arguments.

Tools

Tools publish typed input and output schemas, including nested sources and excerpts. Responses are validated before sending. Text JSON and MCP structuredContent have the same flat structure. Expected failures return error and hint instead of success fields.

Task Tool or action
Find candidate sources web_search(query="...", max_results=5)
Restrict a domain and exclude others web_search(query="...", domain="python.org", exclude_domains=["discuss.python.org"])
Preview a page web_fetch(url="...", max_chars=500)
Continue reading when needed Call response.continuation.tool with response.continuation.arguments if non-null
Expand a selected excerpt Call excerpt.expand.tool with excerpt.expand.arguments
Collect selected pages research_collect(urls=[...])
Collect query variants research_collect(queries=[...], topic="...", max_sources=5)

topic alone does not start a search. Explicit URLs take priority; remaining candidate slots are shared round-robin between query variants. max_sources limits attempted candidates, not guaranteed successful sources. The server does not invent replacement queries or sources.

Reading and version checks

max_chars defaults to 10,000, capped at 20,000 in the default configuration. A preview reduces returned context, not the initial page download. Ready actions contain {tool, arguments} with the final URL, exact offset, reading budget, and expected_content_hash. Actions are optional; generating them makes no additional network request. Clients may qualify the local tool name with a server prefix.

Continuation preserves the effective reading budget. continuation: null means the retained text has ended. Expansion starts at the excerpt's start; its default budget is 3,000 characters, capped by MAX_FETCH_CHARS. You can adjust the budget while keeping the expected hash.

If the retained text differs, the server returns content_changed with no slice or automatic retry. Reacquire the source without the old hash and select coordinates again. A changed hash does not prove an old citation was false. A matching hash is not a freshness check against the origin. Cached text can still match after the website changes. Hashes do not identify cache hits or changes beyond the retained extraction.

Manual reading remains available through start_offset=response.next_start or start_offset=excerpt.start_char. Supply the corresponding source hash as expected_content_hash for server-side version checking. Without it, reading is unguarded. For preceding context, reduce the offset without going below zero. Offsets count Python Unicode characters, not bytes or UTF-16 code units.

truncated means more retained text remains after the slice. text_truncated means extraction exceeded the retained-text limit; pagination cannot recover that discarded tail. total_chars is the retained length.

Sources and limitations

source_id is src_ plus the first 16 hex characters of the normalized final URL's SHA-256. It is stable across calls and restarts, but does not identify a document version. content_hash hashes the entire retained extracted text.

Excerpts are literal slices: excerpt.text == text[start_char:end_char]. BM25 uses positive IDF and bounded passages from long paragraphs. When no positive matches exist, leading eligible passages are returned. There is no lemmatization or semantic relevance assessment. heading is local context, not a full outline. Author, publication date, and HTML canonical URL are not part of this contract.

source_type is a domain-based category, not a credibility rating. Unrecognized domains receive unknown. Domain search operators depend on external engine support. Search pagination is not implemented; max_results controls result count.

Inspect unresponsive_engines and collection gaps for provider failures, blocked/unreadable sources, duplicates, and limits. Empty gaps do not establish topic completeness. The agent decides whether evidence is sufficient.

After upgrading, restart the MCP connection so the client reloads schemas. Version 0.1.3 adds response fields; clients validating against an older strict schema must update it. Source installations should run uv sync --locked.

Configuration

Pass settings in the MCP process environment. Only Docker Compose automatically reads .env. Restart the server after changing settings. Numeric configuration values must be positive and finite.

Variable, prefixed with MCP_SEARCH_ Default
SEARXNG_URL http://127.0.0.1:8081
ENGINES google,bing,duckduckgo,wikipedia
UA Cluefinch/<version> (+https://github.com/cluefinch/mcp-server)
MAX_RESULTS / MAX_SOURCES / MAX_QUERIES 20 / 10 / 10
MAX_FETCH_CHARS / MAX_TEXT_CHARS 20,000 / 100,000 characters
EXPAND_CHARS 3,000 characters, capped at MAX_FETCH_CHARS
MIN_EXTRACTED_CHARS 100 characters
MAX_RESPONSE_BYTES 5,242,880 bytes, checked before and after decompression
MAX_REDIRECTS 5
DOWNLOAD_TIMEOUT 60 seconds, including redirects
FETCH_CONCURRENCY / HOST_INTERVAL 3 / 5 seconds between request starts per hostname
SEARCH_INTERVAL 5 seconds after each SearXNG request completes
FETCH_TTL / SEARCH_TTL 600 / 300 seconds
CACHE_ENTRIES 500 per cache

MCP_SEARCH_UA sets the outgoing User-Agent for page downloads, including pages collected by research_collect. The default identifies Cluefinch and uses the installed package version. Override it for a deployment-specific identity and restart the MCP server. It does not change SearXNG's own requests to search engines.

Search requests are serialized with a five-second pause after completion, including failures. Page downloads use a separate five-second start-to-start interval per hostname and never overlap for that hostname. Up to three downloads to different hosts can run concurrently; redirects also pass through the limiter. Cache hits do not download the page or repeat the search. Limits are per MCP process, not shared across processes or subdomains. Waiting for a page-download slot counts toward DOWNLOAD_TIMEOUT.

These intervals reduce request frequency; they do not guarantee acceptance by a website. The server does not currently enforce robots.txt or Retry-After, and does not automatically retry failed downloads. Respect site and provider policies.

To add engines, update both SearXNG and MCP_SEARCH_ENGINES. When a call omits engines, search uses SearXNG's enabled engines. Caches are process-local with TTL and LRU limits. Character limits are not memory-size limits.

Support and security boundaries

Supports HTML/XHTML over HTTP(S). JavaScript rendering, PDF, authentication, CAPTCHA solving, and bypassing access restrictions are not implemented. Insufficient extracted text produces an error; this can indicate a short page as well as a JavaScript-rendered page. The transport requests gzip/identity; unsupported encodings and malformed or concatenated gzip fail explicitly. Decoding considers HTTP charset, BOM, and HTML meta-charset.

Outbound fetching rejects URL credentials, private/local/reserved and multicast IP addresses, scoped hosts, and mixed public/private DNS answers. Redirects are validated. Connections use validated numeric IPs while retaining the original hostname for Host, TLS SNI, and certificate verification. Environment proxies are disabled. Custom NAT64 prefixes or unusual routing require an infrastructure egress policy. Request limits apply to actual HTTP transitions, including redirects.

These controls do not filter prompt injection. Retrieved content is untrusted data, not instructions. The sample deployment is local, not a public hosted-service security profile. See the security policy.

Development

uv sync --locked
uv run pytest -q
uv run ruff check mcp_search tests scripts
uv run ruff format --check mcp_search tests scripts
uv build

Tests include real MCP stdio exchanges without external network access. uv run python scripts/smoke.py additionally checks live search and pages; it needs internet and SearXNG and accepts --url and --query overrides. CI checks Windows/Linux with Python 3.12/3.13.

See development checks and publishing.

License

Original code is licensed under Apache-2.0. NOTICE and third-party notices describe component boundaries. SearXNG is a separate AGPL-licensed service; the core license does not cover its code, dependencies, or retrieved content.

See contributing for Apache-2.0 and DCO requirements, and SearXNG integration requirements before bundling SearXNG or deploying a hosted service.

Release files for cluefinch 0.1.3

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for cluefinch 0.1.3
File Size Uploaded
cluefinch-0.1.3.tar.gz 143.3 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for cluefinch 0.1.3
File Interpreter ABI Platform
cluefinch-0.1.3-py3-none-any.whl Python 3 none any Details

Total release size: 188.4 kB

Release files / cluefinch-0.1.3.tar.gz

Download URL cluefinch-0.1.3.tar.gz
Size 143.3 kB
Tags Source
SHA-256 checksum
How to use checksums
612360024952d31170e3c4bb1a5bb3a94b4f6e868bc74ce980e30e87ace96499
BLAKE2b-256 checksum
How to use checksums
a942eba2a91c42c6903db00006ca93f0bfa527a319061f879041303a16166301
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 15, 2026.

Transparency log

Release files / cluefinch-0.1.3-py3-none-any.whl

Download URL cluefinch-0.1.3-py3-none-any.whl
Size 45.1 kB
Tags Python 3
SHA-256 checksum
How to use checksums
48cb1cf6f4f871fc9be5eb821f75992e7ae6a5a09f796c13c394f772823526d8
BLAKE2b-256 checksum
How to use checksums
8ea4c0e234a322a4f3bdf639adb9d527fbfa9146a08f91f2bb994e1803cf5929
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 15, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

0.1.3 This release

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page