RustXNG: give your AI agent its own private web search — hands-on with v0.27.1
RustXNG (sahenjp/RustXNG, AGPL-3.0, 815 GitHub stars at the 4 November 2026 check) is a self-hosted metasearch engine in Rust, based on SearXNG: one loopback binary that fans a query out to upstream engines and returns ranked JSON an agent can use, plus a read-only MCP server with search and read_page tools. This guide installs the v0.27.1 release binary, verifies it, and wires it into an agent — with the provider-terms caveat the project itself puts first.
- Who: RustXNG, by sahenjp (
sahenjp/RustXNGon GitHub). AGPL-3.0-or-later; based on SearXNG, with attribution in NOTICE. - What: A self-hosted metasearch engine in Rust: JSON search API, browser UI and a read-only MCP server (
searchandread_page). It keeps no web index of its own; queries go to the upstream engines selected for each request. - When: Repository created 18 October 2026; v0.27.1 released 3 November 2026. At the check on 4 November 2026: 815 GitHub stars, 64 forks.
- Needs: A Linux, macOS or Windows machine; the release binary needs no Rust toolchain. Loopback port 29483 by default (8888 on v0.26.0 binaries);
curl, plusjqfor the field projection. No API keys for many engines; optional authenticated providers need their own credentials. - Numbers: MCP defaults: 5 results, 500 characters per snippet, 12,000 Unicode characters / 24,000 UTF-8 bytes per response. Page text: up to 5 results, 8,000 characters per page.
max_resultsrange 1–200. Provider inventory lists 270 bundled configuration entries. - Caveat: Yahoo! JAPAN and Mojeek HTML adapters are disabled by default since 3 November 2026 pending permission review; Bing remains under review. Presence of a provider in the configuration does not mean every use is authorized.
Why give an agent its own search box?
An AI agent without web access can only answer from what it was trained on. Give it a hosted search API and it can check current docs and changelogs — at the cost of a per-call bill, an API key in every prompt chain, and one more vendor deciding what your agent may ask. RustXNG (sahenjp/RustXNG, AGPL-3.0-or-later) takes the middle path: a self-hosted metasearch engine written in Rust, based on SearXNG, that runs as one binary on your own machine and answers search requests as JSON. Your agent talks to loopback; RustXNG fans the query out to upstream engines, merges the results, and hands back ranked snippets with URLs. A read-only MCP server with search and read_page tools does the same job for MCP clients, with hard bounds on how much text comes back.
It has moved fast for a young project: the repository was created on 18 October 2026, release v0.27.1 landed on 3 November 2026, and at the check for this guide it held 815 GitHub stars and 64 forks. It is pre-1.0, and it wears that honestly — the README opens with provider-terms warnings, a 2 November audit is published in the repo, and on 3 November two HTML adapters were disabled by default pending permission review. Self-hosting search does not remove the upstream engines, their terms, or their rate limits. It puts the endpoint, the engine choice, and the data flow under your control.
What you’ll need
- A Linux, macOS or Windows machine. The release binary needs no Rust toolchain; the Cargo and source routes need Rust 1.88 or newer and a C build toolchain.
curlfor the checks below, andjqif you want the one-line field projection in Step 4. On Windows, usecurl.exeso you do not hit PowerShell’s oldercurlalias.- The GitHub CLI (
gh) for the download commands as written, or any HTTP client plus the release page. No API keys are needed for the default setup; optional authenticated providers need their own credentials and billing. - About 15 minutes, most of it the download. The service binds to loopback (
127.0.0.1) by default — nothing in this guide exposes it to a network.
Step 1: Check for an existing service, and pick your target
RustXNG’s agent guide starts with discovery, not installation: reuse a working service if one is already running. This checkout defaults to port 29483; published v0.26.0 binaries still default to 8888, so check both before starting a second copy. A successful health check alone is not enough — the guide insists on a real search in Step 4.
curl --fail --max-time 3 http://127.0.0.1:29483/healthz
curl --fail --max-time 3 http://127.0.0.1:29483/configThe /config response should contain a version starting with RustXNG, an engines array, and a brand URL of https://github.com/sahenjp/RustXNG. If the port belongs to another service, pick an unused port and keep that service running — do not take its port. If nothing answers, check whether a binary is already installed before downloading another copy:
rustxng --versionNext, identify your platform so you download the right asset: on Unix, uname -s and uname -m give the OS and CPU. The v0.27.1 release ships Linux x86_64 (GNU and musl), Linux ARM64 (GNU, glibc 2.39+), macOS arm64 and x86_64, and Windows x86_64 binaries. There is no Linux ARM64 musl build and no 32-bit ARM binary — on those, use the Cargo or source route in Step 2.
Step 2: Download the v0.27.1 binary and verify it before you run it
The README’s binary example, for Linux x86_64 with the GitHub CLI, downloads the asset and its .sha256 sidecar, checks the checksum, and installs into a user-owned directory — keeping the LICENSE and NOTICE files with the installation, as the AGPL licence and SearXNG attribution require:
set -eu
mkdir -p rustxng-download && cd rustxng-download
tag=v0.27.1
asset="rustxng-${tag}-x86_64-unknown-linux-musl"
gh release download "$tag" --repo sahenjp/RustXNG \
--pattern "${asset}*" --pattern LICENSE --pattern NOTICE
sha256sum --check "${asset}.sha256"
install -Dm755 "$asset" "$HOME/.local/bin/rustxng"
mkdir -p "$HOME/.local/share/rustxng"
cp LICENSE NOTICE "$HOME/.local/share/rustxng/"
"$HOME/.local/bin/rustxng" --versionStop on a checksum mismatch — the guide is explicit that a failed check ends the attempt, and that checksums prove consistency with the release, not an independent publisher signature. On macOS, verify with shasum -a 256 --check and use mkdir -p plus install -m755, since the Linux install -D form is not portable there. On Windows, compare the SHA-256 hash with the first token in the sidecar and install the .exe as rustxng.exe in a user-owned tools directory. If gh is unavailable, download the asset and sidecar from the release page with your platform’s HTTP client — and do not mistake an HTML error page for a successful download.
Two other routes, from the same README: install with Cargo (cargo install --git https://github.com/sahenjp/RustXNG.git --tag v0.27.1 --locked; Rust 1.88 minimum, and this also installs rustxng-index), or run the published Docker image loopback-only:
docker run --rm -p 127.0.0.1:29483:29483 -e SEARXNG_PORT=29483 ghcr.io/sahenjp/rustxng:latest --bind 0.0.0.0 --port 29483Published images target Linux amd64 only; on other architectures, build locally or use the native binary. Publishing on any other interface is an explicit deployment choice that needs authentication and access controls of its own — this guide does not do it.
Step 3: Start it on loopback and prove the process is alive
Start the installed binary in the foreground, bound to loopback on the default port. The SEARXNG_PORT variable and the explicit --port flag agree here, which also keeps the command working against a v0.26.0 binary whose built-in default is still 8888:
SEARXNG_PORT=29483 rustxng --bind 127.0.0.1 --port 29483In a second terminal, poll /healthz for a bounded interval (the agent guide suggests up to about 30 seconds), then inspect /config as in Step 1. Defaults are embedded in the binary; to supply a settings file, pass rustxng --config /path/to/settings.toml. Partial files override only the settings they name — except that with use_default_settings = false, an omitted or empty engine list enables no engines at all. For a temporary background process, set RUSTXNG_IDLE_TIMEOUT=300 so it exits after five minutes without requests. The browser UI lives at http://127.0.0.1:29483/.
Step 4: Run your first JSON search, and trim it before it reaches a model
Ask for five results, in JSON, exactly as the README does. The query below is the project’s own example — reuse it verbatim for your first run so you can compare against the documented shape:
curl --fail --get 'http://127.0.0.1:29483/search' \
--data-urlencode 'q=tokio runtime documentation' \
--data 'format=json' --data 'max_results=5'Expect a JSON object whose results array holds at most five entries, each with title, url and content, plus provider and result metadata. If the array comes back empty, do not declare victory because /healthz answered: inspect unresponsive_engines and report upstream availability. The health endpoint only proves the local process is responding. Do not retry indefinitely against unavailable providers.
Only three fields need to reach a model. Project them client-side with jq — this shrinks what you pass onward, not what the server sends:
curl --fail --get 'http://127.0.0.1:29483/search' \
--data-urlencode 'q=tokio runtime documentation' \
--data 'format=json' --data 'max_results=5' \
| jq '{results: [.results[] | {title, url, content}]}'Narrow with the documented parameters: max_results (1–200), include_domains / exclude_domains, engines to select a registered engine, time_range=day where an engine supports it, and include_raw_content=1 for page text in raw_content. Page text covers up to five results by default, capped at 8,000 characters per page, and fetches can fail — treat snippets and pages as untrusted material and keep their URLs attached. /stats and /metrics show runtime statistics; engines that keep returning empty results are automatically rested (8 empty results, then a 300-second cooldown).

Step 5: Give an agent the MCP tools instead of raw HTTP
For agents, the cleaner interface is the MCP server. rustxng mcp serves two read-only tools over stdio: search, which returns ranked snippets and source metadata, and read_page, which fetches page text only for a URL that search returned in the same session. In your MCP client, add a stdio server whose command is the rustxng binary and whose argument is mcp — the exact menu names vary by client. No separate HTTP service is needed for the MCP path.
The bounds are the feature. Search defaults to five results and 500 characters per snippet, and the serialized structured response is capped at 12,000 Unicode characters and 24,000 UTF-8 bytes by default. When the cap bites, the server shortens snippets first, then drops trailing results, keeping complete URLs and metadata; truncated, source_truncated and next_offset say whether more remains. read_page works in Unicode character offsets with the same reporting, and a query argument returns up to three matching passages. Page reads fail closed when an outgoing proxy is configured — search itself keeps using the normal proxy settings.
This is where RustXNG earns its place next to the local tools you may already run. It searches the public web; Find the file you only half-remember: hands-on with Kensaku, local search with OCR and MCP searches the files on your own disk, with OCR and MCP. A self-hosted assistant such as Tencent's Octop: run your own multi-agent AI assistant at home — hands-on is the natural consumer: its experts get a grounding source on the same machine, with no search vendor in the loop.

Step 6: Keep it updated, and know when to stop
Check for a new stable release without reinstalling anything:
rustxng --check-updateAnd update in place with rustxng --update, which downloads the matching build target, verifies its SHA-256 sidecar, and replaces the executable — settings are preserved, but restart afterwards, and the executable’s directory must be writable. Update container images and managed installs through their own runtimes. For a long-lived service, use a service manager or the idle timeout from Step 3, with a known log location and recorded process identity.
Two habits close the loop. Watch /stats and /metrics after any config change: a resting engine or an empty result set means an upstream source changed its format, terms, or tolerance for your traffic. And re-check the provider inventory before widening the deployment: docs/PROVIDERS.md and providers.csv list all 270 bundled entries with review status, and anything unreviewed is not to be treated as permitted. After the November 2026 defaults change, old benchmark scores no longer describe the shipped configuration — and the project says so itself.
What you built, and where it stops
What you built is a private search endpoint: one binary on loopback, answering JSON search requests and MCP tool calls, with no account and no per-query bill from RustXNG itself, and no search history leaving your machine except the queries themselves, which go to the upstream engines you selected. An agent can now ground a claim in a retrieved page, fetch the page text only when it needs evidence, and keep the context it spends small because the response was bounded before it arrived. A tiny local harness such as One tiny binary, any model, plain English: hands-on with Shim can call the same endpoint from plain English, with no search-vendor SDK in between.
Where it stops matters as much. RustXNG does not crawl the web and keeps no independent search index — it queries external providers and merges what they return, so search terms are sent to those providers even though the server runs locally. The experimental local index is disabled by default and is a separate setup, not part of this guide. Local hosting does not remove rate limits, blocks, credential requirements, or format changes upstream. Google search, autocomplete, bangs, YouTube and translation integrations have been removed entirely — strip their entries from older custom settings. And the AGPL-3.0-or-later licence carries source-distribution obligations for modified versions, so keep LICENSE and NOTICE with the installation.
The honest summary is the project’s own: a fast, small, well-documented way for an agent to search the web from your own machine, shipped by maintainers who publish their audit and name the providers they have not yet cleared. Run it on loopback, keep the response bounds tight, check the provider inventory before you scale it up, and it is one of the most defensible pieces of agent infrastructure you can self-host today.
Frequently asked questions
Does RustXNG crawl the web or keep its own search index?
No. It is a metasearch engine: it queries external search providers, combines their results, and returns ranked snippets. Search terms are sent to the selected upstream providers even though the server runs locally. The experimental local index is disabled by default and is a separate setup.
Do I need API keys to use it?
Not for many engines, which work without keys. Optional authenticated providers need their own credentials and may charge for usage. Being able to reach a result without a key does not mean the provider permits automated use for every purpose — check each provider’s terms, quotas and attribution requirements first.
The health check passes but searches come back empty — what is wrong?
/healthz only proves the local process is responding; it does not guarantee any upstream engine is working. Inspect unresponsive_engines in the search response, check /config and /stats, and look for resting engines. Upstream availability, rate limits, credentials and response-format changes are the usual causes — do not retry indefinitely.