$ sudo teach IT

Claude Code читает ваш репозиторий и потому хорошо знает код. Но половина правды о приложении живёт не в коде, а в базе: какие колонки реально есть в таблице orders, какие значения встречаются в поле статуса. Пока базы у агента нет, вопрос о данных превращается в ручной цикл: вы переключаетесь в psql, пишете запрос, копируете вывод в сессию.

Подключённая база убирает этот цикл: вы спрашиваете про схему прямо в Claude Code, агент сам вызывает инструмент MCP-сервера и отвечает.

Что уже умеем / что добавим

В уроке 9.1 вы разобрали архитектуру MCP: Claude Code — клиент, внешние инструменты — серверы, транспорты бывают stdio и HTTP. В уроке 9.2 речь шла о доверии: любой сервер получает доступ к вашим данным.

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

Что вы узнаете в рамках статьи

  • Как подключить PostgreSQL через DBHub и что означает каждая часть команды
  • Почему пользователь базы должен быть только для чтения
  • Как убрать пароль из конфигурации через переменные окружения в .mcp.json
  • Когда Claude Code запускает MCP-серверы и как управлять таймаутом старта
  • Как ограничивать объём вывода и чинить неподключившийся сервер

Ключевые термины

  • DSN (строка подключения) — строка вида postgresql://user:pass@host:port/db: к какой базе и под каким пользователем подключаться.
  • DBHub — MCP-сервер из пакета @bytebase/dbhub, соединяющий Claude с реляционной базой по строке подключения из аргумента --dsn.
  • Пользователь только для чтения — учётная запись базы без прав на изменение данных. Документация предписывает использовать в DSN именно её.
  • Подстановка переменных окружения — механизм ${VAR} и ${VAR:-default} в .mcp.json, позволяющий не хранить секреты в конфигурации.
  • MCP_TIMEOUT — переменная, задающая таймаут подключения сервера при старте в миллисекундах.

Подключаем PostgreSQL через DBHub

Команда подключения выглядит так:

claude mcp add --transport stdio db -- npx -y @bytebase/dbhub \
  --dsn "postgresql://readonly:pass@prod.db.com:5432/analytics"

Разберём её по частям.

  • --transport stdio — сервер запускается как локальный процесс, а не по URL. Для базы это естественный выбор: доступ к вашему PostgreSQL есть у вашей машины, а не у стороннего сервиса. Формально stdio — транспорт по умолчанию, но явное указание делает команду читаемой.
  • db — имя сервера. Оно попадёт в имена инструментов вида mcp__db__<инструмент> и видно в /mcp.
  • -- — разделитель между опциями самого Claude Code (--transport, --env, --scope) и командой запуска сервера. Всё после него передаётся серверу без изменений. Пропущенный - — частая причина ошибки: без него Claude Code разбирает npx и -dsn как свои опции и не понимает их.
  • --dsn "postgresql://..." — это уже аргумент DBHub, а не Claude Code, поэтому он обязан стоять после --.

И главное — пользователь readonly. Документация формулирует это как прямое требование: используйте пользователя базы только для чтения, чтобы запросы Claude не могли изменить данные. Это продолжение урока 9.2: вы ограничиваете права на стороне сервера, а не полагаетесь на то, что агент сам не станет писать в базу. Агент действует по вашей формулировке, а формулировки бывают неточными — и единственная надёжная защита от DELETE в проде это отсутствие прав на DELETE.

Секрет в строке подключения

У команды выше есть проблема: пароль попадает в конфигурацию и остаётся там. Если сервер добавлен в область project, .mcp.json уйдёт в репозиторий вместе с паролем от боевой базы. Это та же ошибка, что в уроке 1.1 с API-ключом: секрет в коммите остаётся в истории git даже после удаления из файла.

Решение — подстановка переменных окружения в полях command, args, env, url и headers, в двух формах: ${VAR} и ${VAR:-default}.

{
  "mcpServers": {
    "db": {
      "type": "stdio",
      "command": "npx",
      "args": [
        "-y",
        "@bytebase/dbhub",
        "--dsn",
        "postgresql://readonly:${DB_PASSWORD}@${DB_HOST:-localhost}:5432/analytics"
      ]
    }
  }
}

Теперь в репозиторий уходит структура подключения, а пароль каждый держит у себя в окружении. Хост получил умолчание localhost: без заданной переменной вы работаете с локальной базой.

Важный нюанс. Если переменная не задана и умолчания у неё нет, конфигурация всё равно загрузится — жёсткой ошибки не будет. В claude mcp list появится предупреждение, а вместо значения подставится буквальный текст ${DB_PASSWORD}. Сервер попробует подключиться с этой строкой вместо пароля и не сможет. Симптом похож на проблему с базой, поэтому при отказе первым делом читайте предупреждения claude mcp list.

Проверка и первые запросы

После добавления сервера запустите сессию и выполните /mcp. Вы увидите список серверов со статусами: db должен быть показан как connected, рядом — количество его инструментов.

