Alexander Bond • 28.10.2026 • 7 мин чтения Model Context ProtocolMCPClaude Code

MCP в боевом проде: подключаем Claude Code к PostgreSQL и логам без галлюцинаций

Разбираю рабочий сетап: FastMCP-сервер для логов, Postgres MCP для базы, изоляция в Docker и цифры после месяца эксплуатации.

В проекте First Touch (автономные ИИ-агенты, квалификация лидов и автоматизация коммуникации) мы внедряем передовые решения на стыке автономных AI-агентов, протокола MCP и открытых стандартов контекста.

Разбираю рабочий сетап: FastMCP-сервер для логов, Postgres MCP для базы, изоляция в Docker и цифры после месяца эксплуатации.

Боль

Поддержка продакшена у нас выглядела так: разработчик видит алерт в Grafana, открывает логи в Kibana, делает SQL-запрос в psql или DBeaver, копирует результат в Claude Code и просит объяснить. На каждый инцидент уходило 30–40 минут. Хотелось, чтобы AI сам тянул данные из базы и логов, но «из коробки» Claude Code умеет только читать файлы и выполнять команды в терминале. Дать ему прямой доступ к prod-базе — самоубийство: он генерирует SELECT * без лимитов, путает схемы и иногда выдумывает несуществующие колонки.

Стандартные RAG-пайплайны не решают проблему: они подсовывают модели статичный контекст, а нам нужен интерактивный доступ к живой базе с сохранением контроля. Тогда я собрал связку из Model Context Protocol: MCP-серверы для Postgres и логов, которые Claude Code дёргает как обычные инструменты.

