fats 0.1.2 · 2026-10-17
Install
fats is one binary: a CLI and, as fats mcp, a local stdio MCP server with one tool, fats(cmd).
This guide installs it (prebuilt or from source), adds a provider key, connects it to an agent host, and checks every step.
Agents: follow the checklist at the end; each step has a check command.
Never print, echo or paste a key value; key names and fats status lines are enough.
Lines marked ❓ are not verified yet.
| Thing | Where |
|---|---|
| Binary | ~/.cargo/bin/fats (from the installer script or cargo install; Homebrew: its own prefix) |
| Keys | macOS ~/Library/Application Support/fatsearch/ · Linux ${XDG_CONFIG_HOME:-~/.config}/fatsearch/ · Windows %APPDATA%\fatsearch\ · or FATS_KEY_DIR |
| Cache (pages live ≤ 1 h) | macOS ~/Library/Caches/fatsearch/ · Linux ${XDG_CACHE_HOME:-~/.cache}/fatsearch/ · Windows %LOCALAPPDATA%\fatsearch\ · or FATS_CACHE (a relative dir is resolved once against the working dir; ~/…, / and $HOME are refused; swept only if fats created it) |
| Spend ledger | spend.log in the key dir (time, cost and cache dir per paid record; fats stats sums it) |
| Exact paths on this machine | fats config (rows cache and key_dir, each with its source) |
1. Prerequisites
A prebuilt binary (section 2) needs none of this. Building from source (section 3) needs:
- Rust 1.99 (pinned in
rust-toolchain.toml), via rustup. - CMake 3.22+, a C and C++ compiler, and libclang: the TLS stack compiles BoringSSL from source and generates its bindings with bindgen, which loads libclang.
macOS (tested, Apple silicon): the Command Line Tools bring the compiler and libclang.
xcode-select --install
brew install cmake
Ubuntu / Debian (CI builds on Ubuntu; this minimal package set is ❓ untested on a clean machine):
sudo apt-get install -y build-essential cmake libclang-dev git
Windows ❓ untested. What the build scripts ask for: Visual Studio Build Tools with the C++ workload,
CMake 3.22+, NASM (BoringSSL’s x86_64 assembly on Windows),
and LLVM for libclang (winget install LLVM.LLVM, then set LIBCLANG_PATH to LLVM’s bin folder).
2. Install a prebuilt binary
Each GitHub release carries fats for macOS (Apple silicon, Intel), Linux (x86_64, ARM64; glibc 2.35+) and
Windows (x86_64), each archive with a .sha256 checksum and a GitHub build attestation. No Rust toolchain needed.
macOS, Linux:
curl --proto '=https' --tlsv1.2 -LsSf https://github.com/fatsearch/fatsearch/releases/latest/download/fatsearch-installer.sh | sh
Windows (PowerShell):
powershell -ExecutionPolicy Bypass -c "irm https://github.com/fatsearch/fatsearch/releases/latest/download/fatsearch-installer.ps1 | iex"
The installer (generated by cargo-dist) picks the archive for this
machine and puts fats in $CARGO_HOME/bin (default ~/.cargo/bin, %USERPROFILE%\.cargo\bin on Windows), the
folder cargo install uses. It adds that folder to PATH: on macOS and Linux through ~/.cargo/env, sourced
from .profile, .bashrc, .zshrc and fish’s conf.d; on Windows in the user’s Path registry value.
FATSEARCH_NO_MODIFY_PATH=1 skips that. It also writes an install receipt, fatsearch-receipt.json, to
${XDG_CONFIG_HOME:-~/.config}/fatsearch/ (Windows %LOCALAPPDATA%\fatsearch\); fats never reads it
(that folder is also the key dir on Linux and the cache dir on Windows; the receipt holds no key and the cache
sweep never deletes it). FATSEARCH_DISABLE_UPDATE=1 skips the receipt.
The installer always installs the version of the release it came from.
Other ways, same release archives:
- npm ❓ (the package is not published yet):
npm i -g fatsearchinstallsfats;npx fatsearch --versionruns it without a global install. The npm package holds no binary: its install script downloads this release’s archive for the machine from GitHub into the package folder, so it needs network at install and does not work with--ignore-scripts. Node 14.14+. Uninstall:npm uninstall -g fatsearch. - Homebrew ❓ (the tap is not published yet):
brew install fatsearch/tap/fatsearch(installsfats) - cargo-binstall ❓:
cargo binstall fatsearchtakes the release archive; for a version without one (0.1.0) it falls back to building from source - By hand: download the archive for your platform from the
releases page, then check it before unpacking:
shasum -a 256 -c fatsearch-<target>.tar.xz.sha256andgh attestation verify fatsearch-<target>.tar.xz --repo fatsearch/fatsearch. The archive holdsfats(fats.exe) in afatsearch-<target>/folder; put it anywhere onPATH.
Check: fats --version prints = fats <version> · status: fats · guide: fats guide.
3. Build from source
git clone https://github.com/fatsearch/fatsearch
cd fatsearch
rustup toolchain install 1.99.0
cargo install --locked --path .
Or straight from crates.io, no clone: cargo install --locked fatsearch.
Either compiles BoringSSL once (a few minutes) and installs fats (the package is named fatsearch).
If fats is not found afterwards, add ~/.cargo/bin to PATH (. "$HOME/.cargo/env").
Check: fats --version prints = fats 0.1.2 · status: fats · guide: fats guide; fats guide = the cheat sheet.
4. Keys (optional)
Without a key, fats reads what a plain HTTP request gets, for $0.
With any one provider key it also renders JS pages and gets past walls through that provider;
with both, it routes between them. Each key goes only to its own provider; there is no telemetry.
| Provider | Sign up | Key | Variables |
|---|---|---|---|
| Oxylabs | https://dashboard.oxylabs.io/en/registration | a Web API instance’s key in the dashboard | OXYLABS_WEB_API_KEY |
| Bright Data | https://brightdata.com/cp/start | https://brightdata.com/cp/setting/users | BRIGHTDATA_API_KEY + BRIGHTDATA_UNLOCKER_ZONE (a Web Unlocker zone) |
Put the key in the environment (or in ./.env as NAME=value), then run fats setup
(fats setup dry:true first shows where each key was found, with no call and no write). It:
- Looks for each key in this order: environment,
./.envin the current directory, the Bright Data CLI’s own login files (read only), the key dir. - Checks it for $0: Oxylabs lists its scrapers; Bright Data lists zone names and types.
- Saves it to the key dir as
oxylabs.key/brightdata.key(mode 600, dir 700), and the Bright Data zone asbrightdata.zone:zone:<name>if given, else the configured one, else the account’s only Web Unlocker zone. - Never prints a key.
Fetches read a key from the environment first, then the key dir. A key only in ./.env works after
fats setup has saved it. Saved keys are the simplest way to give keys to every MCP host:
hosts differ in which environment variables they pass to a server.
5. Verify
$ fats https://example.com
= j1.u1 Example Domain · example.com · 1 sections · 0 photos · 142tok · plain 53ms spent $0.0000
[u1#1] # part 1
This domain is for use in documentation examples without needing permission. …
(whole page shown) · filter: fats u1 <words> · links: fats u1 links
The first line starts with =; ids, timing and token counts vary. fats alone prints the status:
session, cache path, keys, provider health, and mcp: ready · fats mcp = stdio server, one tool fats(cmd).
Its keys row reads keys none → fats setup · network on before setup and like
keys oxy:file bd:file · bd zone <zone> · network on after (env, file = key dir, none).
Check the MCP server without any host (prints two JSON lines: initialize and tools/list):
printf '%s\n' \
'{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-06-18","capabilities":{},"clientInfo":{"name":"check","version":"0"}}}' \
'{"jsonrpc":"2.0","method":"notifications/initialized"}' \
'{"jsonrpc":"2.0","id":2,"method":"tools/list"}' | fats mcp
6. Connect an agent host
All hosts below start fats mcp as a local process. Notes that apply to every one:
- GUI apps do not read the shell’s
PATH. If a host reports it cannot startfats, use the absolute path fromcommand -v fats(Windows:where fats) ascommand. The examples usefatsfor brevity. - Keys: run
fats setuponce (section 4) and leave keys out of host configs. To pass them through a host instead, use itsenvfield (shown below where the host has one); prefer a${VAR}reference to a value. - Local files: over MCP,
fatsreads files only under the server’s working directory and its cache. - A slow page answers
pendingafter 5 s (wait:), so tool calls stay short; the reply names the next command. - Without installing ❓ (the npm package is not published yet): a host with Node can run
npx -y fatsearch mcpas the command ("command": "npx", "args": ["-y", "fatsearch", "mcp"]); the first start downloads the binary. The server is listed in the MCP Registry asio.github.fatsearch/fats❓.
Claude Code
claude mcp add --scope user fats -- fats mcp # all your projects
claude mcp add fats -- fats mcp # default scope local: this project, only you
claude mcp add --scope project fats -- fats mcp # writes .mcp.json in the project root, for the team
Scopes: local and user live in ~/.claude.json; project lives in .mcp.json. Everything after --
is the server command. To pass a key, put --env before the name with another option between them:
claude mcp add --transport stdio --env OXYLABS_WEB_API_KEY="$OXYLABS_WEB_API_KEY" fats -- fats mcp.
.mcp.json (an entry without type is stdio; ${VAR} expands from the environment):
{ "mcpServers": { "fats": { "command": "fats", "args": ["mcp"],
"env": { "OXYLABS_WEB_API_KEY": "${OXYLABS_WEB_API_KEY}" } } } }
Check: claude mcp get fats or claude mcp list (✔ Connected); inside a session, /mcp.
A project .mcp.json server waits for approval the first time claude runs in that folder.
Claude Desktop
Settings → Developer → Edit Config opens claude_desktop_config.json:
- macOS:
~/Library/Application Support/Claude/claude_desktop_config.json - Windows:
%APPDATA%\Claude\claude_desktop_config.json - Linux ❓: not in the official docs; community builds use
~/.config/Claude/claude_desktop_config.json. Use Edit Config to find the real file.
{ "mcpServers": { "fats": { "command": "/home/you/.cargo/bin/fats", "args": ["mcp"] } } }
Use the absolute path (command -v fats), then quit Claude Desktop completely and start it again.
Server logs: ~/Library/Logs/Claude/mcp-server-fats.log (macOS), %APPDATA%\Claude\logs (Windows).
One-click .mcpb bundles exist as a format; fats does not ship one yet.
Codex CLI
codex mcp add fats -- fats mcp, or edit ~/.codex/config.toml (or .codex/config.toml in a trusted project):
[mcp_servers.fats]
command = "fats"
args = ["mcp"]
# optional: forward keys from Codex's environment
env_vars = ["OXYLABS_WEB_API_KEY", "BRIGHTDATA_API_KEY", "BRIGHTDATA_UNLOCKER_ZONE"]
Check: codex mcp list, or /mcp in the codex TUI. Default tool_timeout_sec is 60, well above fats’ 5 s wait:.
Cursor
~/.cursor/mcp.json (every project) or .cursor/mcp.json (this project):
{ "mcpServers": { "fats": { "command": "fats", "args": ["mcp"],
"env": { "OXYLABS_WEB_API_KEY": "${env:OXYLABS_WEB_API_KEY}" } } } }
Stdio servers also take "envFile": "<path>". Check the server in Cursor’s MCP settings list.
VS Code (Copilot)
.vscode/mcp.json in the workspace (note the top-level key servers), or run MCP: Open User Configuration:
{ "servers": { "fats": { "type": "stdio", "command": "fats", "args": ["mcp"] } } }
From a shell: code --add-mcp '{"name":"fats","command":"fats","args":["mcp"]}'.
Check: MCP: List Servers → fats → Show Output.
Windsurf
Cascade panel → ... → Open MCP config file. The docs place it at ~/.config/devin/mcp_config.json
(macOS, Linux; $XDG_CONFIG_HOME/devin/ if set) and %APPDATA%\devin\mcp_config.json (Windows).
{ "mcpServers": { "fats": { "command": "fats", "args": ["mcp"] } } }
Zed
Settings → AI → MCP Servers → Add Server → Add Local Server, or edit the settings file (zed: open settings file):
{ "context_servers": { "fats": { "command": "fats", "args": ["mcp"], "env": {} } } }
Gemini CLI
gemini mcp add --scope user fats fats mcp writes ~/.gemini/settings.json (default scope project:
.gemini/settings.json) with { "mcpServers": { "fats": { "command": "fats", "args": ["mcp"] } } }.
Gemini CLI strips inherited variables whose names contain KEY, TOKEN and similar, so
OXYLABS_WEB_API_KEY does not reach the server unless set in env ("OXYLABS_WEB_API_KEY": "$OXYLABS_WEB_API_KEY").
Saved keys (fats setup) avoid this. Check: /mcp.
ChatGPT and other OpenAI apps: not supported yet
ChatGPT connects to remote MCP servers over a public HTTPS (streamable HTTP) endpoint. fats mcp is
stdio only: no HTTP, no OAuth, no remote server. OpenAI’s Secure MCP Tunnel can forward to a local stdio
server for workspaces that have custom MCP access; ❓ untested with fats. Codex CLI (above) works today.
7. Plain shell use (any agent)
An agent that can run shell commands needs no MCP at all:
fats https://example.com # outline with ids, cached as u1
fats u1#3 # read section 3
fats u1 price # lines that match, inside the page
fats u1 json # the same answer as one JSON record (or FATS_JSON=1)
Every command: README, “All commands”. Full reference: reference.md.
8. Uninstall
fats config | grep -E '^(cache|key_dir) ' # note both paths first
cargo uninstall fatsearch # removes ~/.cargo/bin/fats
Installed with the installer script: rm ~/.cargo/bin/fats (Windows: del %USERPROFILE%\.cargo\bin\fats.exe)
and the receipt fatsearch-receipt.json (section 2). Homebrew: brew uninstall fatsearch. npm:
npm uninstall -g fatsearch.
Then delete the two folders it printed (defaults in the table at the top). The key dir holds oxylabs.key,
brightdata.key, brightdata.zone and the spend ledger spend.log. In the cache dir, pages and searches go
within the hour; the session id lists (an id’s URL cleared once its page is gone and its job an hour old),
index.json (rows of live pages only), jobs.json (commands cleared after an hour) and account.json stay
until you delete the dir.
Remove the host entry too: claude mcp remove fats (add --scope user|project to match), or delete the
fats entry from the host’s config file. fats never writes to the Bright Data CLI’s files.
9. Troubleshooting
| You see | Cause | Fix |
|---|---|---|
is `cmake` not installed? during the build |
CMake missing | install CMake 3.22+ (section 1) |
couldn't find any valid shared libraries matching: [...libclang...] |
libclang missing | install it (section 1) or set LIBCLANG_PATH to its folder |
a CMake error about ASM_NASM (Windows) ❓ |
NASM missing | install NASM, put it on PATH |
fats: command not found |
~/.cargo/bin not on PATH |
. "$HOME/.cargo/env", or use the absolute path |
host: server failed to start / ENOENT |
GUI app without your shell PATH |
absolute path from command -v fats |
keys none → fats setup (status), or ! no_key oxy · would try … · set OXYLABS_WEB_API_KEY → fats setup · oxy <sign-up page> |
no key; the page needs a provider | either provider’s key (section 4); plain pages still work |
! bad_key replace OXYLABS_WEB_API_KEY → fats setup |
key rejected | new key from the dashboard, fats setup again |
! no_zone … unblocker zones: a, b → fats setup zone:a or ! bad_zone bd <zone> → fats setup |
no zone picked, or an unknown one | fats setup zone:<name>; no zone yet: create a Web Unlocker zone in the Bright Data panel |
! key_mode oxylabs.key is 644, readable by others → chmod 600 <path> |
key file too open | run the printed chmod |
! offline |
FATS_OFFLINE is set |
unset it |
! not_allowed <file> (over MCP) |
file outside the server’s working directory | save it under that directory |
! bad_setting FATS_… · want … · using … |
an env value fats refused |
fix or unset that variable |
Every ! row ends with → and the command that fixes it; fats config shows each setting and its source.
Agent checklist
Run in order. Stop at the first failed check and report its output. Never print key values.
With a published release (section 2), its one-liner replaces steps 1–4: run it, check fats --version
starts with = fats , continue at step 5.
- Tools present. Check:
cmake --version(3.22+),cc --version,rustup --version,git --version. - Clone:
git clone https://github.com/fatsearch/fatsearch && cd fatsearch. Check:test -f rust-toolchain.toml. - Toolchain:
rustup toolchain install 1.99.0. Check:rustc --versionin the clone printsrustc 1.99.0. - Install:
cargo install --locked --path .Check:command -v fatsprints a path;fats --versionstarts with= fats. - Plain fetch:
fats https://example.comCheck: the first line starts with=and containsExample Domain. - Keys, only if a key is already in the environment or
./.env:fats setupCheck:fats | grep '^keys'showsoxy:fileorbd:file. No key: skip; report that plain pages work. - MCP server: run the
printf … | fats mcpblock from section 5. Check: the output contains"name":"fats"in thetools/listreply. - Register with the host in use (section 6), using the absolute path.
Claude Code:
claude mcp add --scope user fats -- "$(command -v fats)" mcp; checkclaude mcp get fats. Codex:codex mcp add fats -- "$(command -v fats)" mcp; checkcodex mcp list. Gemini CLI:gemini mcp add --scope user fats "$(command -v fats)" mcp; check/mcp. File-based hosts: write the JSON block withcommand= the output ofcommand -v fats, then ask the user to restart the app. - Final status:
fatsCheck: akeysrow andmcp: ready · fats mcp = stdio server, one tool fats(cmd).