Releases: ihor-sokoliuk/mcp-searxng
Release list
v1.11.0
Added
-
In-memory search result cache: Repeated
searxng_web_searchcalls with identical arguments are now served from a per-process cache instead of re-querying the instance, mirroring the existing URL-reader cache. The cache key is a SHA-256 of the tool name plus the search arguments canonicalized with sorted object keys, so semantically identical requests hit the same entry regardless of argument order, while any change to the query or parameters caches separately. Two new variables tune it:SEARCH_CACHE_TTL_MS(default86400000, 24 hours) sets the entry lifetime, andSEARCH_CACHE_MAX_ENTRIES(default200) caps the cache, evicting the least-frequently-used entry first with the oldest entry as the tie-breaker. Invalid or non-positive values fall back to the defaults. (FEAT-008, #164) -
Per-instance HTTP Basic Auth from
SEARXNG_URLuserinfo: Credentials can now be embedded directly in eachSEARXNG_URLentry (https://user:pass@host), and each semicolon-separated replica carries its own credentials — so a mixed deployment of one auth-gated private instance and one public instance no longer sends the private credentials to the public host. The legacy globalAUTH_USERNAME/AUTH_PASSWORDvariables are now a fallback used only for entries that have no userinfo, preserving existing single-instance setups. Percent-encode special characters in the username or password (for example, writep@ssasp%40ss). (FEAT-049, #160) -
SEARCH_USER_AGENToverride for SearXNG-instance requests: A new per-groupSEARCH_USER_AGENTvariable sets theUser-Agentfor all SearXNG-instance traffic —searxng_web_search,/configcapability discovery, and search suggestions — independently of theweb_url_readgroup'sURL_READER_USER_AGENT. Both groups fall back toUSER_AGENTwhen unset, and if neither the group override norUSER_AGENTis set, noUser-Agentheader is added. (FEAT-050, #150)
Fixed
-
Basic Auth and custom CA certs now applied on every SearXNG endpoint:
SEARXNG_URLBasic Auth credentials and theNODE_EXTRA_CA_CERTScustom CA bundle were previously honored on the main search request but not on the/configcapability-discovery and/autocompletersuggestion fetches, so those two paths failed against auth-gated or custom-CA instances. All three now go through the same authenticated, TLS-aware request path. A follow-up also fixes Windows, where settingNODE_EXTRA_CA_CERTShad dropped the bundled Mozilla root store instead of adding to it. (#152) -
Clearer "content too large" message from
web_url_read: When a page exceeds the size limit, the error now reports the size with an explicit, unambiguous unit and gives accurate advice for narrowing the request, replacing the earlier misleading wording. (#148)
Security
SEARXNG_URLuserinfo redacted in the config resource: Now that credentials can be embedded per instance, theconfigMCP resource redacts anyuser:pass@userinfo from the reported instance URLs, and thehasAuthindicator is userinfo-aware so it reflects embedded credentials as well as the legacyAUTH_USERNAME/AUTH_PASSWORDvariables — keeping embedded secrets out of client-visible configuration output.
Contributors
- @wchy1128 - #152 fix(auth+tls): Basic Auth on /config and /autocompleter; honor NODE_EXTRA_CA_CERTS everywhere
Full Changelog: v1.10.1...v1.11.0
v1.10.1
Fixed
USER_AGENTnow applied to the/configand suggestions requests: The configuredUSER_AGENTheader is now sent on the SearXNG/configinstance-info fetch and on search-suggestion fetches. These two paths previously always used the default agent while the main search andweb_url_readpaths already honoredUSER_AGENT, so instances that filter or rate-limit by User-Agent behaved inconsistently. The header is now merged in one shared request-config helper covering every outbound instance request. (BUG-009, #145)
Security
- SSRF guard now blocks CGNAT and the remaining IANA special-purpose IPv4 ranges: The private-address guard that protects
web_url_read— and the DNS-rebinding lookup hook that re-validates every resolved answer — previously only rejected RFC1918, loopback, link-local, and0.0.0.0/8. It now also blocks CGNAT (100.64.0.0/10, Tailscale's default range plus container overlays and ISP CGNAT), the TEST-NET ranges, benchmarking (198.18.0.0/15), IETF protocol assignments (192.0.0.0/24), 6to4 relay anycast, multicast (224.0.0.0/4), and reserved/broadcast (240.0.0.0/4). All blocked ranges are consolidated into a single auditable CIDR table (RFC 6890) enforced at both the literal-hostname and DNS-resolved paths; IPv4-mapped IPv6 delegates here and is covered too. (SEC-024, #147)
Full Changelog: v1.10.0...v1.10.1
v1.10.0
Added
-
Content-type-aware
web_url_read: The URL reader now inspects the responseContent-Typebefore converting. HTML is converted to markdown as before; JSON (application/jsonand*+json) is pretty-printed in a fenced block; and plain text, YAML, TOML, and XML are returned as readable fenced text. Binary, media, archive, and PDF responses are now rejected with a short hint instead of being decoded into unreadable bytes — fixing the case where fetching a PDF URL fed garbage to the model. Responses whose declared type is missing or generic are sniffed for a NUL byte in the first kilobyte and rejected if they look binary, which also catches binaries mislabeled astext/plain; anything textual continues through the existing HTML pipeline unchanged. (FEAT-045, #142, resolves #133) -
Actionable errors when a SearXNG instance returns non-JSON: When a search gets a
200response whose body is not JSON — an HTML results page because the instance never enabledformat: json, or a Cloudflare/WAF interstitial — the error now names both fixes (enable- jsonundersearch.formatsin the instance'ssettings.yml, or setSEARXNG_HTML_FALLBACK=true) while still including the response preview, instead of failing with an opaque "Invalid JSON format". (FEAT-053, #141, resolves #137) -
Documented
NODE_EXTRA_CA_CERTSfor Windows and corporate-proxy TLS: A new "TLS / Corporate CA" section inCONFIGURATION.mdexplains that Linux and macOS auto-detect the system CA bundle, while Windows users behind a TLS-inspecting corporate proxy (Zscaler, Netskope, Palo Alto, Blue Coat) must export the proxy's root CA to PEM and point the standard Node.jsNODE_EXTRA_CA_CERTSvariable at it — with the PowerShell export steps and an explicit warning never to use the insecureNODE_TLS_REJECT_UNAUTHORIZED=0. No code change; the variable was already honored by Node/undici. (FEAT-054, #143, resolves #138)
Full Changelog: v1.9.0...v1.10.0
v1.9.0
Added
- Configurable Express
trust proxyfor HTTP mode (MCP_HTTP_TRUST_PROXY): When the Streamable HTTP transport runs behind a trusted reverse proxy, setMCP_HTTP_TRUST_PROXYso Express resolves the real client IP fromX-Forwarded-Forbefore computing rate-limit keys and request logs. Acceptstrue, a trusted hop count such as1, or a subnet/preset such asloopbackor10.0.0.0/8; unset,false, or0disables it, which stays the secure default (enabling it without a real proxy in front lets clients spoofX-Forwarded-For). This is distinct from the outboundHTTP_PROXY/HTTPS_PROXYsettings that govern this server's own requests. (FEAT-051, #140)
Fixed
-
HTTP session recovered after a server restart: The Streamable HTTP
sessionsmap is in-memory, so a client that reused itsmcp-session-idacross a server restart got wedged — a freshinitializestill carried the stale header and fell through to400 / -32000.initializeis now accepted regardless of any stale session header, and unknown session IDs on non-initializePOSTs return404 / -32001 "Session not found"(matching the MCP SDK's own shape) so clients can detect a dead session and re-initialize. (BUG-010, #139) -
Search JSON-parse errors keep the real response preview: A
fetchresponse body is single-use, and the old path calledresponse.text()in the catch afterresponse.json()had already consumed it, so a JSON-parse failure always degraded to[Could not read response text]. The body is now read as text first and then parsed, so the error carries the actual response preview — making misconfigured or HTML-returning instances far easier to diagnose. (BUG-008, #131)
Security
SEARXNG_URLcredentials redacted in errors, logs, and provenance: Embedded userinfo (user:pass@host) inSEARXNG_URLno longer leaks into model-visible error messages, client logs, orservedByprovenance. A shared redaction helper is now applied at every instance-URL emission point — the aggregate failover error, theECONNREFUSEDnested message, request/fallback logs, error context, andservedBy. (BUG-007, #136)
Full Changelog: v1.8.0...v1.9.0
v1.8.0
Added
-
Multi-instance failover and optional parallel fanout for
SEARXNG_URL:SEARXNG_URLnow accepts several semicolon-separated SearXNG replica URLs that are treated as interchangeable. In the default failover mode a search tries each instance in order until one returns results; an instance with 3 consecutive hard failures is skipped for 60 seconds, while a200 OKwith an empty result set is treated as healthy and does not trigger cooldown. Set the newSEARXNG_FANOUT=trueto instead query all healthy instances in parallel and merge results — deduplicated by canonical URL, keeping the highest-scoring copy and ordered by descending score. A single-URLSEARXNG_URLbehaves exactly as before, so no configuration change is required. (FEAT-047, #128) -
Capability discovery aggregated across all instances for filter guidance:
searxng_instance_infoand thecategories/enginessearch parameters now aggregate live/configcapabilities from every reachable configured instance instead of a single one. The tool reportscommoncategories and engines (supported on every reachable instance, so safe for consistent multi-instance results) alongside best-effortavailablevalues, keeping filter guidance accurate when replicas differ in their enabled engines. A/configendpoint that fails is skipped for about 60 seconds, or retried immediately whensearxng_instance_infois called withrefresh=true. (FEAT-048, #130)
Fixed
-
safesearchaccepted as a string enum and honoring the instance default when omitted:safesearchis now declared as a string enum ("0","1","2") so MCP clients that send every tool argument as a string — notably Gemini and Antigravity — no longer fail schema validation. The schema default was also dropped, so omittingsafesearchnow falls back to each instance's server-side default instead of forcing a value. (BUG-006, #127) -
Docker Compose HTTP transport reachable from the host: The HTTP transport in the provided
docker-composesetup now binds to0.0.0.0instead of a loopback address, so the mapped port is reachable from the host rather than only from inside the container.
Full Changelog: v1.7.2...v1.8.0
v1.7.2
Security
- Container image now runs as a non-root user (UID 1000): The published Docker image previously ran as
root, so Kubernetes deployments using therunAsNonRoot: truepod security context were rejected at admission. The image now sets a numericUSER 1000(thenodeaccount already present in thenode:lts-alpinebase), which satisfiesrunAsNonRootwithout an additionalrunAsUseroverride and reduces the container's blast radius. No configuration change is required. (Reported by @nogweii, #122)
Full Changelog: v1.7.1...v1.7.2
v1.7.1
Security
- DNS-resolved private-address SSRF in
web_url_readblocked (GHSA-mrvx-jmjw-vggc): The URL reader previously validated only the literal hostname string, so a public-looking hostname that DNS-resolves to a private, loopback, or link-local address (for example a domain pointing at127.0.0.1/10.0.0.0/8or a cloud metadata endpoint like169.254.169.254) bypassed the SSRF guard. Direct (no-proxy) reads now validate every resolved DNS answer before connecting and pin the connection to the validated address, closing the DNS-rebinding window. TheMCP_HTTP_ALLOW_PRIVATE_URLS=trueopt-out still applies. When a URL-reader proxy is configured the proxy performs DNS resolution, so those deployments must rely on egress/firewall controls (documented inSECURITY.md). - Unbounded response-body read in
web_url_readcapped (GHSA-xcqx-9jf5-w339): The page-size limit was advisory only — a server using chunked transfer encoding, a failing/absent HEAD response, or a body larger than its reportedContent-Lengthcould force the entire response into memory (denial of service). The body is now read through a bounded stream that enforcesURL_READ_MAX_CONTENT_LENGTH_BYTES(default 5 MB) against the decompressed size and stops once the cap is exceeded, before any conversion or caching.
Full Changelog: v1.7.0...v1.7.1
v1.7.0
✨ Added
- HTML-search fallback (
SEARXNG_HTML_FALLBACK=true) — opt-in compatibility mode for SearXNG instances that disable JSON output. When a search hits a403/404or a non-JSON response, it is automatically retried withoutformat=jsonand results (title, URL, snippet) are parsed from the regular HTML results page and markedsourceFormat: "html". Triggers strictly on format rejections — never on401,5xx, network, or timeout errors. Enabling JSON on a SearXNG instance you control remains the recommended setup (see the README troubleshooting section).
🔒 Security
undici→ 7.28.0 — resolves two HIGH advisories affecting 7.0.0–7.27.2: GHSA-vmh5-mc38-953g (TLS certificate validation bypass in the SOCKS5ProxyAgent) and GHSA-pr7r-676h-xcf6 (cross-user information disclosure via shared-cache whitespace bypass).form-data→ 4.0.6 — clears a CRLF-injection advisory (GHSA-hmw2-7cc7-3qxx) in the test toolchain.
Full Changelog: v1.6.0...v1.7.0
v1.6.0
This release rolls up everything since v1.4.0. Note: 1.5.0 was published to npm and Docker Hub on 2026-06-12 but never received a GitHub release — those changes are included below alongside the new 1.6.0 work.
✨ Added
enginesparameter onsearxng_web_search— a comma-separated list (e.g.google,bing,duckduckgo) routes a search to specific SearXNG engines instead of the category defaults.- Validated & normalized
categories/engines— values are trimmed and matched case-insensitively against the connected instance's live/config, and canonical names are sent to SearXNG. Unknown values are rejected up front with the available options listed, fixing silent search degradation from miscased names. - Configurable URL cache controls —
CACHE_TTL_MS(default 24 h) andCACHE_MAX_ENTRIES(default 500). - Bounded URL cache eviction — entries track hit counts and use LFU eviction with oldest-entry tie-breaking.
searxng_suggestionstool — returns search autocomplete suggestions from the instance.searxng_instance_infotool — discovers instance capabilities (engines, categories, languages, safe-search).- JSON response format —
searxng_web_searchacceptsresponse_format("text"|"json") for programmatic result processing. - Search metadata in text output — answers, spelling corrections, infoboxes, and suggestions surface alongside ranked results.
🔧 Changed
- URL cache TTL default raised from 60 s to 24 h within a running server (entries still expire/evict).
🐛 Fixed
- Metadata (answers, corrections, infoboxes) is preserved in text output even when
min_scorefilters out all web results. - Unresponsive engines are no longer listed in text output.
searxng_suggestionsandsearxng_instance_infonow route through the configured search proxy and default TLS dispatcher.
🔒 Security
- Least-privilege Docker workflow permissions —
security-events: writeis isolated to a dedicated image-scan job in both the publish and rebuild workflows, withid-token: writeconfined to the publish/sign job and workflow-level permissions kept read-only. - Patched bundled
hono— pinned the transitivehonodependency to ≥ 4.12.25 (npmoverrides) to resolve CVE-2026-54290 (CORS middleware origin reflection) in the published Docker image.
🏗️ Build / CI
- Added a CI workflow running lint plus unit and integration tests on every pull request and push to
main.
Full Changelog: v1.4.0...v1.6.0
v1.5.0
Backfilled release —
1.5.0was published to npm and Docker Hub on 2026-06-12 but the GitHub release was missed at the time.
✨ Added
searxng_suggestionstool — returns search autocomplete suggestions from the SearXNG instance.searxng_instance_infotool — discovers the connected instance's capabilities (enabled engines, supported categories, available languages, safe-search settings).- JSON response format —
searxng_web_searchaccepts aresponse_formatparameter ("text"|"json");"json"returns raw structured data for programmatic processing. - Search metadata in text output —
searxng_web_searchtext responses now include answers, spelling corrections, infoboxes, and autocomplete suggestions when the instance returns them.
🐛 Fixed
- Metadata (answers, corrections, infoboxes) is preserved in text output even when
min_scorefilters out all web results. - Unresponsive engines are no longer listed in text output.
searxng_suggestionsandsearxng_instance_inforequests route through the configured search proxy and default TLS dispatcher.
Full Changelog: v1.4.0...v1.5.0