Сервер MCP
MCP Server
Используйте FourA из любого клиента Model Context Protocol (Claude Desktop, Claude Code, Cursor, Windsurf, VS Code) в виде четырех нативных инструментов и шести workflow-промптов. Без кода интеграции и кастомных HTTP-клиентов.
Открытый исходный код на GitHub; в npm как @fouradata/mcp. Текущий релиз: 0.7.3.
Quick Start: локальный stdio (рекомендуется для Claude Desktop)
Получите ключ на foura.ai/dashboard#api-keys (в один клик, показывается один раз при создании, формат pk_live_...). Добавьте это в конфиг вашего MCP-клиента:
{
"mcpServers": {
"foura": {
"command": "npx",
"args": ["-y", "@fouradata/mcp"],
"env": { "FOURA_API_KEY": "pk_live_..." }
}
}
}
Важная деталь для Claude Desktop: полностью закройте Claude Desktop (
Cmd+Qна macOS) до редактирования файла конфигурации. Если приложение все еще запущено, оно перезапишет ваши изменения своей конфигурацией из памяти при выходе.
Команда npx скачивает @fouradata/mcp при первом запуске и выполняет его как подпроцесс вашего MCP клиента. Глобальная установка не требуется.
| Клиент | Расположение конфигурации |
|---|---|
| Claude Desktop (macOS) | ~/Library/Application Support/Claude/claude_desktop_config.json |
| Claude Desktop (Windows) | %APPDATA%\Claude\claude_desktop_config.json |
| Claude Code | claude mcp add foura -- npx -y @fouradata/mcp (сначала установите FOURA_API_KEY в env) |
| Cursor | ~/.cursor/mcp.json |
| Windsurf | ~/.codeium/windsurf/mcp_config.json |
| VS Code (расширение MCP) | .vscode/mcp.json |
Перезапустите клиент. Инструменты (foura_auto, foura_single, foura_proxy, foura_browser) и шесть промптов появятся в вашем списке инструментов.
Быстрый старт: хостинг (Streamable HTTP)
Для клиентов с поддержкой транспорта Streamable HTTP (Cursor, Windsurf, VS Code, Claude Code с --transport http), укажите на размещенный endpoint вместо запуска локального подпроцесса:
{
"mcpServers": {
"foura": {
"url": "https://mcp.foura.ai/mcp",
"headers": {
"Authorization": "Bearer pk_live_..."
}
}
}
}
Для Claude Desktop используйте конфигурацию stdio выше или перенаправьте хостируемый endpoint через mcp-remote:
{
"mcpServers": {
"foura": {
"command": "npx",
"args": ["-y", "mcp-remote", "https://mcp.foura.ai/mcp", "--header", "Authorization: Bearer pk_live_..."]
}
}
}
Справочник по hosted endpoint
| Свойство | Значение |
|---|---|
| URL | https://mcp.foura.ai/mcp |
| Транспорт | Streamable HTTP (POST /mcp, SSE-ответы) |
| Аутентификация | Authorization: Bearer pk_live_... для каждого запроса |
| MCP-Protocol-Version | Согласно @modelcontextprotocol/sdk (сейчас 2025-11-25, 2025-06-18, 2025-03-26, 2024-11-05, 2024-10-07) |
| Запрос 401 | WWW-Authenticate: Bearer realm="foura-mcp" |
Запрос 401 намеренно не содержит параметра RFC 9728 resource_metadata. Его указание заставляет клиенты с поддержкой OAuth запускать процесс, который данный сервер не реализует. Отправьте ваш ключ pk_live_ в качестве Bearer-токена, и ошибка 401 исчезнет.
Размещенный сервер не сохраняет состояние. Каждый запрос передает собственный ключ, который сервер перенаправляет в FourA API как X-API-Key. Один ключ открывает доступ ко всем четырем инструментам.
Для защиты от DNS-rebinding (CVE-2025-66414) сервер валидирует заголовок Host (должен быть mcp.foura.ai или localhost) и заголовок Origin при его наличии (в белом списке: mcp.foura.ai, claude.ai, app.cursor.sh, app.cursor.com). Межсерверные клиенты (curl, MCP-клиенты в режиме stdio bridge) не отправляют Origin и проходят без проверок.
Инструменты
Все четыре инструмента снабжены аннотациями readOnlyHint: true и openWorldHint: true согласно спецификации MCP 2025-06-18. Клиенты, которые автоматически одобряют доверенные инструменты только для чтения, вызывают их без диалогового окна подтверждения для каждого запроса.
foura_auto является стандартным выбором по умолчанию: передайте ему URL, и он вернет контент, подобрав способ получения за вас. Остальные три инструмента представляют собой низкоуровневые примитивы, которыми он управляет. Используйте их, когда вам нужен явный контроль.
foura_auto
Передайте URL, когда хотите, чтобы FourA сама выбрала метод выполнения запроса. Она делает ограниченное количество попыток через доступные пути HTTP, proxy и браузера. Передавайте validate для защищенных ресурсов, чтобы ответ обязательно содержал контент, идентифицирующий реальную страницу. Если ни одна попытка не удовлетворяет валидации, инструмент возвращает ошибку вместо того, чтобы считать страницу с проверкой успешным результатом.
Ответ включает детали выполнения в meta и, по умолчанию, повторно используемый объект session с полями proxy, cookies и userAgent. Для обычного последующего запроса вызовите foura_single с параметром session.proxy в виде proxy, сериализуйте cookie в заголовок Cookie и отправьте session.userAgent в качестве заголовка User-Agent. Для рендеринга JavaScript передайте значения сессии в соответствующие поля foura_browser.
foura_single
Один HTTP-запрос, один ответ. Напрямую транслирует POST /api/single/ один к одному.
Используйте для статических страниц, JSON API и HTML, отрендеренного на стороне сервера.
Выбор браузера для представления
По умолчанию запрос представляется последней версией Google Chrome. Если целевой ресурс принимает один браузер и блокирует другой, задайте browser (Chrome, Edge, Safari, Firefox или Tor), os (Windows, macOS, Android или iOS) или version, либо передайте точный идентификатор profile:
{
"method": "GET",
"url": "https://example.com",
"browser": "Firefox",
"os": "Windows"
}
При совпадении нескольких профилей выбирается самая новая версия. Если комбинация не существует, возвращается ошибка со списком доступных вариантов, поэтому request никогда не отправляется от имени браузера, который вы не выбирали. Для выбора требуется unblocker, включенный по умолчанию. Каталог опубликован по адресу GET /api/profiles и не требует API key.
Те же четыре поля находятся внутри объекта request в foura_proxy.
foura_proxy
Маршрутизация одного HTTP request через ротируемые proxy с автоматическим повтором. Используйте, когда foura_single заблокирован или целевой ресурс требует определенную страну выхода.
Установите exitCountries в строгий список разрешенных двухбуквенных кодов стран, видимых целевому ресурсу, переданных пользователем или требуемых ресурсом:
{
"maxTries": 5,
"exitCountries": ["CZ", "GB"],
"request": {
"method": "GET",
"url": "https://example.com/pricing",
"browser": "Chrome",
"os": "Windows"
}
}
Значения очищаются от пробелов, переводятся в верхний регистр и дедуплицируются. Прокси с неизвестными точками выхода исключаются, а запрос никогда не переключается на незапрошенную страну. Для выбора используются последние доступные метаданные страны, видимые целевому ресурсу (обычно обновляются в течение десяти минут); это не динамический поиск геолокации во время запроса. Не определяйте обслуживающую страну по хост-адресу прокси.
Успешный ответ со скоупом возвращает exitCountry и переиспользуемый ID proxy. Убедитесь, что exitCountry входит в запрошенный список разрешений. Если в текущем пуле нет совпадений, инструмент возвращает code: "no_eligible_proxy" с нормализованным скоупом в details.exitCountries. Сохраните этот скоуп и повторите попытку позже. Изменяйте или расширяйте его только тогда, когда пользователь явно меняет требование. Выбор страны включен начиная с тарифа Startup. На тарифах без этой опции вызов с exitCountries отклоняется с 403 и X-FourA-Limit: plan_limit_feature.
Если выбранной странице позже потребуется JavaScript, передайте возвращенный ID proxy в foura_browser.proxy, чтобы браузер повторно использовал ту же точку выхода.
Установите exitClass: "premium" для цели, которую стандартный пул не может открыть независимо от количества перепробованных точек выхода. Это разрешение, а не жесткая инструкция: стандартный пул по-прежнему конкурирует за ответ и обычно побеждает, а запрос, на который он ответил до попытки обращения к premium-выходу, не расходует premium-трафик. Попытка через premium учитывает переданный трафик, даже если она завершилась ошибкой. Ответ возвращает exitClass, premium или standard, позволяя увидеть для каждого запроса, какой класс его обслужил. standard также возвращается после того, как включенный в тариф premium-трафик израсходован; это штатный результат, а не ошибка. exitClass: "standard" полностью запрещает эскалацию. exitClass: "premium" на тарифе без premium-выходов отклоняется с code: "plan_limit_premium". См. exitClass.
Когда для получения ответа ротации пришлось переключиться на другое семейство браузеров, успешный ответ содержит profile с выбранным семейством. Повторите запрос с ним, иначе следующий вызов снова использует версию, завершившуюся ошибкой.
Неудачная ротация возвращает attemptReport рядом с ошибкой: одно предложение summary, а также счетчики, разделяющие точки выхода, которые не ответили (noResponse), точки выхода, отклоненные проверкой на ботов (defense, с указанием поставщиков в vendors), страницы, которые были получены и отклонены только вашим собственным правилом validate.data (contentRejected), statusRejected и other. В profilesTried перечислены браузеры, отправленные задачей, в порядке первого использования, где default означает, что запрос ушел ровно в исходном виде. Высокое значение contentRejected означает, что FourA доставил настоящие страницы, а ваше собственное правило их отклонило. См. Why a Proxy Request Ran Out of Tries.
foura_browser
Полноценная сессия браузера. JavaScript выполняется, DOM рендерится, cookie возвращаются. Повторяет POST /api/browser/.
Используйте для одностраничных приложений (SPA), ленивой загрузки контента или страниц с проверками, требующими полноценного браузера.
Форматы входных данных, значения по умолчанию и правила валидации для каждого инструмента приведены в REST endpoint reference. Схемы инструментов полностью совпадают с полями REST API, плюс доступна опция offload_large только для MCP (см. ниже).
Когда целевой ресурс запускает проверку на ботов
foura_single и foura_proxy возвращают defense, если целевой ресурс выполнял проверку на ботов перед отдачей тела ответа. defense.solved: true означает, что проверка пройдена и data содержит настоящую страницу; false означает, что тело ответа может содержать страницу с вызовом (challenge). Повторите попытку с другим браузером, ОС или версией, либо перейдите на foura_proxy или foura_browser, вместо того чтобы обрабатывать страницу проверки как контент.
Типизированные ответы
Каждый ответ инструмента содержит как content (текстовую сводку для чтения человеком), так и structuredContent (типизированный JSON, валидированный по outputSchema инструмента). У каждого инструмента своя уникальная структура:
foura_auto: единый формат{ status, headers, data }плюсmeta({ rung, solved, attempts, credits }, присутствует всегда, гдеrungпринимает одно из значенийcache,probe,proxy,browser,warmup,fail) и по умолчаниюsession({ proxy, cookies, userAgent }) для повторного воспроизведения через низкоуровневые инструменты. Полеtotal_timeотсутствует.foura_single:{ status, headers, data, total_time, ... }(headers является массивом, по одной записи на каждый шаг редиректа)foura_proxy: аналогично одиночному запросу плюс{ proxy, total }; успешный ответ с ограничением области также включаетexitCountry, запрос с указанием класса включаетexitClass, ротация со сменой семейства браузера включаетprofile, а ошибка включаетattemptReportfoura_browser: отдельная структура{ status, headers: object, body, cookies, userAgent }(примечание:bodyможет быть строкой или объектом в зависимости от content-type)
Каждый инструмент также сообщает стоимость вызова и данные для его трассировки, полученные из заголовков ответа API:
credits: количество кредитов, потраченных на этот вызов. Присутствует и при ошибках, поскольку работа была выполнена в любом случае. Оплата взимается только за успешные вызовы, поэтому при ошибке кредиты отображаются здесь, но фактически не списываются.request_id: идентификатор вызова в FourA. Указывайте его при обращении в поддержку.exitClass:premium, если вызов обслуживался через премиум-выход. Вfoura_singleиfoura_browserэто происходит, когдаproxyповторно использует выход, найденныйfoura_proxy.
Каждое поле отсутствует, если API ничего не вернул, поэтому клиенты, написанные под более ранние версии, продолжают работать без изменений. Эти же значения описаны в Response Headers.
Клиенты с поддержкой structuredContent могут передавать типизированный объект напрямую в LLM без необходимости парсить JSON из обычного текста.
Заголовки ответа с несколькими значениями
Заголовки, встречающиеся несколько раз (Set-Cookie, Link, WWW-Authenticate), возвращаются в виде массивов:
{
"headers": [
{
"result": { "version": "HTTP/2", "code": 200, "reason": "" },
"content-type": "text/html",
"set-cookie": ["a=1; Path=/", "b=2; Path=/"]
}
]
}
Это важно для сайтов, которые устанавливают session, tracking и consent cookie в одном ответе (большая часть e-commerce).
Большие ответы: offload_large (по умолчанию: inline)
По умолчанию (начиная с v0.2.0) полные тела ответов возвращаются inline в structuredContent независимо от размера. Это работает во всех клиентах MCP из коробки.
Если ваш клиент поддерживает MCP resources/read И вы хотите экономить токены на больших страницах, передавайте offload_large: true в каждом вызове инструмента. В этом случае ответы размером >= 50 КБ записываются на диск, возвращаются как resource_link, и клиент запрашивает тело только тогда, когда оно действительно нужно. На хостинг-сервере кэшированные полезные нагрузки удаляются через 1 час. На собственном инстансе сохраненные полезные нагрузки автоматически не удаляются: очищайте файлы старше одного часа из директории полезной нагрузки самостоятельно.
{
"method": "GET",
"url": "https://en.wikipedia.org/wiki/Web_scraping",
"offload_large": true
}
| Клиент | offload_large: true |
|---|---|
| Claude Desktop | пока нет, оставьте значение по умолчанию false |
| Claude Code, Cursor, Windsurf | поддерживается |
| Расширение VS Code MCP | поддерживается |
Изоляция клиентов: каждый API key получает собственное пространство имен (sha256(apiKey)[:16]). Только ключ, сохранивший полезную нагрузку, может прочитать ее обратно. Попытки межклиентского чтения возвращают Payload not found без утечки данных о существовании ресурса.
Встроенные промпты
Шесть шаблонов рабочих процессов доступны в /prompts в любом MCP клиенте. Каждый принимает именованные аргументы и возвращает шаблонное сообщение пользователя, координирующее один или несколько инструментов.
| Промпт | Аргументы | Назначение |
|---|---|---|
smart_fetch |
url, опционально must_contain, extract |
Автоматическая загрузка (выбирает метод, обходит защиту от ботов), затем возвращает или извлекает контент |
scrape_product_page |
url |
Загрузка через браузер, затем извлечение названия товара, цены, изображения, наличия, SKU в формате JSON |
extract_article |
url |
Одиночный запрос с переключением на proxy, затем очистка от навигации/рекламы и возврат чистого JSON статьи |
monitor_pricing |
url, опционально target_price |
Загрузка через proxy, извлечение текущей цены, сравнение с целевой |
check_endpoint_health |
url, опционально expected_text |
Одиночный запрос со строгой валидацией, возврат доступности и времени ответа |
bulk_fetch_urls |
urls (через запятую) |
Параллельные одиночные запросы, автоматическое переключение на proxy для каждого URL, возврат только метаданных |
Промпты не расходуют токены в режиме ожидания. Только вызванные промпты попадают в контекст LLM.
Полный текст и резервные промпты для ручной настройки: MCP Recipes.
Конверт ошибки
Каждая ошибка (isError: true) содержит конверт structuredContent. Минимальный набор полей для каждой ошибки:
{
"service": "auto | single | proxy | browser",
"code": "rate_limited",
"error": "Rate limit exceeded"
}
При ошибках upstream с HTTP-статусом также присутствует status. При ошибках rate limit и емкости upstream envelope добавляет retryAfter, current.{concurrency, rpm} и limits.{maxConcurrency, maxRpm}. Формат базового REST ответа описан в разделе API Errors.
Стабильные значения code:
| Код | HTTP | Значение | Безопасен повтор? |
|---|---|---|---|
ssrf_blocked |
n/a | Целевой адрес является приватным или зарезервированным (RFC 5735, 6598, IPv6 reserved), URL не http(s), или имя хоста не разрешилось | Нет, проверьте URL. Кратковременную ошибку DNS lookup можно повторить |
upstream_non_json |
различается | Upstream вернул некорректное тело ответа | Возможно, требуется анализ |
output_validation_failed |
n/a | outputSchema MCP-сервера отклонил upstream response, или инструмент не смог выполнить вызов (API-ключ не настроен, API недоступен) |
Возможно: проверьте конфигурацию, затем сообщите об ошибке |
bad_request |
400 | Формат входных данных отклонен | Нет, исправьте аргументы |
auth_failed |
401 | Ключ отсутствует, недействителен или деактивирован | Нет, исправьте ключ |
forbidden |
403 | Целевой ресурс вернул 403, и ваш validate отклонил его (проверка сайта, ограничение по стране) |
Нет, или переключитесь на foura_proxy |
not_found |
404 | Целевой ресурс или endpoint не найден | Нет |
rate_limited |
429 | Превышен лимит RPM | Да, подождите retryAfter |
at_capacity |
503 | Превышен лимит параллельных запросов | Да, подождите retryAfter |
service_disabled |
503 | Сервис отключен на обслуживание. Инструмент, не входящий в тарифный план, возвращает plan_limit_feature |
Обратитесь в поддержку |
service_unavailable |
503 | Общая ошибка 503 | Да, короткий backoff |
upstream_error |
500+ или 0 | Целевой ресурс ответил ошибкой сервера, либо в foura_proxy сервисы foura_browser и foura_auto не ответили |
Да, экспоненциальный backoff |
upstream_client_error |
4xx | Другие ошибки 4xx | Обычно нет |
upstream_unknown |
другое | Запрос выполнен, но не дал принятого ответа: в foura_single целевой ресурс не ответил (таймаут, сброс соединения), а в любом другом инструменте ваш validate отклонил ответ 2xx или 3xx. Проверьте status и error |
Требуется анализ |
no_eligible_proxy |
n/a | Нет proxy, соответствующего строгому scope exitCountries |
Повторите позже; меняйте scope только явно |
plan_limit_* |
403 или 429 | Один из лимитов вашего тарифного плана отклонил вызов: plan_limit_ со значением feature, premium, concurrency, rate, browser_daily, credits или bandwidth. См. MCP Server Errors |
Подождите retryAfter, если указано; иначе повтор невозможен до сброса лимита или смены плана |
LLM-агенты могут читать code напрямую для логики повторов без парсинга текста. Руководство по аутентификации: Authentication.
Limits
- Inline body по умолчанию. С
offload_large: trueответы >= 50 КБ сохраняются на диск +resource_link(для каждого tenant, TTL 1 час). - Запросы к приватным адресам отклоняются (RFC 5735, RFC 6598, зарезервированные блоки IPv6) на уровне MCP. Перенаправляются только публичные хосты.
- Лимит размера тела запроса 256 КБ для входящих запросов
/mcp(реальные полезные нагрузки MCP составляют < 4 КБ). - Rate limits применяются FourA API для каждого сервиса. См. Rate Limits.
Self-Hosting
Полный исходный код сервера доступен публично на GitHub под лицензией @fouradata/mcp. Клонируйте репозиторий, выполните npm install, npm run build и запустите node dist/http.js, чтобы поднять собственный инстанс. Работает без сохранения состояния (stateless) в одном контейнере за любым балансировщиком нагрузки.
Переменные окружения:
| Переменная | По умолчанию | Назначение |
|---|---|---|
PORT |
3076 |
Порт прослушивания HTTP |
FOURA_API_BASE |
https://api.foura.ai/api |
Базовый URL upstream FourA REST |
FOURA_MCP_PAYLOADS_DIR |
папка foura-mcp-payloads в системном временном каталоге (в комплекте Docker Compose задает /data/payloads) |
Место кэширования ответов >= 50 КБ на диске (с offload_large: true) |
FOURA_MCP_ALLOWED_HOSTS |
mcp.foura.ai,localhost,127.0.0.1,[::1] |
Разрешенные имена хостов для заголовка Host (защита от DNS-rebinding) |
FOURA_MCP_ALLOWED_ORIGINS |
https://mcp.foura.ai,https://claude.ai,https://app.cursor.sh,https://app.cursor.com |
Список разрешенных Origin для браузерных клиентов |
Официальный контейнер запускается от имени uid 1001 (non-root). Bind mount хоста /data/payloads должен быть доступен для записи этому uid.
Масштабируйте горизонтально за любым балансировщиком нагрузки. Клиенты передают свой ключ в каждом запросе, поэтому привязка сессий (sticky sessions) не требуется.