Привет, Хабр. Меня зовут Дима, я делаю WebAsk — конструктор опросов, исследований и тестов. Четыре года назад я писал тут про тотализатор на коленке, спагетти-код из 5000 строк и борьбу с мобильным скроллом. С тех пор сервис вырос из пет-проекта в рабочий инструмент на 50 000+ пользователей.
Но сегодня не про это. Сегодня — про то, как мы дали ИИ-ассистентам прямой доступ к WebAsk через MCP, какие грабли собрали по дороге и что из этого получилось.
Для тех, кто пропустил хайп: MCP (Model Context Protocol) — открытый стандарт от Anthropic. Он позволяет Claude, Cursor, Copilot и другим ассистентам подключаться к внешним сервисам и управлять ими напрямую — без браузера, без ручных обёрток, без копипасты. На Хабре уже штук пятнадцать статей про сам протокол, так что пересказывать не буду.

Зачем нам это сдалось
Мы долго наблюдали один и тот же сценарий. Человек сидит в 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 конфиги чуть другие, всё есть в документации.

Что внутри. По спецификации 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 токенов контекста, которые модель получает при каждом обращении. Мы пробовали отдавать описания группами (ленивая загрузка): сначала только базовые, остальные — по запросу. Не взлетело. Модель не знала о существовании инструментов из непрогруженных групп и даже не пыталась их запросить. Вернулись к полному списку — дороже по токенам, но модель видит всю картину и выбирает точнее.
Описания отдельно от кода. Ещё одно архитектурное решение, которое себя оправдало: описания инструментов хранятся отдельно от бизнес-логики обработчиков. Итерируем их независимо — можно переписать описание, не трогая код, и наоборот. Звучит очевидно, но когда ты в спешке пишешь всё в одном файле — потом это больно разделять.

Это то, что получилось. А теперь — про грабли.
Его величество описания инструментов
Вот это был, пожалуй, главный сюрприз. Мы потратили на текстовые описания инструментов значительно больше времени, чем на саму техническую интеграцию с API. И не потому что мы медленно пишем тексты.
Проблема вот в чём. Когда LLM получает список из 40+ инструментов, она должна по описанию понять, какой из них вызвать и с какими параметрами. Если описание нечёткое или двусмысленное — модель промахивается. Вызывает не тот инструмент. Передаёт неправильные параметры. Или вообще решает, что нужного инструмента нет, и начинает импровизировать.
Мы сначала пошли по пути экономии. Написали краткие описания — по одному предложению на инструмент. Логика была простая: меньше токенов на контекст → дешевле → быстрее. Красиво на бумаге.
На практике: промах в ~30% случаев на сложных цепочках. Модель путала update_widgets и update_texts. Не понимала разницу между quiz://{id}/answers и quiz://{id}/summary. При дублировании опроса забывала передать ID шаблона.
Переписали все описания на подробные — с пояснениями, примерами параметров, типичными сценариями использования. Да, это больше токенов. Да, это немного дороже на каждый запрос. Но точность выросла радикально. Экономия на описаниях — ложная экономия.
Конкретный пример: у нас есть два похожих инструмента — один обновляет тексты приветственного и финального экранов, другой — тексты самих вопросов. В первой версии оба были описаны как «обновить тексты опроса». Модель путала их в каждом втором случае. Когда мы явно прописали, что первый работает только с экранами приветствия и благодарности, а для вопросов нужен другой инструмент — путаница прекратилась.
Разница — как между «закрой дверь» и «закрой входную дверь, которая слева, а не дверь в ванную». Для человека и так понятно. Для LLM — нет.

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}/answers, quiz://{id}/summary и ещё полтора десятка. Подключили к Клоду, открыли диалог, попросили прочитать ответы опроса.
Claude вежливо ответил, что не может. Ресурс существует, но читать его он не умеет — в текущей интеграции доступны только инструменты. Ни ресурсы, ни промпты. Просто не поддерживаются.
Claude Code и Cursor — поддерживают всё: и ресурсы, и промпты. Но Клод — самый массовый клиент, и рассчитывать на то, что все пользователи сидят в CLI или Cursor, мы не могли.
Решение: обернули все 19 ресурсов в инструменты-обёртки. get_quiz_answers, get_quiz_summary, get_quiz_structure — по одной обёртке на каждый ресурс. Тулз вызывает ресурс внутри себя и возвращает данные. Для модели это выглядит как обычный инструмент, для пользователя — разницы ноль.
Мораль: если делаете MCP-сервер и хотите, чтобы он работал не только в CLI — дублируйте ресурсы как тулзы. По спецификации это не нужно. На практике — без этого половина клиентов вас не увидит.
Как этим пользуются на практике
Когда мы запустили MCP и начали смотреть логи — обнаружили, что наши представления о «типичном использовании» были неправильными примерно на 180 градусов.
Мы думали, что киллер-фича — создание опросов. Ну логично: мы конструктор, значит, люди будут конструировать. Через Claude вместо интерфейса — быстрее, удобнее, без переключения контекста. Пять вызовов — create, update_widgets, update_texts, apply_theme, publish — и опрос с вопросами, темой и публичной ссылкой готов. Это и правда работает, и это и правда быстрее.
Но самый частый сценарий оказался другим.
Главный сюрприз: никто не хотел создавать. Все хотели читать
Ресурсы аналитики вызываются значительно чаще, чем инструменты создания. Типичная история: у человека есть опрос, который уже неделю собирает ответы. Накопилось 500 текстовых ответов на открытые вопросы. И ему нужно из этой каши вытащить смысл — основные темы, повторяющиеся жалобы, какой-нибудь нонсенс.
Раньше это означало: открыть отчёт, начать скроллить, к пятидесятому ответу забыть, что было в десятом, к сотому — потерять волю к жизни. На 500 ответах — это полдня работы и желание никогда больше не делать опросы с открытыми вопросами.
Через MCP — Cursor читает все ответы, группирует по темам, выделяет паттерны, считает метрики и отдаёт структурированную выжимку. Плюс экспорт в Excel — и данные уже готовы для отчёта руководителю. Минута вместо трёх часов.
Оказывается, людям лень читать ответы на собственные опросы. Мы их понимаем — мы тоже такие.

Но по-настоящему 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 — для ИИ-агентов.

Что дальше
Мы продолжаем расширять MCP-сервер. В планах: больше инструментов (особенно для работы с логикой ветвлений), потоковая передача данных для более быстрого взаимодействия, и умный отчёт с ИИ-аналитикой — анализ тональности открытых ответов, автоматическая группировка по темам, выявление аномалий. По сути — превращение сырой аналитики из набора цифр в осмысленные выводы.
На момент публикации WebAsk — единственный российский сервис опросов с MCP-сервером. Не говорю это с пафосом — просто констатирую факт и надеюсь, что другие тоже подтянутся. Конкуренция в этой области всем на пользу.
Метрики эффекта пока не даём — запустились в марте, данных объективно мало. Первые наблюдения: аналитика популярнее создания, цепочки ценнее одиночных вызовов, описания инструментов — самая итерируемая часть системы. Когда накопится статистика — расскажем отдельно.
Если хотите попробовать: Настройки → API/MCP → сгенерировать ключ. Документация — webask.io/dev/api/mcp. Если что-то непонятно или сломается — пишите, мы читаем и комменты, и поддержку.
Если вы делали свой MCP-сервер — расскажите в комментариях, как решали проблему описаний инструментов. У нас ощущение, что можно лучше, но пока не понимаем как.
Респект всем, кто дочитал.