Привет, Хабр. Меня зовут Дима, я делаю WebAsk — конструктор опросов, исследований и тестов. Четыре года назад я писал тут про тотализатор на коленке, спагетти-код из 5000 строк и борьбу с мобильным скроллом. С тех пор сервис вырос из пет-проекта в рабочий инструмент на 50 000+ пользователей.

Но сегодня не про это. Сегодня — про то, как мы дали ИИ-ассистентам прямой доступ к WebAsk через MCP, какие грабли собрали по дороге и что из этого получилось.

Для тех, кто пропустил хайп: MCP (Model Context Protocol) — открытый стандарт от Anthropic. Он позволяет Claude, Cursor, Copilot и другим ассистентам подключаться к внешним сервисам и управлять ими напрямую — без браузера, без ручных обёрток, без копипасты. На Хабре уже штук пятнадцать статей про сам протокол, так что пересказывать не буду.

Схема работы MCP-сервера WebAsk: ИИ-ассистент подключается по протоколу MCP, сервер обращается к бэкенду WebAsk и данным
Схема работы MCP-сервера WebAsk: ИИ-ассистент подключается по протоколу MCP, сервер обращается к бэкенду WebAsk и данным

Зачем нам это сдалось

Мы долго наблюдали один и тот же сценарий. Человек сидит в Claude — пишет текст, разбирает код, готовит отчёт. И тут ему прилетает задача: «надо собрать обратную связь по конференции» или «создай опрос для сотрудников в отделе HR». Что происходит дальше?

Новая вкладка. Логин в WebAsk. 15 минут тыканья в конструктор. Копирование ссылки. Возврат в Claude. Контекст потерян, мысль ушла, кофе остыл, коллега уже написал «ну что там с опросом?», а ты ещё даже тему не выбрал. И так каждый раз.

Параллельно мы видели, что весь мировой рынок зашевелился. Typeform выкатил свой MCP-сервер в бету. Atlassian, Google, MongoDB — уже подключились. Anthropic и Cursor добавили нативную поддержку MCP-серверов прямо в свои клиенты. Для SaaS-продуктов это перестало быть экзотикой — MCP превращается в такой же ожидаемый интеграционный слой, как REST API и вебхуки пять лет назад.

И тут мы посмотрели на российский рынок. Знаете, сколько сервисов опросов в России поддерживают MCP?

Ноль.

Anketolog — нет. Testograf — нет. Survio — нет. Ни один сервис создания опросов или анкетирования. Мы проверили всех, кого смогли вспомнить.

У нас к тому моменту уже был REST API v3, уже работала ИИ-генерация опросов, уже были вебхуки. Добавить MCP-сервер поверх этого было логичным следующим шагом. Не потому что модно, а потому что задача понятная: дать ассистенту прямой доступ ко всему, что умеет WebAsk, чтобы пользователю не приходилось переключаться между окнами.

«Подожди, а зачем вообще конструктор, если ИИ и так умеет в опросы?»

ChatGPT может сгенерить опрос за тридцать секунд. Claude напишет анкету на React с ветвлениями. Зачем тогда отдельный сервис?

Потому что сгенерировать вопросы — это 5% работы. Остальные 95% — это инфраструктура:

  • Кто захостит опрос? Куда 10 000 респондентов пойдут отвечать?

  • Кто соберёт ответы? В какую базу? Кто гарантирует, что ничего не потеряется?

  • Кто посчитает аналитику? NPS-сегментацию из тысячи ответов? Тепловую карту из двух тысяч кликов по макету?

  • Кто экспортирует результаты в Excel для отчёта руководителю?

  • Кто отправит данные в Bitrix24, в MAX или Telegram, в Google Sheets?

Это как сказать «зачем Stripe, если ИИ может написать платёжную страницу». Страницу — может. Платежи обработать — нет. Генерация вопросов — это фронтенд. А за ним нужен бэкенд: хостинг, сбор данных, аналитика с сегментацией, интеграции, экспорт.

ИИ сам может сгенерировать вопросы. Но захостить опрос, собрать ответы, посчитать аналитику и экспортировать — для этого нужна инфраструктура
ИИ сам может сгенерировать вопросы. Но захостить опрос, собрать ответы, посчитать аналитику и экспортировать — для этого нужна инфраструктура

MCP как раз про это. Он не помогает ИИ придумывать вопросы — с этим ИИ и сам справляется. Он даёт ИИ доступ к работающей инфраструктуре: создать опрос, который реально захостится и будет принимать ответы. Собрать данные с живых респондентов. Посчитать NPS с разбивкой на промоутеров и критиков. Построить тепловую карту по клик-тесту. Выгрузить всё в Excel. И всё это — через один диалог.

