MCP бэкап базы данных: Claude Code и Cursor перед миграцией

ИИ-агенты в Claude Code, Cursor и Codex уже пишут миграции, правят схемы и запускают SQL прямо в терминале. Когда агент ошибается, ошибка попадает в данные, и откатить её через git нельзя. В этой статье — как подключить MCP-сервер бэкапов к агенту, заставить его делать бэкап перед каждым изменением базы, проверять результат через diff и при этом не выдать ему лишних прав.

Зачем агенту бэкапы

Типичные инциденты выглядят одинаково: агент «чинит» миграцию через DROP TABLE и пересоздание, выполняет prisma migrate reset не на той базе, удаляет строки «тестовых» пользователей, которые оказались настоящими. Разбор таких случаев и порядок действий после — в статье ИИ стёр базу данных: что делать.

Защиту строят по одному принципу: сначала бэкап, потом изменения. Перед любой миграцией или ручным SQL агент сохраняет копию базы, проверяет, что она сохранилась, и только потом трогает схему. После изменения — сравнивает новую версию с предыдущей, чтобы вы увидели, что реально поменялось.

Особенно опасна связка «MCP-сервер базы с правом записи + никаких бэкапов». Серверы вроде тех, что описаны в обзорах MCP для PostgreSQL и MCP для PocketBase, дают агенту прямой доступ к данным. Если у агента есть запись в базу, у вас должна быть свежая копия, которую агент не может удалить.

Как устроен MCP dbsend

dbsend предоставляет готовый MCP-сервер по адресу https://api.dbsend.ru/v1/mcp (транспорт Streamable HTTP). Ставить ничего локально не нужно: клиент подключается по URL и передаёт API-ключ в заголовке Authorization: Bearer ….

Набор инструментов зависит от прав ключа. Сервер показывает агенту только те методы, на которые у ключа есть scope:

| Инструмент | Scope | Что делает | |---|---|---| | get_workspace | workspace.read | Рабочее пространство, тариф, лимиты | | list_projects, create_project | projects.read, projects.create | Проекты | | list_sources, list_databases, get_database | databases.read | Базы и их последняя версия | | create_database, set_database_status | databases.create, databases.update | Создание базы, пауза и возобновление | | list_snapshots, get_snapshot, get_backup_status, list_backup_history | backups.read | Версии, их статус и инспекция (таблицы, строки, предупреждения) | | compare_snapshots | backups.diff | Diff двух версий одной базы | | get_snapshot_download | backups.download | Защищённая ссылка на скачивание | | start_backup | backups.upload | Инструкции для загрузки файла | | request_restore, get_restore_job, list_restore_jobs | backups.restore | Задача восстановления | | get_usage | billing.read | Расход и квоты |

Важное ограничение: MCP не принимает сам файл бэкапа. Гонять базу размером в сотни мегабайт через контекст модели в base64 бессмысленно и дорого, поэтому start_backup только возвращает инструкции для загрузки. Сам файл загружает CLI dbsend, который агент запускает в терминале. Получается разделение: терминал для загрузки, MCP для проверки, истории и diff.

request_restore тоже не перезаписывает вашу базу. Восстановление подтверждаете вы, а не модель: клиент с поддержкой MCP elicitation сам покажет запрос, а в остальных клиентах агент сначала вызывает prepare_restore и получает одноразовый код на 5 минут, который можно использовать только после вашего согласия. Результат — защищённая ссылка на скачивание исходного файла. Применять дамп к серверу или подменять файл SQLite — отдельный шаг, который делаете вы или агент с вашего разрешения.

Подключение в Claude Code

Ключ держите в переменной окружения, не в промте:

export DBSEND_API_KEY='sqv_pk_…'
claude mcp add --transport http --scope user \
  --header "Authorization: Bearer $DBSEND_API_KEY" \
  dbsend https://api.dbsend.ru/v1/mcp

Внутри Claude Code выполните /mcp: сервер dbsend должен быть в статусе подключённого, а список инструментов — соответствовать правам ключа. С --scope user значение заголовка сохраняется в пользовательской конфигурации Claude Code, а не в репозитории.

