# Web search MCP for Claude Code

Web search MCP for Claude Code means one extra tool: an MCP server that searches and reads pages through a provider you pick, next to the built-in WebSearch. Below is the whole setup with FATSEARCH, and the output each step printed on our machine (FATSEARCH 0.1.3, Claude Code 2.1.280, a scratch config, so nothing here came from a tuned setup).

> We make FATSEARCH. The numbers below are our own runs, dated. Where another reader is the better pick, we say so.

Why bother, when Claude Code has WebSearch? Its search backend [can't be configured](https://code.claude.com/docs/en/tools-reference); Claude Code's own docs say to add an MCP server for another provider. And WebFetch, the tool that reads the results, gets refused by sites with bot protection ([Claude Code web fetch 403](/guides/claude-code-web-fetch-403/)). What each built-in tool returns: [web fetch vs web search](/guides/claude-code-web-fetch-vs-web-search/).

## Install FATSEARCH and check it

Pick an install line from the [installation guide](/docs/installation/) (shell script, Homebrew, npm or cargo) or from the box at the end of this page. Then:

```sh
fats --version
```

```text
= fats 0.1.3 · status: fats · guide: fats guide
```

`fats` alone prints its status. Before any key:

```text
keys none → fats setup · network on
health (last 10 calls, whole cache): provider ok/n p50ms outcomes (– cancelled)
plain - no calls yet
bd no key
oxy no key
oxyjs no key
account: not read yet · fats account
mcp: ready · fats mcp = stdio server, one tool fats(cmd)
```

## Add a search key

Reading pages works without a key, through a free plain request. Searching needs one: an Oxylabs or a Bright Data key ([signup links and variables](/docs/installation/#4-keys-optional)). Put it in the environment, then save it once:

```sh
fats setup dry:true   # shows where each key was found; no call, no write
fats setup            # checks the key for $0 and saves it
```

Saved keys are the simplest way to reach the MCP server: Claude Code then doesn't need to pass any environment. Without a key, a search over MCP answers with what's missing instead of failing silently:

```text
= ! no_key search "claude code webfetch 403" · no search provider can run · 0ms spent $0
! no_key bd · would try web search ≤$0.0015 · set BRIGHTDATA_API_KEY + BRIGHTDATA_UNLOCKER_ZONE → fats setup · bd https://brightdata.com/cp/start
! no_key oxy · would try web search ≤$0.0010 · set OXYLABS_WEB_API_KEY → fats setup · oxy https://dashboard.oxylabs.io/en/registration
```

## Check the MCP server on its own

Before Claude Code is involved, send the server the MCP handshake. This is the check from the installation guide:

```sh
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
```

Two JSON lines come back: `initialize` names the server and its version, `tools/list` shows the one tool, `fats`, which takes a command line (`cmd`). Together 724 tokens. Claude Code defers MCP tool definitions by default, so until Claude uses the tool only its name and the server's instructions sit in context ([cost docs](https://code.claude.com/docs/en/costs)):

```text
{"jsonrpc":"2.0","id":1,"result":{"protocolVersion":"2025-06-18","capabilities":{"tools":{}},"serverInfo":{"name":"fats","version":"0.1.3"},"instructions":"fats turns web pages, PDFs and documents into small, clean, cached Markdown. The one tool `fats` takes the same command line as the `fats` CLI and returns the same text.\n\nfats <url|file.pdf>     fetch, outline           fats u3  u3#2  u3#2 l4  page  section  link\nfats u3#2 <words>       filter inside            fats <words>  web search → ids  site:ex.com  since:7d\nmods key:value   limit:20  match:exact|words  country:de  js:true  cost:0.5  wait:30 (s, then pending)  provider:plain|bd|oxy|auto (auto = table order)  device:mobile\nmore  up  all  full  json     fats = status  fats setup = keys  fats account = balance, usage     j8.u3 = id from another session\n\nEvery reply starts with a `=` line (what happened, which id); ids it prints (u1, u1#3, l4) are what the next cmd takes. A `!` row names what failed and, after →, the command that fixes it. Pages stay cached in this session: re-reading u1#3 fetches nothing. Local files: the working directory and the cache only. `guide` prints the card; an empty cmd prints the status."}}
{"jsonrpc":"2.0","id":2,"result":{"tools":[{"name":"fats","description":"Web pages, PDFs and local documents as small cached Markdown with ids. cmd = one fats command line, e.g. `https://example.com/menu.pdf` (fetch → outline with ids) or `u1#3` / `u1 tuna price` (read section 3 / the lines with those words).","inputSchema":{"type":"object","properties":{"cmd":{"type":"string","description":"e.g. u1#3"}},"required":["cmd"]},"annotations":{"readOnlyHint":false,"destructiveHint":false,"openWorldHint":true}}]}}
```

The same tool with a search, keys set. It ran on Oxylabs in 2.2s for $0.001:

```text
= j1 search "claude code webfetch 403" · 10 results · 3 shown u1-u3 · oxylabs · 2.2s · spent $0.0010
u1  github.com/anthropics/claude-code/issue…  [BUG] WebFetch returns 403 on Wikipedia and other sites des… — "February 3, 2026 - Issue: The WebFetch tool in Cowork mode returns 403 Forbidden errors f…"
u2  github.com/anthropics/claude-code/issue…  [BUG] Webfetch not working in cloud version · Issue #13718 … — "December 11, 2025 - I am using the latest version of Claude Code · WebFetch not working i…"
u3  github.com/anthropics/claude-code/issue…  [BUG] WebFetch fails with 403 on npmjs.com URLs · Issue #17… — "January 13, 2026 - The WebFetch tool fails with a 403 Forbidden error when attempting to …"
prefetching u1 free, plain only (detached; fetch:0 = none) · status: fats
open one: fats u1 · filter: fats u1 <words> · more: fats more
```

## Add it to Claude Code

One command. Pick a scope (from the [installation guide](/docs/installation/#claude-code)):

```sh
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
```

Then check it:

```sh
claude mcp list
claude mcp get fats
```

What ours printed (the file path is our scratch config; yours is `~/.claude.json`):

```text
$ claude mcp add --scope user fats -- fats mcp
Added stdio MCP server fats with command: fats mcp to user config
File modified: /tmp/fs-cap/cchome/.claude/.claude.json

$ claude mcp list
Checking MCP server health…

fats: fats mcp - ✔ Connected

$ claude mcp get fats
fats:
  Scope: User config (available in all your projects)
  Status: ✔ Connected
  Type: stdio
  Command: fats
  Args: mcp
  Environment:

To remove this server, run: claude mcp remove fats -s user
```

Inside a session, `/mcp` shows the same status. A project `.mcp.json` server waits for your approval the first time `claude` runs in that folder.

## Verify from inside Claude Code

The last check is Claude itself calling the tool. We ran Claude Code with the `fats` tool as its only tool and asked it to open npm's `react` page, a page WebFetch couldn't read in our [Claude Code web fetch 403](/guides/claude-code-web-fetch-403/) test. Claude's first call, a free plain request in 167 ms (733 tokens):

```text
= j1.u1 react · www.npmjs.com · 8 sections · 1 photo · 824tok · plain 167ms spent $0.0000
u1#0 info | React is a JavaScript library for building user interfaces.. Latest version: 19.3.1, last…
```

Then it asked for the lines mentioning the version instead of reading the page (160 tokens):

```text
= j1.u1 filter "version ." · 3 hit · match:all auto · cache 0s
u1#0 React is a JavaScript library for building user interfaces.. Latest version: 19.3.1, last…
u1#2 - 2,981 Versions [l6]
u1#3 Note: by default, React will be in development mode. The development version includes extra warnings about common mistakes, whereas the production version includes extra performance optimizations and…
read: fats u1#0

```

## Web search MCP: if it doesn't connect

- **`fats` not found.** Claude Code starts the server as a process; if it can't find `fats`, use the absolute path from `command -v fats` as the command.
- **No install at all.** With Node, the server can run as `npx -y fatsearch mcp`; the first start downloads the binary. It's also in the MCP Registry as `io.github.fatsearch/fats`.
- **Keys not reaching the server.** Run `fats setup` once and leave keys out of the Claude Code config. To pass one anyway: `claude mcp add --transport stdio --env OXYLABS_WEB_API_KEY="$OXYLABS_WEB_API_KEY" fats -- fats mcp`.
- **A slow page.** The tool answers `pending` after a few seconds and names the command to check again, so a tool call stays short.

Other readers you could plug in instead, measured on the same page: [web scraping MCP](/compare/).

## Questions

### Can Claude Code do web search?

Yes. The built-in WebSearch tool returns result titles and URLs from Anthropic's search backend, and WebFetch reads a page. The backend can't be changed; Claude Code's docs say to add an MCP server with a search tool if you want a different provider. Amazon Bedrock doesn't expose the built-in search tool at all.

### Why isn't the Claude web search tool working?

Three common causes from Claude Code's docs: an interactive session is capped at 200 WebSearch calls, after which searches do nothing until you raise CLAUDE_CODE_MAX_WEB_SEARCHES_PER_SESSION, wait for the cap to refill on newer versions, or run /clear; an overloaded API returns an error after retries; and Amazon Bedrock doesn't offer the tool. An MCP search server isn't bound by the cap or by Bedrock, at the cost of a provider key.

### Why is my Claude code using so many tokens?

Mostly context size: Claude Code's cost docs say token costs scale with how much context Claude processes, and suggest /clear between tasks and /context to see what's using space. Web pages are a big part of it: a whole page can run to tens of thousands of tokens. On our run of 38 hard pages, Claude's built-in web tools used 8.3k input tokens per question and FATSEARCH 2.6k. FATSEARCH answers with an outline (733 tokens for the npm page below) and Claude opens only the section it needs.

## Related

- [Web scraping MCP: every reader we measured](https://fatsearch.com/compare/)
- [Benchmarks: every run, charted](https://fatsearch.com/benchmarks/)
- [Method: one page, six readers](https://fatsearch.com/docs/benchmarks/#one-page-six-readers)
- [Method: the hard-pages run](https://fatsearch.com/docs/benchmarks/#other-readers)

By FATSEARCH · data as of 2026-10-19 · reviewed 2026-10-19 · https://fatsearch.com/guides/web-search-mcp-for-claude-code/
