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


  1. freiman
    16.04.2026 06:12

    А сколько такой тест выполняется, интересно? Пока что не вижу плюсов именно для регулярного прогона тестов через ИИ.
    Думается мне, что быстрее навайбкодить автотест на Playwright+TS, а потом его гонять без использования ИИ-шки. В случае падения теста из-за изменений на странице можно точно так же навайбкодить фикс.


  1. almostyunglean
    16.04.2026 06:12

    без единой строки SQL

    Под капотом все равно вызывается sql.

    Все ещё нет причины доверять такому тесту. Нет никакой гарантии что он не будет лже зеленым.

    Поднимать mcp для read-only тестов и гонять их через агент это overhead, а не оправданный tradeoff.


  1. werewolfvit
    16.04.2026 06:12

    Надежность таких тестов оставляет желать лучшего