ИИ — офигительный интерфейс. Но для проведения исследования ему нужна инфраструктура за спиной. Без MCP он может придумать вопросы. С MCP — провести исследование от создания до экспорта результатов.

Как мы это строили

Начну с технической части — а потом расскажу, где мы набили шишки.

Эндпоинт: POST https://mcp.webask.io/mcp/v1. Протокол — JSON-RPC 2.0, авторизация через Bearer-токен. Ключ генерируется в личном кабинете (Настройки → API/MCP) и показывается ровно один раз.

Подключение к Claude Desktop выглядит вот так:

{
  "mcpServers": {
    "webask": {
      "command": "npx",
      "args": ["-y", "@anthropic-ai/mcp-fetch"],
      "env": {
        "MCP_URL": "https://mcp.webask.io/mcp/v1",
        "MCP_AUTH_HEADER": "Authorization",
        "MCP_AUTH_VALUE": "Bearer YOUR_API_KEY"
      }
    }
  }
}

Скопировал, вставил, перезапустил Claude Desktop — всё, инструменты WebAsk появились в списке. Для Cursor и VS Code конфиги чуть другие, всё есть в документации.

Claude Desktop после подключения MCP-сервера WebAsk — инструменты появляются в списке автоматически
Claude Desktop после подключения MCP-сервера WebAsk — инструменты появляются в списке автоматически

Что внутри. По спецификации MCP предусматривает три типа возможностей: ресурсы (чтение данных), инструменты (действия) и промпты (подсказки). На практике выяснилось, что Claude Desktop поддерживают только инструменты — ресурсы и промпты они просто игнорируют. Курсор и Клод Код (CLI) поддерживает всё, но мы не могли рассчитывать только на него.

Поэтому мы обернули все ресурсы в инструменты-обёртки. Хочешь прочитать ответы? Вызываешь инструмент get_quiz_answers. Сводку? get_quiz_summary. Структуру опроса? get_quiz_structure. 19 таких обёрток — по одной на каждый ресурс.

В итоге получилось 40+ инструментов действий плюс 19 инструментов чтения — итого под 60 тулзов. Когда мы посчитали итоговое количество — сами немного офигели.

Группы инструментов:

Группа

Что внутри

Жизненный цикл

Создать, переименовать, дублировать, архивировать, удалить, опубликовать

Контент

Редактировать вопросы, тексты, настройки, логику ветвлений, загружать медиа

Оформление

Применить тему, создать свою, настроить под бренд

Аналитика

Сводка, фильтрованные отчёты, теги ответов, ссылки для шеринга

Экспорт

CSV, XLSX, PDF, Word

Промокоды

Создать группы, добавить коды, управлять списками

Как это устроено внутри. MCP-сервер написан на Node.js и работает как прослойка между MCP-клиентами (Claude, Cursor) и основным бэкендом WebAsk. По сути — тонкий слой маршрутизации: получил JSON-RPC запрос, определил какой инструмент вызвать, провалидировал параметры, дёрнул API, отдал результат.

Каждый инструмент — отдельный обработчик со своей схемой валидации. Общий роутер разбирает запрос по имени инструмента и перенаправляет в нужный обработчик. Упрощённо это выглядит так:

// описания лежат отдельно от логики
const tools = loadToolDescriptions('./tools/descriptions/')

// роутер
function handleToolCall(name, params) {
  const handler = handlers[name]        // находим обработчик
  const schema = tools[name].params     // берём схему валидации
  validate(params, schema)              // валидируем параметры
  return handler.execute(params)        // вызываем API v3
}

// обработчик — один файл на один инструмент
// tools/handlers/rename_quiz.js
export function execute({ quiz_id, name }) {
  return api.patch(`/quizzes/${quiz_id}`, { name })
}

Ничего космического, но когда обработчиков под 60 — важно не превратить это в кашу. Один файл = один инструмент, описания отдельно от логики, валидация автоматическая по схеме.

Проблема контекстного окна. Под 60 описаний инструментов — это примерно 6 000 токенов контекста, которые модель получает при каждом обращении. Мы пробовали отдавать описания группами (ленивая загрузка): сначала только базовые, остальные — по запросу. Не взлетело. Модель не знала о существовании инструментов из непрогруженных групп и даже не пыталась их запросить. Вернулись к полному списку — дороже по токенам, но модель видит всю картину и выбирает точнее.

