Ваш тест на оформление заказа нажимает «Оформить заказ» и видит зелёный тост. Хорошо. Но вот чего он не проверяет: реально ли записалась строка? Правильно ли записались позиции заказа? Уменьшился ли инвентарь? 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-канал. Там мы публикуем полезные подборки от инженеров и делимся инсайтами.
Автор: FaryaRos


