<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Documentation on BetterWebSearch MCP</title><link>https://phantompixeldev.github.io/BetterWebSearch-MCP/docs/</link><description>Recent content in Documentation on BetterWebSearch MCP</description><generator>Hugo</generator><language>en</language><atom:link href="https://phantompixeldev.github.io/BetterWebSearch-MCP/docs/index.xml" rel="self" type="application/rss+xml"/><item><title>Quickstart</title><link>https://phantompixeldev.github.io/BetterWebSearch-MCP/docs/quickstart/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://phantompixeldev.github.io/BetterWebSearch-MCP/docs/quickstart/</guid><description>&lt;p&gt;BetterWebSearch works out of the box with &lt;strong&gt;DuckDuckGo&lt;/strong&gt; — no API keys, no &lt;code&gt;.env&lt;/code&gt;, no configuration.&lt;/p&gt;&#10;&lt;h2 id="option-1-npx-recommended"&gt;Option 1: npx (recommended)&lt;a class="anchor" href="#option-1-npx-recommended"&gt;#&lt;/a&gt;&lt;/h2&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;npx -y better-web-search-mcp --help &lt;span style="color:#75715e"&gt;# keyless — DuckDuckGo works immediately&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;npx -y better-web-search-mcp &lt;span style="color:#75715e"&gt;# start MCP stdio server&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Or install globally:&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;npm i -g better-web-search-mcp&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;better-web-search-mcp --help&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;better-web-search-mcp --version&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="option-2-from-source-30s"&gt;Option 2: From source (30s)&lt;a class="anchor" href="#option-2-from-source-30s"&gt;#&lt;/a&gt;&lt;/h2&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;git clone https://github.com/PhantomPixelDev/BetterWebSearch-MCP.git&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;cd BetterWebSearch-MCP&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;npm install&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;npm run build&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;npx better-web-search-mcp --help&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;BRAVE_API_KEY&lt;span style="color:#f92672"&gt;=&lt;/span&gt; npx better-web-search-mcp &lt;span style="color:#75715e"&gt;# still works, DuckDuckGo fallback&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;No &lt;code&gt;.env&lt;/code&gt; required for the first test. The server boots, prints a provider banner to stderr, and every tool works.&lt;/p&gt;</description></item><item><title>Installation</title><link>https://phantompixeldev.github.io/BetterWebSearch-MCP/docs/installation/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://phantompixeldev.github.io/BetterWebSearch-MCP/docs/installation/</guid><description>&lt;h2 id="requirements"&gt;Requirements&lt;a class="anchor" href="#requirements"&gt;#&lt;/a&gt;&lt;/h2&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;Node.js 20+&lt;/strong&gt; and &lt;strong&gt;npm&lt;/strong&gt;&lt;/li&gt;&#10;&lt;li&gt;No API keys required — DuckDuckGo works out of the box&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;h2 id="install-via-npx-no-install"&gt;Install via npx (no install)&lt;a class="anchor" href="#install-via-npx-no-install"&gt;#&lt;/a&gt;&lt;/h2&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;npx -y better-web-search-mcp --help &lt;span style="color:#75715e"&gt;# keyless — DuckDuckGo works immediately&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;npx -y better-web-search-mcp &lt;span style="color:#75715e"&gt;# start MCP stdio server&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="install-globally"&gt;Install globally&lt;a class="anchor" href="#install-globally"&gt;#&lt;/a&gt;&lt;/h2&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;npm i -g better-web-search-mcp&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;better-web-search-mcp --help&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;better-web-search-mcp --version&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="install-from-source"&gt;Install from source&lt;a class="anchor" href="#install-from-source"&gt;#&lt;/a&gt;&lt;/h2&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;git clone https://github.com/PhantomPixelDev/BetterWebSearch-MCP.git&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;cd BetterWebSearch-MCP&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;npm ci&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;npm run build&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;npm test &lt;span style="color:#75715e"&gt;# 189+ tests, keyless suite&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;npx tsc --noEmit &lt;span style="color:#75715e"&gt;# lint&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="native-binding-note"&gt;Native binding note&lt;a class="anchor" href="#native-binding-note"&gt;#&lt;/a&gt;&lt;/h2&gt;&#10;&lt;p&gt;&lt;code&gt;better-sqlite3&lt;/code&gt; needs a compiled native addon. If it fails to load (older Node, missing build tools, CI sandbox), the cache automatically falls back to an in-memory Map — no action needed. To restore the SQLite cache, run &lt;code&gt;npm rebuild better-sqlite3&lt;/code&gt; (Node 20+ recommended).&lt;/p&gt;</description></item><item><title>Tools Reference</title><link>https://phantompixeldev.github.io/BetterWebSearch-MCP/docs/tools/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://phantompixeldev.github.io/BetterWebSearch-MCP/docs/tools/</guid><description>&lt;p&gt;BetterWebSearch MCP exposes &lt;strong&gt;6 tools&lt;/strong&gt; (5 unique + 1 alias). All are keyless-first — DuckDuckGo provides search without any API keys.&lt;/p&gt;&#10;&lt;h2 id="overview"&gt;Overview&lt;a class="anchor" href="#overview"&gt;#&lt;/a&gt;&lt;/h2&gt;&#10;&lt;table&gt;&#10;&#9;&lt;thead&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;Tool&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;What it does&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;Keyless?&lt;/th&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/thead&gt;&#10;&#9;&lt;tbody&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;web_search&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Fast search (aggregated, deduped, reranked)&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;✓&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;web_research&lt;/code&gt; / &lt;code&gt;deep_search&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Deep research: rewrites question → parallel searches → top-10 extraction → citations&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;✓&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;web_extract&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Clean extraction &lt;code&gt;HTTP → hydration → browser&lt;/code&gt; with &lt;code&gt;confidence&lt;/code&gt; &amp;amp; &lt;code&gt;api_endpoints&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;✓&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;web_find&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;site:&lt;/code&gt; scoped search&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;✓&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;web_news&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Recent news + timeline + diversity&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;✓&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/tbody&gt;&#10;&lt;/table&gt;&#10;&lt;hr&gt;&#10;&lt;h2 id="web_search"&gt;&lt;code&gt;web_search&lt;/code&gt;&lt;a class="anchor" href="#web_search"&gt;#&lt;/a&gt;&lt;/h2&gt;&#10;&lt;p&gt;Fast multi-provider search. Aggregates results from all enabled providers, deduplicates, re-ranks by relevance, and returns the top matches.&lt;/p&gt;</description></item><item><title>Configuration</title><link>https://phantompixeldev.github.io/BetterWebSearch-MCP/docs/configuration/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://phantompixeldev.github.io/BetterWebSearch-MCP/docs/configuration/</guid><description>&lt;p&gt;&lt;strong&gt;All environment variables are optional.&lt;/strong&gt; The server starts and works via DuckDuckGo when no keys are set. Create a &lt;code&gt;.env&lt;/code&gt; only if you want additional providers.&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;cp .env.example .env &lt;span style="color:#75715e"&gt;# then edit&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="environment-variables"&gt;Environment Variables&lt;a class="anchor" href="#environment-variables"&gt;#&lt;/a&gt;&lt;/h2&gt;&#10;&lt;table&gt;&#10;&#9;&lt;thead&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;Variable&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;Required&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;Description&lt;/th&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/thead&gt;&#10;&#9;&lt;tbody&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;BRAVE_API_KEY&lt;/code&gt; or &lt;code&gt;BETTER_WEB_SEARCH_BRAVE_API_KEY&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;no&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Brave Search API key (primary). &lt;a href="https://brave.com/search/api/"&gt;Get one&lt;/a&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;TAVILY_API_KEY&lt;/code&gt; or &lt;code&gt;BETTER_WEB_SEARCH_TAVILY_API_KEY&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;no&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Tavily key. &lt;a href="https://tavily.com/"&gt;tavily.com&lt;/a&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;BETTER_WEB_SEARCH_DISABLE_CACHE&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;no&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;true&lt;/code&gt; → in-memory fallback (no SQLite)&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;BETTER_WEB_SEARCH_CACHE_PATH&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;no&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Custom SQLite path (default &lt;code&gt;data/cache.db&lt;/code&gt;)&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;BETTER_WEB_SEARCH_DISABLE_BROWSER&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;no&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;true&lt;/code&gt; → skip Playwright fallback&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/tbody&gt;&#10;&lt;/table&gt;&#10;&lt;h2 id="key-aliases"&gt;Key aliases&lt;a class="anchor" href="#key-aliases"&gt;#&lt;/a&gt;&lt;/h2&gt;&#10;&lt;p&gt;The config loader supports both the bare name and the &lt;code&gt;BETTER_WEB_SEARCH_*&lt;/code&gt; prefix:&lt;/p&gt;</description></item><item><title>Providers</title><link>https://phantompixeldev.github.io/BetterWebSearch-MCP/docs/providers/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://phantompixeldev.github.io/BetterWebSearch-MCP/docs/providers/</guid><description>&lt;p&gt;BetterWebSearch MCP uses a provider abstraction layer. Each provider implements the same &lt;code&gt;SearchProvider&lt;/code&gt; interface, so the aggregation layer treats them uniformly. Providers are enabled or disabled based on environment keys.&lt;/p&gt;&#10;&lt;h2 id="provider-overview"&gt;Provider overview&lt;a class="anchor" href="#provider-overview"&gt;#&lt;/a&gt;&lt;/h2&gt;&#10;&lt;table&gt;&#10;&#9;&lt;thead&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;Provider&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;Key needed?&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;Env var&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;Status&lt;/th&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/thead&gt;&#10;&#9;&lt;tbody&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;DuckDuckGo&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;No&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;—&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Always on (keyless fallback)&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Brave&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Yes&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;BRAVE_API_KEY&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Primary — better ranking &amp;amp; recency&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Tavily&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Yes&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;TAVILY_API_KEY&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Optional — when present&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;SerpApi&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Yes&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;SERPAPI_KEY&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Stub — not yet implemented&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/tbody&gt;&#10;&lt;/table&gt;&#10;&lt;h2 id="keyless-first-design"&gt;Keyless-first design&lt;a class="anchor" href="#keyless-first-design"&gt;#&lt;/a&gt;&lt;/h2&gt;&#10;&lt;p&gt;DuckDuckGo is &lt;strong&gt;always enabled&lt;/strong&gt; and requires no API key. This means:&lt;/p&gt;</description></item><item><title>Extraction</title><link>https://phantompixeldev.github.io/BetterWebSearch-MCP/docs/extraction/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://phantompixeldev.github.io/BetterWebSearch-MCP/docs/extraction/</guid><description>&lt;p&gt;BetterWebSearch MCP extracts page content through a &lt;strong&gt;three-tier escalation pipeline&lt;/strong&gt; managed by the &lt;code&gt;AccessRouter&lt;/code&gt;. Each tier is progressively more powerful (and slower); the router only escalates when the current tier doesn&amp;rsquo;t produce enough content.&lt;/p&gt;&#10;&lt;h2 id="overview"&gt;Overview&lt;a class="anchor" href="#overview"&gt;#&lt;/a&gt;&lt;/h2&gt;&#10;&lt;pre tabindex="0"&gt;&lt;code&gt;URL → Level 1: HTTP fetch (&amp;lt; 1s)&#10; → Level 2: Hydration / structured data (1–3s)&#10; → Level 3: Playwright browser + API interception (3–10s)&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Only escalates when needed. A page-cache hit short-circuits the entire pipeline.&lt;/p&gt;&#10;&lt;h2 id="tier-1-http-fetch"&gt;Tier 1: HTTP Fetch&lt;a class="anchor" href="#tier-1-http-fetch"&gt;#&lt;/a&gt;&lt;/h2&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;Speed:&lt;/strong&gt; &amp;lt; 1 second&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;Method:&lt;/strong&gt; Standard &lt;code&gt;fetch&lt;/code&gt; with user-agent spoofing, 10s timeout, 2MB cap&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;Confidence:&lt;/strong&gt; 0.85&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p&gt;Fetches the raw HTML and runs &lt;a href="https://github.com/mozilla/readability"&gt;Mozilla Readability&lt;/a&gt; to extract clean markdown. Wins when the page has enough visible text (&amp;gt; 500 characters after stripping tags).&lt;/p&gt;</description></item><item><title>Architecture</title><link>https://phantompixeldev.github.io/BetterWebSearch-MCP/docs/architecture/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://phantompixeldev.github.io/BetterWebSearch-MCP/docs/architecture/</guid><description>&lt;h2 id="system-overview"&gt;System overview&lt;a class="anchor" href="#system-overview"&gt;#&lt;/a&gt;&lt;/h2&gt;&#10;&lt;pre class="mermaid"&gt;graph TD&#10; A[Query / Question] --&amp;gt; B[expandQueries&amp;lt;br/&amp;gt;4–6 variants]&#10; B --&amp;gt; C[Providers&amp;lt;br/&amp;gt;Brave / Tavily / DuckDuckGo]&#10; C --&amp;gt;|Promise.allSettled| D[Deduplicate&amp;lt;br/&amp;gt;normalizeUrl]&#10; D --&amp;gt; E[Rerank&amp;lt;br/&amp;gt;relevance + domainScore + recency]&#10; E --&amp;gt; F[Top 10 Results]&#10; F --&amp;gt; G[AccessRouter]&#10; G --&amp;gt; H[Level 1: HTTP Fetch&amp;lt;br/&amp;gt;&amp;amp;lt; 1s]&#10; H --&amp;gt;|not enough content| I[Level 2: Hydration Data&amp;lt;br/&amp;gt;JSON-LD, __NEXT_DATA__]&#10; I --&amp;gt;|not enough content| J[Level 3: Playwright Browser&amp;lt;br/&amp;gt;3–10s]&#10; H --&amp;gt; K[Content Fusion]&#10; I --&amp;gt; K&#10; J --&amp;gt; K&#10; K --&amp;gt; L{Confidence scores&amp;lt;br/&amp;gt;api 0.99 &amp;amp;gt; jsonld 0.95&amp;lt;br/&amp;gt;&amp;amp;gt; rendered 0.90 &amp;amp;gt; readability 0.85}&#10; L --&amp;gt; M[Structured Response]&#10; M --&amp;gt; N[domainProfile + apiPatterns&amp;lt;br/&amp;gt;SQLite Cache]&lt;/pre&gt;&lt;h2 id="components"&gt;Components&lt;a class="anchor" href="#components"&gt;#&lt;/a&gt;&lt;/h2&gt;&#10;&lt;h3 id="1-mcp-server-srcindexts"&gt;1. MCP Server (&lt;code&gt;src/index.ts&lt;/code&gt;)&lt;a class="anchor" href="#1-mcp-server-srcindexts"&gt;#&lt;/a&gt;&lt;/h3&gt;&#10;&lt;p&gt;The CLI entry point. Parses &lt;code&gt;--help&lt;/code&gt; / &lt;code&gt;--version&lt;/code&gt; flags (exiting before MCP handshake), then starts the stdio MCP server with all 6 tools registered.&lt;/p&gt;</description></item><item><title>Token Efficiency</title><link>https://phantompixeldev.github.io/BetterWebSearch-MCP/docs/benchmarks/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://phantompixeldev.github.io/BetterWebSearch-MCP/docs/benchmarks/</guid><description>&lt;p&gt;The point of doing web work inside the server is that the model never has to&#10;read the pages. This page reports what that is actually worth, measured rather&#10;than asserted. The harness ships in the repository under &lt;code&gt;benchmarks/&lt;/code&gt;.&lt;/p&gt;&#10;&lt;h2 id="method"&gt;Method&lt;a class="anchor" href="#method"&gt;#&lt;/a&gt;&lt;/h2&gt;&#10;&lt;p&gt;Two workflows, the same questions, the same pages:&lt;/p&gt;&#10;&lt;table&gt;&#10;&#9;&lt;thead&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;Path&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;What lands in the agent&amp;rsquo;s context&lt;/th&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/thead&gt;&#10;&#9;&lt;tbody&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;baseline&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;The agent drives the tools: one &lt;code&gt;web_search&lt;/code&gt;, then &lt;code&gt;web_extract&lt;/code&gt; on each of the top 5 results. Every extracted page enters context in full.&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;research&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;One &lt;code&gt;web_research&lt;/code&gt; call. The response is the cited passages plus their metadata.&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/tbody&gt;&#10;&lt;/table&gt;&#10;&lt;p&gt;Both paths open the same URLs, so this isolates the compression the pipeline&#10;performs from any difference in what was retrieved.&lt;/p&gt;</description></item><item><title>Changelog</title><link>https://phantompixeldev.github.io/BetterWebSearch-MCP/docs/changelog/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://phantompixeldev.github.io/BetterWebSearch-MCP/docs/changelog/</guid><description>&lt;p&gt;All notable changes to &lt;strong&gt;better-web-search-mcp&lt;/strong&gt; are documented here.&#10;Format follows &lt;a href="https://keepachangelog.com/en/1.1.0/"&gt;Keep a Changelog&lt;/a&gt; and&#10;&lt;a href="https://semver.org/spec/v2.0.0.html"&gt;Semantic Versioning&lt;/a&gt;.&lt;/p&gt;&#10;&lt;h2 id="044---2026-09-02"&gt;&lt;a href="https://github.com/PhantomPixelDev/BetterWebSearch-MCP/releases/tag/v0.4.4"&gt;0.4.4&lt;/a&gt; - 2026-09-02&lt;a class="anchor" href="#044---2026-09-02"&gt;#&lt;/a&gt;&lt;/h2&gt;&#10;&lt;h3 id="added"&gt;Added&lt;a class="anchor" href="#added"&gt;#&lt;/a&gt;&lt;/h3&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;Second benchmark run with the browser tier enabled, recorded in&#10;&lt;code&gt;benchmarks/results/browser.json&lt;/code&gt;. It is a negative result and is published&#10;as one: enabling Tier 3 leaves the compression unchanged within run-to-run&#10;noise (86.2% versus 86.5% overall, 83.9% versus 83.8% median) while research&#10;spends 24% longer. Tier 3 earns its place on JavaScript-rendered pages that&#10;would otherwise extract nothing, not as a way to return less text&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;h2 id="043---2026-09-02"&gt;&lt;a href="https://github.com/PhantomPixelDev/BetterWebSearch-MCP/releases/tag/v0.4.3"&gt;0.4.3&lt;/a&gt; - 2026-09-02&lt;a class="anchor" href="#043---2026-09-02"&gt;#&lt;/a&gt;&lt;/h2&gt;&#10;&lt;h3 id="fixed"&gt;Fixed&lt;a class="anchor" href="#fixed"&gt;#&lt;/a&gt;&lt;/h3&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;The intermittent CI abort is finally addressed at the right layer.&lt;/strong&gt;&#10;Earlier attempts blamed the wrong thing: switching to forked processes, then&#10;serializing them, then closing handles at process exit each lowered the rate&#10;without removing it. The mechanism is that vitest tears down the&#10;better-sqlite3 addon&amp;rsquo;s N-API environment between test &lt;em&gt;files&lt;/em&gt;, so every file&#10;boundary after the addon has loaded is a chance to hit&#10;&lt;code&gt;Assertion failed: (env) != nullptr&lt;/code&gt;. &lt;code&gt;npm test&lt;/code&gt; now runs the one suite that&#10;opens a real database in its own vitest invocation, where that environment&#10;is destroyed at process exit instead of at a file boundary&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;h2 id="042---2026-09-02"&gt;&lt;a href="https://github.com/PhantomPixelDev/BetterWebSearch-MCP/releases/tag/v0.4.2"&gt;0.4.2&lt;/a&gt; - 2026-09-02&lt;a class="anchor" href="#042---2026-09-02"&gt;#&lt;/a&gt;&lt;/h2&gt;&#10;&lt;h3 id="fixed-1"&gt;Fixed&lt;a class="anchor" href="#fixed-1"&gt;#&lt;/a&gt;&lt;/h3&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;SQLite handles are closed on process exit.&lt;/strong&gt; A &lt;code&gt;Database&lt;/code&gt; left open at exit&#10;is finalized during teardown, and when that happened after the N-API&#10;environment was gone the addon aborted the process with&#10;&lt;code&gt;Assertion failed: (env) != nullptr&lt;/code&gt;. It showed up as intermittent CI&#10;failures that neither forked nor serialized test runs fully removed, but the&#10;same race can strand a WAL file in a real deployment. Open databases are now&#10;tracked and closed synchronously on exit, with the hook installed once rather&#10;than per database&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;h2 id="041---2026-09-02"&gt;&lt;a href="https://github.com/PhantomPixelDev/BetterWebSearch-MCP/releases/tag/v0.4.1"&gt;0.4.1&lt;/a&gt; - 2026-09-02&lt;a class="anchor" href="#041---2026-09-02"&gt;#&lt;/a&gt;&lt;/h2&gt;&#10;&lt;h3 id="fixed-2"&gt;Fixed&lt;a class="anchor" href="#fixed-2"&gt;#&lt;/a&gt;&lt;/h3&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;A cited passage could be an entire page.&lt;/strong&gt; &lt;code&gt;splitPassages&lt;/code&gt; emitted an&#10;over-long block whole, and plenty of extracted pages contain no blank lines&#10;at all, so the whole document became a single passage. &lt;code&gt;web_research&lt;/code&gt; then&#10;returned &lt;em&gt;more&lt;/em&gt; text than reading the pages directly would have — the first&#10;benchmark run measured a 267% increase against the baseline it was supposed&#10;to beat. Blocks longer than 1,200 characters are now windowed on sentence&#10;boundaries, without cutting words and with offsets still addressing the&#10;source&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;h3 id="added-1"&gt;Added&lt;a class="anchor" href="#added-1"&gt;#&lt;/a&gt;&lt;/h3&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;Token-efficiency benchmark&lt;/strong&gt; under &lt;code&gt;benchmarks/&lt;/code&gt;, run with &lt;code&gt;npm run bench&lt;/code&gt;.&#10;It compares an agent driving the tools itself against a single&#10;&lt;code&gt;web_research&lt;/code&gt; call over the same pages, and is what caught the bug above.&#10;Measured over 12 questions: 820,229 characters down to 110,973, an 86.5%&#10;reduction overall and 83.8% median. Payload is counted in characters, which&#10;is exact and tokenizer-independent; the harness makes no claim about answer&#10;quality, which would need a judge model&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;h2 id="040---2026-09-02"&gt;&lt;a href="https://github.com/PhantomPixelDev/BetterWebSearch-MCP/releases/tag/v0.4.0"&gt;0.4.0&lt;/a&gt; - 2026-09-02&lt;a class="anchor" href="#040---2026-09-02"&gt;#&lt;/a&gt;&lt;/h2&gt;&#10;&lt;h3 id="added-2"&gt;Added&lt;a class="anchor" href="#added-2"&gt;#&lt;/a&gt;&lt;/h3&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;Source independence detection.&lt;/strong&gt; URL deduplication only ever caught the&#10;same page twice; syndication went straight through. Five outlets running one&#10;wire story, a vendor press release quoted verbatim, or an article and its own&#10;AMP variant all arrived as distinct URLs and were reported as five sources.&#10;Pages are now clustered by content shingles (Jaccard over 5-word shingles,&#10;union-find so clustering is transitive), and two pages from the same host are&#10;treated as one account&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;&lt;code&gt;evidence&lt;/code&gt; block on &lt;code&gt;web_research&lt;/code&gt; responses&lt;/strong&gt;, reporting only things the&#10;server actually measured: &lt;code&gt;sources_opened&lt;/code&gt;, &lt;code&gt;independent_sources&lt;/code&gt;,&#10;&lt;code&gt;derivative_sources&lt;/code&gt;, &lt;code&gt;query_term_coverage&lt;/code&gt;, and &lt;code&gt;cited_spans&lt;/code&gt;. There is no&#10;language model in this server, so there is no confidence score — an invented&#10;one would be worse than none&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;h3 id="changed"&gt;Changed&lt;a class="anchor" href="#changed"&gt;#&lt;/a&gt;&lt;/h3&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;Citations spread across independent accounts rather than distinct URLs, and&#10;derivative sources no longer contribute quotes at all. Previously the pass&#10;that topped up remaining citation slots could refill them with the same story&#10;under a second byline, presenting one claim as corroborated&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;h2 id="030---2026-09-02"&gt;&lt;a href="https://github.com/PhantomPixelDev/BetterWebSearch-MCP/releases/tag/v0.3.0"&gt;0.3.0&lt;/a&gt; - 2026-09-02&lt;a class="anchor" href="#030---2026-09-02"&gt;#&lt;/a&gt;&lt;/h2&gt;&#10;&lt;h3 id="security"&gt;Security&lt;a class="anchor" href="#security"&gt;#&lt;/a&gt;&lt;/h3&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;SSRF protection.&lt;/strong&gt; &lt;code&gt;web_extract&lt;/code&gt; took URLs straight from the calling agent&#10;and &lt;code&gt;fetchPage&lt;/code&gt; followed them with no validation, so &lt;code&gt;http://localhost:8080/&lt;/code&gt;,&#10;&lt;code&gt;http://192.168.1.1/&lt;/code&gt;, and the cloud metadata endpoint at&#10;&lt;code&gt;http://169.254.169.254/&lt;/code&gt; were all fetchable and came back as ordinary page&#10;content. Every URL is now checked before the request: non-HTTP schemes are&#10;refused, hostnames are resolved, and any private, loopback, link-local,&#10;carrier-grade-NAT, multicast or reserved address is rejected. IPv4-mapped&#10;IPv6 forms such as &lt;code&gt;::ffff:127.0.0.1&lt;/code&gt; are judged by their IPv4 rules&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;Redirects are validated per hop.&lt;/strong&gt; Fetching now uses manual redirects and&#10;re-runs the guard on each &lt;code&gt;Location&lt;/code&gt;, so a public host cannot bounce the&#10;fetcher onto a private one. Chains are capped at 5 hops&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;Prompt-injection screening.&lt;/strong&gt; Page text is attacker-controlled, so every&#10;&lt;code&gt;web_extract&lt;/code&gt; result now carries a &lt;code&gt;security&lt;/code&gt; block marking content untrusted&#10;and reporting text that tries to address an agent, with the matched pattern&#10;and its offset. Suspicious content gets a warning banner; the page text&#10;itself is never rewritten, so extraction stays faithful to the source&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;h3 id="changed-1"&gt;Changed&lt;a class="anchor" href="#changed-1"&gt;#&lt;/a&gt;&lt;/h3&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;&lt;code&gt;web_research&lt;/code&gt; selects passages that answer the question.&lt;/strong&gt; It previously&#10;took the first 400 characters of each of the top 5 pages and never looked at&#10;the question, so answers were largely cookie notices and page intros.&#10;Passages are now scored against the question with BM25, and the best ones&#10;are returned best-first across distinct sources. This also cuts tokens,&#10;since only matching paragraphs are included&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;h3 id="added-3"&gt;Added&lt;a class="anchor" href="#added-3"&gt;#&lt;/a&gt;&lt;/h3&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;&lt;code&gt;web_research&lt;/code&gt; responses include &lt;code&gt;citations&lt;/code&gt;: each cited span carries its&#10;source, the verbatim quote, character offsets into that page&amp;rsquo;s extracted&#10;content, and a relevance score, so a claim can be attributed to a span&#10;rather than to a whole page&lt;/li&gt;&#10;&lt;li&gt;&lt;code&gt;fetchPage&lt;/code&gt; accepts &lt;code&gt;allowPrivateHosts&lt;/code&gt; for local fixture servers and &lt;code&gt;ssrf&lt;/code&gt;&#10;for injecting DNS resolution in tests&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;h2 id="023---2026-09-02"&gt;&lt;a href="https://github.com/PhantomPixelDev/BetterWebSearch-MCP/releases/tag/v0.2.3"&gt;0.2.3&lt;/a&gt; - 2026-09-02&lt;a class="anchor" href="#023---2026-09-02"&gt;#&lt;/a&gt;&lt;/h2&gt;&#10;&lt;h3 id="fixed-3"&gt;Fixed&lt;a class="anchor" href="#fixed-3"&gt;#&lt;/a&gt;&lt;/h3&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;&lt;code&gt;BETTER_WEB_SEARCH_DISABLE_CACHE&lt;/code&gt; and &lt;code&gt;BETTER_WEB_SEARCH_CACHE_PATH&lt;/code&gt; are&#10;finally honored. Both were parsed by the config loader, printed in the&#10;startup banner, and documented in &lt;code&gt;--help&lt;/code&gt;, but nothing passed them to the&#10;cache — the server opened &lt;code&gt;data/cache.db&lt;/code&gt; regardless of what either said&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;h3 id="changed-2"&gt;Changed&lt;a class="anchor" href="#changed-2"&gt;#&lt;/a&gt;&lt;/h3&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;Test files now run serially in a single forked process. Forks alone were not&#10;enough: parallel files still raced the better-sqlite3 addon&amp;rsquo;s own teardown,&#10;tripping &lt;code&gt;Assertion failed: (env) != nullptr&lt;/code&gt; inside the native module&lt;/li&gt;&#10;&lt;li&gt;Security policy now tracks the 0.2.x line and describes the cache&#10;mitigations accurately&lt;/li&gt;&#10;&lt;li&gt;The v0.1.0 launch checklist is marked historical rather than reading as a&#10;current process&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;h2 id="022---2026-09-02"&gt;&lt;a href="https://github.com/PhantomPixelDev/BetterWebSearch-MCP/releases/tag/v0.2.2"&gt;0.2.2&lt;/a&gt; - 2026-09-02&lt;a class="anchor" href="#022---2026-09-02"&gt;#&lt;/a&gt;&lt;/h2&gt;&#10;&lt;h3 id="fixed-4"&gt;Fixed&lt;a class="anchor" href="#fixed-4"&gt;#&lt;/a&gt;&lt;/h3&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;A locked, corrupt, or unwritable &lt;code&gt;data/cache.db&lt;/code&gt; no longer takes the server&#10;down at boot. Opening SQLite is guarded and falls back to the in-memory&#10;cache with a warning on stderr; directory creation is inside the guard too,&#10;so a read-only or permission-denied cache path degrades instead of throwing&lt;/li&gt;&#10;&lt;li&gt;The startup banner no longer advertises SerpApi, which has not been part of&#10;the provider set since 0.2.0&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;h3 id="added-4"&gt;Added&lt;a class="anchor" href="#added-4"&gt;#&lt;/a&gt;&lt;/h3&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;&lt;code&gt;mcp.json&lt;/code&gt; now tracks the package version automatically via the &lt;code&gt;version&lt;/code&gt;&#10;lifecycle hook, with a test asserting the two stay in step — the manifest&#10;had silently read 0.1.0 while npm was publishing 0.2.1&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;h3 id="changed-3"&gt;Changed&lt;a class="anchor" href="#changed-3"&gt;#&lt;/a&gt;&lt;/h3&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;&lt;code&gt;release:*&lt;/code&gt; scripts no longer run &lt;code&gt;npm publish&lt;/code&gt; locally. Publishing is the&#10;tag-triggered workflow&amp;rsquo;s job; doing both meant the local publish won and CI&#10;then failed with &lt;code&gt;E403 cannot publish over the previously published versions&lt;/code&gt;, which is how 0.2.1 shipped without provenance and without a&#10;GitHub release&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;h2 id="021---2026-09-02"&gt;&lt;a href="https://github.com/PhantomPixelDev/BetterWebSearch-MCP/releases/tag/v0.2.1"&gt;0.2.1&lt;/a&gt; - 2026-09-02&lt;a class="anchor" href="#021---2026-09-02"&gt;#&lt;/a&gt;&lt;/h2&gt;&#10;&lt;h3 id="changed-4"&gt;Changed&lt;a class="anchor" href="#changed-4"&gt;#&lt;/a&gt;&lt;/h3&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;Test runner uses forked processes, reducing intermittent&#10;&lt;code&gt;Worker exited unexpectedly&lt;/code&gt; CI failures caused by loading the&#10;better-sqlite3 native addon inside a worker thread (see 0.2.3 for the&#10;follow-up that closed the remaining window)&lt;/li&gt;&#10;&lt;li&gt;Compiled tests are excluded from the published package: 252 files down to&#10;148, 126.4 kB down to 85.1 kB&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;h2 id="020---2026-09-01"&gt;&lt;a href="https://github.com/PhantomPixelDev/BetterWebSearch-MCP/releases/tag/v0.2.0"&gt;0.2.0&lt;/a&gt; - 2026-09-01&lt;a class="anchor" href="#020---2026-09-01"&gt;#&lt;/a&gt;&lt;/h2&gt;&#10;&lt;h3 id="fixed-5"&gt;Fixed&lt;a class="anchor" href="#fixed-5"&gt;#&lt;/a&gt;&lt;/h3&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;The Level 3 browser tier never ran in production.&lt;/strong&gt; No call site passed a&#10;&lt;code&gt;browserPool&lt;/code&gt; to &lt;code&gt;getPage&lt;/code&gt;, so the escalation guard skipped it entirely and&#10;&lt;code&gt;BrowserPool&lt;/code&gt; was constructed only in tests. The router now creates a shared&#10;pool lazily on first escalation, so JS-rendered pages actually get rendered&lt;/li&gt;&#10;&lt;li&gt;&lt;code&gt;web_extract&lt;/code&gt;&amp;rsquo;s flat 8s per-URL budget was shorter than a browser render&amp;rsquo;s&#10;23s worst case (15s navigation + 4s intelligent wait + 4s DOM stability), so&#10;every Level 3 extraction was killed before it could return. The budget is now&#10;sized to the tiers that can run: 8s without the browser, 35s with it&lt;/li&gt;&#10;&lt;li&gt;&lt;code&gt;BETTER_WEB_SEARCH_DISABLE_BROWSER&lt;/code&gt; was documented but never read; it now&#10;actually disables the browser tier&lt;/li&gt;&#10;&lt;li&gt;Aborted requests are no longer retried. Providers share one &lt;code&gt;AbortController&lt;/code&gt;&#10;across attempts, so a retry after the timeout fired could only fail again&#10;instantly, burning the retry budget&lt;/li&gt;&#10;&lt;li&gt;Brave and Tavily now set &lt;code&gt;retryNetworkErrors&lt;/code&gt;, matching DuckDuckGo&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;h3 id="added-5"&gt;Added&lt;a class="anchor" href="#added-5"&gt;#&lt;/a&gt;&lt;/h3&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;Domain-profile shortcut: the per-domain profile written after every&#10;extraction is finally read back, so a domain already served without&#10;JavaScript skips the render. &lt;code&gt;mode: &amp;quot;browser&amp;quot;&lt;/code&gt; still overrides it&lt;/li&gt;&#10;&lt;li&gt;Per-provider 10s timeout inside &lt;code&gt;aggregateSearch&lt;/code&gt; — one hung provider no&#10;longer gates the other providers&amp;rsquo; results&lt;/li&gt;&#10;&lt;li&gt;Clean shutdown on &lt;code&gt;SIGINT&lt;/code&gt;/&lt;code&gt;SIGTERM&lt;/code&gt; so a lazily launched chromium is not&#10;orphaned&lt;/li&gt;&#10;&lt;li&gt;16 tests (229 total), including a browser-tier suite covering pool reuse,&#10;the disable flag, and the profile shortcut&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;h3 id="removed"&gt;Removed&lt;a class="anchor" href="#removed"&gt;#&lt;/a&gt;&lt;/h3&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;The unimplemented SerpApi stub is no longer added to &lt;code&gt;enabledProviders()&lt;/code&gt;;&#10;it was a guaranteed no-op call on every search. The class remains as a&#10;placeholder&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;h3 id="notes"&gt;Notes&lt;a class="anchor" href="#notes"&gt;#&lt;/a&gt;&lt;/h3&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;&lt;code&gt;web_extract&lt;/code&gt; on JavaScript-heavy pages is slower than 0.1.2 (up to 35s) but&#10;now returns real content instead of a confidence-0 fallback&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;h2 id="012---2026-08-31"&gt;&lt;a href="https://github.com/PhantomPixelDev/BetterWebSearch-MCP/releases/tag/v0.1.2"&gt;0.1.2&lt;/a&gt; - 2026-08-31&lt;a class="anchor" href="#012---2026-08-31"&gt;#&lt;/a&gt;&lt;/h2&gt;&#10;&lt;h3 id="added-6"&gt;Added&lt;a class="anchor" href="#added-6"&gt;#&lt;/a&gt;&lt;/h3&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;Project banner in the README and on the site homepage&lt;/li&gt;&#10;&lt;li&gt;Hugo docs site on the hugo-book theme with native sidebar navigation&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;h3 id="changed-5"&gt;Changed&lt;a class="anchor" href="#changed-5"&gt;#&lt;/a&gt;&lt;/h3&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;Node baseline bumped to 22 LTS&lt;/li&gt;&#10;&lt;li&gt;Root directory cleanup and a rewritten end-user README&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;h3 id="fixed-6"&gt;Fixed&lt;a class="anchor" href="#fixed-6"&gt;#&lt;/a&gt;&lt;/h3&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;Release workflow npm authentication&lt;/li&gt;&#10;&lt;li&gt;Sidebar navigation, duplicate H1 headings, and mobile menu on the docs site&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;h2 id="011---2026-08-29"&gt;&lt;a href="https://github.com/PhantomPixelDev/BetterWebSearch-MCP/releases/tag/v0.1.1"&gt;0.1.1&lt;/a&gt; - 2026-08-29&lt;a class="anchor" href="#011---2026-08-29"&gt;#&lt;/a&gt;&lt;/h2&gt;&#10;&lt;h3 id="fixed-7"&gt;Fixed&lt;a class="anchor" href="#fixed-7"&gt;#&lt;/a&gt;&lt;/h3&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;Packaging and release-workflow fixes on top of the initial release&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;h2 id="010---2026-08-29"&gt;&lt;a href="https://github.com/PhantomPixelDev/BetterWebSearch-MCP/releases/tag/v0.1.0"&gt;0.1.0&lt;/a&gt; - 2026-08-29&lt;a class="anchor" href="#010---2026-08-29"&gt;#&lt;/a&gt;&lt;/h2&gt;&#10;&lt;h3 id="added-7"&gt;Added&lt;a class="anchor" href="#added-7"&gt;#&lt;/a&gt;&lt;/h3&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;Initial public release — keyless-first MCP server for web research&lt;/li&gt;&#10;&lt;li&gt;Multi-provider search abstraction: Brave (primary), Tavily (optional), DuckDuckGo (keyless fallback), SerpApi stub — aggregated via &lt;code&gt;Promise.allSettled&lt;/code&gt;, deduplicated and reranked&lt;/li&gt;&#10;&lt;li&gt;Query expansion: 4–6 parallel variants incl. German translations (e.g. &lt;code&gt;unlimited mobile internet Germany&lt;/code&gt; → &lt;code&gt;unbegrenztes Datenvolumen&lt;/code&gt;)&lt;/li&gt;&#10;&lt;li&gt;Ranking pipeline: &lt;code&gt;normalizeUrl&lt;/code&gt; (utm/gclid/fbclid strip, trailing slash, hash), &lt;code&gt;domainScore&lt;/code&gt; curated tiers, &lt;code&gt;rerank&lt;/code&gt; (0.5 overlap +0.2 domain +0.2 recency +0.1 score)&lt;/li&gt;&#10;&lt;li&gt;3-tier extraction: Level 1 &lt;code&gt;fetchPage&lt;/code&gt; (10s, 2MB cap, UA) → Level 2 &lt;code&gt;JSON-LD / __NEXT_DATA__ / self.__next_f / __NUXT__ / __APOLLO_STATE__&lt;/code&gt; → Level 3 Playwright pool (3, image/font/media block, intelligent Race &lt;code&gt;networkidle&lt;/code&gt;/&lt;code&gt;article&lt;/code&gt;/&lt;code&gt;innerText&amp;gt;1000&lt;/code&gt;, &lt;code&gt;page.on('response')&lt;/code&gt; JSON capture)&lt;/li&gt;&#10;&lt;li&gt;Content Fusion with confidence scores (&lt;code&gt;api 0.99&lt;/code&gt; &amp;gt; &lt;code&gt;jsonld 0.95&lt;/code&gt; &amp;gt; &lt;code&gt;rendered 0.90&lt;/code&gt; &amp;gt; &lt;code&gt;readability 0.85&lt;/code&gt;)&lt;/li&gt;&#10;&lt;li&gt;Alternative source discovery: AMP variants &lt;code&gt;?output=1 /amp&lt;/code&gt; + quoted-title &lt;code&gt;site:&lt;/code&gt; searches, snippet evidence &lt;code&gt;search_snippet 0.6&lt;/code&gt;&lt;/li&gt;&#10;&lt;li&gt;SQLite cache (&lt;code&gt;better-sqlite3&lt;/code&gt; WAL, &lt;code&gt;data/cache.db&lt;/code&gt;) + in-memory fallback — &lt;code&gt;search_cache&lt;/code&gt; 15min, &lt;code&gt;page_cache&lt;/code&gt; 1h, &lt;code&gt;api_patterns&lt;/code&gt;, &lt;code&gt;domain_profiles&lt;/code&gt; — &lt;code&gt;domainProfile&lt;/code&gt; self-learning per domain&lt;/li&gt;&#10;&lt;li&gt;6 MCP tools: &lt;code&gt;web_search&lt;/code&gt;, &lt;code&gt;web_research&lt;/code&gt;/&lt;code&gt;deep_search&lt;/code&gt; (parallel queries, bounded concurrency 3, 8s per page, extractive citations), &lt;code&gt;web_extract&lt;/code&gt; (auto/fast/browser), &lt;code&gt;web_find&lt;/code&gt;, &lt;code&gt;web_news&lt;/code&gt; (recency + timeline + diversity)&lt;/li&gt;&#10;&lt;li&gt;Central &lt;code&gt;config&lt;/code&gt; loader: &lt;code&gt;BRAVE_API_KEY&lt;/code&gt; + &lt;code&gt;BETTER_WEB_SEARCH_BRAVE_API_KEY&lt;/code&gt; aliases, cache/browser toggles, keyless hint banner to stderr&lt;/li&gt;&#10;&lt;li&gt;CLI: &lt;code&gt;--help&lt;/code&gt; / &lt;code&gt;--version&lt;/code&gt; (exit before MCP handshake), startup banner listing providers&lt;/li&gt;&#10;&lt;li&gt;OpenCode / Claude / Cursor / VS Code configs: &lt;code&gt;mcp.json&lt;/code&gt;, &lt;code&gt;.vscode/mcp.json&lt;/code&gt;, &lt;code&gt;smithery.yaml&lt;/code&gt;&lt;/li&gt;&#10;&lt;li&gt;195 tests (vitest), &lt;code&gt;tsc&lt;/code&gt; strict, &lt;code&gt;npm run build&lt;/code&gt; emits &lt;code&gt;dist/&lt;/code&gt;&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;h3 id="notes-1"&gt;Notes&lt;a class="anchor" href="#notes-1"&gt;#&lt;/a&gt;&lt;/h3&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;No API keys required for first test — &lt;code&gt;npx better-web-search-mcp&lt;/code&gt; works via DuckDuckGo&lt;/li&gt;&#10;&lt;li&gt;Add &lt;code&gt;BRAVE_API_KEY&lt;/code&gt; for richer ranking &amp;amp; recency filtering&lt;/li&gt;&#10;&lt;li&gt;Publish-ready: &lt;code&gt;npm pack --dry-run&lt;/code&gt; validated, &lt;code&gt;prepare&lt;/code&gt;/&lt;code&gt;prepublishOnly&lt;/code&gt; hooks, &lt;code&gt;files&lt;/code&gt; whitelist&lt;/li&gt;&#10;&lt;/ul&gt;</description></item><item><title>Contributing</title><link>https://phantompixeldev.github.io/BetterWebSearch-MCP/docs/contributing/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://phantompixeldev.github.io/BetterWebSearch-MCP/docs/contributing/</guid><description>&lt;p&gt;Thank you for considering a contribution! Please see the full &lt;a href="https://github.com/PhantomPixelDev/BetterWebSearch-MCP/blob/main/.github/CONTRIBUTING.md"&gt;Contributing Guide&lt;/a&gt; on GitHub for detailed instructions.&lt;/p&gt;&#10;&lt;h2 id="quick-start"&gt;Quick start&lt;a class="anchor" href="#quick-start"&gt;#&lt;/a&gt;&lt;/h2&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;git clone https://github.com/PhantomPixelDev/BetterWebSearch-MCP.git&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;cd BetterWebSearch-MCP&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;npm ci&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;npm run build&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;npm test &lt;span style="color:#75715e"&gt;# 189+ tests — fully keyless&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;npm run lint &lt;span style="color:#75715e"&gt;# tsc --noEmit — must be zero errors&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="key-points"&gt;Key points&lt;a class="anchor" href="#key-points"&gt;#&lt;/a&gt;&lt;/h2&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;Keyless by default&lt;/strong&gt; — no API keys needed to develop or test&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;Node 20+&lt;/strong&gt; required&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;TypeScript strict&lt;/strong&gt; — no &lt;code&gt;any&lt;/code&gt;, no &lt;code&gt;@ts-ignore&lt;/code&gt;&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;Vitest&lt;/strong&gt; for tests — deterministic mocks, no external keys&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;Conventional Commits&lt;/strong&gt; — &lt;code&gt;feat(extraction): ...&lt;/code&gt;, &lt;code&gt;fix(providers): ...&lt;/code&gt;, &lt;code&gt;docs: ...&lt;/code&gt;&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;h2 id="pr-checklist"&gt;PR checklist&lt;a class="anchor" href="#pr-checklist"&gt;#&lt;/a&gt;&lt;/h2&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;code&gt;npm run lint&lt;/code&gt; — zero errors&lt;/li&gt;&#10;&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;code&gt;npm test&lt;/code&gt; — all 189+ tests pass&lt;/li&gt;&#10;&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;code&gt;npm run build&lt;/code&gt; — &lt;code&gt;dist/&lt;/code&gt; compiles cleanly&lt;/li&gt;&#10;&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; New functionality has tests&lt;/li&gt;&#10;&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; Types are explicit — no &lt;code&gt;any&lt;/code&gt; or &lt;code&gt;@ts-ignore&lt;/code&gt;&lt;/li&gt;&#10;&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;code&gt;CHANGELOG.md&lt;/code&gt; updated&lt;/li&gt;&#10;&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;code&gt;npm pack --dry-run&lt;/code&gt; — tarball looks correct&lt;/li&gt;&#10;&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; No secrets, API keys, or &lt;code&gt;.env&lt;/code&gt; values committed&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;h2 id="security"&gt;Security&lt;a class="anchor" href="#security"&gt;#&lt;/a&gt;&lt;/h2&gt;&#10;&lt;p&gt;If you discover a security vulnerability, &lt;strong&gt;do not open a public issue.&lt;/strong&gt; Follow the process in &lt;a href="https://github.com/PhantomPixelDev/BetterWebSearch-MCP/blob/main/.github/SECURITY.md"&gt;SECURITY.md&lt;/a&gt;.&lt;/p&gt;</description></item></channel></rss>