Описания отдельно от кода. Ещё одно архитектурное решение, которое себя оправдало: описания инструментов хранятся отдельно от бизнес-логики обработчиков. Итерируем их независимо — можно переписать описание, не трогая код, и наоборот. Звучит очевидно, но когда ты в спешке пишешь всё в одном файле — потом это больно разделять.

MCP-сервер как прослойка: JSON-RPC запрос → роутер → обработчик инструмента → REST API v3 → данные
MCP-сервер как прослойка: JSON-RPC запрос → роутер → обработчик инструмента → REST API v3 → данные

Это то, что получилось. А теперь — про грабли.

Его величество описания инструментов

Вот это был, пожалуй, главный сюрприз. Мы потратили на текстовые описания инструментов значительно больше времени, чем на саму техническую интеграцию с API. И не потому что мы медленно пишем тексты.

Проблема вот в чём. Когда LLM получает список из 40+ инструментов, она должна по описанию понять, какой из них вызвать и с какими параметрами. Если описание нечёткое или двусмысленное — модель промахивается. Вызывает не тот инструмент. Передаёт неправильные параметры. Или вообще решает, что нужного инструмента нет, и начинает импровизировать.

Мы сначала пошли по пути экономии. Написали краткие описания — по одному предложению на инструмент. Логика была простая: меньше токенов на контекст → дешевле → быстрее. Красиво на бумаге.

На практике: промах в ~30% случаев на сложных цепочках. Модель путала update_widgets и update_texts. Не понимала разницу между quiz://{id}/answers и quiz://{id}/summary. При дублировании опроса забывала передать ID шаблона.

Переписали все описания на подробные — с пояснениями, примерами параметров, типичными сценариями использования. Да, это больше токенов. Да, это немного дороже на каждый запрос. Но точность выросла радикально. Экономия на описаниях — ложная экономия.

Конкретный пример: у нас есть два похожих инструмента — один обновляет тексты приветственного и финального экранов, другой — тексты самих вопросов. В первой версии оба были описаны как «обновить тексты опроса». Модель путала их в каждом втором случае. Когда мы явно прописали, что первый работает только с экранами приветствия и благодарности, а для вопросов нужен другой инструмент — путаница прекратилась.

Разница — как между «закрой дверь» и «закрой входную дверь, которая слева, а не дверь в ванную». Для человека и так понятно. Для LLM — нет.

Краткие описания → промах в 30% случаев. Подробные → модель выбирает точно. Экономия на описаниях — ложная экономия
Краткие описания → промах в 30% случаев. Подробные → модель выбирает точно. Экономия на описаниях — ложная экономия

180 запросов в минуту, или Почему агенты — это стихийное бедствие

Отдельная история — лимит запросов. Когда ты делаешь API для людей, 60 запросов в минуту — это с запасом. Человек физически не нажмёт кнопку 60 раз за минуту.

С ИИ-агентами всё иначе. Агент получает задачу «создай 10 опросов по шаблону с разными параметрами» — и начинает фигачить. Без пауз, без раздумий, без перерыва на кофе. Десять цепочек по 5-7 вызовов = 50-70 запросов за несколько секунд.

Встал выбор. 60 запросов в минуту — безопасно для бэкенда, но агент будет упираться в лимит на любой нетривиальной задаче. 300 в минуту — удобно для агентов, но один активный пользователь с агрессивным автоматизатором может создать проблемы для всех остальных.

Остановились на 180. Хватает для цепочки из 20+ вызовов подряд без задержек. Но не даёт одному агенту устроить DDoS. Ссылки на экспортированные файлы живут час — тоже компромисс между удобством и тем, чтобы не плодить висящие ресурсы.

Тестирование, или «Claude, ты что делаешь?»

Отдельное приключение — тестирование MCP-сервера с реальными LLM. Юнит-тесты, интеграционные тесты — это всё прекрасно и предсказуемо. А потом ты подключаешь реального Claude и понимаешь, что модель — это не детерминированный клиент.

Она может решить вызвать инструменты в неожиданном порядке. Может творчески интерпретировать параметры. Может вежливо проигнорировать половину вашего описания и «помочь» по-своему.

Один из наших любимых багов: мы просили Claude «создай опрос с тремя вопросами и опубликуй». Claude создавал опрос, добавлял три вопроса, потом решал, что неплохо бы ещё добавить приветственный экран с мотивирующим текстом (мы не просили), менял тему на «более подходящую» (мы не просили) и только потом публиковал. Инструменты работали корректно. Просто модель решила проявить инициативу.

Решение: более жёсткие промпты + явные указания в описаниях, что инструмент делает только то, что указано. Плюс мы добавили серверные подсказки, которые направляют модель по правильному пути для типовых сценариев.

