ketch
Web search, public code search, library docs and page-to-markdown scraping from one Go binary
Keyless web search, page fetching, crawling and extraction that run on your own machine
By Towhid Khan (individual) TypeScript Local · stdio Web searchBrowser automation
79 popularity score ★ 5.5k ↓ 1.2k/wk
Opens the app, which asks before it adds the server.
npx wigolo initclaude mcp add wigolo -- npx -y wigolo{
"mcpServers": {
"wigolo": {
"command": "npx",
"args": [
"-y",
"wigolo"
]
}
}
}{
"mcpServers": {
"wigolo": {
"command": "npx",
"args": [
"-y",
"wigolo"
]
}
}
}{
"servers": {
"wigolo": {
"type": "stdio",
"command": "npx",
"args": [
"-y",
"wigolo"
]
}
}
}[mcp_servers.wigolo]
command = "npx"
args = ["-y", "wigolo"]gemini mcp add --scope user wigolo npx -- -y wigoloOpens the app, which asks before it adds the server.
claude mcp add wigolo -- docker run -i --rm -v wigolo-data:/data ghcr.io/knockoutez/wigolo{
"mcpServers": {
"wigolo": {
"command": "docker",
"args": [
"run",
"-i",
"--rm",
"-v",
"wigolo-data:/data",
"ghcr.io/knockoutez/wigolo"
]
}
}
}{
"mcpServers": {
"wigolo": {
"command": "docker",
"args": [
"run",
"-i",
"--rm",
"-v",
"wigolo-data:/data",
"ghcr.io/knockoutez/wigolo"
]
}
}
}{
"servers": {
"wigolo": {
"type": "stdio",
"command": "docker",
"args": [
"run",
"-i",
"--rm",
"-v",
"wigolo-data:/data",
"ghcr.io/knockoutez/wigolo"
]
}
}
}[mcp_servers.wigolo]
command = "docker"
args = ["run", "-i", "--rm", "-v", "wigolo-data:/data", "ghcr.io/knockoutez/wigolo"]gemini mcp add --scope user wigolo docker -- run -i --rm -v wigolo-data:/data ghcr.io/knockoutez/wigolo| Set together: llm | |
|---|---|
WIGOLO_LLM_PROVIDER |
Optional: LLM used to write answers: gemini, anthropic, openai, groq or ollama. |
GEMINI_API_KEY secret |
Optional: Key for the Gemini provider; ANTHROPIC_API_KEY, OPENAI_API_KEY and GROQ_API_KEY serve the others. |
WIGOLO_LOCAL_LLM |
Optional: auto to use a local model for synthesis, or an OpenAI-compatible URL. |
WIGOLO_SEARCH |
Optional: Search backend; hybrid adds an aggregator fallback to the built-in engines. |
WIGOLO_GITHUB_TOKEN secret |
Optional: GitHub token that raises the code-search limit from 10 to 30 requests a minute. |
WIGOLO_TLS_TIER |
Optional: Set to auto for fetch hardening learned per domain. |
WIGOLO_EAGER_WARMUP |
Optional: Set to 1 to load models at start instead of on first use. |
WIGOLO_API_TOKEN secret |
Optional: Bearer token required when wigolo serve listens beyond loopback. |
| Set together: proxy | |
USE_PROXY |
Optional: Set to true to send traffic through PROXY_URL. |
PROXY_URL secret |
Optional: Proxy address used when USE_PROXY is true. |
In a container, a setting goes in with -e NAME=value after docker run.
wigolo is a stdio MCP server that gives a coding agent its own web layer: searching the public web, loading single pages as markdown, crawling whole sites, pulling structured data out of pages, and keeping everything it has seen in a local cache it can query later. It is written in TypeScript and runs as one Node process.
Search queries go straight to public search engines through 18 built-in adapters; the results are merged, re-ranked by a model that runs on your machine, and returned with a quoted excerpt, a citation ID and a score breakdown. search returns 5 results by default, up to 20 with `max_results`. Page loading starts with plain HTTP and switches to a bundled headless browser when a page needs JavaScript or shows an anti-bot check. It can also click, type and scroll before reading a page, read PDFs, and reuse a stored browser login.
The research and agent tools break a question into sub-queries, gather sources and return either a raw brief or, when an LLM is configured (Gemini, Anthropic, OpenAI, Groq, or a local Ollama model), a written answer with citations. agent stops after 60 seconds and 10 pages unless `max_time_ms` and `max_pages` (up to 100) say otherwise. The diff and watch tools track changes to pages and can post them to a webhook. Besides its ten tools, the server offers one resource, a usage guide at wigolo://docs/usage.
The same ten tools are also offered over a local REST API (`wigolo serve`, which also serves MCP over HTTP at /mcp), a CLI, and TypeScript and Python SDKs. The makers describe it as in public beta.
| Runtime | Node.js 22+ |
|---|---|
| Runs on | macOS, Windows, Linux |
| Also |
|
Node.js 22 or newer: the package's engines field at 0.3.0 says >=22 and the installation guide says 22+, though the README badge and text still say Node 20. Run `npx wigolo init` once to download the browser engine and on-device models. Docker works instead of Node: the default image fetches those downloads on first use into the /data volume, while ghcr.io/knockoutez/wigolo:latest-full comes with the browser already in it. Search, fetch, crawl, extract, cache and find_similar need no key; a written answer from research, agent or search needs an LLM provider key or a local Ollama model.
Public beta. Without an LLM configured, research, agent and answer-style search return a brief and evidence rather than a finished answer. Pages behind challenges that do not clear come back as a labelled blocked_by_challenge failure, and its docs note that datacenter IPs clear fewer of these walls than home connections (a proxy is the suggested fix). GitHub code search is limited to 10 requests a minute without a token. watch jobs only run while an MCP session or `wigolo serve` is active, with a 60-second minimum interval. Homebrew, the install script and the single-file binary were not yet published when the installation guide was written.
Suits developers who want their coding agent to search and read the web without paying per query or sending queries to a hosted search API, and who can spare the disk space and a first-run download. Because everything runs locally and the cache stays on disk, it also suits repeated research on the same sites. Pick a hosted search API instead if you cannot install a browser engine and models, run on a datacenter machine where anti-bot walls matter, or need a supported, non-beta service.
7 only read, 2 change things, 1 can delete or overwrite. A ? marks an optional parameter.
searchquery: anymax_results?: numberinclude_content?: booleantime_range?: enuminclude_domains?: arrayexclude_domains?: arraycategory?: enumformat?: enumsearch_depth?: enummode?: enumfetch changesurl: stringrender_js?: enumuse_auth?: booleansection?: stringscreenshot?: booleanheaders?: objectactions?: arraymode?: enumcrawlurl: stringmax_depth?: numbermax_pages?: numberstrategy?: enuminclude_patterns?: arrayexclude_patterns?: arrayuse_auth?: booleanextracturl?: stringhtml?: stringmode?: enumcss_selector?: stringschema?: objectnamed_schema?: enumcache deletesquery?: stringurl_pattern?: stringsince?: stringclear?: booleanstats?: booleancheck_changes?: booleanmode?: enumlimit?: numberfind_similarurl?: stringconcept?: stringmax_results?: numberinclude_cache?: booleaninclude_web?: booleanmode?: enumresearchquestion: stringdepth?: enummax_sources?: numberinclude_domains?: arrayexclude_domains?: arrayschema?: objectstream?: booleanagentprompt: stringurls?: arrayschema?: objectmax_pages?: numbermax_time_ms?: numberstream?: booleandiffold?: objectnew?: objectoutput?: enumgranularity?: enumwatch changesaction: enumurl?: stringurls?: arrayinterval_seconds?: numberselector?: stringnotification?: stringjob_id?: stringwigolo://docs/usage