Перейти к содержанию

Запуск и конфигурация

В этом разделе описано, как MCP‑сервер запускается, как он пишет логи, проверяет аутентификацию и подключается к базе данных.

Точка входа расположена в файле mcp-server/server.py. В начале задаются базовые параметры: логическое имя приложения (APP_NAME), путь MCP‑эндпоинта (APP_PATH, по умолчанию /mcp) и настройки адреса/порта (HOST, PORT). Затем создаётся экземпляр FastMCP, к которому подключается middleware для логирования вызовов инструментов. При запуске файла как скрипта создаётся ASGI‑приложение app = mcp.http_app(path=APP_PATH), и uvicorn стартует сервер на HOST:PORT. В результате MCP‑эндпоинт становится доступен по адресу вида http://<host>:8082/mcp. Этот URL нужно использовать в переменных окружения других сервисов (MCP_SERVER_URL и MCP_LOCAL_URL у бота, MCP_SERVER_URL у SIP Hook).

Условно структура server.py выглядит так (упрощённо, но в соответствии с текущим кодом):

_configure_logging()

mcp = FastMCP(APP_NAME, auth=_configure_auth())
mcp.add_middleware(ToolLoggingMiddleware())

_autodiscover_tools()  # импорт всех модулей из tools/
app = mcp.http_app(path=APP_PATH)

if __name__ == "__main__":
    uvicorn.run(app, host=HOST, port=PORT)

Логирование настраивается функцией _configure_logging(). Она переопределяет базовую конфигурацию loguru, отключает стандартные хендлеры logging и направляет сообщения стандартного логгера через кастомный InterceptHandler в loguru. Формат логов включает дату и время, уровень и текст сообщения. При этом отдельно добавляется фильтр для логгера sse_starlette.sse, чтобы корректно обрабатывать аргументы в байтовом виде. Уровень логирования берётся из переменной окружения LOG_LEVEL, если она не задана — используется значение по умолчанию.

Для аутентификации используется функция _configure_auth(). Если в окружении задан секрет MCP_AUTH_SECRET и алгоритм MCP_AUTH_ALGORITHM (например, HS256), сервер создаёт объект JWTVerifier и включает проверку токенов. Дополнительно можно указать ожидаемые значения iss и aud через MCP_AUTH_ISSUER и MCP_AUTH_AUDIENCE, а также список обязательных scopes (MCP_AUTH_SCOPES), передаваемых в виде строки с разделителями. Если секрет или алгоритм не заданы, MCP‑сервер работает без аутентификации.

JWT‑аутентификация: когда включать

Это место, где приходится сделать выбор:

  • MCP доступен только из приватной сети → обычно проще оставить без JWT. Так меньше точек отказа: не будет ситуации «всё запустилось, но инструменты падают из‑за токена».
  • MCP доступен извне или из нескольких контуров → включайте JWT и требуйте токен от клиентов.

Warning

Частая ловушка: задали MCP_AUTH_SECRET, но забыли MCP_AUTH_ALGORITHM. В этом случае сервер не включит JWT‑проверку (проверьте логи при старте).
Если JWT включили — клиентам нужно передавать MCP_AUTH_TOKEN (Telegram‑боту и SIP Hook), иначе они начнут получать 401/403.

Подключение к базе данных реализовано в модуле prime_lardi/db.py. Здесь из окружения читаются стандартные параметры MYSQL_HOST, MYSQL_PORT, MYSQL_USER, MYSQL_PASSWORD, MYSQL_DATABASE. На их основе строится URL для драйвера mysql+aiomysql, создаётся AsyncEngine SQLAlchemy и фабрика асинхронных сессий SessionLocal. Для удобства работы используется контекстный менеджер session_scope(): он открывает новую сессию, передаёт её в вызывающий код, а затем либо выполняет commit, либо, в случае исключения, делает rollback и пробрасывает ошибку дальше. Базовый класс ORM‑моделей определяется как Base (наследник DeclarativeBase) и используется в файле prime_lardi/models.py.