Как вообще тестировать такое? Формальных eval-фреймворков мы не использовали — может, зря, но на старте важнее было быстро итерировать. Вместо этого собрали набор из ~20 типовых сценариев: «создай опрос с тремя вопросами», «покажи аналитику по последнему опросу», «продублируй шаблон и поменяй приветствие». После каждого изменения описаний — прогоняли весь набор руками.

Цикл выглядел так: пишешь промпт → смотришь, какие инструменты вызвались → если не те — правишь описание → повторяешь. Описания в среднем переписывались 3-4 раза, некоторые особо капризные инструменты — больше.

Самые проблемные — инструменты с похожими названиями (модель путает, какой за что отвечает) и инструменты с кучей необязательных параметров (модель либо передаёт лишнее, либо забывает нужное). По сути, тестирование MCP-сервера — это тестирование промптов. Только промпты — это ваши описания инструментов.

А где мои ресурсы?», или Сюрприз от Claude

Отдельные грабли, о которых стоит предупредить всех, кто собирается делать свой MCP-сервер.

По спецификации MCP умеет три вещи: инструменты (tools), ресурсы (resources) и промпты (prompts). Мы честно реализовали и ресурсы — quiz://{id}/answersquiz://{id}/summary и ещё полтора десятка. Подключили к Клоду, открыли диалог, попросили прочитать ответы опроса.

Claude вежливо ответил, что не может. Ресурс существует, но читать его он не умеет — в текущей интеграции доступны только инструменты. Ни ресурсы, ни промпты. Просто не поддерживаются.

Claude Code и Cursor — поддерживают всё: и ресурсы, и промпты. Но Клод — самый массовый клиент, и рассчитывать на то, что все пользователи сидят в CLI или Cursor, мы не могли.

Решение: обернули все 19 ресурсов в инструменты-обёртки. get_quiz_answersget_quiz_summaryget_quiz_structure — по одной обёртке на каждый ресурс. Тулз вызывает ресурс внутри себя и возвращает данные. Для модели это выглядит как обычный инструмент, для пользователя — разницы ноль.

Мораль: если делаете MCP-сервер и хотите, чтобы он работал не только в CLI — дублируйте ресурсы как тулзы. По спецификации это не нужно. На практике — без этого половина клиентов вас не увидит.

Как этим пользуются на практике

Когда мы запустили MCP и начали смотреть логи — обнаружили, что наши представления о «типичном использовании» были неправильными примерно на 180 градусов.

Мы думали, что киллер-фича — создание опросов. Ну логично: мы конструктор, значит, люди будут конструировать. Через Claude вместо интерфейса — быстрее, удобнее, без переключения контекста. Пять вызовов — create, update_widgets, update_texts, apply_theme, publish — и опрос с вопросами, темой и публичной ссылкой готов. Это и правда работает, и это и правда быстрее.

Но самый частый сценарий оказался другим.

Главный сюрприз: никто не хотел создавать. Все хотели читать

Ресурсы аналитики вызываются значительно чаще, чем инструменты создания. Типичная история: у человека есть опрос, который уже неделю собирает ответы. Накопилось 500 текстовых ответов на открытые вопросы. И ему нужно из этой каши вытащить смысл — основные темы, повторяющиеся жалобы, какой-нибудь нонсенс.

Раньше это означало: открыть отчёт, начать скроллить, к пятидесятому ответу забыть, что было в десятом, к сотому — потерять волю к жизни. На 500 ответах — это полдня работы и желание никогда больше не делать опросы с открытыми вопросами.

Через MCP — Cursor читает все ответы, группирует по темам, выделяет паттерны, считает метрики и отдаёт структурированную выжимку. Плюс экспорт в Excel — и данные уже готовы для отчёта руководителю. Минута вместо трёх часов.

Оказывается, людям лень читать ответы на собственные опросы. Мы их понимаем — мы тоже такие.

Cursor читает ответы, группирует по темам и отдаёт структурированную выжимку
Cursor читает ответы, группирует по темам и отдаёт структурированную выжимку

Но по-настоящему MCP раскрывается в цепочках. Один вызов на создание — это удобно, но не сильно отличается от клика по кнопке. А вот когда агент выстраивает цепочку из 5-9 вызовов подряд — тут начинается совсем другая история.

