Browse by type

Local-first web intelligence over MCP — no keys, no cloud, no metered bill.
works with Claude Code · Cursor · Codex · Gemini CLI · VS Code · Windsurf · Zed · Antigravity
Quickstart · Tools · Why wigolo · Benchmark · Architecture · Configuration · Feedback · FAQ · Available on · Contribute
wigolo runs on your machine as an MCP server and gives an AI coding agent one durable surface for everything web-related — search, fetch, crawl, extract, cache, find-similar, research, and autonomous gather loops. The core tools need no API keys, nothing it touches leaves ~/.wigolo/, and there's no bill that grows with how much your agent thinks.

wigolo went public in early July 2026. It found its audience fast — most of the stars below landed in a single 48-hour window.
Chart generated from the public GitHub star timeline. If it's still climbing when you read this, that's the point — add a ⭐.
Requires Node ≥ 20 and ~1.5 GB of free disk. macOS, Linux, and Windows.
One command wires the local engine into your agent and sets up the MCP connection. init is unattended by default — no prompts, safe in scripts and CI — and does the complete setup: it downloads the browser engine and on-device models, runs a health check, and prints a clear per-component summary, so any setup problem surfaces right here, not silently on your agent's first call:
npx wigolo init --agents=<your-agent>
<your-agent> — one or more of claude-code · cursor · codex · gemini-cli · vscode · windsurf · zed · antigravity (comma-separated). wigolo writes the MCP config and instructions for you — nothing else to set up.--agents — init still sets up the engine, and you point your agent at wigolo's MCP server (npx wigolo mcp) yourself.--interactive gives a plain-text prompt flow (pick your agents step by step); --wizard gives the richer terminal TUI. Both need a real terminal.init? You can wire the MCP server directly (below) without ever running init — the browser engine and models then download automatically on first use.--no-warmup to skip the downloads (components lazy-load on first use instead). (--non-interactive still works — it's just the default now.)init reports what's not ready with the exact fix and still wires your agent — the component retries on first use.That's the whole setup — search, fetch, crawl, extract, cache, and find-similar work with no API key. Check it's healthy:
npx wigolo doctor
Not for you? npx wigolo config --uninstall --yes removes everything, cleanly.
The --agents flag has a built-in installer for each agent listed above — but it can't cover every agent in the world. For anything else — your own custom or in-house agent, or any MCP-capable client we don't wire automatically yet — set wigolo up by hand: it's just another MCP server. Install the engine once, then register it:
npx wigolo init # unattended full setup, no agent wiring (add --no-warmup to defer downloads)
Most clients use an mcpServers block in a JSON config file:
{
"mcpServers": {
"wigolo": {
"command": "npx",
"args": ["-y", "wigolo"]
}
}
}
wigolo with no subcommand starts the MCP stdio server (that is the default). If you installed it globally, use "command": "wigolo", "args": [] instead.
The file location — and the exact key — vary by client:
| Agent | Config file | Servers key |
|---|---|---|
| Cursor | ~/.cursor/mcp.json |
mcpServers |
| Windsurf | ~/.codeium/windsurf/mcp_config.json |
mcpServers |
| Gemini CLI | ~/.gemini/settings.json |
mcpServers |
| Antigravity | ~/.antigravity/mcp.json |
mcpServers |
| VS Code | user mcp.json (Command Palette → MCP: Open User Configuration) |
servers |
| Zed | ~/.config/zed/settings.json |
context_servers |
| Claude Code | (no file) run claude mcp add wigolo --scope user -- npx -y wigolo (--scope user = global; drop it for project-only) |
— |
| Codex | ~/.codex/config.toml (TOML, not JSON) |
[mcp_servers.wigolo] |
| Any other | wherever it registers MCP servers | its MCP-servers key |
Codex uses TOML instead of JSON:
[mcp_servers.wigolo]
command = "npx"
args = ["-y", "wigolo"]
To enable answer synthesis (below) for a hand-wired agent, add the provider and key to the server's env:
{
"mcpServers": {
"wigolo": {
"command": "npx",
"args": ["-y", "wigolo"],
"env": { "WIGOLO_LLM_PROVIDER": "gemini", "GEMINI_API_KEY": "<your-free-key>" }
}
}
}
Setup is simple enough to hand off to an AI. Ask your coding agent (Claude Code, Cursor, …) — or any chat assistant (ChatGPT, Claude, Gemini) — to do it, and it can follow the steps above. Paste a prompt like:
Set up the wigolo MCP server for my agent. wigolo is a local-first MCP server installed with
npx wigolo init(engine only — no API keys). Then register it in my agent's MCP config as anmcpServersentry{ "command": "npx", "args": ["-y", "wigolo"] }. Note the per-client differences: VS Code uses theserverskey with"type": "stdio"; Zed usescontext_servers; Codex uses TOML[mcp_servers.wigolo]; Claude Code uses the CLIclaude mcp add wigolo --scope user -- npx -y wigolo. My agent is and its MCP config is at .
That prompt is self-contained, so even an assistant with no web access can act on it. If the assistant can browse, point it at this README (the Manual MCP setup section above has every client's exact config path) or the project's machine-readable llms.txt — both carry the full procedure, including the optional LLM-synthesis env below.
research, agent, and search format=answer use an LLM to write the final answer. Turn them on by setting a provider and its key (in your shell, or in your agent's MCP env block). WIGOLO_LLM_PROVIDER names the LLM — set it alongside the key:
export WIGOLO_LLM_PROVIDER=gemini
export GEMINI_API_KEY=<your-key> # free from https://aistudio.google.com/apikey — the free tier is plenty
Any provider works — use anthropic + ANTHROPIC_API_KEY, openai + OPENAI_API_KEY, or groq + GROQ_API_KEY. To stay fully local and keyless, set WIGOLO_LLM_PROVIDER=ollama (or a local server URL) instead. Gemini is suggested because its free tier is more than enough for wigolo.
A prebuilt image runs the MCP server without installing Node yourself. The default command is the stdio MCP server. Two variants are published:
latest (default) — a slim image. The OS libraries for the browser engine are baked in, but the browser engine binary and the on-device models download on first use into the data volume. Smallest download; ideal for long-lived MCP setups.latest-full — the browser engine binary is preinstalled at build time. Larger image; ideal for JS-render-heavy work or ephemeral --rm runs with no persistent volume.The data volume is mandatory in every run line — it holds the local cache, the on-device models, the browser engine binary, and your encrypted keys, and persists them across runs. Without it, every run re-downloads those components:
docker run -i --rm -v wigolo-data:/data ghcr.io/knockoutez/wigolo
The -i flag keeps stdin open for the MCP protocol. On first use the slim image downloads the browser engine binary and the models into the volume (a one-time few-hundred-MB download); later runs reuse them. To skip the first-use browser-engine download, use the full variant:
docker run -i --rm -v wigolo-data:/data ghcr.io/knockoutez/wigolo:full
Wire either variant into Claude Code:
claude mcp add wigolo -- docker run -i --rm -v wigolo-data:/data ghcr.io/knockoutez/wigolo
Any MCP client works the same way: set command to docker and args to the run flags above. The image is also on Docker Hub as towhid69420/wigolo.
HTTP serve mode. For a remote or multi-client setup, run the HTTP daemon instead with the packaging/compose.serve.yml snippet, which publishes port 3333 and adds a health check:
docker compose -f packaging/compose.serve.yml up
Bind-mount caveat. The container runs as an unprivileged user (uid/gid 1000). A named volume (as above) just works. If you bind-mount a host directory instead (-v "$PWD/wigolo-data:/data"), that directory must be writable by uid 1000 or the container hits EACCES — either chown 1000:1000 the host path first, or prefer the named volume.
wigolo serve exposes a plain-JSON REST API alongside the MCP transport. Same process, same tools, two surfaces:
POST /v1/{tool} — curl-able, no MCP client needed. Request body is the tool's input; the response is the tool's output as plain JSON./mcp (StreamableHTTP) and /sse — unchanged, for MCP clients.GET /openapi.json — the machine-readable contract.GET /v1/tools — [{name, description, endpoint}].GET /health — always open, no auth.Start it on the default loopback address:
wigolo serve # 127.0.0.1:3333
All ten tools, against a local instance. Request bodies match each tool's input schema (the same schema MCP serves and OpenAPI publishes):
BASE=http://127.0.0.1:3333/v1
# search — multi-engine web search with ranked evidence
curl -sX POST $BASE/search -H 'Content-Type: application/json' \
-d '{"query":"local-first software","max_results":5}'
# fetch — one URL to clean markdown + metadata
curl -sX POST $BASE/fetch -H 'Content-Type: application/json' \
-d '{"url":"https://example.com"}'
# crawl — multi-page crawl (bfs / dfs / sitemap / map)
curl -sX POST $BASE/crawl -H 'Content-Type: application/json' \
-d '{"url":"https://example.com","strategy":"map","max_pages":20}'
# cache — query everything already seen (or stats / clear)
curl -sX POST $BASE/cache -H 'Content-Type: application/json' \
-d '{"query":"local first"}'
# extract — structured data (tables, metadata, JSON-LD, schema, brand)
curl -sX POST $BASE/extract -H 'Content-Type: application/json' \
-d '{"url":"https://example.com","mode":"structured"}'
# find_similar — related pages by URL or concept
curl -sX POST $BASE/find_similar -H 'Content-Type: application/json' \
-d '{"concept":"local-first search engines","include_web":true}'
# research — multi-step research brief
curl -sX POST $BASE/research -H 'Content-Type: application/json' \
-d '{"question":"what is local-first software","depth":"quick"}'
# agent — autonomous data gathering
curl -sX POST $BASE/agent -H 'Content-Type: application/json' \
-d '{"prompt":"summarize this page","urls":["https://example.com"],"max_pages":1}'
# diff — compare two content snapshots
curl -sX POST $BASE/diff -H 'Content-Type: application/json' \
-d '{"old":{"markdown":"a\nb"},"new":{"markdown":"a\nc"},"output":"summary"}'
# watch — register / list / check change-detection jobs
curl -sX POST $BASE/watch -H 'Content-Type: application/json' \
-d '{"action":"list"}'
The OpenAPI document lists every request field and the documented top-level response fields:
curl -s http://127.0.0.1:3333/openapi.json
Auth is optional on loopback, fail-closed off it:
Origin request is still refused, and only loopback Host headers are accepted.--host 0.0.0.0 deployment from being wide open by accident.Authorization: Bearer <token> on /v1/*, /openapi.json, the shim, and the MCP transport routes (/mcp, /sse). /health stays open.Set the toke
browse all types & interfaces →
$ claude mcp add wigolo \
-- python -m otcore.mcp_server <graph>