Логирование
Машинный перевод
Эта страница переведена с английской документации автоматически, и основной версией остаётся английская страница. Если что-то читается неправильно, на странице Переводы объясняется, как об этом сообщить.
Пишите в лог из инструмента так же, как из любой другой функции Python: средствами стандартной библиотеки.
В MCP есть возможность логирования на уровне протокола: сервер мог отправлять свои сообщения лога клиенту в виде уведомлений через методы объекта Context. Ревизия спецификации 2026-07-28 объявляет эту возможность устаревшей и ничем её не заменяет, поэтому в этой документации она не описывается. Полный список того, что устарело и что делать взамен, — на странице Устаревшие возможности.
Взамен делайте то же, что в любой другой программе на Python: используйте стандартную библиотеку.
Инструмент, который пишет в лог
import logging
from mcp.server import MCPServer
logger = logging.getLogger(__name__)
mcp = MCPServer("Bookshop")
@mcp.tool()
def search_books(query: str) -> str:
"""Search the catalog by title or author."""
logger.info("Searching for %r", query)
return f"Found 3 books matching {query!r}."
logging.getLogger(__name__)возвращает логгер, названный по имени модуля. Создайте его один раз, в начале файла.- Внутри инструмента вызывайте
logger.info(...), как в любой другой функции. Ничего не нужно внедрять, ничего не нужно ждать черезawait, ничего специфичного для MCP.
Check
Вызовите инструмент и посмотрите на результат целиком:
result.content # [TextContent(text="Found 3 books matching 'dune'.")]
result.structured_content # {'result': "Found 3 books matching 'dune'."}
Строки лога в нём нет нигде. Логи — для вас, того, кто эксплуатирует сервер. Модель
их никогда не видит. Если модель должна что-то прочитать, верните это через return.
Куда попадает вывод
Для сервера на stdio этот вопрос важнее обычного. Хост запустил ваш сервер как подпроцесс и читает MCP-сообщения из его stdout. Стандартный поток ошибок — ваш.
Стандартная библиотека уже поступает правильно: по умолчанию вывод логов идёт в sys.stderr. Строки из logger.info(...) попадают в терминал (или туда, куда хост собирает stderr подпроцесса), а поток протокола остаётся чистым.
Tip
Не используйте print() в stdio-сервере. print пишет в stdout, а stdout принадлежит протоколу.
Пока сервер работает, SDK перенаправляет в stderr то, что действительно сброшено из буфера stdout,
так что испортить передаваемые данные это не может. Но в процессе с блочной буферизацией вывод
print() обычно лежит несброшенным в буфере sys.stdout, пока интерпретатор не опустошит его
при выходе — прямо в поток протокола. И даже когда строка перенаправлена, она попадает в вывод
логов как есть: без уровня, без имени логгера и без возможности её отфильтровать.
logger.debug("got here") — те же усилия на одну строку, и попадает она куда нужно.
Уровень
Вызывать logging.basicConfig() самостоятельно не нужно. Конструктор MCPServer уже сделал это: с обработчиком, направленным в стандартный поток ошибок, и с уровнем, который вы передаёте в log_level=. Так что MCPServer("Bookshop", log_level="DEBUG") — всё, что нужно, чтобы увидеть строки из logger.debug(...).
По умолчанию — "INFO".
logging.basicConfig() никогда не заменяет уже существующие обработчики. Если настроить логирование самостоятельно до создания сервера, ваша конфигурация имеет приоритет.
Попробуйте сами
Запустите сервер через MCP Inspector:
uv run mcp dev server.py
Вызовите search_books на вкладке Tools. Inspector показывает результат: только возвращённое значение. Строка
Searching for 'dune'
ушла в стандартный поток ошибок: в терминал, а не в передаваемые данные.
Info
Если на самом деле нужна трассировка (каждый запрос, сколько он занял, завершился ли ошибкой), нужны не строки лога, а спаны. Сервер уже их выдаёт: SDK по умолчанию трассирует каждое сообщение с помощью OpenTelemetry. См. OpenTelemetry.
Итоги
- Возможность логирования в протоколе MCP объявлена устаревшей в спецификации 2026-07-28 и ничем не заменена. Не стройте на ней ничего.
logger = logging.getLogger(__name__)на уровне модуля,logger.info(...)в инструменте. Вот и весь паттерн.- Вывод логов никогда не доходит до модели. Доходит только значение, которое вы возвращаете через
return. - Стандартный поток ошибок — ваш; stdout принадлежит протоколу. Пока сервер работает, SDK перенаправляет сброшенный посторонний вывод из stdout в stderr, но несброшенный
print()всё равно может вылиться в поток протокола при выходе, а перенаправленные строки приходят без меток. Используйтеlogging— его обработчик сбрасывает буфер после каждой записи. MCPServer(..., log_level="DEBUG")задаёт уровень, а конфигурацию логирования, которую вы сделали раньше, не трогает.
О том, как сообщить подключённым клиентам, что на сервере что-то изменилось (список инструментов, ресурс), — на странице Подписки.