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-серверов, а не только базу: логика везде одинаковая. Дальше посмотрим, как несколько серверов уживаются друг с другом и как не дать им съесть контекстное окно.