Запуск и конфигурация
В этом разделе описано, как 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 (обязателен).- 1С
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.