Пример из жизни: автоматизация онбординг-опросов. Каждому новому пользователю через три дня после регистрации нужно отправить персонализированную анкету — с его именем, с вопросами под его тариф. А потом собрать ответы и выгрузить в дашборд. Вручную это делать — хочется уволиться на третьем пользователе. Через MCP агент сам дублирует шаблон, подставляет имя через скрытую переменную, настраивает логику ветвлений под тариф, публикует, а через три дня сам же собирает ответы и экспортирует в CSV. Девять вызовов, ноль ручного труда.

webhook → duplicate → create_hidden_variables → update_texts
→ update_logic → publish → [3 дня] → answers → export_csv

Скрытые переменные — отдельная штука, которая тут работает на ура. Создаёте переменную с именем пользователя, привязываете к полю приветствия — и каждый респондент видит «Привет, Маша!», хотя опрос создан из одного шаблона.

Полный цикл автоматизации: от регистрации пользователя до выгрузки ответов в дашборд
Полный цикл автоматизации: от регистрации пользователя до выгрузки ответов в дашборд

Итерации прямо из IDE. Мы подключили MCP к Cursor, и оказалось, что для UX-ресёрчеров это вообще отдельный мир. Прочитал структуру опроса, поправил логику ветвлений, проверил сколько ответов набралось, выгрузил PDF-отчёт для стейкхолдеров — и всё это не выходя из редактора. Звучит как мелочь, но когда ты в потоке и тебе нужно быстро глянуть аналитику между двумя задачами — это экономит не время, а нервы.

Что ещё нас удивило

Модель помнит контекст между вызовами — и это кажется очевидным, пока не увидишь в действии. Человек говорит: «Создай опрос». Потом: «Добавь вопрос про бюджет». Потом: «А покажи, что получилось». Claude помнит ID опроса, знает текущую структуру и не теряет нить. Для пользователя это ощущается как разговор с живым ассистентом, а не как дёрганье API по документации.

Экспорт завершает каждую цепочку. Создал → настроил → собрал → выгрузил в CSV, Excel, PDF или Word. Без экспорта результат остаётся внутри сервиса. С экспортом — попадает в дашборд, в отчёт, в письмо руководителю. Мы чуть не сделали экспорт в последнюю очередь. Это было бы примерно как построить дом и забыть про двери.

MCP vs REST API — зачем два интерфейса

У нас есть полноценный REST API v3, который покрывает всю функциональность. Зачем тогда MCP?

Потому что у них принципиально разные потребители.

API — для разработчиков. Вы пишете код, точно знаете, какой эндпоинт вызвать, какие параметры передать, как обработать ответ. Всё детерминировано, всё предсказуемо.

MCP — для ИИ-агентов. Вы даёте модели набор из ~60 инструментов с описаниями, а она сама решает, что и когда вызвать. Пользователь говорит «создай анкету для оценки сотрудников с NPS-шкалой и логикой ветвлений» — и агент сам разбирает это на шаги, сам выбирает инструменты, сам склеивает результат. Разработчик не писал ни строчки кода.

Это не замена. Это параллельный слой. REST API, вебхуки, MCP — три разных интерфейса для трёх разных задач. API — для интеграций. Вебхуки — для событий. MCP — для ИИ-агентов.

Три интеграционных слоя WebAsk: REST API для разработчиков, вебхуки для событий, MCP для ИИ-агентов
Три интеграционных слоя WebAsk: REST API для разработчиков, вебхуки для событий, MCP для ИИ-агентов

Что дальше

Мы продолжаем расширять MCP-сервер. В планах: больше инструментов (особенно для работы с логикой ветвлений), потоковая передача данных для более быстрого взаимодействия, и умный отчёт с ИИ-аналитикой — анализ тональности открытых ответов, автоматическая группировка по темам, выявление аномалий. По сути — превращение сырой аналитики из набора цифр в осмысленные выводы.

На момент публикации WebAsk — единственный российский сервис опросов с MCP-сервером. Не говорю это с пафосом — просто констатирую факт и надеюсь, что другие тоже подтянутся. Конкуренция в этой области всем на пользу.

Метрики эффекта пока не даём — запустились в марте, данных объективно мало. Первые наблюдения: аналитика популярнее создания, цепочки ценнее одиночных вызовов, описания инструментов — самая итерируемая часть системы. Когда накопится статистика — расскажем отдельно.

Если хотите попробовать: Настройки → API/MCP → сгенерировать ключ. Документация — webask.io/dev/api/mcp. Если что-то непонятно или сломается — пишите, мы читаем и комменты, и поддержку.

Если вы делали свой MCP-сервер — расскажите в комментариях, как решали проблему описаний инструментов. У нас ощущение, что можно лучше, но пока не понимаем как.

Респект всем, кто дочитал.

Комментарии (0)