# Web search MCP server for Claude Code, Claude Desktop, Cursor and other MCP clients

> Web search MCP server for Claude Code, Claude Desktop and Cursor: a short Python file with search_web and read_urls tools, registered in one command. No KYC.

- URL: https://llmwebsearch.com/docs/mcp/
- Last updated: 2026-10-22
- Publisher: LLMWebSearch (https://llmwebsearch.com)

Give any MCP client two tools: `search_web`, which returns ranked sources with the top pages already read, and `read_urls`, which reads links the model already has. The server is one Python file that runs on your machine, with your key in its environment.

**Quick answer — How do I add a web search MCP server to Claude Code or Claude Desktop?**

Save the short Python server on this page, which exposes `search_web` and `read_urls` tools calling **LLMWebSearch**, then register it with `claude mcp add` or in `claude_desktop_config.json`, with your key in `env`. The model can then search the live web and read the top pages as Markdown. A search costs 1 credit, from $1.20/1K searches as of October 2026. No KYC; pay in crypto.

## The MCP server at a glance

| Attribute | Value |
| --- | --- |
| Language | Python 3.10+, with the `mcp` and `httpx` packages |
| Transport | stdio: the client starts the server as a local process |
| Tool 1 | `search_web(query, max_results=5, read=3)` → numbered sources with URLs and page text |
| Tool 2 | `read_urls(urls)` → the main content of 1 to 20 known pages |
| Names | Not `web_search` or `web_fetch`: Claude Code and OpenClaw already ship tools with those names |
| Key | Read from `LLMWEBSEARCH_API_KEY` in the server's environment |
| Billing | One credit pays for one search: up to 20 ranked results, with the pages of the first 3 read and returned as Markdown. Reading 4 to 10 pages makes it 2 credits. A call that ends in an error costs nothing. Reading pages whose URLs you already have costs 1 credit for each started group of 3 pages returned with content, up to 20 URLs per call; refused or failed URLs are not counted |

## Why are the tools called search_web and read_urls?

Because two tools with the same name confuse the client and the model. Claude Code and OpenClaw each include built-in tools named `web_search` and `web_fetch`. Distinct names, with clear descriptions, let the model choose ours on purpose and let you tell the calls apart in logs.

Both tools return text, not raw JSON. Each source starts with a number, a title and its URL, so the model can cite `[1]` or `[2]` and the reader can check the page.

*llmwebsearch_mcp.py*

```python
import os

import httpx
from mcp.server.fastmcp import FastMCP

BASE = "https://llmwebsearch.com/api/v1"
HEADERS = {"Authorization": "Bearer " + os.environ["LLMWEBSEARCH_API_KEY"]}
mcp = FastMCP("llmwebsearch")


def _call(path: str, body: dict) -> dict:
    resp = httpx.post(BASE + path, json=body, headers=HEADERS, timeout=90)
    data = resp.json()
    if resp.status_code != 200:
        err = data.get("error", {})
        raise RuntimeError(err.get("code", str(resp.status_code)) + ": " + err.get("message", ""))
    return data


def _page(n: int, item: dict) -> str:
    head = f"[{n}] {item.get('title') or item['url']}\n{item['url']}\n"
    if item.get("content_status") == "ok":
        return head + item["content"]
    return head + "(not read: " + item.get("content_status", "unknown") + ") " + item.get("snippet", "")


@mcp.tool()
def search_web(query: str, max_results: int = 5, read: int = 3) -> str:
    """Search the live web and return numbered sources; the first `read` pages include their text.

    Use it for current facts, documentation and news. Cite sources by their number.
    """
    body = {"q": query, "max_results": max(1, min(max_results, 20)), "read": max(0, min(read, 10)), "max_chars": 5000}
    data = _call("/search", body)
    return "\n\n".join(_page(i, r) for i, r in enumerate(data["results"], start=1))


@mcp.tool()
def read_urls(urls: list[str]) -> str:
    """Read 1 to 20 public web pages whose URLs you already have and return their main text."""
    data = _call("/extract", {"urls": urls[:20], "max_chars": 12000})
    return "\n\n".join(_page(i, r) for i, r in enumerate(data["results"], start=1))


if __name__ == "__main__":
    mcp.run()

```

## How do I install and test the server?

Create a virtual environment, install `mcp` and `httpx`, and save the file above. `mcp` is the official Python SDK of the Model Context Protocol; its `FastMCP` class turns typed Python functions into tools and uses each docstring as the tool's description.

Start the file once from a terminal with your key set. It then waits quietly for a client on standard input, which means it works; stop it with Ctrl+C. Errors from the API are raised as tool errors with their code, so the model sees `rate_limited` or `insufficient_credits` in plain words.

*Install and start once*

```bash
python -m venv .venv
. .venv/bin/activate
pip install "mcp[cli]" httpx
LLMWEBSEARCH_API_KEY="your-key" python llmwebsearch_mcp.py
```

## How do I add it to Claude Code?

Use `claude mcp add`. Claude Code's documentation gives the form `claude mcp add [options] <name> -- <command> [args...]`: its own options come first, then a double dash, then the command that starts the server. Environment variables go in `--env KEY=value`, and at least one other option, such as `--transport stdio`, must sit between `--env` and the server name.

Add `--scope user` to make the server available in all your projects; the default scope, `local`, covers the current project only. Use absolute paths for the Python of your virtual environment and for the server file.

*Register the server in Claude Code*

```bash
claude mcp add --env LLMWEBSEARCH_API_KEY=your-key --transport stdio --scope user llmwebsearch \
  -- /home/you/llmwebsearch/.venv/bin/python /home/you/llmwebsearch/llmwebsearch_mcp.py
```

## How do I add it to Claude Desktop and other clients?

Claude Desktop reads servers from `claude_desktop_config.json`, under `mcpServers`. Give the server a name, the command, its arguments and an `env` object holding the key, then restart the app; `search_web` and `read_urls` appear in the tools list.

Other MCP clients, such as Cursor, ask for the same three things in their own MCP settings: a command, its arguments and environment variables. The key never appears in a tool argument or in the conversation.

*claude_desktop_config.json*

```json
{
  "mcpServers": {
    "llmwebsearch": {
      "command": "/home/you/llmwebsearch/.venv/bin/python",
      "args": ["/home/you/llmwebsearch/llmwebsearch_mcp.py"],
      "env": { "LLMWEBSEARCH_API_KEY": "your-key" }
    }
  }
}
```

## How do I keep searches cheap and short?

Tell the model how to search in your instructions: one or two searches per question, then read more only if the sources disagree. The server already caps each page at 5,000 characters in `search_web` and 12,000 in `read_urls`; lower those numbers for small models.

Each `search_web` call with `read` up to 3 is one credit. An assistant that runs 40 searches a day uses about 1,200 credits a month, so 5,000 searches ($9.25) lasts around four months. Search credits have no expiry date: what you do not use this month is still there next year.

## What does the model see when a page cannot be read?

The source still appears, with its number, title and URL, followed by the reason in brackets and the search snippet. Our reader respects robots.txt: it introduces itself as LLMWebSearch, follows the rules a site writes for it or for all robots, and leaves out the content of any page it is not allowed to read. When a site turns our reader away, the result comes back without content and with the site's status: we never solve CAPTCHAs, sign in to accounts or work around a block or a paywall. The model can then rely on the other sources or say that one page was not available.

## MCP server: common questions

### Is there an official LLMWebSearch MCP package or hosted endpoint?

No. The file on this page is the integration: about 50 lines you can read and change. It runs on your machine, and your key only travels to our API.

### Should I turn off Claude Code's built-in web search?

No need. Both can stay; the descriptions tell the model what each does. Keep ours when you want page text in the results, a fixed price per search, or one place for your search logs.

### Can I use it with OpenClaw?

Yes, as an MCP server registered with `openclaw mcp add`. The [OpenClaw page](https://llmwebsearch.com/docs/openclaw/) gives the command and explains how it sits next to OpenClaw's built-in search providers.

### Does the server keep my searches?

No. It holds nothing between calls. On our side, We do not train any model on your queries or on what the API returns, and we add no rule of our own against storing results; the rights of the sites whose pages you read still apply.

## Sources

1. [Connect Claude Code to tools via MCP](https://code.claude.com/docs/en/mcp) — Claude Code docs (read 2026-10-22)

---

LLMWebSearch: LLMWebSearch is a web search API for AI agents that returns ranked results with the content of the top pages in Markdown, paid in crypto with no ID upload. Prepaid credits from $1.20/1K searches never expire. No KYC — no ID, no selfie, no documents. Pay in crypto.