Ещё одна важная часть server.py — автоматическая регистрация MCP‑инструментов. Вместо того чтобы импортировать каждый инструмент вручную, сервер обходит пакет tools с помощью pkgutil.iter_modules и импортирует все найденные модули. Любая функция, помеченная декоратором @mcp.tool(...) в этих модулях, автоматически становится доступной как MCP‑инструмент. Это означает, что для добавления нового инструмента достаточно создать файл в каталоге mcp-server/tools/, объявить функцию и оформить её как MCP‑tool — остальное сделает механизм автозагрузки.

Интеграции и переменные окружения

Помимо MYSQL_* и параметров аутентификации MCP, MCP‑сервер использует переменные окружения для внешних интеграций:

  • Lardi API
  • LARDI_API — токен авторизации (обязателен для создания заявок).
  • LARDI_BASE_URL — базовый URL Lardi API (обязателен).
  • ONEC_DISPATCH_URL — эндпоинт для отправки сделок в 1С (обязателен для store_transporter_match).
  • ONEC_DISPATCH_AUTH — опциональный заголовок Authorization для 1С (если требуется на стороне 1С).
  • Сервисные вызовы в Telegram/SIP
  • TG_SERVICE_URL — базовый URL Telegram‑сервиса (используется для уведомлений и отправки DOCX; см. prime_lardi/notifications.py и prime_lardi/docx_sender.py).
  • SIP_SERVICE_URL — базовый URL SIP‑сервиса (используется как fallback для уведомлений; см. prime_lardi/notifications.py).

Внутренние HTTP‑контракты (TG/SIP сервисы)

MCP‑сервер сам по себе не «ходит в Telegram» и не «шлёт SMS». Для этого он вызывает внутренние HTTP‑эндпоинты других сервисов:

  • Telegram‑сервис (TG_SERVICE_URL)
  • POST {TG_SERVICE_URL}/cargo-assigned — уведомление клиенту в Telegram Business (JSON с tg_id, request_id, cargo).
  • POST {TG_SERVICE_URL}/cargo-docx — доставка DOCX пользователю (multipart с tg_id, file, опционально caption, request_id).
  • Детали контрактов и примеры: Telegram‑бот → HTTP API.

  • SIP/SMS‑сервис (SIP_SERVICE_URL)

  • POST {SIP_SERVICE_URL}/cargo-assigned — SMS‑уведомление (JSON с phone, request_id, cargo).
  • Детали контрактов и примеры: SIP Hook → Webhook и маршруты.

Note

Эти сервисные эндпоинты рассчитаны на вызовы внутри контура (по приватным адресам/внутреннему DNS). В типовом деплое они не публикуются в интернет.

Warning

Авторизации на уровне приложений по умолчанию нет. Если по ошибке открыть доступ извне, эти маршруты можно будет вызвать без токена — поэтому важно обеспечить сетевые ограничения (private network, allowlist, mTLS, reverse‑proxy auth).

Практически это обычно выглядит так:

  • наружу (для Telegram/OpenAI) открываем только webhook‑маршруты (WEBHOOK_SECRET_PATH у Telegram‑бота и /sip-hook у SIP Hook);
  • служебные эндпоинты (/cargo-assigned, /cargo-docx) оставляем доступными только внутри сети (например, отдельный internal ingress / service / allowlist).

Логирование

Логирование управляется переменными окружения из .env.example:

  • LOG_LEVEL — общий уровень логов (по умолчанию DEBUG).
  • LOG_DOCKET_LEVEL и LOG_SSE_LEVEL — уровни для шумных логгеров зависимостей.
  • LOG_MCP_RESULT_MODE — режим логирования результата инструмента (full/summary/none).
  • LOG_JSON_FILE и параметры LOG_JSON_MAX_* — запись JSONL‑логов в файл и ограничения на вывод больших payload.