Open-WebSearch: an MCP server, CLI, and local daemon that search without API keys
Multi-engine MCP server, CLI, and local daemon for agent web search and content retrieval — skill-guided workflows, no API keys.
At a glance
- What is it?
- Open-WebSearch v2.2.0 gives coding agents web search and page fetching through multiple engines with no keys, packaged three ways: an MCP server, a one-shot CLI, and a local HTTP daemon. The engine parsers and the fetch limits are where it will hurt you.
- Who is it for?
- Open-WebSearch earns a place in an agent toolchain that has no search budget and no vendor key to hand out: the npm one-liner, the daemon on port 3000, and the package scripts make it easy to try in a single afternoon.
- Can I use it commercially?
- Yes. Apache-2.0 is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 15 days ago.
- What is it written in?
- Mainly TypeScript, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.
Editorial analysis
Eleven engines, zero keys, and why that trade exists
The problem Open-WebSearch addresses is narrow and real: an agent running inside Claude Desktop, Cursor or Cherry Studio needs to look something up, and some search APIs require a credit card and an API key before use. This project's answer is to scrape the engine result pages directly. The engine list is bing, baidu, csdn, duckduckgo, exa, brave, juejin, startpage, sogou and hackernews, plus linux.do, which the feature list marks as temporarily unsupported. Note what is in that list: CSDN, Juejin and Sogou are Chinese developer platforms, not general web search. This is not a Google replacement; it is a project built by someone who wanted reach into Chinese-language technical content as well as the English engines.
The result shape is deliberately plain. Titles, URLs and descriptions come back as structured records, the number of results per search is configurable, and a default engine can be set so that callers do not have to name one. The license is Apache-2.0, and the current package version is 2.2.0.
Three ways in: MCP, CLI, and the long-lived daemon
The packaging is the part worth understanding, because the three paths are not redundant. The MCP server is for editors that speak the protocol over stdio and want the tools to appear in a sidebar. The CLI is for one-shot terminal use and shell scripts, where spinning up a client is wasted effort. The local daemon is for repeated calls from agents that make many queries in a row, because a per-invocation process start is the friction you are trying to remove.
The daemon is explicit, not implicit. `open-websearch serve` starts it; `open-websearch status` reports on it. The HTTP surface includes `status`, `GET /health`, `POST /search` and `POST /fetch-*`, with details in docs/http-api.md. Action commands such as `search` and `fetch-web` try the local daemon first when one is reachable, but passing `--daemon-url` makes that path explicit and switches off the silent fallback to direct execution. That flag is the one to reach for when a script must not quietly bypass a daemon you are debugging.
One trap worth naming: bare `open-websearch` is the MCP compatibility entrypoint, not the daemon start command. Typing it by hand and expecting a listening service is the most likely first-run mistake.
Running the daemon from a checkout with npm run
If you are working from the repository rather than installing globally, the package scripts wrap the compiled binary. Build first, because everything else runs `build/index.js`, and the build step also sets the executable bit on that file.
npm run buildThen start the daemon and ask it what state it is in. The status script takes `--json`, which is what you want if you plan to parse the output.
npm run serve
npm run status -- --jsonA one-shot search runs through the `search:cli` script, and `--json` again gives you machine-readable output to pipe:
npm run search:cli -- "open web search" --jsonThese are three separate process launches, which is exactly the cost the daemon exists to amortize.
Two proxy settings that are not interchangeable
Open-WebSearch splits proxy configuration into install-time and run-time, and conflating them wastes an afternoon. The install proxy applies when npm is fetching packages, the skill, or playwright. In restricted networks the documentation argues npm-specific flags beat generic shell proxy variables:
npm --proxy http://127.0.0.1:7890 --https-proxy http://127.0.0.1:7890 install -g open-websearchThe runtime proxy applies after the daemon is already installed and is about to make live calls. It is two environment variables on the `serve` command:
USE_PROXY=true PROXY_URL=http://127.0.0.1:7890 open-websearch serveIf package installation succeeds but search and fetch fail, that is the expected symptom of a missing runtime proxy, not a broken install.
Environment variables that steer behaviour at startup include `DEFAULT_SEARCH_ENGINE`, whose documented default is bing, and `ENABLE_CORS`, which the compose file pairs with `CORS_ORIGIN`. The docker-compose service ships with `CORS_ORIGIN: "*"`; open that up only when something other than a local client needs to reach it.
Launching the MCP server without installing anything globally
For editor clients, the documented fast path is npx, and the environment variables are set inline per platform. On Linux and macOS:
DEFAULT_SEARCH_ENGINE=duckduckgo ENABLE_CORS=true npx open-websearch@latestPowerShell needs its own syntax, and the CMD example also shows a `MODE` variable that the package scripts use in testing:
$env:DEFAULT_SEARCH_ENGINE="duckduckgo"; $env:ENABLE_CORS="true"; npx open-websearch@latestFor local development across shells, the README installs globally and goes through cross-env instead:
npm install -g open-websearch
npx cross-env DEFAULT_SEARCH_ENGINE=duckduckgo ENABLE_CORS=true open-websearchThere is also an optional agent-facing skill, installed as its own artifact:
npx skills add https://github.com/Aas-ee/open-webSearch --skill open-websearchThe skill is a guidance layer, not a replacement for the three paths above. On first use it checks whether a usable `open-websearch` binary exists, walks setup if not, validates the capability, and only then searches. If the environment cannot activate automatically, the documented fallback is to start the daemon by hand.
Fetching pages: prefer a specific result over a homepage
Fetching is the half of this project most likely to disappoint. Content extraction covers three targets: csdn, github README files, and generic HTTP(S) pages or Markdown. The README's own advice is a workflow rule rather than a feature: search first, then fetch a more specific result page. Homepages and JavaScript-heavy landing pages frequently return nothing readable through `fetch-web`, because the article text is assembled client-side and a plain HTTP fetch never sees it.
So a typical session is two steps, not one: query the engine, pick a URL from the titles and descriptions, fetch that URL. Treating fetch as a universal reader is the design mistake the documentation is warning against. The TODO list still carries optimization of article content extraction and broader site coverage, which puts a ceiling on how far this goes today.
A parser-specific test exists in the package scripts, `test:bing-parser`, alongside `test:bing-http`, `test:cli-search`, `test:engine-normalization` and `test:local-daemon`, which is a reasonable hint at which engines are the most fragile.
Container build carries a native module toolchain
The Dockerfile builds on node:20-alpine and does something that is easy to miss: it installs a C++ and Python toolchain, runs the dependency install, and then deletes the toolchain again. The comment explains why, and it is a concrete constraint for anyone building on linux/arm64 Alpine where no prebuilt koffi package exists and the native module has to compile from source. Alpine does not ship the compiler by default, so this build layer is mandatory, not a leftover.
The image also creates a non-root user with uid and gid 1001, chowns `/app` to it, and switches to it before the entrypoint. `PORT` defaults to 3000 and can be overridden by the deployment environment, and compose maps 3000 to the host. A commented-out Aliyun registry image and a commented-out `extra_hosts` entry for `host.docker.internal` sit in the compose file, which is the shape of a file that has been adapted for different networks more than once.
The build publishes only the `build` directory, with `bin` pointing at `./build/index.js`, so a consumer installing the package gets the compiled output and not the TypeScript sources.
Where scraping search engines stops being the right answer
The honest limitation is structural. Every engine here is a page being parsed, not an API being called, so result shape, ordering and availability can change without notice, and the project's own parser tests are a tell that breakage is expected and needs catching. The list of temporarily unsupported engines confirms that surface is not fully under its control.
Compared with a commercial search API, Open-WebSearch gives you no SLA, no stable response contract, no rate-limit documentation in the README, and no billing path. What it gives in exchange is zero credentials and reach into platforms that do not offer a usable free API. If you need auditable citations, consistent structured data across queries, or a defensible answer about where a fact came from, an engine-backed API is the better foundation.
For an agent doing exploratory lookups where a plausible set of titles and URLs is enough, the trade is a good one. Decide based on that, not on the count of engines. The README also does not document a rollback path for a release, and the HTTP API details live in docs/http-api.md rather than the main page, so read that file before wiring the daemon into anything long-lived.
Editorial conclusion
Open-WebSearch earns a place in an agent toolchain that has no search budget and no vendor key to hand out: the npm one-liner, the daemon on port 3000, and the package scripts make it easy to try in a single afternoon. It is the wrong choice when the answer has to be citable and reproducible, because results are scraped from engines like bing, baidu, csdn, juejin, sogou, startpage, duckduckgo, exa, brave and hackernews rather than pulled from a documented API, and linux.do is listed as temporarily unsupported. Before adopting it, check two things against your own pages: run fetch-web on a JavaScript-heavy page from your target sites and see whether article text comes back, and confirm DEFAULT_SEARCH_ENGINE matches the region your users are in. Maintenance is not the risk here; the last push was on 2026-10-08 and v2.2.0 shipped on 2026-09-28. The risk is scraping fragility, and Apache-2.0 plus a Dockerfile on node:20-alpine mean you can fork the parsers yourself when a page layout changes.
Frequently asked questions
Does Open-WebSearch need an API key to run?
No. The feature list states that no API keys or authentication are required, because results come from parsing search engine pages directly rather than from a vendor API. DEFAULT_SEARCH_ENGINE only selects which engine is used by default.
How do I start and check the local daemon in Open-WebSearch?
Run `open-websearch serve` to start it and `open-websearch status` to check it; `open-websearch status --json` gives machine-readable output. From a checkout the equivalents are `npm run serve` and `npm run status -- --json`, after `npm run build`.
Why does Open-WebSearch fetch return empty text for some pages?
The README says some homepages and JavaScript-heavy landing pages may not expose readable article text through fetch-web. Search first and fetch a more specific result page instead of pointing fetch at a landing page.
How do I make Open-WebSearch work behind a proxy?
Install-time and run-time proxying are separate. For installing packages use `npm --proxy http://127.0.0.1:7890 --https-proxy http://127.0.0.1:7890 install -g open-websearch`; for live traffic set `USE_PROXY=true` and `PROXY_URL` on the `open-websearch serve` command.
Which search engines does Open-WebSearch support?
The documented list covers bing, baidu, csdn, duckduckgo, exa, brave, juejin, startpage, sogou and hackernews, with linux.do marked as temporarily unsupported. The TODO list names Google and other engines as future work.
Can I run Open-WebSearch in Docker?
Yes. The Dockerfile builds on node:20-alpine, installs a native build toolchain for linux/arm64 where prebuilt koffi packages are missing, creates a non-root user, and defaults PORT to 3000. docker-compose pulls ghcr.io/aas-ee/open-web-search:latest and enables ENABLE_CORS with CORS_ORIGIN set to "*".
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/aas-ee-open-websearch)Was this useful?