Skip to main content
Glama

🔍 MyWebSearch

Keyless Multi-Engine AI Web Search & High-Purity Content Extraction Engine
MCP Server · CLI · Local HTTP Daemon · Skill-Guided Agent Workflows

🇨🇳 简体中文 | 🇺🇸 English

npm version npm downloads license GitHub stars M8ven Live Monitored


One server, four ways to use it: connect an AI client over MCP, run a one-shot CLI query, keep a local daemon alive, or use the built-in diagnostics before going live.

Jump to: Quick start · MCP tools · CLI · Configuration · Diagnostics · Development

✨ Features

my-websearch is a full-stack search and technical documentation engine built specifically for AI coding agents (Claude Desktop, Cursor, Cherry Studio, Windsurf, Cline, ZCode, etc.). Out of the box, ready for multiple mainstream AI clients:

  • 🌐 16-Engine Federated Search & Smart Routing
    Aggregates direct domestic engines (Bing, Baidu, CSDN, Juejin, Sogou), global engines (DuckDuckGo, Brave, Startpage, Yahoo, Exa, Bing News), and specialized developer platforms (GitHub, StackOverflow, Hacker News, arXiv). Features automatic language-aware routing (auto), parallel multi-query execution (queries: string[]), URL deduplication, and automatic minResults cascading fallback. When DuckDuckGo is unhealthy, Yahoo automatically joins the English primary group from the fallback pool.

  • ⚡ Native Web Protocol & Proof-of-Work Solvers (Browser-Free Fast Path, Browser Fallback Only When Needed)
    Built on wreq-js with native modern TLS/HTTP2 handshake emulation and persistent session cookies. Includes pure-JS/Rust solvers for Startpage's Anubis SHA-256 PoW challenge and DuckDuckGo's d.js (isJsaChallenge) HTML5/arithmetic challenge, so most challenges resolve without launching a browser. Request stacks are engine-specific: DuckDuckGo requires the wreq Chrome profile via GET (axios POST is challenged with HTTP 202), while Brave defaults to curl HTTP/1.1 (Windows Schannel; tested curl 7/10 before rate limiting, axios 0/10, wreq HTTP/2 429). When a Brave 429 turns out to be an anti-bot challenge page, the engine retries once through a disguised headless CDP browser that clicks the Argon2 PoW button itself (~4–6s; measured 8/8 while plain HTTP stayed 429). Note: DuckDuckGo's page-level HTTP 202 anomaly CAPTCHA ("select all squares containing a duck") is human verification and is intentionally not bypassed — it is reported as bot_challenge; Brave's challenge is computational (Argon2 PoW) and is solved by the page's own JavaScript, not by us. Real URL resolution for Sogou redirect links, Baidu Location, and Bing Base64 links.

  • 📄 High-Purity Markdown Article Extraction & Dedicated Site Purifiers
    Combines Mozilla Readability with intelligent chrome noise stripping. Features dedicated purification rules for WeChat Official Accounts (mp.weixin.qq.com), StackOverflow questions & accepted answers, and transparent internal routing for CSDN & Juejin. Removes <nav>, <aside>, <footer>, and breadcrumbs while faithfully preserving article titles, code blocks, and GFM tables. Supports seamless pagination (startIndex), plus three token-saving modes: BM25 relevance-ranked focus, CSS-selector extract to JSON with no LLM, and numbered citations.

  • 📚 Unified Context7 Library Docs Lookup (queryDocs)
    Directly query official documentation with natural package names (e.g. "next.js", "vue") or Context7 IDs without needing a separate resolve step. Includes automatic candidate ranking, blind-guess 404 self-healing, and related alternatives discovery.

  • 🐙 Extended GitHub / Gitee Resource Fetcher
    fetchGithubContent (formerly fetchGithubReadme) supports both GitHub and Gitee: repository READMEs, any source file (/blob/..., with lines/#L120-L180 slicing), directory trees (/tree/...), complete issue / PR discussions, commits (/commit/<sha>), compare views (/compare/a...b), and releases (/releases, /releases/tag/<tag>).

  • 🌏 Zero-Config Network Detection & Fake-IP Ready
    Auto-detects OS system proxies (Windows Registry / macOS scutil / Linux env). Automatically routes overseas engines through proxy while keeping domestic engines on fast direct lines. Pre-whitelists 198.18.0.0/15 for TUN / Fake-IP compatibility while enforcing strict SSRF security bounds. No proxy is the supported default: outside mainland China, leave PROXY_URL unset and every engine is queried directly — you don't need Clash/v2ray to use this server.

  • 🔌 Versatile Deployment Modes
    Works seamlessly across MCP STDIO (Claude Desktop/Cursor), Streamable HTTP / SSE (Cherry Studio/remote clients), CLI one-shot commands, and a Local HTTP Daemon with connection pool reuse and Prometheus /metrics monitoring.


Related MCP server: web-mcp

🌍 16 Search Engines

Engine

Mainland China Connectivity

API Key

Core Technology

Best For

bing

🇨🇳 Direct

None

Chrome TLS impersonation + Base64 real URL resolution + stealth fallback

General technical search, mixed EN/ZH queries

bing-news

🌐 Proxy in CN

None

Bing News RSS + pubDate 24h filter + apiclick.aspx?url= decoding; direct can 302 to an HTML page, so it is proxy-eligible by default; opt-in vertical engine

Breaking news, last-24h updates

baidu

🇨🇳 Direct

None

Concurrent Location redirect resolution + challenge detection

Chinese news, documentation, domestic forums

csdn

🇨🇳 Direct

None

WAF cookie jar persistence + empty response auto-retry

Chinese error logs, debugging tutorials

juejin

🇨🇳 Direct

None

Direct official API querying for clean long-form articles

Modern frontend/backend technical blogs

sogou

🇨🇳 Direct

None

Desktop & mobile dual parsing + redirect link decoding + ad removal

WeChat ecosystem links & long-tail queries

duckduckgo

🌐 Proxy in CN

None

wreq Chrome-profile GET of the HTML endpoint (202 anomaly CAPTCHA only on the axios fallback); d.js solver retained for the preload fallback

English technical search & open-source discussions

startpage

🌐 Proxy in CN

None

Multi-worker Anubis SHA-256 PoW solver (difficulty ≤ 6) + cookie session (no browser needed)

Google-backed high-privacy results

yahoo

🌐 Proxy in CN

None

SSR HTML + homepage cookie warm-up + RU= redirect decoding; English fallback pool (auto-substitutes when DuckDuckGo is unhealthy)

Stable Bing-index English fallback

brave

🌐 Proxy in CN

None

curl HTTP/1.1 (Windows Schannel; tested 7/10 before 429; axios 0/10; wreq HTTP/2 429) + strict sponsored ad stripping; compatible with Windows' older curl builds (no --compressed requirement); on 429 it auto-triggers the PoW challenge through a disguised desktop headless CDP browser (~4–6s, measured 8/8 while HTTP stayed 429); if that still fails: wait / rotate IP / use BRAVE_API_KEY

Independent English index & technical blogs

exa

🌐 Proxy preferred

Optional Free Key

Official semantic search API (skipped if key is unset); direct works too, but proxy measured ~0.77s vs ~1.17s direct

Semantic similarity, AI research & papers

github

🌐 Direct API

None

Official GitHub Search REST API + exact owner/repo fast path (issues & repositories)

GitHub issues, bug reports, repositories, and exact repo lookup

stackoverflow

🌐 Direct API

None

Official StackExchange 2.3 API with HTML entity decoding

Developer troubleshooting, stack traces & answers

hackernews

🌐 Direct API

None

Algolia HN Search API with points, comments & author metadata

Tech discussions, startup launches & engineering news

arxiv

🌐 Direct API

None

Official arXiv Atom XML API parsing titles, authors & abstracts

Scientific papers, machine learning & AI research

code

🌐 Proxy in CN

None

grep.app API search across global GitHub code with repo, path & exact line numbers

Source code implementations, API usage patterns

Version note: this README tracks the current source tree (1.5.1). 1.5.1 is a search-quality release: diversity-aware early return (usable results + ≥2 engines or ≥3 domains), host cap (≤2 per domain, ≤3 for official docs), Chinese-tech routing to Bing/Baidu/Sogou, entity/title relevance guards, official-intent anchor injection (MCP/Vitest/Node.js/Next.js/React/Vue/TypeScript/Docker/PostgreSQL/Zustand) plus an official LTS page for Node.js version queries, Baidu real-URL extraction, version-aware ranking for date-based specs, a 3.5 s cascade cap / 3.5 s CSDN timeout, apiKeys.gitee support, fast-fail codeSymbol without GITHUB_TOKEN, and an npm run eval:quality 10-scenario benchmark. 1.5.0 unified the test suite (all legacy scripts migrated to Vitest, single runner in CI), centralized every process.env read behind src/config/env.ts (enforced by ESLint), splits the four largest modules, adds a 180 s browser-only window after a Brave 429, lazy-loads the server stack for a ~0.32 s CLI cold start, adds doctor --network cache-hit-rate / circuit-remaining / P50-P95 metrics, upgrades core dependencies (MCP SDK 1.32, axios 1.21, cheerio 1.2, express 5.3, zod 4), and requires Node.js ≥22 (Vitest 5 and the optional unpdf PDF parser both require it; node:sqlite is used when available, with a sharded-JSON fallback) plus a Windows CI job on Node 22. Earlier: 1.4.2 added Brave 429 challenge detection (captcha vs quota) and the disguised CDP browser fallback; 1.4.1 fixed Windows curl 8.4 compatibility; 1.4.0 added codeSymbol, CDP device profiles and DDG 202 fallback. npm latest may lag until the package is published.


🛠️ 5 Core MCP Tools (Minimal & Token-Efficient)

💡 Token Budget & Slimming: All tool descriptions are strictly kept within 250 characters (total description characters ≤ 1200), while detailed routing guidance is delegated to McpServer({ instructions }), significantly reducing LLM context consumption.

Tool Name

Purpose

Key Highlights

search

Federated web & code search (16 engines)

Supports parallel queries, timeRange: day|week|month|year date filter, site: string[] filter, and query operators (site:, filetype:, after:, before:, -exclude) translated per engine with local post-filtering; fetchTop preview injection, code engine (grep.app); explicit engines defaults to minResults=0 (no unconstrained cascade); returns inline diagnostics on failure

fetchWebContent

Web page extraction, Markdown & transparent PDF parsing

All-in-one content extractor: Built-in disk-level Markdown cache (Node 22 node:sqlite / partitioned JSON fallback, 200MB LRU, cache: default|reload); transparent PDF parsing (up to 20MB / 50 pages, [page N] tags, scanned doc detection); pagination & focus keyword targeting (bm25 relevance-ranked blocks by default, window for the legacy fixed window); selector to scope extraction to a CSS subtree (errors instead of silently returning the whole page); extract for CSS-selector JSON with no LLM; citations for numbered references; retainLinks to strip URLs (-50% on index pages)

fetchGithubContent

Comprehensive GitHub / Gitee content reader

Fetches README, one source file (/blob/<ref>/<path>, optional lines/#L120-L180 slicing with a 400-line cap), directory trees (/tree/, lock/build artifacts filtered), Issue / PR discussions, commits (/commit/<sha>), compare (/compare/a...b, capped patch + lockfile filtering), and releases (/releases[/tag/<tag>], releaseLimit 1-30); ref may be a branch, tag, or commit; Gitee parity via API (optional GITEE_TOKEN); returns warnings

queryDocs

All-in-one official library documentation

Resolves library names or Context7 IDs; optional version pins Context7/npm/PyPI; 24h local cache (cache: reload bypasses it); fallback chain npm → PyPI → crates.io → Go module proxy → Maven Central → GitHub README; returns source, confidence, and warnings

codeSymbol

Remote GitHub symbol lookup

GitHub code search + raw/CDN files; optional Tree-sitter AST (grammar downloaded/cached in background, scanner fallback, one parse for definitions + call sites); multi-line signatures, Python decorators, lexical brace matching, filtered call sites, re-export + monorepo tsconfig extends/paths; TypeScript/JavaScript checker types plus Python/Go/Rust annotation-level types; symbol/content/analysis TTL caches and a soft time budget with partial results; private repos via Contents API; requires GITHUB_TOKEN; unresolved imports become any

💡 Backward Compatibility: Legacy fetchCsdnArticle and fetchJuejinArticle are automatically routed under fetchWebContent; legacy resolveLibraryId is merged into queryDocs (which accepts a library name or the legacy libraryId alias). The separate legacy tools were removed — the REGISTER_LEGACY_ARTICLE_TOOLS switch is gone, because keeping three unregistered handlers around still cost tool-description budget for nothing.

🧩 MCP Prompts: deep-research (multi-source research with citations) and code-lookup (official docs + source + release notes) are registered as server-side prompt templates; clients that support MCP Prompts can invoke them directly.

🗂️ MCP Resources: read-only websearch://cache/pages / websearch://cache/docs indexes plus per-entry Markdown resources expose already-cached content without another tool call. Resources never trigger network fetches.


🚀 Quick Start

1. Run with NPX (Zero Configuration)

No installation required:

npx -y my-websearch@latest

💡 Automated Proxy Discovery: The server automatically detects your operating system's proxy settings. If a local proxy environment is active, overseas engines automatically use the proxy while domestic engines stay on fast direct lines. 198.18.0.0/15 is whitelisted out of the box for Fake-IP environments.

2. Configure in AI Clients

init detects installed MCP clients, writes the server entry into their config files, and keeps a .bak backup:

npx -y my-websearch@latest init                      # auto-detect and write
npx -y my-websearch@latest init --dry-run            # preview the diff, write nothing
npx -y my-websearch@latest init --client cursor,code # target specific clients

Supported out of the box: Claude Desktop, Cursor, and VS Code (workspace .vscode/mcp.json). An existing entry is never overwritten unless you pass --force, corrupt config files are left untouched, and on Windows it writes cmd /c npx for you. Restart the client, then verify with my-websearch doctor.

🔹 Manual configuration

Claude Desktop / Cursor / Windsurf / Cline (STDIO Mode)

Add to your MCP settings file:

{
  "mcpServers": {
    "my-websearch": {
      "command": "npx",
      "args": ["-y", "my-websearch@latest"],
      "env": {
        "MODE": "stdio"
      }
    }
  }
}

(For Windows: init handles this automatically. When configuring manually, if npx is not in the system path, set command to cmd and args to ["/c", "npx", "-y", "my-websearch@latest"])

🔹 Cherry Studio (Streamable HTTP Mode)

Start the server in your terminal with npx my-websearch@latest (default port 3211), then configure:

{
  "mcpServers": {
    "web-search": {
      "name": "MyWebSearch",
      "type": "streamableHttp",
      "baseUrl": "http://localhost:3211/mcp"
    }
  }
}

💻 CLI & Local Daemon

my-websearch can be used directly from your terminal as a standalone CLI tool or persistent daemon. Use --json in automation and keep the daemon on 127.0.0.1 unless you explicitly need remote access:

# Global install
npm install -g my-websearch

# Detect installed MCP clients and write their config (--dry-run to preview)
my-websearch init

# Start persistent local HTTP daemon (port 3210 by default)
my-websearch serve

# One-shot terminal search (reuses running daemon automatically)
my-websearch search "Model Context Protocol best practices" --limit 5 --min-results 5 --json

# Only results published within the last week (day|week|month|year)
my-websearch search "typescript 5.9 release" --time-range week --json

# Extract web page as clean Markdown
my-websearch fetch-web "https://blog.vuejs.org/posts/vue-3-5" --max-chars 15000 --json

# View daemon status and Prometheus metrics (/health, /status, /metrics)
my-websearch status --json

# Clear in-memory search cache
my-websearch cache-clear

🩺 Diagnostics

Use the built-in doctor command before troubleshooting a proxy, browser, or engine:

# Local configuration and browser checks (path only; use --browser to verify launch)
my-websearch doctor

# Verify the Chromium-based browser can actually launch (auto-detected, CHROME_PATH, or PLAYWRIGHT_CDP_ENDPOINT)
my-websearch doctor --browser

# Real proxy/engine probes (may contact upstream services)
my-websearch doctor --network

# Limit network probes to selected engines
my-websearch doctor --network --engine bing,duckduckgo --json

# Reset and clear cached engine circuit breaker / health state
my-websearch doctor --reset-health

The report separates configuration, proxy TCP reachability, HTTP reachability, application parsing, browser launch, and challenge verification status. For Brave, a 429 is additionally classified as captcha (human verification — retrying usually stays challenged) or quota (rate-limit window) in both the text report (challenge=...) and --json (challengeKind). Network mode also summarizes cache hit rates (search cache and fetch page cache), remaining circuit cooldowns per engine, and P50/P95 engine latency when persisted samples exist. Network mode performs real requests and should not be used as a high-frequency health check.

🌐 Proxy Troubleshooting & Upstream Rate Limiting

When configuring or diagnosing proxy connectivity, refer to these common edge cases:

  1. Startup log shows 🌐 Proxy: disabled even though proxy.url is set?

    • Check useProxy flag: In ~/.my-websearch/config.json, setting "useProxy": false takes precedence and explicitly overrides and disables url (setting PROXY_URL='false'). Change "useProxy": true or simply omit the field (providing a valid url automatically enables the proxy).

    • System proxy is auto-detected: when no explicit proxy is configured, the OS system proxy (Windows registry / macOS scutil / HTTPS_PROXY) is used for overseas engines and generic fetches — you do not need PROXY_URL just because a proxy client is running. If detection fails or you want to pin a specific proxy, set PROXY_URL (e.g. http://127.0.0.1:7897).

    • Prefer ~/.my-websearch/config.json over client env: put proxy.url and API keys in the config file. Some MCP clients (e.g. WorkBuddy) fingerprint the server by command + args + env key names + cwd, so adding a PROXY_URL env entry changes the trust fingerprint and the server may silently drop out of the session. Config-file settings are read at startup and avoid that.

    • Where to put the proxy (the error message used to say only "MCP client config", which was ambiguous):

      Location

      Use it when

      ~/.my-websearch/config.json → "proxy": { "url": "http://127.0.0.1:7897" }

      Recommended. Applies to every client (CLI, daemon, MCP) and does not change client trust fingerprints.

      MCP client env → PROXY_URL

      Per-client override. Restart the client; some clients include env keys in their trust fingerprint.

      Proxy client's "system proxy" switch

      No config at all. Since 1.3.8 it is auto-detected for overseas engines and generic fetches.

  2. Proxy works, but an overseas engine still fails or times out? (Per-engine diagnosis, not a config error)

    • DuckDuckGo returns HTTP 202 / challenge: the 202 body is DDG's anomaly CAPTCHA (human verification), not a plain per-IP rate limit; the d.js arithmetic solver does not bypass it. The engine first requests the HTML endpoint with a wreq Chrome-profile GET, which normally returns 200 even when the axios POST path is challenged with 202 — so a 202 now only appears if that path fails and the axios fallback is used. If you still see 202, confirm your build includes the wreq GET path (1.3.8 and earlier do not), then retry or check that the proxy is attached. DDG remains best-effort: the same exit can still be challenged intermittently, so do not treat it as an SLA; for stability use Bing/Startpage or configure BRAVE_API_KEY/EXA_API_KEY. Note: SEARCH_MODE=playwright:duckduckgo is not supported (DDG has no browser-rendering path), so it falls back to HTTP.

    • Bing returns HTTP 200 but 0 results: the wreq impersonation path now falls back to the axios SERP path automatically when it parses an empty page. If both paths stay empty, the query/IP is likely rate-limited.

    • Brave returns HTTP 429 Too Many Requests: after a limited number of requests the CloudFront edge starts serving an anti-bot challenge page (HTTP 429) to the exit IP, while the first requests often still depend on the client TLS/HTTP stack. Fresh-node measurements: axios (Node OpenSSL, HTTP/1.1) → 0/10, all 429; curl (Schannel, HTTP/1.1) → 7/10 then 3/3 429; wreq (HTTP/2 Chrome) → 429; .NET Schannel HTTP/2 → 200/429 mixed. After curl hit 429, retrying .NET Schannel HTTP/2 on the same URL was 0/3, and on fresh URLs 0/3 — once the IP quota is exhausted, changing the client stack does not help. The Brave web path always uses curl (Windows Schannel; no axios fallback) and trips a rolling 60-second window of 6 requests — the 7th request is challenged (measured on a clean exit at 1 request / 10 s: 6 × 200, then 429). The 429 body is not a plain quota page: it is Brave's SPA challenge (captcha + Argon2 challengeSet), so it is reported as bot_challenge rather than rate_limited. Recovery follows the window, not a fixed timer: requests pass again once the oldest request of the burst ages out of 60 s (measured 62.9 s after a 6-request burst; ~15 s when the same 6 requests were spread over 52 s). Retrying inside the window adds requests and extends it — probing every 15 s / 30 s kept the IP blocked for 255 s / 6.5 min respectively. The engine therefore trips the Brave circuit for 60 s (then 120 → 240 → 300 s) and retries once through a disguised desktop headless CDP browser that clicks the PoW 验证 button automatically (8/8 success, ~4–6 s per query on a hard-blocked IP). That fallback only serves that search and does not clear the HTTP window: after a successful browser pass, the next HTTP attempt succeeded once and then hit 429 again. Client-stack swaps do not help either (axios 0/10; wreq HTTP/2 429; curl Schannel HTTP/1.1 7/10 before the window trips). The official API (BRAVE_API_KEY) remains the stable path. BRAVE_BROWSER_FALLBACK=0 disables both the retry and the window. After a 429 the engine enters a 180 s browser-only window (long-running MCP/daemon processes only; one-shot CLI invocations start fresh): HTTP is skipped entirely and every Brave call goes straight to the disguised browser (no wasted curl request that would only extend the server-side window); browser-only engines stay eligible but are ranked last by auto routing and cascade, so they do not slow down normal searches; if the browser fails too, the circuit opens (60 → 120 → 240 → 300 s) and routing/cascade substitute other engines.

    • Startpage times out or Anubis PoW difficulty spikes: difficulty 6 is now solved inline by up to 4 worker threads (~3–12s); >6 is skipped. Pass-challenge socket errors / transient 5xx are retried automatically.

    • 💡 Resolution: these are upstream anti-bot/rate-limit behaviours, not a broken MCP configuration. Handle them per engine: DDG 202 → upgrade/retry (the wreq GET path; in auto mode Yahoo also replaces an unhealthy DDG from the fallback pool); Brave 429 → the disguised-browser fallback usually rescues it (see above); otherwise wait out the window, rotate the exit IP, or set BRAVE_API_KEY; Bing 0 results → retry or adjust the query; Startpage PoW → retry. Switch exit IP only after the engine-specific step fails. As a last resort use engines: ["bing", "baidu"], or configure an official key (BRAVE_API_KEY / EXA_API_KEY) for an SLA path.

🔐 Security Model (read before exposing the server)

The defaults are safe as a package, and every one of them matters:

Default

What it protects

Bind to 127.0.0.1

Nothing outside the machine can reach the port

No authentication

Acceptable only because of loopback binding

Host header validation

Blocks DNS-rebinding attacks from a browser on the same machine

CORS disabled

No cross-origin browser access

Relaxing one without the others silently removes the protection:

  • HOST=0.0.0.0 (Docker) → the Host allowlist follows the bind address automatically; if you also use a public domain, add it via OPEN_WEBSEARCH_ALLOWED_HOSTS (comma-separated).

  • Exposing to the public internet → put it behind a reverse proxy with authentication (or an SSH tunnel). The daemon prints a warning when bound to a non-loopback address.

  • MCP session IDs are identifiers, not credentials — anyone who can reach the port can resume a session.

  • FETCH_WEB_INSECURE_TLS=true disables certificate verification for user-supplied URLs; only enable it for a trusted network.

  • The app copies API keys it finds in ~/.gemini/config/mcp_config.json / ~/.workbuddy/mcp.json into ~/.my-websearch/config.json (mode 0600) on first run. Run my-websearch doctor to see where each key came from; set MYWEBSEARCH_NO_AUTO_BOOTSTRAP=1 to disable the copy.

⚙️ Configuration & Environment Variables

Global Configuration (~/.my-websearch/config.json)

To share settings across all MCP clients without duplicate configuration:

{
  "apiKeys": {
    "context7": "ctx7sk-...",
    "exa": "...",
    "github": "ghp_...",
    "gitee": "...",
    "brave": "..."
  },
  "proxy": {
    "url": "http://127.0.0.1:7897",
    "useProxy": true,
    "engines": ["duckduckgo", "exa", "brave", "startpage"]
  }
}

⚠️ Note on useProxy: When "url" is configured, proxy is enabled automatically. Setting "useProxy": false will explicitly override and disable url. If you want proxy enabled, set "useProxy": true or omit the field entirely. Keys & restart: entries under apiKeys are mapped to env vars at startup (github → GITHUB_TOKEN, gitee → GITEE_TOKEN, context7 → CONTEXT7_API_KEY, …) and only fill variables that are not already set in the client env. Restart the MCP server after editing the file; my-websearch doctor shows which keys are currently visible.

📋 Exhaustive Environment Variables Reference

Can be set via the global configuration file (~/.my-websearch/config.json), local .env, or system environment variables:

Precedence (highest first): process environment → project .env → project .my-websearch.json → ~/.my-websearch/config.json → built-in defaults.

0. 🖥️ Server & Runtime

Variable

Default

Allowed Values / Description

MODE

both

both / http / stdio. http enables Streamable HTTP + SSE.

HOST / OPEN_WEBSEARCH_HOST

127.0.0.1

MCP HTTP bind address. Binding to a non-loopback address also registers that host in the Host allowlist and prints a no-auth warning.

PORT

3211

MCP HTTP port

OPEN_WEBSEARCH_ALLOWED_HOSTS

empty

Extra Host-header allowlist entries (comma-separated), needed when serving through a public domain/reverse proxy

OPEN_WEBSEARCH_DAEMON_HOST / OPEN_WEBSEARCH_DAEMON_PORT

127.0.0.1 / 3210

Local REST daemon bind address (no auth: keep it on loopback)

METRICS_ENABLED

false

Enables in-process counters and the daemon /metrics endpoint

FETCH_WEB_DEADLINE_MS

45000

Hard deadline for one fetchWebContent call (cookie + browser + retries combined)

GITHUB_CONTENT_CDN_FIRST

false

Prefer jsDelivr over raw.githubusercontent.com for README and source files (public repos only). Legacy alias GITHUB_README_CDN_FIRST still works.

GITHUB_CONTENT_BUDGET_MS

12000 (6000 in CDN-first)

Total time budget for one fetchGithubContent call; per-attempt timeout is capped at 4.5s.

BING_PLAYWRIGHT_BUDGET_MS

6000

Legacy name retained for compatibility: budget for the Bing browser fallback (now backed by raw CDP) before HTTP results are kept

MYWEBSEARCH_NO_AUTO_BOOTSTRAP

unset

Set to 1 to stop copying API keys out of other apps' MCP configs on first run

1. 🔍 Search & Routing Orchestration

Variable

Default

Allowed Values / Description

DEFAULT_SEARCH_ENGINE

auto

Default engine: auto (smart query routing: Chinese baidu,sogou, English/foreign bing,duckduckgo). Supports all 16 engines: auto, bing, bing-news, baidu, sogou, duckduckgo, brave, csdn, juejin, startpage, yahoo, exa, github, stackoverflow, hackernews, arxiv, code (vertical developer engines can be configured as default, though auto or general web engines are recommended for global default)

ALLOWED_SEARCH_ENGINES

all

Comma-separated whitelist of allowed search engines (e.g. bing,baidu,duckduckgo)

BING_BASE_URL

https://cn.bing.com/search

Base URL for Bing queries. Overseas users or reverse proxy nodes can set to https://www.bing.com/search (legacy alias OPEN_WEBSEARCH_BING_HOST supported)

DEFAULT_MIN_RESULTS

5

Cascade threshold: triggers fallback engines when usable results are fewer than this value

DEFAULT_SEARCH_LIMIT

10

Default result limit when not explicitly specified in tool calls (max 50)

SEARCH_DEADLINE_MS

30000

Global hard deadline for multi-engine search execution (milliseconds)

SEARCH_FUSION

legacy

Result fusion mode: legacy (engine-hit count + arrival order) or rrf (Reciprocal Rank Fusion over per-engine ranks, which also replaces the position/consensus terms in re-ranking). RRF stays opt-in until a larger evaluation exists.

SEARCH_FUSION_RRF_K

20

RRF constant k; lower values amplify rank differences. Only used when SEARCH_FUSION=rrf.

ENGINE_CIRCUIT_BASE_COOLDOWN_MS

30000

First circuit-breaker cooldown for an engine (429 / 202 / bot_challenge). Repeated failures back off exponentially (30s → 60s → 120s…). Brave overrides the first step to 60s because its 429 is a rolling 60-second window of 6 requests (the 7th is challenged) and recovery only starts once the oldest request ages out; setting this variable explicitly disables the per-engine override.

ENGINE_CIRCUIT_MAX_COOLDOWN_MS

300000

Upper bound for the exponential circuit-breaker backoff (default 5 minutes).

SEARCH_AUTHORITY_DOMAINS

empty

Additional authority domain whitelist for result re-ranking (comma-separated, appended to built-in list)

SEARCH_MODE

auto

Search mode and browser policy. Supports single mode, multi-engine per mode, and compound multi-mode combinations:• Global mode: auto (default fallback), request/none (pure HTTP), playwright (force browser; legacy value name, now backed by CDP)• Single mode, multiple engines: playwright:bing,startpage, auto:bing,startpage, bing,startpage• Compound multiple modes: playwright:bing;auto:startpage (bing forces browser, startpage uses auto fallback), auto;request:startpage (global auto but startpage uses pure HTTP)

BRAVE_BROWSER_FALLBACK

1

When the keyless Brave web path returns HTTP 429 / an anti-bot challenge, retry once through a disguised desktop headless CDP browser that auto-triggers the Argon2 PoW 验证 button (1 enabled, 0 disables and fails fast). A 429 then opens a 180 s browser-only window: HTTP is skipped and every Brave call in the window goes straight to the browser; if that also fails the engine trips its circuit (60 → 120 → 240 → 300 s) and routing/cascade substitute other engines. Measured 8/8 success at ~4–6s per query while plain HTTP stayed 429. Still best-effort: it cannot pass the interactive slider CAPTCHA

AUTO_ROUTE_EN_ENGINES

bing,duckduckgo

Comma-separated engines for default English auto-routing

AUTO_ROUTE_ZH_ENGINES

baidu,sogou

Comma-separated engines for default Chinese auto-routing

2. 🌐 Proxy & Network Security

Variable

Default

Allowed Values / Description

PROXY_URL

empty (off)

Consolidated upstream proxy configuration (merges previous USE_PROXY and PROXY_ENGINES). Not needed in TUN mode.• Default proxy: passing empty PROXY_URL="" or PROXY_URL=true activates default http://127.0.0.1:7897 (common local proxy ports include 7897, 7890, 10809; overseas engines use proxy, domestic engines stay direct)• Custom address: PROXY_URL=http://127.0.0.1:10809• Custom engines: PROXY_URL="http://127.0.0.1:7897;duckduckgo,brave" or all engines PROXY_URL=";all"

FAKE_IP_CIDRS

198.18.0.0/15

Whitelisted CIDRs for Fake-IP / TUN mode to avoid SSRF false-positive blocking

CUSTOM_DNS_SERVERS

223.5.5.5,119.29.29.29,1.1.1.1,8.8.8.8

Comma-separated DNS servers used by the internal c-ares resolver (helps when the system DNS is polluted). Overrides the built-in list entirely

IMPERSONATE_BROWSER

chrome_149

wreq-js browser TLS/H2 fingerprint profile (e.g. chrome_149, safari_18)

IMPERSONATE_OS

windows

Operating system platform for fingerprint impersonation (windows, macos, linux)

BING_IMPERSONATE

true

Toggle Chrome TLS impersonation for Bing HTTP mode (auto-trips circuit breaker after consecutive empty results)

ANUBIS_MAX_POW_DIFFICULTY

6

Maximum difficulty threshold for Startpage Anubis PoW solver; skips/falls back when difficulty exceeds this

DIRECT_FIRST_PROBE_TIMEOUT_MS

3500

Timeout in ms for direct-first connection probes before proxy fallback

FETCH_WEB_INSECURE_TLS

false

Disable TLS certificate verification for fetchWebContent only (for broken legacy site certs)

GITHUB_README_CDN_FIRST

false

When true, forces skipping raw.githubusercontent.com direct probe and queries jsDelivr CDN first (domestic network acceleration)

Custom proxy engine lists: if you set proxy.engines in ~/.my-websearch/config.json or use the ;engine1,engine2 suffix of PROXY_URL, yahoo and bing-news are added automatically because they cannot be reached directly from CN (Yahoo times out in 15–20s; Bing News returns a 302/HTML page). Removing the list entirely is still recommended: defaults include them and keep the direct API engines (GitHub / Stack Overflow / Hacker News / arXiv) off the proxy.

3. 🔐 Credentials & API Keys

Variable

Default

Allowed Values / Description

CONTEXT7_API_KEY

empty

Context7 API Key (strongly recommended for proxy/TUN users to avoid shared IP quotas)

EXA_API_KEY

empty

Exa Free API Key (only required if using the exa semantic search engine)

BRAVE_API_KEY

empty

Brave Search API Key (optional; uses official high-reliability API when set)

GITHUB_TOKEN

empty

GitHub Personal Access Token (optional; raises rate limit to 5,000 req/hr)

GITEE_TOKEN

empty

Gitee Personal Access Token (optional; raises Gitee API rate limits and enables private repos). Also configurable as piKeys.gitee in ~/.my-websearch/config.json.

STACKOVERFLOW_API_KEY

empty

Stack Apps Key (optional; raises quota to 10,000 req/day)

4. 🖥️ Server Modes, Concurrency & Session Reaper

Variable

Default

Allowed Values / Description

MODE

both

MCP transport mode: stdio (stdin/stdout only), http (HTTP/SSE only), both (concurrent)

PORT

3211

MCP HTTP/SSE listen port (local persistent daemon uses 3210 by default)

MAX_CONCURRENT_SEARCHES

20

Max concurrent searches in daemon mode (0 for unlimited)

MCP_MAX_SESSIONS

100

Max retained MCP HTTP sessions before returning HTTP 429 Too Many Requests

MCP_SESSION_TTL_MS

1800000

Idle session expiration duration before reaping (default 30 min)

MCP_SESSION_REAPER_MS

300000

Session reaper scan interval (default 5 min)

LOG_LEVEL

info

Log level: quiet (completely silent), debug, info, warn, error

SECURITY_AUDIT

false

Enable SSRF blocking and host header security audit logging

OPEN_WEBSEARCH_ALLOWED_HOSTS

loopback

Host header whitelist for HTTP server (DNS Rebinding protection, comma-separated)

5. 🧭 CDP Browser & Stealth Controls (legacy Playwright env names kept)

NOTE

The browser fallback usesraw Chrome DevTools Protocol via chrome-remote-interface, so it requires a Chromium-based browser: Chrome, Edge, Chromium, Brave, Vivaldi or Opera (Firefox/WebKit are not supported). Standard install paths for all of these are auto-detected; override with CHROME_PATH / BROWSER_PATH / PLAYWRIGHT_EXECUTABLE_PATH, or connect a remote browser via PLAYWRIGHT_CDP_ENDPOINT (no local install needed). my-websearch doctor --browser reports which browser was found and how to fix a missing one. The PLAYWRIGHT_* env names and SEARCH_MODE=playwright value are kept for backward compatibility only. Browser fallback behavior is governed by SEARCH_MODE.

Two independent knobs — don't mix them up:

  • BROWSER_DRIVER picks the driver library: cdp (default, built in via chrome-remote-interface) or playwright (legacy escape hatch that requires you to install playwright-core).

  • PLAYWRIGHT_CDP_ENDPOINT / CHROME_PATH / BROWSER_PATH / PLAYWRIGHT_EXECUTABLE_PATH decide where the browser comes from: an already-running local/remote CDP endpoint, an explicit executable, or auto-detection.

Every browser path — Bing fallback, Startpage, DuckDuckGo, Brave, fetchWebContent, CSDN article fetch, and doctor --browser — goes through the same entry point, so these settings apply to all of them.

Variable

Default

Allowed Values / Description

BROWSER_DRIVER

cdp

Browser backend. cdp (default, raw CDP). playwright is a legacy escape hatch and requires you to install playwright-core manually; it is no longer bundled.

BROWSER_PROFILE

off

CDP device profile: off, windows-chrome-8, windows-chrome-16, macos-chrome-8, or random. Applies UA, screen/DPR, timezone and locale to browser sessions. It does not affect HTTP-only engines such as DuckDuckGo/Brave.

DDG_BROWSER_FALLBACK

1

When DuckDuckGo's HTTP paths return 202/CAPTCHA, retry the HTML endpoint through the CDP browser. Uses BROWSER_PROFILE when set, otherwise the coherent windows-chrome-8 default; set 0 to disable.

PLAYWRIGHT_CDP_ENDPOINT

empty

Remote Chrome/Edge CDP endpoint URL (e.g. http://127.0.0.1:9222 or ws://...); legacy name, used by the CDP driver

PLAYWRIGHT_EXECUTABLE_PATH

auto

Absolute path to a Chromium-based browser executable. Auto-detection covers Chrome / Edge / Chromium / Brave / Vivaldi / Opera in standard locations; CHROME_PATH and BROWSER_PATH are checked first and work as equivalents; legacy name

PLAYWRIGHT_HEADLESS

true

Run headless (on Windows, an isolated hidden desktop window is used); legacy name

PLAYWRIGHT_NAVIGATION_TIMEOUT_MS

20000

Hard page navigation timeout (milliseconds); legacy name, applied to CDP navigation

6. 🛠️ Application Directory & Tool Customization

Variable

Default

Allowed Values / Description

MYWEBSEARCH_DATA_DIR

~/.my-websearch

Root directory for configuration and persistent cookie files

OPEN_WEBSEARCH_RESPONSE_CAP_BYTES

60000

Maximum character limit returned to LLMs to prevent prompt context explosion

MCP_TOOL_SEARCH_NAME

search

Custom registration name for the search tool in MCP

MCP_TOOL_FETCH_WEB_NAME

fetchWebContent

Custom registration name for the content extraction tool

MCP_TOOL_FETCH_GITHUB_NAME

fetchGithubContent

Custom registration name for the GitHub/Gitee content tool (set to fetchGithubReadme for backward compatibility)

💡 Zero-Config Upgrades (Redundant Variables Removed):

  • CORS Switches (ENABLE_CORS/CORS_ORIGIN): CORS is disabled by default; enable it explicitly and restrict origins when browser clients need cross-origin access.

  • Browser Backend: raw CDP via chrome-remote-interface; playwright-core is no longer bundled. PLAYWRIGHT_* names and SEARCH_MODE=playwright remain as compatibility aliases.

  • Emoji Switch (OPEN_WEBSEARCH_NO_EMOJI): Automatic console code page detection smoothly falls back to ASCII tags on legacy terminals.

  • Fragmented Debug Flag (OPEN_WEBSEARCH_DEBUG): Unified into standard LOG_LEVEL=debug.

  • Cookie Persistence TTL (MYWEBSEARCH_COOKIE_TTL_DAYS): Solidified to 30 days with automated sliding renewal.


🤝 Contributing & Tests

Pull requests and issues are welcome! To run the test suite locally:

npm install
npm run build
npm test              # Run the Vitest suite (`npm test` prints the current file/test counts)
npm run check:docs    # Verify README env tables match docs/env-schema.json (edit the schema, then `npm run docs:env`)
npm run test:live     # Run bounded-concurrency live integration tests
npm run eval:live     # Run 23-case live STDIO JSON-RPC evaluation suite

Acknowledgements

Author: wtznicy

This project evolved from Open-WebSearch (originally created by Aas-ee) — special thanks to the original author. Thanks also to:

Available Tools

5 tools
codeSymbolA
Read-onlyIdempotent

Find a symbol declaration and references in a remote GitHub repo. Uses GitHub code search + raw files; returns signature, code block, and reference lines. Requires GITHUB_TOKEN. Example: repo="fastapi/fastapi", symbol="Depends".

NameRequiredDescriptionDefault
refNoOptional branch/tag/commit for raw file fetch
kindNoOptional declaration kind filter
repoYesGitHub repository: owner/repo or https://github.com/owner/repo
symbolYesExact symbol name (class/function/interface/type/const)
maxResultsNoMax definitions to return (1-10, default 5)

TDQS

A4.2/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnly/idempotent/openWorld/non-destructive, so the description's marginal value is in disclosing the auth requirement (GITHUB_TOKEN) and the retrieval mechanism (code search plus raw file fetch). It also discloses the return payload (signature, code block, reference lines), which matters since there is no output schema.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Three tight sentences, front-loaded with the core purpose, then the mechanism, then the prerequisite and example. No redundant or filler wording.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With no output schema, the description usefully summarizes what is returned and states the auth requirement, and the schema fully covers inputs. Minor gaps remain around rate limits or code-search coverage limits, which would matter for an openWorld remote-search tool.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so all five parameters (including ref, kind, maxResults) are already documented in the schema. The description's example illustrates repo and symbol formats but adds no semantics beyond that, so the baseline 3 applies.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb+resource ('Find a symbol declaration and references') scoped to 'a remote GitHub repo', and the method note (GitHub code search + raw files) distinguishes it from siblings like fetchGithubContent and search. An agent can tell what this returns without opening the schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Provides a concrete usage example (repo="fastapi/fastapi", symbol="Depends") and a prerequisite (GITHUB_TOKEN), which gives clear context for invocation. It stops short of naming when-not-to-use or pointing to the sibling tools for whole-file retrieval, so it doesn't reach 5.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

fetchGithubContentA
Read-onlyIdempotent

Fetch GitHub/Gitee by URL: README, source file (/blob/, with lines), tree, issue, PR, commit, compare, or releases (releaseLimit for recent N). Example: https://github.com/o/r/blob/main/src/index.ts — ref can be branch/tag/commit; not a repo clone.

NameRequiredDescriptionDefault
urlYes
linesNoOptional source-file line range, 1-based inclusive (e.g. "120-180"). Only valid for /blob/ URLs; URL hash #L120-L180 also works.
releaseLimitNoOptional number of releases to return for /releases URLs (1-30, default 10).

TDQS

A3.5/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnly, idempotent, openWorld, and non-destructive, so the safety profile is covered. The description adds real context: which URL path shapes are recognized, that ref may be branch/tag/commit, and that lines apply only to /blob/ URLs. It stays silent on authentication needs for private repos, rate limits, and failure behavior (e.g., what happens on a non-matching URL pattern).

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Dense but front-loaded — the artifact list comes first, then the example, then the two caveats. Every clause carries information; the only mild cost is that cramming the URL-type list, example, ref semantics, and clone exclusion into one sentence makes it slightly hard to scan.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness3/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

No output schema exists, so the description carries the burden of explaining what comes back, and it only implies it ("with lines" suggests line-numbered source). For a multi-mode reader spanning eight different URL types, it should say more about the shape of results and about private-repo authentication before an agent can call it confidently in all modes.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 67%, and the undocumented parameter is url itself. The description compensates well: it gives a concrete example URL, enumerates the path patterns the tool accepts, and explains that ref can be a branch, tag, or commit. It also reinforces the /blob/-only constraint on lines, adding cross-parameter meaning the schema only states in isolation.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

Names a specific verb (fetch) and resource (GitHub/Gitee URL content) and enumerates the supported content kinds: README, source file at /blob/, tree, issue, PR, commit, compare, releases. It also rules out one adjacent capability ("not a repo clone"), though it never names the sibling fetchWebContent or search to sharpen the boundary.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Usage is implied rather than stated: you supply a GitHub/Gitee URL and the tool resolves the corresponding artifact. The one explicit exclusion ("not a repo clone") helps, but there is no guidance on when to prefer fetchWebContent, search, or queryDocs, and no mention of prerequisites such as private-repo auth.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

fetchWebContentA
Read-onlyIdempotent

Fetch readable web content/docs/PDFs from public URLs. Auto-cleans ads, keeps code/tables. Batch urls (1-3), CSS selector scoping, bm25 focus, startIndex paging, cache, schema extract to JSON, citations, link retention.

NameRequiredDescriptionDefault
rawNoReturn the raw response body (HTML/plain text) without extraction
urlNo
urlsNoBatch URLs (1~3 URLs run concurrently, splitting maxChars budget; ideal for comparing search results)
cacheNoCache mode: 'default' uses disk Markdown cache; 'reload' forces re-fetching upstream
focusNoKeyword or section name to target (e.g. 'Auth', 'Config'); returns targeted window (~5000 chars) instead of burning tokens on full document
formatNoContent format (default: 'markdown' when raw is false): 'markdown' preserves headings, lists, fenced code blocks (with language) and GFM tables — better for technical docs; use 'text' for plain text
extractNoExtract structured JSON instead of markdown, using CSS selectors — no LLM needed. fields: [{name, selector, type: text|html|markdown|attribute|list, attribute?, fields?, all?}]; selector '@attr' reads an attribute of the current node
maxCharsNo
selectorNoCSS selector: return only the matched subtree, keeping code blocks and tables. Use when auto-extraction grabs the wrong container. Errors instead of silently returning the whole page when nothing matches
citationsNoRewrite inline links as numbered citations and append a '## References' list, so the answer can cite sources
focusModeNoHow focus selects text: 'bm25' (default) ranks paragraphs by relevance and keeps the best ones; 'window' keeps the old ±2500-char window around the first match
startIndexNoCharacter offset to start reading from (for paging through long content)
readabilityNo
retainLinksNoInline link retention: 'all' (default) keeps [label](url); 'text' keeps only the label (strips URLs, big win on index/list pages); 'none' removes the link entirely. Ignored inside code blocks
includeLinksNo

TDQS

A3.5/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already cover the safety profile (read-only, idempotent, open-world, non-destructive), and the description still adds real behavior: ad stripping, disk Markdown caching, batch URLs splitting the maxChars budget, and selector failing loudly rather than silently returning the whole page. Missing are failure modes for inaccessible URLs, rate limiting, or what the default response looks like.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness3/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The opening sentence is well front-loaded and earns its place. The follow-on feature list is telegraphic ('bm25 focus, startIndex paging, cache, schema extract to JSON') and largely restates schema parameters, adding tokens without adding meaning.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness3/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a 15-parameter tool with a nested extract object and no output schema, the description covers the main modes but omits that at least one of url/urls must be supplied (zero required params), and never characterizes the default return shape. It is minimally sufficient but leaves real gaps for a tool this complex.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 73%, so most parameters are already documented in the schema itself. The description's second sentence names capabilities (bm25 focus, startIndex paging, cache, citations, link retention) but adds no syntax or defaults beyond what the parameter descriptions already state, so it earns only the baseline.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource ('Fetch readable web content/docs/PDFs from public URLs') plus the transformation applied ('Auto-cleans ads, keeps code/tables'). The 'public URLs' scope implicitly separates it from fetchGithubContent and queryDocs, but siblings are never named explicitly.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Several in-line cues imply usage: batch urls are 'ideal for comparing search results', selector is for 'when auto-extraction grabs the wrong container', focus avoids 'burning tokens on full document'. However there is no explicit when-to-use versus fetchGithubContent/queryDocs/search, and no stated preconditions such as needing at least one of url or urls.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

queryDocsB
Read-onlyIdempotent

Get official docs, API references, and code snippets for libraries/packages (e.g. 'react', 'fastapi', 'next.js'). Queries Context7 with fallback to npm/PyPI registry and GitHub README. Direct, no proxy needed.

NameRequiredDescriptionDefault
cacheNoUse the 24h local docs cache (default) or bypass/refresh it with 'reload'
limitNoMaximum number of code snippets to return (default 5)
queryNoThe question, feature, or task to get relevant documentation for (optional; defaults to an overview when omitted, e.g. 'how to set up middleware with auth')
strictNoIf true, rejects low-confidence library name matches with an error instead of returning loosely matched candidate docs (default false)
libraryNoLibrary or package name (e.g. 'next.js', 'react', 'fastapi') or exact Context7 library ID (e.g. '/vercel/next.js', version-pinnable like '/vercel/next.js@v15.1.8')
versionNoOptional explicit version (e.g. '14.2.0' or 'v15.1.8'); overrides an @version embedded in library
libraryIdNoLegacy alias for library (e.g. /vercel/next.js)

TDQS

B3.4/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnly, idempotent, non-destructive, and openWorld, so the safety profile is covered. The description adds genuinely new behavior: a prioritized source chain (Context7 primary, then npm/PyPI registry, then GitHub README) and that it connects directly with no proxy. With annotations carrying most of the burden, this extra sourcing context earns a 3 rather than a 4, since it says nothing about latency, rate limits, or what a fallback result looks like.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Three short sentences, front-loaded with the core purpose before the source/fallback detail. Minor waste: 'Direct, no proxy needed' is vague and an agent cannot act on it.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness3/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With seven optional parameters and no output schema, the description does at least say what kind of content comes back (docs, API references, code snippets). But it leaves the fallback behavior undefined from the caller's perspective, does not explain how multiple sources are merged or ordered in the response, and gives no steer on typical parameter combinations.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, and every parameter (cache, limit, query, strict, library, version, libraryId) is documented at the field level. The description only echoes the library examples already in the schema and adds no meaning for cache, strict, limit, or the libraryId alias, so the baseline 3 applies.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource ('Get official docs, API references, and code snippets') scoped to libraries/packages with concrete examples ('react', 'fastapi', 'next.js'). It implicitly separates itself from fetchWebContent and fetchGithubContent by naming its own source chain (Context7, npm/PyPI registry, GitHub README), though it never names the siblings outright.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Usage is implied rather than stated: the agent can infer this is for library/package documentation lookups, and the source-fallback chain hints at why it may succeed where a plain web fetch fails. There is no explicit when-to-use vs when-not-to-use guidance relative to search, fetchWebContent, fetchGithubContent, or codeSymbol.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

  1. 5 tool updatesv1.5.1
    • ChangedcodeSymbol1 field changed
      • changedInput schema / additionalProperties
        Previous value: -trueNew value: +{}
    • ChangedfetchGithubContent1 field changed
      • changedInput schema / additionalProperties
        Previous value: -trueNew value: +{}
    • ChangedfetchWebContent4 fields changed
      • changedInput schema / additionalProperties
        Previous value: -trueNew value: +{}
      • changedInput schema / properties / extract / additionalProperties
        Previous value: -trueNew value: +{}
      • changedInput schema / properties / extract / properties / fields / items / additionalProperties
        Previous value: -trueNew value: +{}
      • addedInput schema / properties / startIndex / maximum
        Added value: +9007199254740991
    • ChangedqueryDocs1 field changed
      • changedInput schema / additionalProperties
        Previous value: -trueNew value: +{}
    • Changedsearch1 field changed
      • changedInput schema / additionalProperties
        Previous value: -trueNew value: +{}
  2. 1 tool updatev1.4.2
    • AddedcodeSymbol
  3. 1 tool updatev1.3.12
    • ChangedfetchGithubContent1 field changed
      • addedInput schema / properties / releaseLimit
        Added value: +{
        +  "description": "Optional number of releases to return for /releases URLs (1-30, default 10).",
        +  "maximum": 30,
        +  "minimum": 1,
        +  "type": "integer"
        +}
  4. 5 tool updatesv1.3.10
    • AddedfetchGithubContent
    • RemovedfetchGithubReadme
    • ChangedfetchWebContent7 fields changed
      • changedInput schema / additionalProperties
        Previous value: -falseNew value: +true
      • addedInput schema / properties / cache
        Added value: +{
        +  "description": "Cache mode: 'default' uses disk Markdown cache; 'reload' forces re-fetching upstream",
        +  "enum": [
        +    "default",
        +    "reload"
        +  ],
        +  "type": "string"
        +}
      • addedInput schema / properties / citations
        Added value: +{
        +  "description": "Rewrite inline links as numbered citations and append a '## References' list, so the answer can cite sources",
        +  "type": "boolean"
        +}
      • addedInput schema / properties / extract
        Added value: +{
        +  "additionalProperties": true,
        +  "description": "Extract structured JSON instead of markdown, using CSS selectors — no LLM needed. fields: [{name, selector, type: text|html|markdown|attribute|list, attribute?, fields?, all?}]; selector '@attr' reads an attribute of the current node",
        +  "properties": {
        +    "baseSelector": {
        +      "minLength": 1,
        +      "type": "string"
        +    },
        +    "fields": {
        +      "items": {
        +        "additionalProperties": true,
        +        "properties": {
        +          "all": {
        +            "type": "boolean"
        +          },
        +          "attribute": {
        +            "minLength": 1,
        +            "type": "string"
        +          },
        +          "fields": {
        +            "items": {},
        +            "type": "array"
        +          },
        +          "name": {
        +            "minLength": 1,
        +            "type": "string"
        +          },
        +          "selector": {
        +            "minLength": 1,
        +            "type": "string"
        +          },
        +          "type": {
        +            "enum": [
        +              "text",
        +              "html",
        +              "markdown",
        +              "attribute",
        +              "list"
        +            ],
        +            "type": "string"
        +          }
        +        },
        +        "required": [
        +          "name"
        +        ],
        +        "type": "object"
        +      },
        +      "maxItems": 50,
        +      "minItems": 1,
        +      "type": "array"
        +    }
        +  },
        +  "required": [
        +    "fields"
        +  ],
        +  "type": "object"
        +}
      • addedInput schema / properties / focusMode
        Added value: +{
        +  "description": "How focus selects text: 'bm25' (default) ranks paragraphs by relevance and keeps the best ones; 'window' keeps the old ±2500-char window around the first match",
        +  "enum": [
        +    "bm25",
        +    "window"
        +  ],
        +  "type": "string"
        +}
      • addedInput schema / properties / retainLinks
        Added value: +{
        +  "description": "Inline link retention: 'all' (default) keeps [label](url); 'text' keeps only the label (strips URLs, big win on index/list pages); 'none' removes the link entirely. Ignored inside code blocks",
        +  "enum": [
        +    "all",
        +    "none",
        +    "text"
        +  ],
        +  "type": "string"
        +}
      • addedInput schema / properties / selector
        Added value: +{
        +  "description": "CSS selector: return only the matched subtree, keeping code blocks and tables. Use when auto-extraction grabs the wrong container. Errors instead of silently returning the whole page when nothing matches",
        +  "minLength": 1,
        +  "type": "string"
        +}
    • ChangedqueryDocs4 fields changed
      • changedInput schema / additionalProperties
        Previous value: -falseNew value: +true
      • addedInput schema / properties / cache
        Added value: +{
        +  "description": "Use the 24h local docs cache (default) or bypass/refresh it with 'reload'",
        +  "enum": [
        +    "default",
        +    "reload"
        +  ],
        +  "type": "string"
        +}
      • addedInput schema / properties / strict
        Added value: +{
        +  "description": "If true, rejects low-confidence library name matches with an error instead of returning loosely matched candidate docs (default false)",
        +  "type": "boolean"
        +}
      • addedInput schema / properties / version
        Added value: +{
        +  "description": "Optional explicit version (e.g. '14.2.0' or 'v15.1.8'); overrides an @version embedded in library",
        +  "minLength": 1,
        +  "type": "string"
        +}
    • Changedsearch10 fields changed
      • changedInput schema / additionalProperties
        Previous value: -falseNew value: +true
      • changedInput schema / properties / engines / description
        Previous value: -"Search engines to use (default: server default, which may auto-route by query language)"New value: +"Search engines to use (default: auto-routes by query language; explicit engines do not cascade unless minResults is specified)"
      • changedInput schema / properties / engines / items / description
        Previous value: -"Search engine name. Valid values (normalize alias to canonical name): baidu, bing, csdn, duckduckgo, exa, brave, juejin, startpage, sogou, github, stackoverflow, hackernews, arxiv"New value: +"Search engine name. Valid values (normalize alias to canonical name): baidu, bing, bing-news, csdn, duckduckgo, exa, brave, juejin, startpage, yahoo, sogou, github, stackoverflow, hackernews, arxiv, code"
      • changedInput schema / properties / fetchTop / description
        Previous value: -"Two-in-one search & fetch: automatically fetch full readable Markdown content for top N results (0~3) in a single turn (up to 4000 chars per article)"New value: +"Two-in-one search & fetch: automatically fetch full readable Markdown content for top N results (0~3) in a single turn"
      • changedInput schema / properties / limit / description
        Previous value: -"Max results (default: server DEFAULT_SEARCH_LIMIT, usually 10)"New value: +"Target total results after merging all engines (default: server DEFAULT_SEARCH_LIMIT, usually 10). Not a per-engine quota: once enough results are collected, slower engines may be cancelled (see cancelledEngines). Pass explicit `engines` to disable early cancellation."
      • changedInput schema / properties / minResults / description
        Previous value: -"Auto-run additional engines when fewer than this many USABLE results (relevant, non-entry-page) come back (default: server DEFAULT_MIN_RESULTS, usually 5; max 50 — larger values only burn the search deadline)"New value: +"Auto-run additional engines when fewer usable results come back (default: 5 when engines omitted, 0 when engines explicitly specified)"
      • changedInput schema / properties / queries / description
        Previous value: -"1-4 queries run concurrently and merged (required if 'query' is omitted) — for covering multiple intents in one call (e.g. official docs / Chinese community / English). Response includes 'cached: true' only when all sub-queries hit the TTL cache."New value: +"1-4 queries run concurrently and merged (required if 'query' is omitted)"
      • addedInput schema / properties / searchMode / description
        Added value: +"Execution mode: 'request' (HTTP only), 'auto' (HTTP with browser fallback), or 'playwright' (headless browser only)"
      • addedInput schema / properties / site
        Added value: +{
        +  "description": "Restrict search to specific site domain(s) (e.g. ['github.com', 'developer.mozilla.org'])",
        +  "items": {
        +    "type": "string"
        +  },
        +  "minItems": 1,
        +  "type": "array"
        +}
      • addedInput schema / properties / timeRange
        Added value: +{
        +  "description": "Publication time range filter ('day', 'week', 'month', 'year')",
        +  "enum": [
        +    "day",
        +    "week",
        +    "month",
        +    "year"
        +  ],
        +  "type": "string"
        +}
  5. 3 tool updatesv1.3.1
    • RemovedfetchCsdnArticle
    • RemovedfetchJuejinArticle
    • ChangedqueryDocs1 field changed
      • removedInput schema / required
        Removed value: -[
        -  "library"
        -]
  6. 4 tool updatesv1.2.1
    • ChangedfetchWebContent3 fields changed
      • addedInput schema / properties / focus
        Added value: +{
        +  "description": "Keyword or section name to target (e.g. 'Auth', 'Config'); returns targeted window (~5000 chars) instead of burning tokens on full document",
        +  "minLength": 1,
        +  "type": "string"
        +}
      • addedInput schema / properties / urls
        Added value: +{
        +  "description": "Batch URLs (1~3 URLs run concurrently, splitting maxChars budget; ideal for comparing search results)",
        +  "items": {
        +    "format": "uri",
        +    "type": "string"
        +  },
        +  "maxItems": 3,
        +  "minItems": 1,
        +  "type": "array"
        +}
      • removedInput schema / required
        Removed value: -[
        -  "url"
        -]
    • ChangedqueryDocs4 fields changed
      • addedInput schema / properties / library
        Added value: +{
        +  "description": "Library or package name (e.g. 'next.js', 'react', 'fastapi') or exact Context7 library ID (e.g. '/vercel/next.js', version-pinnable like '/vercel/next.js@v15.1.8')",
        +  "minLength": 1,
        +  "type": "string"
        +}
      • changedInput schema / properties / libraryId / description
        Previous value: -"Exact Context7-compatible library ID (e.g. /vercel/next.js, /packages/express; optional version like /vercel/next.js@v15.1.8)"New value: +"Legacy alias for library (e.g. /vercel/next.js)"
      • changedInput schema / properties / query / description
        Previous value: -"The question or task to get relevant documentation for (optional; defaults to an overview when omitted, e.g. 'how to set up middleware with auth')"New value: +"The question, feature, or task to get relevant documentation for (optional; defaults to an overview when omitted, e.g. 'how to set up middleware with auth')"
      • changedInput schema / required
        Previous value: -[
        -  "libraryId"
        -]New value: +[
        +  "library"
        +]
    • RemovedresolveLibraryId
    • Changedsearch3 fields changed
      • changedInput schema / properties / engines / items / description
        Previous value: -"Search engine name. Valid values (normalize alias to canonical name): baidu, bing, csdn, duckduckgo, exa, brave, juejin, startpage, sogou"New value: +"Search engine name. Valid values (normalize alias to canonical name): baidu, bing, csdn, duckduckgo, exa, brave, juejin, startpage, sogou, github, stackoverflow, hackernews, arxiv"
      • addedInput schema / properties / fetchTop
        Added value: +{
        +  "description": "Two-in-one search & fetch: automatically fetch full readable Markdown content for top N results (0~3) in a single turn (up to 4000 chars per article)",
        +  "maximum": 3,
        +  "minimum": 0,
        +  "type": "integer"
        +}
      • changedInput schema / properties / limit / type
        Previous value: -"number"New value: +"integer"
  7. 2 tool updatesv1.0.25
    • ChangedfetchWebContent1 field changed
      • changedInput schema / properties / format / description
        Previous value: -"Content format: 'markdown' preserves fenced code blocks (with language) and GFM tables — better for technical docs"New value: +"Content format (default: 'markdown' when raw is false): 'markdown' preserves headings, lists, fenced code blocks (with language) and GFM tables — better for technical docs; use 'text' for plain text"
    • Changedsearch2 fields changed
      • changedInput schema / properties / queries / description
        Previous value: -"1-4 queries run concurrently and merged (required if 'query' is omitted) — for covering multiple intents in one call (e.g. official docs / Chinese community / English)"New value: +"1-4 queries run concurrently and merged (required if 'query' is omitted) — for covering multiple intents in one call (e.g. official docs / Chinese community / English). Response includes 'cached: true' only when all sub-queries hit the TTL cache."
      • addedInput schema / properties / verbose
        Added value: +{
        +  "description": "Include verbose diagnostic fields (engineMetrics, full failure hints, and redundant source hostnames); default false to save tokens",
        +  "type": "boolean"
        +}
  8. 1 tool updatev1.0.21
    • Changedsearch2 fields changed
      • changedInput schema / properties / queries / description
        Previous value: -"1-4 queries run concurrently and merged (dedup by URL) — for covering multiple intents in one call (e.g. official docs / Chinese community / English)"New value: +"1-4 queries run concurrently and merged (required if 'query' is omitted) — for covering multiple intents in one call (e.g. official docs / Chinese community / English)"
      • changedInput schema / properties / query / description
        Previous value: -"Single search query (use queries for multi-intent fan-out)"New value: +"Single search query (required if 'queries' is omitted; use 'queries' for multi-intent fan-out)"
  9. 2 tool updatesv1.0.17
    • ChangedfetchJuejinArticle1 field changed
      • addedInput schema / properties / format
        Added value: +{
        +  "description": "Output format (default: text). 'markdown' keeps fenced code blocks (with language) and GFM tables — recommended for technical posts",
        +  "enum": [
        +    "text",
        +    "markdown"
        +  ],
        +  "type": "string"
        +}
    • Changedsearch2 fields changed
      • changedInput schema / properties / minResults / description
        Previous value: -"Auto-run additional engines when fewer than this many USABLE results (relevant, non-entry-page) come back (default: server DEFAULT_MIN_RESULTS, usually 5)"New value: +"Auto-run additional engines when fewer than this many USABLE results (relevant, non-entry-page) come back (default: server DEFAULT_MIN_RESULTS, usually 5; max 50 — larger values only burn the search deadline)"
      • addedInput schema / properties / minResults / maximum
        Added value: +50
  10. 2 tool updatesv1.0.15
    • ChangedfetchWebContent1 field changed
      • addedInput schema / properties / format
        Added value: +{
        +  "description": "Content format: 'markdown' preserves fenced code blocks (with language) and GFM tables — better for technical docs",
        +  "enum": [
        +    "text",
        +    "markdown"
        +  ],
        +  "type": "string"
        +}
    • Changedsearch8 fields changed
      • removedInput schema / properties / engines / default
        Removed value: -[
        -  "bing"
        -]
      • addedInput schema / properties / engines / description
        Added value: +"Search engines to use (default: server default, which may auto-route by query language)"
      • removedInput schema / properties / limit / default
        Removed value: -10
      • addedInput schema / properties / limit / description
        Added value: +"Max results (default: server DEFAULT_SEARCH_LIMIT, usually 10)"
      • changedInput schema / properties / minResults / description
        Previous value: -"Auto-run additional engines when fewer than this many results come back (default: disabled)"New value: +"Auto-run additional engines when fewer than this many USABLE results (relevant, non-entry-page) come back (default: server DEFAULT_MIN_RESULTS, usually 5)"
      • addedInput schema / properties / queries
        Added value: +{
        +  "description": "1-4 queries run concurrently and merged (dedup by URL) — for covering multiple intents in one call (e.g. official docs / Chinese community / English)",
        +  "items": {
        +    "maxLength": 500,
        +    "minLength": 1,
        +    "type": "string"
        +  },
        +  "maxItems": 4,
        +  "minItems": 1,
        +  "type": "array"
        +}
      • addedInput schema / properties / query / description
        Added value: +"Single search query (use queries for multi-intent fan-out)"
      • removedInput schema / required
        Removed value: -[
        -  "query"
        -]
  11. 7 tool updatesv1.0.11
    • First observedfetchCsdnArticle
    • First observedfetchGithubReadme
    • First observedfetchJuejinArticle
    • First observedfetchWebContent
    • First observedqueryDocs
    • First observedresolveLibraryId
    • First observedsearch

TDQS

A3.7/5.0

Scored across 5 tools

Disambiguation4/5

Each tool targets a reasonably distinct need: general web search, generic URL/PDF extraction, GitHub-specific artifacts, library documentation lookup, and symbol-level code search. The main friction is between fetchWebContent and fetchGithubContent (both fetch content, and the boundary is only implied by URL type) and between queryDocs and search (docs lookup can fall back to GitHub READMEs). Descriptions largely resolve these, but an agent must read carefully to pick correctly for a github.com URL.

Naming Consistency4/5

Four of five tools use camelCase verb_noun-ish names (fetchWebContent, fetchGithubContent, queryDocs, codeSymbol), giving a predictable pattern. The lone 'search' breaks the pattern by being a bare verb, a minor deviation rather than a systemic inconsistency.

Tool Count5/5

Five tools is well-scoped for a web search/fetch server; each covers a genuinely different retrieval target (search, generic page, GitHub artifact, docs, symbol). No tool appears redundant or thrown in as filler.

Completeness4/5

The surface covers the core retrieval lifecycle: discovery (search, queryDocs), retrieval (fetchWebContent, fetchGithubContent), and code navigation (codeSymbol), with pagination and caching handled inside fetchWebContent. Minor gaps exist — no dedicated repo-wide listing/browsing, no explicit cache management or multi-page crawl tool — but agents can work around these via search and URL paging.

Maintenance

ActivityActive
ResponsivenessNo recent community issues

Related MCP Connectors

Related MCP Servers

  • F
    license
    Not graded
    quality
    D
    maintenance
    MCP server providing web search, news search, and X/Twitter search capabilities via HTTP or stdio.
    -
  • A
    license
    Not graded
    quality
    C
    maintenance
    MCP server for multi-engine web search and web page fetching, supporting parallel search, content extraction, and optional LLM-powered search summarization and deep search.
    5
    MIT
  • A
    license
    Not graded
    quality
    A
    maintenance
    Enables LLMs to run web and academic searches across multiple engines (Baidu, Bing, DuckDuckGo, Tavily, Exa, Doubao and 9 scholarly sources) with local relevance scoring, deduplication and caching, plus SSRF-protected page fetching and PDF parsing, and works without any API key. It plugs into MCP clients like Claude Code, Cursor and Qwen Code, or can be embedded as a Go module.
    29
    MIT