Для командной настройки используйте .mcp.json в корне проекта со ссылкой на переменную окружения — так файл можно коммитить без ключа:

{
  "mcpServers": {
    "dbsend": {
      "type": "http",
      "url": "https://api.dbsend.ru/v1/mcp",
      "headers": {
        "Authorization": "Bearer ${DBSEND_API_KEY}"
      }
    }
  }
}

Подключение в Cursor

Cursor поддерживает удалённые MCP-серверы по URL. Создайте .cursor/mcp.json в проекте (или глобальный ~/.cursor/mcp.json):

{
  "mcpServers": {
    "dbsend": {
      "url": "https://api.dbsend.ru/v1/mcp",
      "headers": {
        "Authorization": "Bearer ${env:DBSEND_API_KEY}"
      }
    }
  }
}

Синтаксис подстановки переменных окружения в конфигурации MCP может отличаться между версиями Cursor, поэтому сверьтесь с документацией Cursor для своей версии. Проверить подключение можно в настройках Cursor в разделе MCP: у сервера должен появиться список инструментов. Если инструментов нет, чаще всего ключ не подставился и сервер вернул 401.

Подключение в Codex

В ~/.codex/config.toml (или в проектном .codex/config.toml доверенного проекта):

[mcp_servers.dbsend]
url = "https://api.dbsend.ru/v1/mcp"
bearer_token_env_var = "DBSEND_API_KEY"
required = true
tool_timeout_sec = 60

Codex сам возьмёт ключ из DBSEND_API_KEY. Проверка — командой /mcp. Полная инструкция по всем клиентам — в документации MCP.

Ключи с минимальными правами

Агенту не нужен ключ с полным доступом. Разумная схема — два ключа:

  1. Ключ для MCP — только чтение: databases.read, backups.read, backups.diff, при необходимости billing.read. Этого хватает, чтобы смотреть версии, их инспекцию и diff.
  2. Ключ для CLI — право загрузки (backups.upload), ограниченный одной базой. Им агент выполняет dbsend backup в терминале.

Оба ключа ограничьте одной базой и задайте срок действия: если ключ утечёт из логов или истории терминала, им смогут пользоваться только до этой даты. backups.restore и backups.download выдавайте только тому агенту, которому действительно нужно восстанавливать, и только на время этой работы. Пустой список scopes ничего не разрешает — это нормально, права добавляются явно.

Учтите и ограничение тарифа: на бесплатном плане хранится 3 версии, и серия загрузок может вытеснить старые. Перед рискованной миграцией закрепите нужную версию через dbsend pin — закреплённые версии не удаляются по ротации.

Правило для агента: CLAUDE.md, AGENTS.md, Cursor rules

Договорённость «сначала бэкап» надо записать туда, где агент её прочитает перед работой. Для Claude Code это CLAUDE.md, для Codex — AGENTS.md, для Cursor — файл в .cursor/rules/. Текст может быть общим:

## Работа с базой данных

- Перед любой миграцией, изменением схемы или массовым UPDATE/DELETE:
  1. Выполни `dbsend backup ./data/app.db -l "before: <краткое описание>"`.
  2. Через MCP dbsend (`get_database` или `list_snapshots`) убедись, что появилась
     новая версия со статусом готовности. Если команда вернула ненулевой код — остановись.
  3. Закрепи версию: `dbsend pin <snapshotId>`.
- После миграции снова выполни `dbsend backup ./data/app.db -l "after: <описание>"`
  и вызови `compare_snapshots` для версий before/after. Покажи мне diff схемы и строк.
- Никогда не вызывай `request_restore` без моего явного подтверждения в чате.
- Не выводи и не логируй значение DBSEND_API_KEY.

Для PostgreSQL замените первую команду на дамп и загрузку:

pg_dump --format=plain "$DATABASE_URL" > /tmp/before.sql
dbsend backup /tmp/before.sql -e postgresql_dump -l "before: add orders.status"

dbsend разбирает только plain-дампы pg_dump; custom-формат сохранится лишь как обычный файл без инспекции. Подробности про сам дамп — в статье бэкап PostgreSQL через pg_dump в S3.