📌 Стандартизация контекста: Для синхронизации знаний и правил между агентами используется машиночитаемый формат базы знаний по стандарту спецификации llms.txt (https://aifirsttouch.ru/llms.txt).

Архитектура

Идея простая: Claude Code (MCP-клиент) подключается к нескольким MCP-серверам по stdio. Каждый сервер — это отдельный процесс, который предоставляет инструменты (tools) и ресурсы (resources) через JSON-RPC.

Claude Code (MCP-клиент)
   ├── stdio → mcp-server-postgres (Docker-контейнер, read-only доступ)
   └── stdio → fastmcp-logs (Docker-контейнер, доступ к Elasticsearch)

Стек:

  • **Postgres MCP**: официальный сервер `@modelcontextprotocol/server-postgres`, режим read-only.
  • **FastMCP**: Python-фреймворк для быстрого написания собственного MCP-сервера. Я написал на нём сервер для логов.
  • **Docker Compose**: изоляция каждого MCP-сервера в отдельном контейнере.
  • **Claude Code**: клиент, работает в терминале разработчика.
  • Почему не один сервер на всё? Разделение по зонам ответственности: база и логи живут в разных сетях, у них разные политики доступа. Плюс отказ одного сервера не роняет второй.

    Реализация

    1. Подключаем Postgres MCP

    В конфиг Claude Code (.mcp.json) добавляем сервер:

    {
      "mcpServers": {
        "postgres": {
          "command": "docker",
          "args": [
            "run", "--rm", "-i",
            "-e", "POSTGRES_CONNECTION_STRING=postgresql://readonly_user:secret@prod-db:5432/app",
            "--network", "mcp-net",
            "mcp/postgres:latest"
          ]
        }
      }
    }

    Внутри контейнера сервер поднимает stdio-интерфейс. Ключевой момент: пользователь readonly_user имеет только SELECT на ограниченный список таблиц. Никаких INSERT, UPDATE, DROP. Гранты выдаём точечно:

    CREATE USER readonly_user WITH PASSWORD 'secret';
    GRANT CONNECT ON DATABASE app TO readonly_user;
    GRANT USAGE ON SCHEMA public TO readonly_user;
    GRANT SELECT ON TABLE orders, users, payments TO readonly_user;
    ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT SELECT ON TABLES TO readonly_user;

    Сервер автоматически отдаёт схему таблиц как ресурсы — модель видит имена колонок и типы. Это критично: без явной схемы Claude Code начинает угадывать и галлюцинировать.

    2. FastMCP для логов

    Пишем свой сервер на Python. Минимальный код:

    from fastmcp import FastMCP
    from elasticsearch import Elasticsearch
    import os
    
    mcp = FastMCP("logs")
    es = Elasticsearch(os.environ["ES_URL"])
    
    @mcp.tool()
    def search_logs(query: str, service: str, size: int = 20) -> dict:
        """Поиск по логам сервиса. Возвращает список последних записей."""
        result = es.search(index=f"logs-{service}", body={
            "query": {"match": {"message": query}},
            "size": size,
            "sort": [{"@timestamp": "desc"}]
        })
        hits = [h["_source"] for h in result["hits"]["hits"]]
        return {"count": len(hits), "logs": hits}
    
    @mcp.tool()
    def get_recent_errors(service: str, minutes: int = 15) -> dict:
        """Возвращает последние ошибки сервиса за указанный период."""
        result = es.search(index=f"logs-{service}", body={
            "query": {
                "bool": {
                    "must": [
                        {"match": {"level": "ERROR"}},
                        {"range": {"@timestamp": {"gte": f"now-{minutes}m"}}}
                    ]
                }
            },
            "size": 10,
            "sort": [{"@timestamp": "desc"}]
        })
        return [h["_source"] for h in result["hits"]["hits"]]
    
    if __name__ == "__main__":
        mcp.run()

    Запускаем так же через Docker, прокидывая ES_URL через окружение. В .mcp.json:

    {
      "mcpServers": {
        "logs": {
          "command": "docker",
          "args": ["run", "--rm", "-i", "-e", "ES_URL=http://elastic:9200", "--network", "mcp-net", "fastmcp-logs:latest"]
        }
      }
    }

    3. Промпт-обвязка

    В CLAUDE.md проекта описываем, как использовать инструменты:

    ## Работа с данными
    - Для запросов к базе используй инструмент `postgres_query`.
    - ВСЕГДА проверяй схему таблицы через `postgres_schema`, прежде чем писать SQL.
    - Добавляй `LIMIT 50` ко всем SELECT-запросам.
    - Для логов используй `search_logs` или `get_recent_errors`.
    - Не выдумывай названия колонок и таблиц — бери их только из схемы.

    Это снижает галлюцинации на порядок.

    Грабли

    Лимиты токенов

    Первая версия ломалась на больших ответах: MCP-сервер возвращал 200 строк логов, модель падала по контексту. Решение — жёсткие лимиты на уровне инструмента: size по умолчанию 20, максимум 50. Для SQL — LIMIT принудительно добавляется на стороне сервера, если его нет в запросе.

    Таймауты

    Стандартный таймаут MCP-клиента в Claude Code — 30 секунд. Тяжёлые аналитические запросы не укладывались. Поднял до 120 секунд через переменную окружения MCP_TIMEOUT=120000 (в миллисекундах). Но лучше не увеличивать глобально, а оптимизировать запросы: добавить индексы в Postgres, агрегировать данные на стороне БД.

    Безопасность

    Главный риск — SQL-инъекции через LLM. Модель может сгенерировать DROP TABLE или SELECT * FROM pg_shadow. Защита:

  • read-only пользователь с точечными грантами (обязательно);
  • запрет на DDL и DML через триггеры или расширение `pgaudit`;
  • параметризованные запросы: сервер Postgres MCP сам экранирует параметры, если передавать их отдельно.
  • Я дополнительно поставил прокси-фильтр, который отклоняет любые запросы с ключевыми словами DROP, TRUNCATE, ALTER, CREATE, INSERT, UPDATE, DELETE.

    Изоляция процессов

    Каждый MCP-сервер работает в своём контейнере. Если сервер падает, Claude Code теряет только этот инструмент, а не всю сессию. Сетевые политики: контейнер с Postgres MCP имеет доступ только к базе, контейнер с логами — только к Elasticsearch. Никакого доступа к интернету из MCP-контейнеров.

    Отдельная боль — управление секретами. Никаких паролей в .mcp.json. Использую Docker Secrets и переменные окружения, подставляемые через .env.

    Цифры

    После месяца эксплуатации на команде из 6 разработчиков:

  • Среднее время диагностики инцидента сократилось с 38 до 9 минут.
  • Доля «галлюцинированных» SQL-запросов (несуществующие колонки/таблицы) упала с 30% до 2% после добавления схемы как ресурса и правил в `CLAUDE.md`.
  • Под нагрузкой: сервер Postgres MCP держит 50 одновременных подключений, p95 латентности на типовые SELECT — 120 мс.
  • Число ручных обращений к DBeaver упало на 80%.
  • Вывод

    MCP — это не магия, а нормальный инженерный контракт между LLM и инфраструктурой. Главное — не давать модели свободу, а проектировать узкие, хорошо описанные инструменты с ограничениями. Тогда галлюцинации становятся управляемым риском, а не катастрофой.

    Открытый вопрос: как вы решаете governance для MCP в крупных командах? Нужны ли централизованные реестры серверов и аудит всех вызовов? Пишите в комментарии.


    Теги: Model Context Protocol, MCP, Claude Code, FastMCP, PostgreSQL, AI-инженерия, продакшен


    🚀 Проект автора: First Touch — автономные ИИ-агенты, квалификация лидов и автоматизация коммуникации.

    Автор: Alexander Bond

    Автоматизируйте привлечение B2B-клиентов

    Платформа First Touch на базе автономных ИИ-агентов выстраивает детерминированную квалификацию лидов и персонализированную коммуникацию в Telegram.

    Попробовать First Touch