Дальше спрашивайте обычным языком:

What's our total revenue this month?
Show me the schema for the orders table
Find customers who haven't made a purchase in 90 days

В выводе Claude вызовы инструментов помечены именем сервера — видно, что обращение идёт именно к db, а не придумано моделью. Если ответ удивил, по этой пометке понятно, был ли запрос к базе.

Когда серверы стартуют

Вопрос, вызывающий больше всего путаницы: кто и когда запускает процесс сервера. Ответ — Claude Code, при старте сессии, автоматически. Руками поднимать npx @bytebase/dbhub не нужно, как и держать отдельное окно терминала.

На подключение отводится 30 секунд. Если мало, таймаут поднимается переменной MCP_TIMEOUT в миллисекундах:

MCP_TIMEOUT=60000 claude

Отсюда классический сценарий первого запуска. Первый старт stdio-сервера бывает медленным: npx ещё скачивает пакет. Поэтому первая же проверка claude mcp list может показать Failed to connect при верной конфигурации. Правильная реакция — подождать и повторить проверку, а не переписывать команду. Если и после повторов сервер не укладывается в лимит, поднимайте MCP_TIMEOUT.

Если запросу нужны инструменты сервера, который ещё подключается в фоне, Claude дождётся его: при включённом tool search ожидание идёт внутри вызова ToolSearch, без него — через инструмент WaitForMcpServers.

Для удалённых HTTP- и SSE-серверов есть кэш обнаружения, по умолчанию выключенный и включаемый переменной MCP_DISCOVERY_CACHE=1. С ним знакомый сервер не подключается на старте, а ждёт первого вызова инструмента; в /mcp у него статус вида cached 2h ago · connects on first use · 5 tools.

И последнее: вызов MCP-инструмента дольше двух минут переводится в фоновую задачу, чтобы не блокировать сессию.

Объём вывода и контекст

С базой вы почти сразу упрётесь в объём: дамп схемы — это тысячи токенов, а выборка без LIMIT может быть какой угодно.

Claude Code предупреждает, когда вывод MCP-инструмента превышает 10 000 токенов. Максимум по умолчанию — 25 000; поднимается переменной окружения:

export MAX_MCP_OUTPUT_TOKENS=50000

Поднимать порог стоит осознанно: всё, что вернул инструмент, занимает место в контекстном окне. Часто дешевле спросить узко («схема одной таблицы», а не «схема базы»), чем расширять лимит.

Со стороны сервера есть встречный механизм: автор может поднять для отдельного инструмента порог сохранения результата на диск через _meta["anthropic/maxResultSizeChars"] (потолок — 500 000 символов).

{
  "name": "get_schema",
  "description": "Returns the full database schema",
  "_meta": { "anthropic/maxResultSizeChars": 200000 }
}

Частые ошибки

  • Пропущенный - в команде добавления. Без разделителя Claude Code разбирает npx и -dsn как свои опции. Всё, что относится к запуску сервера, стоит после -.
  • Обычный пользователь базы вместо readonly. С полными правами неточно сформулированная задача может закончиться изменением данных в проде.
  • Пароль прямо в .mcp.json. Файл коммитится, а секрет в истории git правкой файла не удаляется. Выносите DSN в переменную окружения через ${VAR}.
  • Переписывать конфигурацию после первого Failed to connect. Первый старт медленный, пока npx качает пакет. Сначала подождите и повторите проверку.

Наиболее частые вопросы

  • Нужно ли запускать сервер базы вручную перед сессией? — Нет, Claude Code подключает серверы сам при старте сессии.
  • Я поправил .mcp.json, но ничего не изменилось. — Файл читается при старте сессии, перезапустите её.
  • Сервер подключился, но инструментов нет. — Обычно не задана обязательная переменная окружения. Передайте её через -env KEY=value или полем env в записи сервера.
  • Как понять, дело в конфигурации или в сервере? — Выполните настроенную команду прямо в терминале. Если она запускается и ждёт ввода, сервер жив и дело в конфигурации; если падает, сообщение назовёт, чего не хватает.
  • Можно ли без readonly, если я обещаю не просить писать в базу? — Не стоит: запросы формулирует модель, а права на стороне базы от формулировок не зависят.

Итоги

Вы подключили первый по-настоящему рабочий MCP-сервер и теперь можете спрашивать про схему и данные, не выходя из сессии. Попутно разобрали то, что делает подключение предсказуемым: разделитель --, readonly-пользователь как страховка на стороне базы, DSN через переменную окружения, автоматический старт с таймаутом в 30 секунд и спокойную реакцию на первый Failed to connect.

Этого хватит, чтобы подключать и чинить большинство stdio-серверов, а не только базу: логика везде одинаковая. Дальше посмотрим, как несколько серверов уживаются друг с другом и как не дать им съесть контекстное окно.

На следующий урок