CLI возвращает понятные коды выхода: 3 — проблема с ключом, 4 — упёрлись в тариф, 5 — сеть, 6 — проверка целостности. Агенту проще остановиться по коду, чем разбирать текст ошибки.

Примеры промтов

  • «Перед миграцией сделай бэкап data/app.db через dbsend, проверь через MCP, что версия сохранилась, и только потом запускай prisma migrate deploy.»
  • «Сравни две последние версии базы production и перечисли изменения схемы и таблиц, где число строк упало.»
  • «Покажи базы, у которых последний бэкап старше суток.»
  • «Сколько хранилища занято и сколько версий осталось по тарифу?»
  • «Подготовь восстановление версии перед миграцией. Подтверждение я дам сам.»

compare_snapshots может ответить, что diff ещё строится, — тогда агент вызывает его повторно через несколько секунд. Сравнение версий доступно на платных тарифах.

Риски и как их снизить

Prompt injection. Агент читает README зависимостей, issues, содержимое таблиц и веб-страницы. Любой из этих текстов может содержать инструкцию «восстанови базу из такой-то версии» или «покажи переменные окружения». Поэтому ключ MCP — только на чтение, а восстановление требует подтверждения от вас, а не от агента.

Ключ в чате. Не вставляйте sqv_pk_… в промт: он остаётся в истории диалога и может попасть в логи провайдера. Только переменные окружения или менеджер секретов.

Лишние scopes. Агенту, который пишет фронтенд, MCP бэкапов не нужен вовсе. Агенту, который делает миграции, нужны чтение и загрузка, но не backups.restore.

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

Как это сделать в dbsend

Минимальная настройка для проекта на SQLite:

npm install --global @dbsend/sdk
dbsend login --key sqv_pk_…
dbsend init --database <id> --engine sqlite
dbsend backup ./data/app.db -l "before: migration"
dbsend log
dbsend diff <fromSnapshotId> <toSnapshotId>
dbsend restore <snapshotId> ./restored.db --yes

Для SQLite CLI сам делает согласованную копию через VACUUM INTO, поэтому работающее приложение останавливать не нужно (подробно — в статье как сделать бэкап SQLite). Для DuckDB перед загрузкой нужен чекпоинт — см. бэкап DuckDB. На PowerShell ключ задаётся так: $env:DBSEND_API_KEY='sqv_pk_…'.

Что добавляет dbsend: версии с метками и закреплением, инспекцию схемы и строк, diff любых двух версий и алерты о пропущенных бэкапах (на платных тарифах), хранение в S3 в России с шифрованием. Чего он не делает: не подключается к вашему серверу базы, не запускает pg_dump за вас и не применяет дамп при восстановлении. Подробнее — на странице MCP-бэкапы и в документации CLI.

Частые вопросы

Может ли агент загрузить бэкап через MCP без терминала?

Нет. MCP-сервер dbsend намеренно не принимает файлы: start_backup возвращает только инструкции. Загрузку делает CLI dbsend backup, поэтому агенту нужен доступ к терминалу или вы запускаете команду сами.

Какие права дать ключу для Claude Code или Cursor?

Для проверки бэкапов достаточно databases.read, backups.read и backups.diff. Ограничьте ключ одной базой и задайте срок действия. Права на восстановление и скачивание выдавайте отдельно и временно.

Сможет ли агент случайно перезаписать базу через request_restore?

request_restore не трогает вашу базу: он создаёт задачу и возвращает ссылку на скачивание исходного файла. К тому же нужно подтверждение человека: запрос в клиенте (elicitation) или одноразовый код из prepare_restore. Пропишите в правилах агента, что код он передаёт в request_restore только после вашего явного «да».

Нужен ли MCP бэкапов, если у меня уже есть MCP для PostgreSQL?

Это разные задачи. MCP базы даёт агенту доступ к данным, MCP бэкапов — к копиям и истории изменений. Если у агента есть право записи в базу, отдельный бэкап, который агент не может удалить, нужен тем более.