fats 0.1.2 · 2026-10-17

Install

View as MarkdownSource on GitHub

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 fatsearch installs fats; npx fatsearch --version runs 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 (installs fats)
  • cargo-binstall ❓: cargo binstall fatsearch takes 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.sha256 and gh attestation verify fatsearch-<target>.tar.xz --repo fatsearch/fatsearch. The archive holds fats (fats.exe) in a fatsearch-<target>/ folder; put it anywhere on PATH.

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, ./.env in 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 as brightdata.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 start fats, use the absolute path from command -v fats (Windows: where fats) as command. The examples use fats for brevity.
  • Keys: run fats setup once (section 4) and leave keys out of host configs. To pass them through a host instead, use its env field (shown below where the host has one); prefer a ${VAR} reference to a value.
  • Local files: over MCP, fats reads files only under the server’s working directory and its cache.
  • A slow page answers pending after 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 mcp as the command ("command": "npx", "args": ["-y", "fatsearch", "mcp"]); the first start downloads the binary. The server is listed in the MCP Registry as io.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.

  1. Tools present. Check: cmake --version (3.22+), cc --version, rustup --version, git --version.
  2. Clone: git clone https://github.com/fatsearch/fatsearch && cd fatsearch. Check: test -f rust-toolchain.toml.
  3. Toolchain: rustup toolchain install 1.99.0. Check: rustc --version in the clone prints rustc 1.99.0.
  4. Install: cargo install --locked --path . Check: command -v fats prints a path; fats --version starts with = fats .
  5. Plain fetch: fats https://example.com Check: the first line starts with = and contains Example Domain.
  6. Keys, only if a key is already in the environment or ./.env: fats setup Check: fats | grep '^keys' shows oxy:file or bd:file. No key: skip; report that plain pages work.
  7. MCP server: run the printf … | fats mcp block from section 5. Check: the output contains "name":"fats" in the tools/list reply.
  8. Register with the host in use (section 6), using the absolute path. Claude Code: claude mcp add --scope user fats -- "$(command -v fats)" mcp; check claude mcp get fats. Codex: codex mcp add fats -- "$(command -v fats)" mcp; check codex mcp list. Gemini CLI: gemini mcp add --scope user fats "$(command -v fats)" mcp; check /mcp. File-based hosts: write the JSON block with command = the output of command -v fats, then ask the user to restart the app.
  9. Final status: fats Check: a keys row and mcp: ready · fats mcp = stdio server, one tool fats(cmd).