Введение
Claude Code — CLI-агент для разработки. У него есть встроенные инструменты WebSearch и WebFetch. Проблема: в продакшен-окружениях их часто блокируют:
- Переменная
CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC=1 - Кастомные API-прокси, которые не пробрасывают эти инструменты
- Enterprise security policies
Нужно научить Claude Code искать в интернете. На рынке есть три подхода. Разберём каждый.
Вариант 1. Встроенные WebSearch / WebFetch
Как работает
Claude Code вызывает свой внутренний WebSearch, получает результаты, потом WebFetch загружает страницы.
Плюсы
- Настроен из коробки — не надо ничего ставить
- WebFetch обрабатывается маленькой моделью — не тратит токены основной сессии
- Поддержка параллельных запросов — можно загрузить 4 страницы одновременно
Минусы
- Не работает за прокси — если API-прокси не пробрасывает эти инструменты, они мертвы
- Зависит от переменной окружения —
CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC=1отключает полностью - Нет контроля над поисковиком — нельзя выбрать Brave, Yandex или другой движок
- Enterprise-блокировки —
skipWebFetchPreflightможет потребоваться для обхода blocklist-проверки
Вердикт
Идеально, когда работает. Но в продакшене часто не работает вообще.
Вариант 2. MCP-серверы (Brave Search MCP, Tavily MCP, Exa MCP)
Как работает
Подключаешь MCP-сервер через settings.json:
{
"mcpServers": {
"brave-search": {
"command": "npx",
"args": ["-y", "@anthropic-ai/mcp-server-brave-search"],
"env": { "BRAVE_API_KEY": "..." }
}
}
}
Claude Code подключается к MCP-серверу по stdio, получает список инструментов, вызывает их через JSON-RPC.
Плюсы
- Красивая интеграция — инструмент появляется в списке доступных, как нативный
- Автономность — Claude сам решает когда и как вызвать поиск
- Структурированный ответ — MCP возвращает готовые данные, не нужно парсить JSON
Минусы
Токеновый оверхед
MCP-сервер — это дополнительное звено в цепочке. Каждый запрос проходит:
- Claude формирует JSON-RPC запрос → ~200 токенов
- MCP-сервер принимает, вызывает API → 0 токенов (но Node.js-процесс ест RAM)
- MCP-сервер формирует JSON-RPC ответ → ~300 токенов
- Claude получает ответ, переформулирует → ~500 токенов
Итого: ~1000 токенов на каждый поисковый запрос только на протокол MCP. Сам ответ поисковика — это ещё 500–1000 токенов.
Итого за сессию
| Операция | Токенов (MCP) | Токенов (curl) |
|---|---|---|
| 1 поисковый запрос | ~1000 | ~50 |
| 3 поиска + 2 загрузки | ~3500 | ~150 |
| Сессия из 10 запросов | ~10 000 | ~500 |
| День активной работы (30 запросов) | ~30 000 | ~1500 |
При стоимости Sonnet $3/1M входных токенов: MCP стоит $0.09/день, curl — $0.0045/день. Не критично для одного разработчика, но в масштабах команды — разница в 20×.
Зависимости
- Node.js — каждый MCP-сервер это
npx→npm install→ запуск процесса - RAM — каждый запущенный MCP-сервер ест 50–150 МБ
- Время запуска — при старте Claude Code подключается ко всем MCP-серверам, это 3–10 секунд на каждый
Сложность отладки
MCP-сервер молчит при ошибке. JSON-RPC вернул error: "internal" — и что? Логи MCP-сервера нужно смотреть отдельно. А curl сразу показывает 401 Unauthorized.
Вердикт
Красиво, но избыточно для задачи «сделать HTTP-запрос к поисковому API». MCP-сервер нужен, когда инструмент сложный (Playwright для браузера, база данных, файловая система). Для простого REST API — это overengineering.
Вариант 3. Skill + curl (рекомендуемый)
Как работает
Skill — это markdown-файл с инструкциями для Claude Code. Он описывает:
- Какой API вызывать
- Какую команду
curlвыполнить - Как разобрать ответ через
jq - Что делать с результатами
curl -s "https://api.search.brave.com/res/v1/web/search?q=Laravel+auth&count=10"
-H "X-Subscription-Token: $BRAVE_API_KEY"
-H "Accept: application/json" | jq -r '.web.results[] | "[(.title)]((.url)) — (.description)"'
Плюсы
Нулевой токеновый оверхед на поиск
Bash — это просто команда. Её вызов не тратит токены. Claude Code не отправляет запрос к API-провайдеру когда выполняет curl — он просто запускает процесс. Результат возвращается как stdout, и только он попадает в контекст.
| Что | Токенов |
|---|---|
| Вызов Bash(curl) | 0 |
| stdout результат (10 результатов) | ~300 |
| Итого | ~300 |
Сравните с MCP: ~1000 токенов на тот же запрос.
Skill кэшируется
Skill загружается один раз при старте сессии и кэшируется. Описание методов поиска (3–5 KB) не повторяется в каждом запросе.
Нет зависимостей
curl— уже стоит на любом Linux/macOSjq—apt install jqилиbrew install jq- Никаких Node.js-процессов, никаких npm-пакетов
Быстрый старт
Claude Code не тратит секунды на подключение MCP-серверов при старте. Сессия начинается мгновенно.
Прозрачная отладка
Ошибка? Ты видишь точный curl-запрос и ответ. 401 — ключ неверный. 429 — кончилась квота. 0 results — запрос кривой.
Работает за любым прокси
Не зависит от CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC. Не зависит от поддержки WebFetch в API-прокси. curl работает всегда, пока есть сеть.
Плюсы (дополнительные)
- Предсказуемость — Claude не вызывает поиск «сам», только когда ты просишь или явно вызываешь skill. Это плюс: никаких неожиданных API-запросов, полный контроль над каждым вызовом.
- stdout попадает в контекст — результат
curlвиден в транскрипте (это плюс — прозрачность)
Минусы
- Требует
jq— без него парсить JSON сложнее (но можно черезgrep+sed)
Вердикт
Минимальное решение. 0 токенов на оверхед, 0 зависимостей, 0 MCP-серверов. Для задачи «поиск по API» — это ровно столько сложности, сколько нужно.
Сравнительная таблица
| Критерий | WebSearch/WebFetch | MCP-сервер | Skill + curl |
|---|---|---|---|
| Токены на запрос | ~500–1000 | ~1000–1500 | ~300 |
| Зависимости | Нет | Node.js + npm пакет | curl + jq |
| Работает за прокси | ❌ | ✅ | ✅ |
| Время старта | Мгновенно | 3–10 сек на сервер | Мгновенно |
| RAM | 0 | 50–150 МБ | 0 |
| Отладка | Логи прокси | Логи MCP-процесса | stdout/stderr |
| Выбор поисковика | Фиксированный | Любой | Любой |
| Кэширование | Встроенное | Нет | Skill кэшируется |
| Настройка | 0 строк | 10+ строк JSON | 3 строки env |
| Автономность | ✅ | ✅ | Вызов по запросу |
Почему именно Brave или Tavily
Google Custom Search не подошёл:
- Требует включённый Custom Search API в Cloud Console — который не всегда активируется
- Programmable Search Engine не даёт включить «Search the entire web» без обходных путей
- Нужен billing-аккаунт даже для бесплатного тира
- 403-ошибка на JSON API даже после включения — API может требовать enterprise-доступа
Brave Search API:
- Бесплатно $5 кредитов каждый месяц (≈ 1000 запросов)
- Регистрация — нужна валютная карта, спишут $1 для верификации
- Тариф: $5 за 1000 запросов сверх бесплатных кредитов
- Качество результатов на уровне Google для технических запросов
- Простой REST API: один эндпоинт, один header (
GET)
Tavily Search API:
- Researcher (Free): 1000 кредитов/мес, без карты, только email
- Pay as you go: $0.008 за кредит, платишь только за использование
- Регистрация без карты (только email)
- Оптимизирован для AI-аентов — возвращает сразу
title,url,content - POST REST API: один эндпоинт, ключ в body
- Бонус: Tavily возвращает извлечённый контент страниц — не нужен отдельный
curlдля загрузки статей
Практическая настройка за 3 минуты
Вариант A: Brave Search API
- Зайти на api.search.brave.com → создать API-ключ (нужна карта, спишут $1)
- Добавить в
~/.claude/settings.json:
{
"env": {
"BRAVE_API_KEY": "BSAxxxxx"
}
}
Вариант B: Tavily Search API (без карты)
- Зайти на app.tavily.com → создать API-ключ (только email)
- Добавить в
~/.claude/settings.json:
{
"env": {
"TAVILY_API_KEY": "tvly-xxxxx"
}
}
Общее
# Убрать CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC если есть
# Установить jq
sudo apt install jq # Ubuntu/Debian
brew install jq # macOS
Skill уже установлен. Запрос в чат: «найди лучшие практики аутентификации в Laravel» — и через секунду результаты.
Сравнение Brave и Tavily для curl
| Критерий | Brave | Tavily |
|---|---|---|
| Метод | GET |
POST |
| Ключ | Header X-Subscription-Token |
Body api_key |
| Результаты | title + url + description |
title + url + content |
| Контент страниц | Отдельный curl на каждую |
Встроен в ответ (include_raw_content) |
| Регистрация | Карта + $1 | Только email |
| Бесплатно | $5 кредитов/мес (~1000) | 1000 кредитов/мес (Researcher, без карты) |
| Платно | $5/1000 запросов | $0.008/кредит (pay as you go) |
Когда MCP всё-таки нужен
Skill + curl не заменяет MCP-серверы полностью. MCP незаменим когда:
- Нужен stateful инструмент — браузер (Playwright MCP), база данных, SSH-сессия
- Сложная логика — несколько шагов, аутентификация, retries, fallbacks
- Автономность — Claude должен сам решать когда и как использовать инструмент
- Инструмент работает с файловой системой — чтение/запись, watching, watching changes
Но для простого REST API — одного HTTP-запроса — skill + curl быстрее, дешевле и надёжнее.
Сам skill
Skill — это markdown-файл, который Claude Code загружает при старте сессии. Вот что получилось в итоге:
---
name: web-search
description: Поиск информации в интернете через Tavily API (предпочтительно) или Brave Search API (curl/bash). Используй когда нужно найти актуальную информацию, документацию, ответы на вопросы, новости или любой контент из интернета.
---
# Web Search
Поиск через Tavily API (предпочтительно) или Brave Search API (fallback). Bash + curl, без MCP.
## Когда использовать
- Нужна актуальная информация из интернета
- Поиск документации, руководств, примеров
- Поиск новостей, статей, блогов
- Проверка фактов и поиск источников
- Поиск решений проблем (StackOverflow, GitHub Issues)
## Приоритет API
1. **Tavily** — предпочтительно. Возвращает контент страниц, не нужны отдельные запросы.
2. **Brave** — fallback если Tavily не работает (429, 401).
---
## Tavily Search API (основной)
### Эндпоинт
```
POST https://api.tavily.com/search
Content-Type: application/json
```
### Body (JSON)
```json
{
"api_key": "$TAVILY_API_KEY",
"query": "запрос",
"search_depth": "basic",
"max_results": 10,
"include_answer": true
}
```
### Параметры
| Параметр | Описание |
|---|---|
| `api_key` | API-ключ (из env `TAVILY_API_KEY`) |
| `query` | Поисковый запрос |
| `search_depth` | `basic` (быстро) или `advanced` (глубже, медленнее) |
| `max_results` | Количество результатов (1-20) |
| `include_answer` | `true` — включить AI-генерированный summary |
| `include_raw_content` | `true` — включить контент страниц (~1000 слов на страницу) |
| `days` | Ограничение по свежести (дни) |
| `topic` | Тема: `general` или `news` |
### Структура ответа
```json
{
"query": "Laravel auth",
"answer": "AI-generated summary",
"results": [
{
"title": "Заголовок",
"url": "https://example.com/page",
"content": "Извлечённый контент"
}
],
"response_time": 2.5
}
```
### Квоты
- **Free**: 1000 запросов/мес
- **Pro**: $69/мес, 5000 запросов
- Регистрация без карты (только email)
---
## Brave Search API (fallback)
### Эндпоинт
```
GET https://api.search.brave.com/res/v1/web/search?q={query}&count=10
```
### Заголовки
| Заголовок | Описание |
|---|---|
| `X-Subscription-Token` | API-ключ (из env `BRAVE_API_KEY`) |
| `Accept` | `application/json` |
### Параметры
| Параметр | Описание |
|---|---|
| `q` | Поисковый запрос |
| `count` | Количество результатов (1-20) |
| `offset` | Смещение (0, 20, 40...) |
| `country` | Страна: `ru`, `us`, `de`... |
| `search_lang` | Язык поиска: `en`, `ru`... |
| `freshness` | `pd` (день), `pw` (неделя), `pm` (месяц), `py` (год) |
### Квоты
- **Бесплатно**: $5 кредитов/мес (~1000 запросов)
- **Сверх кредита**: $5/1000 запросов
- Регистрация требует карту (спишут $1)
---
## Пошаговый процесс
### Шаг 1: Поиск (Tavily, 1 вызов)
```bash
curl -s -X POST https://api.tavily.com/search \
-H "Content-Type: application/json" \
-d "{\"api_key\":\"$TAVILY_API_KEY\",\"query\":\"Laravel 12 authentication\",\"max_results\":10,\"include_answer\":true}" | jq -r '(.answer + "\n") // "", (.results[] | "[\(.title)](\(.url)) — \(.content[:200])")'
```
Если Tavily вернул 429 или 401 — использовать Brave:
```bash
curl -s "https://api.search.brave.com/res/v1/web/search?q=Laravel+12+authentication&count=10&country=us&search_lang=en" \
-H "X-Subscription-Token: $BRAVE_API_KEY" \
-H "Accept: application/json" | jq -r '.web.results[] | "[\(.title)](\(.url)) — \(.description)"'
```
### Шаг 2: Выбрать релевантные URL
Из вывода выбрать 2-4 наиболее релевантных. Критерии:
- Совпадение ключевых слов
- Авторитетность домена
- Свежесть
### Шаг 3: Загрузить контент (параллельно)
Для Tavily: если нужен подробный контент, повторить запрос с `"include_raw_content": true` — и отдельные запросы не нужны.
Для Brave: использовать WebFetch или curl:
```
WebFetch:
url: {найденный_url}
prompt: "Извлеки ключевую информацию по теме {тема}. Верни краткую сводку."
```
Если WebFetch недоступен:
```bash
curl -sL "https://example.com/page" | html2text 2>/dev/null | head -200
```
### Шаг 4: Представить результат
1. Краткая сводка (2-4 предложения)
2. Ключевые findings с указанием источника
3. Ссылки для дальнейшего чтения
---
## Примеры
### Техническая документация (Tavily)
```bash
curl -s -X POST https://api.tavily.com/search \
-H "Content-Type: application/json" \
-d "{\"api_key\":\"$TAVILY_API_KEY\",\"query\":\"Laravel 12 validation rules custom\",\"max_results\":10,\"include_answer\":true}"
```
### Свежие новости (Tavily)
```bash
curl -s -X POST https://api.tavily.com/search \
-H "Content-Type: application/json" \
-d "{\"api_key\":\"$TAVILY_API_KEY\",\"query\":\"PHP 9 release\",\"max_results\":10,\"topic\":\"news\",\"days\":30}"
```
### С контентом страниц (Tavily — замена WebFetch)
```bash
curl -s -X POST https://api.tavily.com/search \
-H "Content-Type: application/json" \
-d "{\"api_key\":\"$TAVILY_API_KEY\",\"query\":\"PostgreSQL jsonb performance\",\"max_results\":5,\"include_raw_content\":true,\"search_depth\":\"advanced\"}"
```
### Русскоязычный поиск (Brave)
```bash
curl -s "https://api.search.brave.com/res/v1/web/search?q=Laravel+авторизация+Socialite&count=10&country=ru&search_lang=ru" \
-H "X-Subscription-Token: $BRAVE_API_KEY" | jq -r '.web.results[] | "[\(.title)](\(.url)) — \(.description)"'
```
---
## Обработка ошибок
### Tavily 401 Unauthorized
Проверить ключ: `echo $TAVILY_API_KEY` → [app.tavily.com](https://app.tavily.com/home)
### Tavily 429 Too Many Requests
Лимит исчерпан → переключиться на Brave
### Brave 401
Проверить ключ: `echo $BRAVE_API_KEY` → [api.search.brave.com](https://api.search.brave.com/app/keys)
### curl возвращает пустой результат
1. Проверить сеть: `curl -sI https://api.tavily.com | head -5`
2. Попробовать запрос на английском
3. Убрать `country`/`search_lang`
### WebFetch не может загрузить страницу
```bash
curl -sL "https://example.com/page" | html2text 2>/dev/null | head -300
```
---
## Советы
- Пиши запросы на английском для лучших результатов
- Tavily: используй `include_raw_content` чтобы получить контент страниц без отдельных запросов
- Tavily: `include_answer` даёт готовый AI-summary — можно использовать как краткий ответ
- Добавляй год к запросам для актуальности (например "2026")
- Для технических вопросов Tavily и Brave лучше чем Google Custom Search
- `max_results`/`count` по умолчанию 10, максимум 20
Почему skill работает лучше чем описание в CLAUDE.md
Можно было бы описать поиск в CLAUDE.md или ~/.claude/CLAUDE.md. Почему skill лучше:
| Критерий | CLAUDE.md | Skill |
|---|---|---|
| Загрузка в контекст | Всегда, каждую сессию | Только при вызове /web-search или когда Claude решает использовать |
| Токены на описание | Тратятся каждый запрос | Тратятся один раз при активации |
| Структура | Смешивается с правилами проекта | Изолирован, можно обновлять независимо |
| Вызов | Claude может забыть | /web-search — явный trigger |
Для задачи, которая нужна не каждый запрос, skill экономит токены и не загрязняет основной контекст.
Итог
| Подход | Когда выбирать |
|---|---|
| WebSearch/WebFetch | Когда работает из коробки (нет прокси, нет блокировок) |
| MCP-сервер | Когда нужен stateful или сложный инструмент |
| Skill + curl | Для HTTP API-запросов (поиск, погода, курсы валют, мониторинг) |