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

OpenTelemetry

Машинный перевод

Эта страница переведена с английской документации автоматически, и основной версией остаётся английская страница. Если что-то читается неправильно, на странице Переводы объясняется, как об этом сообщить.

Ваш сервер уже трассируется. Добавлять ничего не нужно.

Каждый созданный вами сервер порождает спан OpenTelemetry для каждого обработанного сообщения. Вы этого не писали и не импортируете. Это появляется в тот момент, когда вы вызываете MCPServer(...).

server.py
from mcp.server import MCPServer

mcp = MCPServer("Bookshop")


@mcp.tool()
def search_books(query: str) -> str:
    """Search the catalog by title or author."""
    return f"Found 3 books matching {query!r}."

Это уже готовый сервер с трассировкой. Вызовите search_books — и для него будет создан спан. То же самое верно для низкоуровневого Server: трассировка есть в обоих.

Что вы получаете

Каждое входящее сообщение становится спаном SERVER, названным по методу и его цели. Так, tools/call для search_books даёт спан tools/call search_books, а просто tools/list — спан tools/list.

Каждый спан несёт несколько атрибутов:

  • mcp.method.name и mcp.protocol.version — на каждом спане.
  • jsonrpc.request.id — на запросе (у уведомления его нет).
  • Обработчик, выбросивший исключение, переводит статус спана в ошибку. То же делает результат инструмента с is_error=True.

А поскольку трассировать вызов инструмента хочется особенно часто, спаны tools/call следуют семантическим соглашениям GenAI из OpenTelemetry:

  • gen_ai.operation.name со значением "execute_tool".
  • gen_ai.tool.name с именем вызываемого инструмента.

Спан prompts/get в том же духе получает gen_ai.prompt.name. Методы списков не несут ключей gen_ai.*, потому что называть там нечего.

Tip

Именно благодаря этим атрибутам GenAI интерфейс трассировки группирует ваши вызовы инструментов так же, как вызовы любого другого агента. Эта группировка достаётся даром, без дополнительного кода.

Это ничего не стоит, пока вам не понадобится

Вот что делает «включено по умолчанию» комфортным вариантом по умолчанию.

SDK зависит только от opentelemetry-api — лёгкой половины OpenTelemetry. Пока не установлены ни SDK OpenTelemetry, ни экспортёр, создание спана ничего не делает. Так что спаны, которые ваш сервер порождает прямо сейчас, почти ничего не стоят, и никто их не собирает.

В тот день, когда захочется их увидеть, установите вторую половину и направьте её куда-нибудь:

uv add opentelemetry-sdk opentelemetry-exporter-otlp

Настройте экспортёр обычным для OpenTelemetry способом — и все спаны, которые SDK тихо создавал, станут видны. Код сервера не меняется. Ни одной строки.

Info

Pydantic Logfire — один из таких бэкендов, и он берёт настройку на себя: pip install logfire, logfire.configure() — и ваши MCP-спаны появляются в живом просмотре. Он построен на OpenTelemetry, поэтому всё сказанное ниже относится и к нему.

Трассы, пересекающие сеть

Трасса полезнее всего, когда она сопровождает запрос от клиента до сервера в одной связной картине.

Когда и клиент, и сервер работают на SDK, эта связь возникает автоматически. Клиент внедряет в запрос контекст трассировки W3C, а сервер считывает его обратно, так что серверный спан вкладывается в клиентский в рамках одной трассы. Это SEP-414, и вы получаете его, ничего не запрашивая.

Если входящее сообщение не несёт контекста трассировки — например, запрос от клиента, который не является SDK, — серверный спан просто становится дочерним к тому спану, который уже текущий на сервере, а не начинает совершенно новую трассу-сироту.

Как отключить

Трассировка — это middleware, первый в списке вашего сервера. Если действительно нужен сервер, который не порождает спанов, уберите его:

from mcp.server._otel import OpenTelemetryMiddleware

mcp._lowlevel_server.middleware[:] = [
    m for m in mcp._lowlevel_server.middleware if not isinstance(m, OpenTelemetryMiddleware)
]

Warning

В этом импорте есть ведущее подчёркивание, и это намеренно. Класс предварительный, так же как предварителен Server.middleware, поэтому будьте готовы к тому, что путь импорта изменится. Это почти никогда не нужно: без установленного экспортёра спаны бесплатны, так что обычный ответ — оставить их включёнными и не устанавливать экспортёр.

Итоги

  • Каждый MCPServer и каждый низкоуровневый Server по умолчанию порождает один спан SERVER на каждое входящее сообщение. Вы ничего не пишете.
  • Спаны несут mcp.method.name и mcp.protocol.version; tools/call и prompts/get дополнительно несут атрибуты GenAI, так что ваши вызовы инструментов группируются как у любого другого агента.
  • Это ничего не стоит, пока вы не установите SDK OpenTelemetry и экспортёр, — а затем всё становится видно без изменений в сервере.
  • Контекст трассировки от клиента к серверу распространяется автоматически, когда обе стороны работают на SDK.

Решает, будет ли запрос выполнен вообще, Авторизация.