Comet Opik
официальныйЗапрашивайте и анализируйте ваши логи Opik, трейсы, промпты и все остальные телеметрические данные от ваших LLM на естественном языке.
Что можно делать с Comet Opik MCP?
-
Запросы трассировок и проектов — Спросите «перечисли мои проекты Opik» или «какие трассировки в проекте 'demo' завершились с ошибкой сегодня?», чтобы просмотреть данные рабочего пространства с помощью
listиread. -
Оценка и комментирование трассировок — Прикрепляйте числовые оценки обратной связи, например, с указанием причины, или добавляйте текстовые комментарии к трассировкам, спанам или потокам.
-
Управление версиями промптов — Сохраняйте новые версии промптов, создавая промпты по имени, если они еще не существуют.
-
Проверка схем записи — Используйте
schema, чтобы проверить точные JSON-структуры, обязательные поля и проверенные примеры перед выполнением любой операции записи. -
Мониторинг состояния проекта — Получайте обзоры за 7 дней с количеством трассировок, частотой ошибок, длительностью и стоимостью, или стройте графики метрик во времени.
-
Разбор проблем Diagnostics — Перечисляйте открытые проблемы агентских инсайтов, решайте или закрывайте их, а также включайте или запускайте сканирование.
Документация
Opik MCP Server
Официальный сервер Model Context Protocol (MCP) для Opik, платформы наблюдения и оценки LLM с открытым исходным кодом, созданной Comet. Подключите свой AI-хост (Claude Code, Cursor, VS Code Copilot, Codex, opencode или любой MCP-клиент) напрямую к вашему рабочему пространству Opik: читайте трейсы, записывайте оценки и сохраняйте версии промптов — всё прямо из чата.
Создан для LLM-инженеров, которые уже используют Opik и хотят управлять им из того же AI-ассистента, с которым они пишут код.
Миграция со старого
npx opik-mcp? TypeScript-сервер устарел и будет отключён 2026-11-15. Заменитеnpx -y opik-mcpнаuvx opik-mcp@latestв конфигурации вашего MCP-клиента. Полное руководство:legacy/typescript/MIGRATION.md.
You: "Which traces in project 'demo' failed today?"
Claude: → list(entity_type="trace", project_name="demo") → "Three traces failed…"
You: "Score trace 7f2e… 0.9 on helpfulness with reason 'great recovery'."
Claude: → write(score.create) → done
Быстрый старт
Одна команда регистрирует сервер в AI-клиентах на вашей машине, устанавливает
набор навыков Opik и проверяет подключение. Требуется uv
и не требуется Opik SDK:
uvx opik mcp configure
Команда обнаруживает Claude Code, Cursor, VS Code Copilot, Codex и opencode и использует хостируемый сервер на Opik Cloud (вход через браузер, без хранения API-ключей) или этот локальный сервер в других случаях. Любой другой MCP-клиент может использовать хостируемый URL напрямую:
npx add-mcp https://www.comet.com/opik/api/v1/mcp --name opik-mcp
Руководство по настройке, устранение неполадок и FAQ: comet.com/docs/opik/mcp-server. Остальная часть этого README описывает локальный сервер, который команда выше настраивает для самостоятельно размещённого Opik и Opik с открытым исходным кодом, и который вы также можете настроить вручную.
Ручная установка
opik-mcp — это Python-пакет (требуется Python 3.13+). Рекомендуемый способ
запуска — uvx, который загружает и запускает последнюю опубликованную версию по требованию —
без глобальной установки и управления виртуальными окружениями.
Установите uv один раз:
curl -LsSf https://astral.sh/uv/install.sh | sh # macOS / Linux
# or: brew install uv
Вам понадобятся две вещи из вашего рабочего пространства Opik:
OPIK_API_KEY— получите его наcomet.com/api/my/settings/.OPIK_WORKSPACE— имя вашего рабочего пространства (в нижнем регистре, как оно указано в URL). Например,https://www.comet.com/acme-ai/...→OPIK_WORKSPACE=acme-ai.COMET_WORKSPACEпринимается как устаревший псевдоним.
Облако, с API-ключом: укажите его, если рабочее пространство по умолчанию вашей учётной записи не то, что вам нужно. Если не указано, сервер отправляет
default, который Comet сопоставляет с рабочим пространством по умолчанию вашей учётной записи. Это работает, но если вы на самом деле работаете в именованном рабочем пространстве, вас перенаправят в другое без каких-либо уведомлений — ваши чтения вернутся из неправильного места, а не завершатся ошибкой.Облако, через OAuth: оставьте поле пустым. Рабочее пространство берётся из токена, который вы авторизовали, и сервер полностью игнорирует этот параметр.
Локально / с открытым исходным кодом: оставьте поле пустым. Opik с открытым исходным кодом имеет одно рабочее пространство с именем
defaultи не позволяет создавать другие, что и даёт запасной вариант.Самостоятельно размещённый Comet: укажите его. В отличие от версии с открытым исходным кодом, в таких развёртываниях есть настоящие именованные рабочие пространства, и применяется тот же риск тихого переключения на неправильное рабочее пространство.
Что бы ни применялось, убедитесь, что значение действительно подставлено. В сниппетах в интернете встречаются заполнители вроде
<your-workspace>или${input:OPIK_WORKSPACE}; вставленные как есть, они не являются именами рабочих пространств. Теперь сервер отклоняет их напрямую, а не позволяет бэкенду ответить ошибкой аутентификации, которая ничего не объясняет.
Claude Code
Добавьте сервер одной командой:
claude mcp add --transport stdio opik-mcp \
--env OPIK_API_KEY=<your-key> \
--env OPIK_WORKSPACE=<your-workspace> \
-- uvx opik-mcp
Или отредактируйте ~/.claude.json напрямую:
{
"mcpServers": {
"opik-mcp": {
"type": "stdio",
"command": "uvx",
"args": ["opik-mcp"],
"env": {
"OPIK_API_KEY": "<your-key>",
"OPIK_WORKSPACE": "<your-workspace>"
}
}
}
}
Перезапустите Claude Code. Проверьте с помощью /mcp — opik-mcp должен отобразиться как подключённый.
Затем в чате спросите: «список моих проектов Opik» — Claude вызовет инструмент list
и вы увидите проекты вашего рабочего пространства.
Cursor
Отредактируйте ~/.cursor/mcp.json (глобально) или .cursor/mcp.json (для проекта) или откройте
Cmd+Shift+J → Features → Model Context Protocol:
{
"mcpServers": {
"opik-mcp": {
"type": "stdio",
"command": "uvx",
"args": ["opik-mcp"],
"env": {
"OPIK_API_KEY": "<your-key>",
"OPIK_WORKSPACE": "<your-workspace>"
}
}
}
}
Перезагрузите Cursor; зелёная точка рядом с opik-mcp на панели MCP подтверждает
подключение. Спросите в чате: «список моих проектов Opik».
Таймаут Cursor 60 секунд. Cursor применяет жёсткий таймаут вызова инструмента, который не сбрасывается при уведомлениях о прогрессе. См. Известные ограничения хостов.
VS Code Copilot
.vscode/mcp.json в вашем рабочем пространстве (или в JSON настроек пользователя):
{
"servers": {
"opik-mcp": {
"type": "stdio",
"command": "uvx",
"args": ["opik-mcp"],
"env": {
"OPIK_API_KEY": "<your-key>",
"OPIK_WORKSPACE": "<your-workspace>"
}
}
}
}
Перезагрузите окно; индикатор MCP в Copilot Chat покажет opik-mcp, когда
сервер станет доступен. Спросите в чате: «список моих проектов Opik».
MCP Inspector (ручное тестирование)
OPIK_API_KEY=<your-key> OPIK_WORKSPACE=<your-workspace> \
npx @modelcontextprotocol/inspector uvx opik-mcp
Самостоятельно размещённый Opik
Добавьте COMET_URL_OVERRIDE (и OPIK_URL, если Opik находится по нестандартному пути) в
тот же блок env в конфигурации вашего хоста:
{
"mcpServers": {
"opik-mcp": {
"type": "stdio",
"command": "uvx",
"args": ["opik-mcp"],
"env": {
"OPIK_API_KEY": "<your-key>",
"OPIK_WORKSPACE": "<your-workspace>",
"COMET_URL_OVERRIDE": "https://opik.your-company.com",
"OPIK_MCP_ANALYTICS_SOURCE": ""
}
}
}
}
Опустите OPIK_WORKSPACE в развёртывании с открытым исходным кодом, где default — единственное
рабочее пространство; сохраните его в самостоятельно размещённом Comet, где есть настоящие именованные.
Установка OPIK_MCP_ANALYTICS_SOURCE="" исключает вашу установку из
облачной метки источника Comet в событиях телеметрии.
Инструменты
opik-mcp предоставляет небольшой, ориентированный на результат набор инструментов, покрывающий весь
жизненный цикл (чтение → аннотирование → курирование → создание → итерация).
| Инструмент | Назначение |
|---|---|
read | Универсальное чтение по id / имени / URI opik:// |
list | Универсальный список с необязательным фильтром по имени + пагинация |
write | Универсальная запись — логирование трейсов/спанов, оценка, комментарии, сохранение промптов, управление датасетами и экспериментами |
schema | Просмотр схем операций записи (используется LLM для создания корректных полезных нагрузок) |
read_skill | Чтение одного из навыков агента Opik, входящих в этот сервер |
read
Один инструмент для любых вопросов вида «покажи мне X». Принимает entity_type плюс id
(UUID или, для типов с именами, имя) или полный URI opik://. Составные чтения
(trace, prompt, thread, agent_insights_issue) встраивают свои дочерние элементы, так что
один вызов возвращает полную картину.
Запись, которую вы называете, возвращается целиком. Встроенные дочерние элементы — нет: их
тела извлекаются с помощью truncate=true бэкенда, поэтому поле размером более ~10 КБ
обрезается в ClickHouse, а изображения base64 заменяются на "[image]" — одно вложение,
продублированное на 200 спанов, иначе стоило бы больше, чем всё остальное в чтении.
Ответ сообщает об этом в spanBodies / messageBodies, и любой дочерний элемент
снова становится целым через собственный read("span", id) или read("trace", trace_id),
которые обращаются к конечным точкам без параметра truncate вообще.
Встроенная коллекция также ограничена по длине: 200 спанов, 200 витков, 100
версий промптов. После этого spansTruncated / messagesTruncated /
versionsTruncated становится true, а рядом с ним строка moreSpans / moreMessages /
moreVersions содержит количество и точный вызов list(...), который
продолжает с того места, где остановилась встроенная часть.
Поддерживаемые сущности: project, trace, span, dataset, dataset_item,
experiment, prompt, thread, agent_insights_issue. Поиск по имени доступен
для project, experiment, prompt, dataset (медленнее — два API-
вызова — и может вернуть несколько совпадений). thread и agent_insights_issue
привязаны к проекту: передайте project_id или project_name, или ссылку/URI, который
содержит проект. dataset и dataset_item ранее назывались test_suite и
test_suite_item; старые имена по-прежнему распознаются, но не
рекламируются, и новый код должен использовать новые.
read(entity_type="trace", id="7f2e3c8a-…")
read(entity_type="project", id="demo") # name lookup
read(entity_type="trace", id="opik://traces/7f2e3c8a-…")
read(entity_type="agent_insights_issue", id="<issue-uuid>", project_id="<project-uuid>")
read(
entity_type="agent_insights_issue",
id="https://www.comet.com/opik/<ws>/projects/<pid>/diagnostics?issue=<id>",
)
Ссылка, скопированная из интерфейса Opik, работает как id: ссылка на ветку или
ссылка на страницу диагностики содержит проект, поэтому project_id не требуется, а
тип сущности берётся из ссылки.
Чтение project отвечает на вопрос «как дела у моего проекта» одним вызовом. Оно возвращает
{project, summary, vocabulary, contains, url}: запись, затем четыре
показателя, которые страница Logs отображает в виде карточек (количество трейсов, доля ошибок, средняя
длительность, общая стоимость) за последние 7 дней по сравнению с предыдущими 7, только SDK-трафик,
как на экране. since / until перемещают это окно; since="30d" — то, что
открывает интерфейс. Доля или среднее за период без трейсов возвращается
как null, потому что 0% ошибок за неделю без трафика выглядит как здоровая неделя.
vocabulary — это карта, которая нужна, прежде чем задавать любые другие вопросы:
имена оценок обратной связи проекта, его ключи использования токенов и правила автоматизации,
оценивающие его трейсы. Это имена, которые используются в фильтре или в
series= ниже, и их угадывание возвращает пустую страницу, которая выглядит как хорошие новости.
Имена оценок и правила ограничены, всегда сообщают истинное общее количество и называют
вызов, который возвращает остальное; ключи использования перечислены полностью, поскольку ничто
другое их не перечисляет. contains называет самый свежий эксперимент, датасет, версию
промпта и запуск оптимизации, так что вопрос «что здесь происходило» не требует
ещё четырёх вызовов. Часть, которую не удалось загрузить, сообщает об этом, а не выглядит пустой,
а пустая часть опускается.
Чтение agent_insights_issue возвращает {issue, example_trace_ids, details}:
запись проблемы диагностики (имя, описание, причина, предлагаемое исправление,
серьёзность, статус), дедуплицированные id трейсов, в которых она проявляется (та же
выборка, которую показывает страница Diagnostics — откройте одну с помощью read("trace", id)),
и разбивку по дням. Тела трейсов не встраиваются, поэтому чтение остаётся одним
вызовом бэкенда. since / until сужают строки по дням; по умолчанию —
за всё время. Когда сервер знает URL Opik и рабочее пространство сеанса,
чтение также содержит url (страницу Diagnostics проблемы) и trace_url_template
(глубокую ссылку для любого из примеров трейсов), чтобы ассистент мог передать вам
что-то кликабельное; в OAuth-сеансе, где рабочее пространство не удалось
определить, ссылки опускаются, а не угадываются.
Сами трейсы не содержат URL — ссылку для трейса нельзя вывести из
полей, возвращаемых read или list, а угаданная форма даёт 404. В инструкциях
сеанса вместо этого указан шаблон для неё,
.../v1/session/redirect/projects/?trace_id={trace_id}&path=..., чтобы
ассистент заполнил id и передал вам ссылку. Она проходит через редирект opik-backend,
который определяет проект и рабочее пространство по трейсу, поэтому она работает там,
где прямой URL проекта не может, включая OAuth-сеанс с неопределённым рабочим пространством.
Это та же ссылка, которую Python SDK выводит для трейса.
list
Просмотр или поиск коллекции с пагинацией. Типы, привязанные к проекту (trace,
span, thread, agent_insights_issue, dataset_item, prompt_version),
требуют родителя: UUID или имя проекта, UUID датасета или UUID промпта.
list(entity_type="experiment", page=1, size=25)
list(entity_type="experiment", name="rerank") # name substring filter
list(entity_type="agent_insights_issue", project_name="demo") # open Diagnostics issues
list(entity_type="agent_insights_issue", project_id="<uuid>", status="resolved")
list(entity_type="trace", project_name="demo") # latest traces of one project
list(
entity_type="trace", project_name="demo", filters="error_info is_not_empty AND duration > 5000"
)
list(
entity_type="span",
project_name="demo", # spans across the whole project
filters='type = "llm" AND usage.total_tokens > 10000',
)
list(
entity_type="thread",
project_name="demo",
filters="number_of_messages > 20 AND feedback_scores.helpfulness < 0.5",
)
list(entity_type="experiment", filters='dataset_id = "<dataset-uuid>" AND tags contains "baseline"')
Фильтры. trace, span, thread, experiment и dataset_item принимают
строку OQL, ту же грамматику, что и search_traces(filter_string=…) в SDK:
<field>[.<key>] <op> <value> [AND ...]
ops: = != > >= < <= contains not_contains starts_with ends_with is_empty is_not_empty in not_in
Строки заключаются в двойные кавычки, числа указываются без кавычек, duration — в миллисекундах,
даты — это моменты ISO-8601 с часовым поясом ("2026-09-08T10:00:00Z").
Оценки и словари принимают ключ: feedback_scores.accuracy < 0.5,
metadata.environment = "prod". AND — единственный соединитель.
Как и на странице Logs в интерфейсе, списки трейсов, спанов и веток добавляют source = "sdk", чтобы
трейсы оценщика, песочницы и экспериментов не мешали; назовите source
сами, чтобы увидеть их. Первая строка вывода повторяет применённый фильтр.
Плохой фильтр не доходит до бэкенда с тем, что нужно для его исправления:
позицией синтаксической ошибки, ближайшим именем поля, допустимыми операторами
для типа поля или ожидаемым форматом значения. Поля с закрытым набором
значений (source, span type, thread status, visibility_mode) проверяются
по нему тоже, включая каждый элемент списка in. source — это то, что
бэкенд проверяет сам, и он отвечает на неизвестное значение кодом 500,
а не 400, поэтому source = "SDK" иначе был бы непрозрачной серверной ошибкой для
заглавной буквы. Остальные сравниваются как строки и отвечают пустой страницей,
что читается как «нет совпадений», хотя означает «нет такого значения». Спросите
schema("list.trace") (или list.span, list.thread, list.experiment) для
полного справочника полей, включая допустимые значения.
Поиск одного случая в наборе данных. list(entity_type="dataset_item", dataset_id=…) filters on the case itself: data.<key> для ключей, с которыми
был создан набор данных, full_data для подстроки всей полезной нагрузки (полное
сканирование — укажите ключ, когда можете), плюс id, tags, source, trace_id,
span_id и временные метки. data.<key> принимает только шесть строковых операторов
(=, !=, contains, not_contains, starts_with, ends_with);
бэкенд отвечает на сравнение кодом 400, поэтому этот оператор отклоняется до
вызова. У конечной точки нет сортировки и полнотекстового поиска — sort отклоняется,
а не игнорируется. read(entity_type="dataset_item", id=…) возвращает один случай
целиком, что позволяет прочитать значение, обрезанное таблицей.
list(entity_type="dataset_item", dataset_id="<uuid>", filters='data.question contains "install"')
list(
entity_type="dataset_item", dataset_id="<uuid>", filters='trace_id = "<trace-uuid>"'
) # the case made from that trace
read(entity_type="dataset_item", id="<item-uuid>") # the case, uncut
С experiment_ids тот же список становится сравнением — случаи с
каждым прикреплённым прогоном — и фильтрует по прогонам (feedback_scores.<name>,
output, duration). Это два разных набора полей на двух конечных точках
бэкенда: schema("list.dataset_item_case") — собственные случаи набора данных,
schema("list.dataset_item") — сравнение.
Сортировка. trace, span, thread и experiment принимают
sort="<field> [asc|desc]", desc по умолчанию и только одно поле:
sort="duration desc", sort="total_estimated_cost",
sort="feedback_scores.accuracy asc", sort="usage.total_tokens". Поле
проверяется по списку сортируемых полей сущности до вызова, потому что бэкенд
молча игнорирует поля, по которым не может сортировать. На очень больших рабочих
областях бэкенд полностью отключает сортировку; заголовок сообщает об этом, когда
это происходит.
dataset_item сортирует только как сравнение (с experiment_ids): конечная точка
элементов не принимает параметр сортировки, поэтому сортировка в обычном списке
отклоняется, а не игнорируется.
Временное окно и поиск. trace, span и thread принимают since и
until, каждый — относительный интервал ("30m", "1h", "7d") или момент времени
в формате ISO-8601 с часовым поясом, так что «последний час» не требует арифметики
с часами. Окно задаётся по времени создания записи, что дёшево для бэкенда и
совпадает с start_time в пределах секунд для живого трафика. Для точной
границы поместите start_time в filters. Те же три типа принимают search — свободный
текст, сопоставляемый в любом месте id, name, input, output, metadata, tags и
thread id. Поиск сканирует весь проект на бэкенде, поэтому первый вызов в большом
проекте может занять десятки секунд. Эти вызовы получают тайм-аут 60 секунд.
Добавление since снова делает их быстрыми.
Чтение таблицы. Длительности помечены duration_ms / ttft_ms и
показаны в целых миллисекундах; поле остаётся duration в filters и
sort. Временные метки показаны с точностью до секунды, а стоимости — как
простые десятичные числа. Строки проекта несут last_updated_trace_at, чтобы вы видели, какой
проект имеет живой трафик; строки thread несут первое сообщение. Пустая страница
в временном окне сообщает, когда приземлился последний trace проекта, а пустая
страница под стандартным source = "sdk" сообщает, как увидеть другие источники.
Опечатка в project_name возвращается с ближайшим существующим именем.
list(
entity_type="trace",
project_name="demo",
since="1h",
filters="error_info is_not_empty",
sort="duration desc",
)
list(entity_type="trace", project_name="demo", search="order-42")
Проблемы диагностики. agent_insights_issue — это страница Diagnostics через
MCP: повторяющиеся сбои, сгруппированные заданием Diagnostics Opik для проекта,
ранжированные так, как их ранжирует UI (сначала самые недавние). Столбцы: severity,
status, total_occurrences (сумма за всё время), latest_count (самый последний
день отчёта, число, на которое ссылается описание проблемы) и last_seen.
Открытые проблемы перечислены по умолчанию; передайте status="resolved" или "closed" для
остальных. read и list также отвечают на issue, как это называет UI;
длинное имя — это то, что в перечислении entity_type, так что эта сущность
не появляется там дважды. Счётчики за всё время, поэтому они совпадают с UI; те же since / until,
что и для traces, сужают окно, усечённое до UTC-дней отчёта, потому что
Diagnostics агрегирует по дням.
Пустой список объясняет, почему он пуст, потому что иначе «ничего не сломано» и «никто не включил Diagnostics» читаются одинаково. Есть пять состояний: Diagnostics недоступен в этом развёртывании, не включён для этого проекта, выключен, включён, но не сканировался недавно, или включён и чист с временем последнего сканирования. Те, на которые вы можете повлиять, называют вызов, который нужно сделать, и каждое состояние ссылается на страницу Diagnostics проекта.
Непустой список датирует себя. Проблемы — это то, что сгруппировало последнее
сканирование, поэтому ответ заканчивается Report covers data through <time>, и когда окно,
о котором вы спросили, выходит за его пределы, он называет непокрытый хвост и
как его закрыть: триггер, когда повторное сканирование достигает достаточно
далеко назад, иначе сырые traces с since, который он вам даёт. Спросите
неделю для проекта, сканируемого еженощно, и последний день отсутствует в
сгруппированном ответе; именно это здесь и сообщается.
write("agent_insights_job.enable", {"project_name": "demo"}) включает Diagnostics.
С этого момента он сканирует ежедневно, и повторный вызов безопасен.
write("agent_insights_job.trigger", …) сканирует последние 24 часа сейчас, не
дожидаясь ночного запуска. Оба требуют того же разрешения, что и чтение проблем,
и оба отказываются там, где в развёртывании нет Diagnostics.
Проблема проходит свой жизненный цикл с помощью
write("agent_insights_issue.resolve", {"issue_id": "<uuid>", "project_name": "demo"})
— обработана — или …close для той, на которую не стоит реагировать, и …reopen, чтобы вернуть
любую из них в открытый список. Все три требуют того же разрешения и отвечают
ссылкой на представление, в которое переместилась проблема, поскольку решённая
проблема больше не находится на странице по умолчанию. Исправлен ли сбой, —
это оценочное суждение, поэтому эти действия для случаев, когда вы просите:
у ассистента нет права прибирать список во время триажа.
Метрики во времени. project_metric отображает одну метрику для проекта в виде
таблицы временных интервалов: количество traces, spans и threads, длительности,
частоты ошибок, стоимости, использование токенов и оценки обратной связи. Он
отвечает на вопрос, который следует за обзором, — когда что-то изменилось.
list(entity_type="project_metric", project_name="demo", metric_type="trace_count")
list(
entity_type="project_metric",
project_name="demo",
metric_type="trace_error_rate",
since="14d",
interval="daily",
)
list(
entity_type="project_metric", project_name="demo", metric_type="span_count", breakdown="model"
) # one column per model
list(
entity_type="project_metric",
project_name="demo",
metric_type="span_duration",
breakdown="model",
series="p99",
) # the p99 of each model
Строки — это временные интервалы, а не записи, поэтому page, size и sort отклоняются,
а не игнорируются. interval — это hourly, daily, weekly или total;
если не указано, он следует окну так, как вкладка Metrics — почасово до 3
дней, ежедневно до 30, еженедельно за пределами — так что диаграмма по умолчанию
составляет несколько десятков строк при любом диапазоне, а почасовой месяц
(721 строка) — это то, о чём вы просите. since / until принимают те же формы, что и везде,
и по умолчанию — последние 7 дней. filters использует поля той сущности, о которой
метрика, поэтому метрика span фильтруется по полям span.
breakdown разбивает каждый интервал по tags, name, error_info, error_type,
model, provider, span_type, guardrail_name или metadata.<key>. Не
каждая метрика принимает каждый из них, и семь не принимают ни одного; инструмент
знает, какие, и сообщает об этом до вызова бэкенда, называя метрику, которая
отвечает на тот же вопрос, если такая существует. Три семейства возвращаются как
несколько серий одновременно (длительность как p50/p90/p99, оценка обратной
связи по имени, использование токенов по ключу), и бэкенд отображает одну из них
за раз при группировке, поэтому series= выбирает её: процентиль, имя оценки
или ключ использования. Длительность по умолчанию — p50, а использование
токенов — total_tokens, и то, что использовалось, повторяется в первой строке.
Пустые интервалы пропускаются и подсчитываются внизу, так что тихий месяц — это несколько строк вместо столбца нулей, а частота за интервал без traces отсутствует, а не сообщается как ноль.
Спросите schema("list.project_metric") для таблицы метрик, интервалов и
матрицы группировки по метрикам.
Имена проекта. score_name перечисляет имена оценок обратной связи, записанные в
проекте, а online_rule — оценщики правил автоматизации, настроенные на нём,
откуда и происходит большинство этих имён. Оба — те же списки,
которые несёт read("project", …), полностью и с пагинацией, для случаев, когда
ограниченной версии в обзоре недостаточно.
list(entity_type="score_name", project_name="demo")
list(entity_type="online_rule", project_name="demo")
write
Универсальный диспетчер записи. Передайте operation + data, и диспетчер
проверит полезную нагрузку, применит правильный REST-глагол и вернёт
ответ бэкенда.
Операции:
| Операция | Что она делает |
|---|---|
trace.create | Записать один trace (или пакет). Родитель для spans / scores / comments. |
trace.update | Финализировать или изменить существующий trace. |
span.create | Записать span на существующем trace (или пакет). |
score.create | Прикрепить числовую оценку обратной связи к trace, span или thread. |
comment.create | Прикрепить текстовый комментарий к trace, span или thread. |
prompt_version.save | Сохранить новую версию prompt (создаёт prompt по имени, если отсутствует). |
dataset.create | Создать набор данных — type: "test_suite" делает его тестовым набором для оценки. |
dataset_item.upsert | Вставить элементы в набор данных (всегда форма envelope). |
experiment.create | Создать эксперимент, ограниченный набором данных. |
experiment_item.create | Прикрепить строки trace + dataset_item к эксперименту. |
thread.close | Закрыть thread (пометить как неактивный). Передайте thread_id и проект. |
thread.open | Открыть закрытый thread. Передайте thread_id и проект. |
agent_insights_job.enable | Включить Diagnostics для проекта (ежедневные сканирования, безопасно повторять). |
agent_insights_job.trigger | Запустить сканирование Diagnostics сейчас, за последние 24 часа. |
agent_insights_issue.resolve | Пометить проблему Diagnostics как обработанную (сначала спросите пользователя). |
agent_insights_issue.close | Пометить проблему Diagnostics как не стоящую действий (сначала спросите пользователя). |
agent_insights_issue.reopen | Вернуть решённую или закрытую проблему Diagnostics в открытый список. |
write(
operation="score.create",
data={
"target": "trace",
"target_id": "7f2e3c8a-…",
"name": "helpfulness",
"value": 0.9,
"reason": "great recovery",
},
)
schema
Проверьте точную JSON-форму и обязательные поля любой операции записи перед
вызовом — полезно, когда вы не уверены, как должен выглядеть data. Возвращает
схему, область OAuth и один проверенный пример. Чистый поиск, без вызова
бэкенда.
schema(operation="score.create")
schema(operation="prompt_version.save")
Тот же инструмент отвечает на list.trace, list.span, list.thread и
list.experiment справочником инструмента list для этой сущности: каждое
фильтруемое поле с его типом и допустимыми операторами, сортируемые поля, применимы ли
временное окно и полнотекстовый поиск, и два примера фильтров.
schema(operation="list.trace")
Конфигурация
Каждый параметр — это переменная окружения. Обязательные выделены жирным.
Идентичность / конечная точка
| Переменная | По умолчанию | Примечания |
|---|---|---|
OPIK_API_KEY | — | Обязательна для любого аутентифицированного чтения/записи. |
OPIK_WORKSPACE | не задано | Имя рабочей области. В облаке с API-ключом, если не задано, отправляется default, что разрешается в стандартную рабочую область вашей учетной записи — задайте её явно, если работаете в другой, иначе чтение будет молча выполняться из неправильной рабочей области. Оставьте не заданным при OAuth (токен несёт её) и в локальной/OSS-установке (default — единственная рабочая область там). |
COMET_WORKSPACE | — | Устаревший псевдоним для OPIK_WORKSPACE (обратная совместимость). OPIK_WORKSPACE имеет приоритет, если заданы обе. |
COMET_WORKSPACE_ID | не задано | Необязательный UUID рабочей области. Записывается в события аналитики, если задан, и имеет приоритет над разрешённым. Редко нужен — OAuth-установки получают UUID из токена автоматически. |
COMET_URL_OVERRIDE | https://www.comet.com | Укажите ваш self-hosted Comet хост, или https://dev.comet.com для staging. |
OPIK_URL | выводится из COMET_URL_OVERRIDE + /opik/api | Переопределяйте только если Opik живёт на другом хосте/пути, чем Comet UI. |
OPIK_DEFAULT_PROJECT_NAME | не задано | Если задано, блоб instructions для каждой сессии сообщает LLM передавать это как project_name при каждом вызове инструмента, если пользователь не назвал другой проект. |
Сервер / транспорт
| Переменная | По умолчанию | Примечания |
|---|---|---|
OPIK_MCP_TRANSPORT | stdio | stdio для запуска хостом, streamable-http для прослушивания порта. |
OPIK_MCP_HOST | 127.0.0.1 | Хост привязки uvicorn (только streamable-http). |
OPIK_MCP_PORT | 8080 | Порт привязки uvicorn (только streamable-http). |
OPIK_MCP_RELOAD | false | true для включения uvicorn --reload (только для разработки). |
OPIK_MCP_AS_URL | не задано | URL сервера авторизации OAuth, рекламируется в /.well-known/oauth-protected-resource (RFC 9728) и используется как прокси-цель для AS-discovery запросов. Требуется для MCP-хостов, чтобы запустить OAuth-процесс через HTTP. |
OPIK_MCP_RESOURCE_URI | не задано | Канонический публичный URI этого сервера, рекламируется как resource в метаданных защищённого ресурса и используется для вывода подсказки WWW-Authenticate. |
OPIK_MCP_OAUTH_VALIDATION_CACHE_TTL_S | 30 | Как долго «валидный» ответ от token introspection opik-backend доверяется перед тем, как следующий запрос с тем же OAuth-токеном спросит снова. Ограничивает нагрузку на бэкенд от проверки каждого запроса и окно, в котором просроченный токен всё ещё пересылается (это окно также заканчивается на первом 401, который возвращает бэкенд). Ограничено собственным expires_at токена, если бэкенд его сообщает. |
OPIK_MCP_LOG_LEVEL | INFO | Порог логгера stderr. |
Выбор транспорта
Две формы bearer-токенов, два контракта на HTTP-транспорте. OAuth-токен доступа opik_mcp_at_… проверяется при каждом запросе через endpoint token introspection opik-backend (кэшируется, см. OPIK_MCP_OAUTH_VALIDATION_CACHE_TTL_S); просроченный или отозванный токен получает HTTP 401 с WWW-Authenticate: Bearer error="invalid_token", на что MCP-хосты опираются для тихого гранта refresh_token. Opik API-ключ не проверяется локально: он пересылается дословно в opik-backend, который является единственной точкой контроля. Выбирайте транспорт по форме развёртывания:
| Сценарий | Транспорт |
|---|---|
| MCP-клиент и Opik на одной машине (локальная OSS-установка) | stdio (рекомендуется — проще всего, без порта и настройки OAuth) |
| Локальный MCP-клиент → удалённый Opik (Comet cloud / self-hosted) | stdio с OPIK_API_KEY, или HTTP с OAuth (OPIK_MCP_AS_URL указывает на бэкенд) |
| Хостируемый opik-mcp за тем же edge, что и opik-backend | HTTP — bearer-токены проверяются бэкендом при каждом запросе |
Примечание для локальных OSS-установок: OSS-бэкенд не аутентифицирует запросы, поэтому HTTP opik-mcp перед ним так же открыт, как и сам OSS REST API. Оставьте привязку по умолчанию 127.0.0.1 (и предпочитайте stdio) в общих сетях.
Телеметрия
Анонимные события использования (только тип события и тайминги — без содержимого запросов). Включается SHA-256 дайджест вашего API-ключа, чтобы поддержка могла найти вашу учётную запись; сырой ключ никогда не покидает процесс. Отказ: OPIK_MCP_ANALYTICS_ENABLED=false.
| Переменная | По умолчанию | Примечания |
|---|---|---|
OPIK_MCP_ANALYTICS_ENABLED | true | Установите в false, чтобы отключить всю телеметрию. |
OPIK_MCP_ANALYTICS_URL | https://stats.comet.com/notify/event/ | Переопределение для staging. |
OPIK_MCP_ANALYTICS_ENVIRONMENT | prod | Тег на каждом событии (prod / staging / dev). |
OPIK_MCP_ANALYTICS_SOURCE | comet.com | Приёмник использует это для пометки on_prem=False. On-prem установки должны переопределить на "" или свой домен. |
OPIK_MCP_ANALYTICS_CONNECT_TIMEOUT_S | 5.0 | HTTP таймаут соединения. |
OPIK_MCP_ANALYTICS_TOTAL_TIMEOUT_S | 10.0 | HTTP общий таймаут запроса. |
Известные ограничения хостов
Хосты различаются по тому, как долго они позволяют выполняться одному вызову инструмента:
- Claude Code — нет документированного таймаута вызова инструмента. Рекомендуется.
- Cursor — жёсткий таймаут 60 секунд, который не сбрасывается при прогрессе (известный баг).
- MCP Inspector —
MAX_TOTAL_TIMEOUTограничивает общую длительность (по умолчанию 60 секунд). Поднимите его в UI Inspector для длительных операций.
Если вызов зависает, установите OPIK_MCP_LOG_LEVEL=DEBUG для полного журнала запросов.
Устранение неполадок
OPIK_API_KEY не подхватывается — переменная не достигает процесса сервера. В Claude Code / Cursor / VS Code переменные окружения применяются только внутри блока env конфигурации MCP-сервера, а не из вашей оболочки. Перезапустите хост после редактирования.
Вызов Cursor истекает через 60 секунд — известный баг Cursor, не opik-mcp. Либо сузьте вызов (меньше size, более узкое окно), либо выполните ту же операцию в Claude Code, где нет жёсткого лимита.
Сервер не отображается, вход не открывается, неправильная рабочая область, uvx не найден. Это описано в разделе устранения неполадок документации. opik mcp status (из того же CLI uvx opik) перечисляет каждый клиент, у которого настроен сервер, и не отклонялся ли его конфиг.
Разработка
git clone git@github.com:comet-ml/opik-mcp.git
cd opik-mcp
make install # uv sync --locked --extra dev
make check # lint + typecheck + test
make run-dev # uvicorn with --reload + DEBUG logs
make inspect # MCP Inspector against the running server
Общие цели:
| Цель | Что делает |
|---|---|
make install | uv sync --locked --extra dev |
make run | Запуск MCP-сервера (stdio по умолчанию). |
make run-dev | Запуск с DEBUG-логированием + uvicorn --reload. |
make dev | Запуск через mcp dev (обёртка Inspector dev-mode). |
make inspect | Запуск MCP Inspector против работающего сервера. |
make test | uv run pytest -q. |
make lint | ruff check + проверка форматирования. |
make format | ruff format + ruff check --fix. |
make typecheck | mypy. |
make check | lint + typecheck + test. |
Структура репозитория:
opik-mcp/
├── src/opik_mcp/ ← server, tools, analytics
├── tests/ ← pytest suites
├── scripts/ ← live-BE smoke + MCP-session smoke
├── legacy/typescript/ ← migration guide for the deprecated v2 TS server (source: tag `legacy-typescript-final`)
├── pyproject.toml
└── Makefile
Получить помощь
- Открыть issue для багов и запросов функций
- Документация Opik для SDK / документации бэкенда
- Comet community Slack для вопросов
Обновление с v2? Легаси TypeScript-сервер всё ещё публикуется на npm как
opik-mcp@^2(npx -y opik-mcp); его исходный код находится на git-тегеlegacy-typescript-final. См.legacy/typescript/DEPRECATED.mdдля политики поддержки.
Лицензия
Apache-2.0.