Ваш тест на оформление заказа нажимает «Оформить заказ» и видит зелёный тост. Хорошо. Но вот чего он не проверяет: реально ли записалась строка? Правильно ли записались позиции заказа? Уменьшился ли инвентарь? UI написал «подтверждено», но UI иногда врёт — проглоченная ошибка, откаченная транзакция, очередь, которая молча дропнула сообщение.
Классическое решение некрасиво: нужно подключить ORM или низкоуровневый драйвер базы данных внутри тестового харнеса, управлять отдельными учётными данными, писать SQL-ассерты вручную и надеяться, что схема не изменится. Работает. Но это накладные расходы на поддержку, которые вы платите за каждый тест.
Сейчас есть паттерн лучше. И в нём ноль SQL с вашей стороны.
Что если один AI-агент сможет делать обе половины — управлять браузером при оформлении заказа и затем переключиться в базу данных для проверки записи — используя два MCP-сервера?
Именно это разбирается в статье:
Playwright MCP управляет браузерной автоматизацией (навигация, клики, заполнение форм, снапшоты).
PostgreSQL MCP управляет интроспекцией базы данных и read-only запросами.
Агент последовательно их использует. Завершает оформление заказа, получает order ID со страницы подтверждения, затем переключает контекст и использует инструменты базы данных для верификации. Весь сценарий описывается на обычном языке.
Что понадобится
Работающее веб-приложение с флоу оформления заказа (любой стек — это работа на уровне браузера)
PostgreSQL или MySQL с данными приложения
MCP-клиент (Claude Desktop, Claude Code или любой MCP-совместимый клиент)
Пакеты MCP-серверов для Playwright и базы данных
Шаг 1: Настройка двух MCP-серверов
Добавьте оба сервера в конфигурацию MCP-клиента. Вот как выглядит claude_desktop_config.json:
{ "mcpServers": { "playwright": { "command": "npx", "args": ["@anthropic/mcp-playwright"] }, "postgres": { "command": "npx", "args": [ "@anthropic/mcp-postgres", "postgresql://readonly:****@localhost:5432/shop" ] } } }
Два важных момента. Первый: подключение к базе данных использует read-only пользователя. Это принципиально — вы даёте AI-агенту доступ к базе, поэтому он должен только читать, никогда не писать. Второй: если у вас MySQL, а не PostgreSQL, просто замените @anthropic/mcp-postgres на @anthropic/mcp-mysql. Интерфейс инструментов идентичен.
Шаг 2: Браузерная часть
Теперь вы даёте агенту промпт с описанием UI-флоу:
Перейди на localhost:3000/products. Добавь «Wireless Charger» в корзину. Перейди к оформлению заказа. Заполни имя покупателя «Ada Lovelace» и email «ada@test.dev». Выбери «Credit Card» как способ оплаты и нажми «Place Order». Дождись страницы подтверждения и захвати order ID.
Под капотом агент переводит это в последовательность вызовов Playwright MCP:
browser_navigate({ url: "http://localhost:3000/products" }) browser_click({ selector: "text=Wireless Charger" }) browser_click({ selector: "button:has-text('Add to Cart')" }) browser_click({ selector: "a:has-text('Checkout')" }) browser_fill({ selector: "#name", value: "Ada Lovelace" }) browser_fill({ selector: "#email", value: "ada@test.dev" }) browser_click({ selector: "text=Credit Card" }) browser_click({ selector: "button:has-text('Place Order')" }) browser_snapshot()
Агент читает снапшот страницы подтверждения и извлекает: Order #10472.
Никаких переменных, никаких тестовых фикстур. Агент просто запоминает order ID в своём контексте и несёт его дальше.
Шаг 3: Верификация базы данных — ноль SQL
Вот где становится интересно. Продолжаете тот же промпт (или добавляете вторую инструкцию):
Теперь проверь базу данных. Подтверди, что заказ 10472 существует в таблице orders и принадлежит ada@test.dev. Проверь, что в таблице line_items есть запись для «Wireless Charger» с количеством 1. Также проверь, что инвентарный остаток товара был уменьшен.
Агент переключается на PostgreSQL MCP-сервер. Первым делом он изучает схему — не предполагает названия столбцов заранее:
list_tables() → orders, line_items, products, customers ... describe_table({ table: "orders" }) → id, customer_email, status, total, created_at ...
Затем строит и выполняет запросы для верификации:
read_query({ sql: "SELECT * FROM orders WHERE id = 10472" }) read_query({ sql: "SELECT * FROM line_items WHERE order_id = 10472" }) read_query({ sql: "SELECT name, stock FROM products WHERE name = 'Wireless Charger'" })
Эти запросы вы не писали. Агент составил их, изучив схемы таблиц через list_tables и describe_table, а затем построил SQL на лету. Если у вас столбец называется qty вместо quantity или product_title вместо name — агент адаптируется, потому что сначала прочитал схему.
Затем агент возвращает что-то вроде:
Full-Stack Verification — Order #10472 ─────────────────────────────────────── ✓ строка orders существует customer_email: ada@test.dev status: confirmed total: $34.99 ✓ строка line_items найдена product_name: Wireless Charger quantity: 1 unit_price: $34.99 ✓ products.stock уменьшен было: 48 → стало: 47 3/3 ассертов прошли
Три проверки, ноль строк SQL с вашей стороны.
Полный промпт
На практике весь сценарий можно задать одной инструкцией. Агент сначала выполнит браузерную часть, извлечёт order ID, затем автоматически переключится в базу данных:
## Full-Stack Checkout Verification Используй Playwright MCP-сервер: 1. Перейди на localhost:3000/products 2. Добавь «Wireless Charger» в корзину 3. Оформи заказ как «Ada Lovelace» (ada@test.dev), оплата — Credit Card 4. Захвати order ID со страницы подтверждения Затем переключись на Postgres MCP-сервер и проверь: - Строка заказа существует с правильным email - Запись line_item для «Wireless Charger» (qty 1) присутствует - Инвентарный остаток товара уменьшен на 1 Выведи результат pass/fail для каждого ассерта.
Это весь тест. Один промпт. Два MCP-сервера. Полное покрытие стека.
Как сделать это production-ready
Несколько паттернов, которые помогают при выходе за пределы демо.
Всегда используйте read-only учётные данные. Инструмент read_query должен быть единственным активным инструментом базы данных. Это защищает от случайной мутации данных во время верификации.
Добавьте тайминг-гарды для асинхронных записей. Если приложение использует очереди, event sourcing или eventual consistency, строка может ещё не существовать в момент запроса агента. Напишите: «Жди появления строки заказа до 5 секунд, опрашивая каждые 500 мс». Агент будет повторять запрос до разрешения или таймаута.
Делайте снапшоты до и после. Для регрессионного тестирования попросите агента запросить нужные таблицы до UI-действия и после, затем сравнить результаты. Это ловит непредвиденные побочные эффекты: дублирующие записи, пропущенные audit-столбцы, нарушения foreign key, которые были проглочены.
Расширяйте за пределы SQL. Тот же двухфазный паттерн работает с любым backend MCP-сервером. Redis MCP — для проверки инвалидации кеша. Elasticsearch MCP — для подтверждения индексации документа. S3 MCP — для проверки, что файл действительно загрузился. Добавляйте столько слоёв верификации, сколько нужно.
Почему это важно
Традиционный подход к full-stack верификации тестов требует поддержки параллельной тестовой инфраструктуры: драйверы баз данных, пулы соединений, конфигурации ORM, SQL-строки, которые ломаются при переименовании столбца. Это не тяжёлая работа, но постоянная — и она существует в странном нейтральной полосе между тестовым набором и кодом приложения.
MCP-подход сворачивает всё это в вызовы инструментов, которые агент обнаруживает и составляет в рантайме. Вы описываете, что проверять — агент разбирается, как. Когда схема меняется, вы не обновляете тестовые ассерты: агент заново обнаруживает схему при следующем запуске.
Это не магия. Это просто перенос адаптационного слоя из вашего кода в контекст агента. Для задач верификации, где нужно читать, а не писать — этот трейдоф почти всегда оправдан.
Подписывайтесь на наш Telegram-канал. Там мы публикуем полезные подборки от инженеров и делимся инсайтами.
Комментарии (3)

almostyunglean
16.04.2026 06:12без единой строки SQLПод капотом все равно вызывается sql.
Все ещё нет причины доверять такому тесту. Нет никакой гарантии что он не будет лже зеленым.
Поднимать mcp для read-only тестов и гонять их через агент это overhead, а не оправданный tradeoff.
freiman
А сколько такой тест выполняется, интересно? Пока что не вижу плюсов именно для регулярного прогона тестов через ИИ.
Думается мне, что быстрее навайбкодить автотест на Playwright+TS, а потом его гонять без использования ИИ-шки. В случае падения теста из-за изменений на странице можно точно так же навайбкодить фикс.