Opik
io.github.comet-ml由 GitHub 账号 comet-ml 发布v3.0.9更新于 Nov 7, 2026
Read and score Opik traces, experiments, datasets and prompts from your AI assistant.
概览
Opik 官方 MCP 服务器:让助手读取 Opik 工作区中的 trace、实验、数据集和提示词,并写入评分、评论和提示词版本。
- 可以做什么
- 按 id、名称或 Opik 链接读取项目、trace、span、thread、数据集、数据集条目、实验、提示词和诊断问题,并获取项目概览与词表
- 分页列出并按 OQL 过滤 trace、span、thread、实验和数据集条目
- 写入 trace 和 span、附加反馈评分与评论、保存提示词版本,创建数据集、实验和标注队列
- 开启、关闭和解决诊断问题,启用或触发诊断扫描
- 查看写入操作与列表过滤的 schema,并读取随附的 Opik 智能体技能
- 适用场景
- 适合已经使用 Opik(Opik Cloud、开源版或自建 Comet)的团队,希望在写代码的同一个助手里排查失败的 trace、打分或标注、整理数据集与提示词,或查看项目健康状况。
- 运行要求
- 可使用 Opik Cloud 上的托管服务器(浏览器 OAuth 登录,无需 API 密钥),或用 uvx 以 stdio 运行本地包。本地部署需要为自建 Comet 或未走 OAuth 的云端设置 OPIK_API_KEY,非默认工作区需设置 OPIK_WORKSPACE,开源或自建部署需设置 OPIK_URL 或 COMET_URL_OVERRIDE。需要能访问 Opik API 的网络。
安装
在 SourceWeft 中
- 打开 控制台中的 Opik,将其添加到工作区。
- 连接 所需的 凭据。它们会被私密存储,绝不会在公开页面上展示。
- 为需要使用其工具的对话启用该服务。
Web executable,通过 Streamable HTTP。 远程服务在工作区中配置后即可从网页运行时运行。
交给智能体安装
把这段提示词粘贴到 Claude Code、Codex、Cursor 等智能体,或 SourceWeft 对话中。智能体会读取该服务器的安装指南,先向你展示发布者、端点和登录方式,经你同意后再把它添加到你的客户端。密钥不会写进任何命令。
阅读 https://sourceweft.com/mcp/io.github.comet-ml%2Fopik-mcp/install.md,并按其中说明把这个 MCP 服务器接入我的客户端。修改任何配置之前,先告诉我它的发布者、端点和登录方式,等我确认。不要把 API 密钥写进命令或我会提交的文件;问我密钥应从哪里获取。其他 MCP 客户端
把它添加到你客户端的 mcpServers 配置中。 客户端会在首次连接时完成 OAuth 登录。
{
"mcpServers": {
"opik": {
"type": "http",
"url": "https://www.comet.com/opik/api/v1/mcp"
}
}
}README
Opik MCP Server
The official Model Context Protocol (MCP) server for Opik, the open-source LLM observability and evaluation platform, built by Comet. Plug your AI host (Claude Code, Cursor, VS Code Copilot, Codex, opencode, or any MCP client) directly into your Opik workspace: read traces, log scores, and save prompt versions, all from the chat.
Built for LLM engineers who already run Opik and want to drive it from the same AI assistant they code with.
Quick start
One command sets Opik up in the AI clients on your machine, Claude Code
included. It finds your Opik (the one saved in ~/.opik.config, one running on
localhost, or it asks which), registers the MCP server, installs the Opik skill
pack, and checks the connection. On Opik Cloud there is no API key to handle:
your client signs in in the browser. It needs uv
and no Opik SDK:
Without a terminal, as from a coding agent or a script, name the client:
--ai-client also takes codex, cursor, vscode and opencode. Run that
way it uses the Opik saved in ~/.opik.config, API key included, or one
answering on localhost, and otherwise stops and asks for --deployment.
A coding agent asked to "install opik mcp" gets the full steps, including what
to ask the user, from uvx opik-mcp@latest --help. They are the same as
Install with a coding agent below.
Registering the server by hand, with the client commands under Set it up by hand, skips the check of which Opik you use and the skill pack, so it is for clients the installer doesn't support.
Clients load MCP servers when a session starts, so start a new session afterwards.
Setup guide, troubleshooting and FAQ: comet.com/docs/opik/mcp-server.
Opik Cloud: the hosted server
Comet runs the server at https://www.comet.com/opik/api/v1/mcp. Your client
connects over HTTP and opens a browser sign-in the first time. There is nothing
to install, no API key, and no workspace to set: the server works in the
workspace you pick when you sign in. After adding it, start a new session and
ask: "list my Opik projects".
The Quick start command sets this up for Claude Code, Codex, Cursor, VS Code Copilot and opencode, with the skill pack. In Claude Code, the plugin does the same in one command. The buttons below add it to Cursor or VS Code in one click; other ways to register it by hand are under Set it up by hand.
[Add to Cursor] [Install in VS Code]
Claude Code plugin
The opik plugin installs the Opik skills and registers the hosted MCP server
for Opik Cloud:
On Claude Code before 2.1.275, run /plugin marketplace add comet-ml/opik-mcp,
then /plugin install opik@opik. The skills load as opik:<skill>, such as
opik:opik-instrument, and /mcp shows the server as plugin:opik:opik-cloud.
The server is Opik Cloud's. Start a new session, then sign in from /mcp →
Authenticate. For a self-hosted Comet that runs the MCP OAuth server, add
it with claude mcp add --transport http opik-mcp https://<host>/opik/api/v1/mcp;
for any other self-hosted or open-source Opik, use the
Quick start command. Then disable plugin:opik:opik-cloud in
/mcp. Claude Code does not update a plugin from
this marketplace on its own: run /plugin marketplace update opik, then
/plugin update opik@opik, or turn on auto-update for the marketplace in
/plugin. This marketplace serves main, which can be ahead of the last
release. An update arrives only when the plugin's version changes, at each
release.
If you added opik-mcp before at the same URL, Claude Code keeps your copy and
skips the plugin's. If yours is another server, such as the local
uvx opik-mcp, both load: run claude mcp remove opik-mcp to keep only the
plugin's. Skills from the skill pack also load next to the plugin's copies;
remove them with npx skills remove --global --agent claude-code, which asks
which ones.
Self-hosted and open-source Opik: the local server
opik-mcp runs on your machine: the client starts it with uvx opik-mcp and
talks to it over stdio. The Quick start command sets it up from
your ~/.opik.config or a local Opik; to register it by hand, see
Set it up by hand. Install uv once; it
fetches the package, and Python 3.13 if needed, on first use:
uvx opik-mcp reuses the copy uv has cached, so it starts quickly;
uv cache clean opik-mcp makes the next start fetch the newest release.
uvx opik-mcp@latest asks PyPI on every start, which adds about a second and a
half. Codex waits mcp_optional_startup_grace_ms (1 s by default) for servers
before it builds the first tool list, so a slower start can leave the tools out
of the first turn. The one-off commands in this README (opik mcp configure,
opik mcp status, --help, --check) carry @latest, so they never run a
copy uv cached months ago.
Env vars point the server at your Opik:
- Open source serves its API at
/apiand has one workspace,default, so it needs noOPIK_WORKSPACE.COMET_URL_OVERRIDEwould point the server at/opik/api, which open source does not serve. - A self-hosted Comet has named workspaces. Set
OPIK_WORKSPACEto the segment after/opik/in your Opik URL; left out, reads come from your account's default workspace, with no error to say so. - A self-hosted Comet that runs the MCP OAuth server (off by default) can use
the hosted flow instead, at
https://<host>/opik/api/v1/mcp. - Substitute every value. The server refuses a placeholder workspace such as
<your-workspace>or${input:OPIK_WORKSPACE}; a placeholder URL is sent as-is and fails to connect. OPIK_MCP_ANALYTICS_SOURCE=""in theenvblock opts a self-hosted install out of the cloud-Comet source label on telemetry events.
Before adding the server to a client, check the settings: run it with the same
env and --check. It makes one call to Opik and prints the workspace and how
many projects it sees, or what to fix with a link to the docs, and exits 0 or 1.
A client can't tell you this before a new session: Claude Code shows Connected
even with a wrong key, and Codex starts nothing until then.
Then register it with your client: the local server, by hand.
Install with a coding agent
For an AI agent asked to install the server, as in "install opik mcp". The aim
is the server registered for the user's Opik, the Opik skill pack installed,
and the user signed in. Work out which Opik from this machine, and ask the user
only what it can't tell you: one question per message, each answer before the
next. The installer in step 3 does the whole setup in one run, so settle steps
1 and 2 before you run it. uvx opik-mcp@latest --help prints these steps.
-
See what is there.
It shows the Opik saved in
~/.opik.config(URL and workspace, never the key) and the clients that already have the server. In Claude Code, also runclaude mcp list: it shows claude.ai connectors and entries under other names. It also prints each entry's command, which for an old npx entry can hold an API key: don't repeat it.- A server for
https://www.comet.com/opik/api/v1/mcpunder any name, such as a claude.ai connector, means it is registered: don't add a second one. Install the skill pack on its own withnpx skills add comet-ml/opik-skills -g --all. Go to step 4 if the server shows! Needs authentication. - The installer replaces an existing
opik-mcpentry without asking, such as one for the old npx server. Ask the user before you run it.
- A server for
-
Find the user's Opik.
- Saved in
~/.opik.config: use it, and tell the user which one you are setting up. The installer reads it, API key included, so don't ask for a key. - No
~/.opik.config:curl -s http://localhost:5173/api/is-alive/ping. An answer is an open-source Opik on this machine. In a sandboxed shell, such as Codex's, no answer can mean the shell has no network rather than no Opik. - Neither: ask, and don't pick one yourself. An Opik URL in the
project, such as
OPIK_URL_OVERRIDEin.env, makes it a yes-or-no question. Otherwise: "Which Opik do you use: Opik Cloud (www.comet.com), an open-source Opik (its URL), or a self-hosted Comet platform (its URL and workspace)?"
- Saved in
-
Run the installer for the client you run in. It installs the Opik skill pack with the server, with or without
--skills; keep the flag in a command you give the user to run later. On Opik Cloud it opens the browser sign-in and waits a minute for it, so tell the user first.--ai-clientalso takescodex,cursor,vscodeandopencode. For an Opik saved in~/.opik.configor running on localhost, run it as it is:--deploymentsets the saved config aside, API key included. With neither, add the flag for the Opik the user named in step 2:If it fails, as when the Opik doesn't answer, tell the user what it printed and what to check, such as a VPN or the URL. Don't switch to another Opik.
-
Sign-in, for Opik Cloud. If the installer reports the server as not signed in yet, give the user
claude mcp login opik-mcpto run, or/mcpin a Claude Code session, rather than running it yourself: it waits on the browser. A claude.ai connector signs in from/mcp. The sign-in asks for a workspace; name the one saved in~/.opik.config, if any. -
Finish. Say what was installed and what is left. Name the skill pack: the Opik skills, installed for every project, which teach the agent to instrument, evaluate and debug with Opik. Clients load MCP servers and skills when a session starts: ask the user to start a new session, then try "list my Opik projects".
On every path:
- Don't ask the user to paste an API key into the chat. The hosted server needs
none; otherwise take it from the shell environment (
"$OPIK_API_KEY"), or let the user run the command. - Don't guess the workspace. It is the segment after
comet.com/opik/(or/opik/on a self-hosted Comet) in the user's Opik URL. - Don't print
~/.claude.jsonor~/.opik.config: both can hold API keys.uvx opik@latest mcp statusandclaude mcp listshow what you need, and the installer reads the config itself. - If a permission check blocks a command, don't work around it. Give the user
the command to run (in Claude Code,
!before it runs it from the prompt).
For a client the installer doesn't know, register by hand with the commands in Set it up by hand: the hosted server for Opik Cloud, the local server for the rest.
- Before registering the local server, run it with the env you will pass and
--check, withOPIK_API_KEYexported in the shell rather than written on the command:OPIK_URL=http://localhost:5173/api uvx opik-mcp@latest --check. It exits 0 and names the workspace it sees, or prints what to fix. Once registered, Claude Code reports Connected even with a wrong key, and Codex has no check. - Claude Code refuses to add over an existing
opik-mcpentry, so remove it first withclaude mcp remove opik-mcp --scope user; Codex'saddreplaces it. - After registering, in Claude Code, read only the status line:
claude mcp get opik-mcp | grep Status. The full output prints theenvblock, API key included. The hosted server shows! Needs authenticationuntilclaude mcp login opik-mcphas run. Codex has nothing that starts the server before a session;codex mcp get opik-mcpshows what was stored, with env values masked.
Set it up by hand (no Opik check, no skill pack)
The Quick start command does all of this for Claude Code, Codex, Cursor, VS Code Copilot and opencode, and also checks which Opik you use and installs the skill pack. Register by hand only for another client, or to see what the installer writes. A coding agent installing for a user runs the installer: see Install with a coding agent.
Hosted server (Opik Cloud)
Claude Code, by hand
Then sign in from /mcp → Authenticate in a Claude Code session. It opens
a browser, so the person at the keyboard does it; from their own terminal,
claude mcp login opik-mcp does the same. --scope user makes the server available in every project; without
it, Claude Code registers it for the current directory only. Over SSH,
claude mcp login opik-mcp --no-browser prints the sign-in URL to open on your
own machine; the last step needs an interactive terminal (ssh -t).
Codex, by hand
add opens the sign-in; codex mcp login opik-mcp opens it again. In
~/.codex/config.toml the same server is:
Cursor, by hand
Use the button under the hosted server, or add to
~/.cursor/mcp.json:
VS Code Copilot, by hand
Use the button under the hosted server, or add to
.vscode/mcp.json in your workspace or to your
user mcp.json (MCP: Open User Configuration):
Other clients
Any client that takes a URL can use the hosted server:
A client that can only start local commands can reach it through
npx -y mcp-remote https://www.comet.com/opik/api/v1/mcp.
Opik Cloud with an API key
Where nobody can complete the browser sign-in, as when an agent runs unattended
from a script or a client has no MCP OAuth support, use an API key from
comet.com/api/my/settings/ instead,
with the local server
pointed at Opik Cloud:
The other clients take the same two variables in their env block. Set
OPIK_WORKSPACE to the segment after comet.com/opik/ in your Opik URL
(https://www.comet.com/opik/acme-ai/projects → acme-ai). Left out, the
server sends default, which Comet resolves to your account's default
workspace, so reads can come from the wrong workspace without an error.
Local server (self-hosted and open-source Opik)
The examples use a local open-source Opik. For a self-hosted Comet, swap in the three variables from the table. After adding the server, start a new session and ask: "list my Opik projects".
Claude Code, by hand
On a self-hosted Comet, with the key in your shell's OPIK_API_KEY:
Or edit ~/.claude.json directly:
claude mcp get opik-mcp shows ✔ Connected once the server starts. That does
not prove the URL or key are right, because only a tool call reaches Opik;
--check (the local server) does. It also prints the env block, API key included.
Codex, by hand
Or edit ~/.codex/config.toml:
Codex gives a local server only the variables in env and the names in
env_vars, so a key exported in your shell does not reach it otherwise.
Cursor, by hand
Add to ~/.cursor/mcp.json (global) or .cursor/mcp.json (project), or use
Cmd+Shift+J → Features → Model Context Protocol:
Cursor 60s timeout. Cursor enforces a hard tool-call timeout that doesn't reset on progress notifications. See Known host limits.
VS Code Copilot, by hand
Add to .vscode/mcp.json in your workspace, or to your user mcp.json
(MCP: Open User Configuration):
MCP Inspector (manual testing)
Coming from npx opik-mcp?
The TypeScript server (npm opik-mcp@2) is deprecated and stops serving
requests on 2026-11-15. For a new install, run the
Quick start command; uvx opik-mcp is the command a client runs
to start the server, not an installer. To move an existing config on Opik Cloud,
switch to the hosted server and drop the API key. Otherwise, in your MCP client
config, replace npx -y opik-mcp with uvx opik-mcp. Some env vars were renamed and command-line flags are no
longer read: see the migration
guide.
Support policy: DEPRECATED.md.
The TypeScript source is at the git tag legacy-typescript-final.
Tools
opik-mcp exposes a small, outcome-oriented surface that covers the full
lifecycle (read → annotate → curate → author → iterate).
read
One tool for any "show me X" question. Takes an entity_type plus an id
(UUID or, for nameable types, a name) or a full opik:// URI. Composite reads
(trace, prompt, thread, agent_insights_issue) inline their children so
a single call returns the full picture.
The record you name comes back whole. Inlined children do not: their bodies
are fetched with the backend's truncate=true, so a field over ~10 KB is cut
in ClickHouse and base64 images are replaced with "[image]" — one attachment
echoed across 200 spans would otherwise cost more than everything else in the
read. The answer says so in spanBodies / messageBodies, and any child is
whole again through its own read("span", id) or read("trace", trace_id),
which hit endpoints that have no truncate parameter at all.
An inlined collection is also bounded in length: 200 spans, 200 turns, 100
prompt versions. Past that, spansTruncated / messagesTruncated /
versionsTruncated is true and a moreSpans / moreMessages /
moreVersions line beside it carries the count and the exact list(...) call
that continues from where the inlined part stopped.
Supported entities: project, trace, span, dataset, dataset_item,
experiment, prompt, thread, agent_insights_issue. Name-based lookup is
available for project, experiment, prompt, dataset (slower — two API
calls — and may return multiple matches). thread and agent_insights_issue
are project-scoped: pass project_id or project_name, or a link/URI that
carries the project. dataset and dataset_item were called test_suite and
test_suite_item before; the old names still resolve, but they are not
advertised and new code should use the new ones.
A link copied from the Opik UI works as the id: a thread link or a
Diagnostics page link carries the project, so no project_id is needed and
the entity type is taken from the link.
A project read answers "how is my project doing" in one call. It returns
{project, summary, vocabulary, contains, url}: the record, then the four
figures the Logs page shows as cards (trace count, error rate, average
duration, total cost) for the last 7 days against the 7 before, SDK traffic
only, as on screen. since / until move that window; since="30d" is what
the UI opens on. A rate or an average over a period with no traces comes back
as null, because 0% errors on a week with no traffic reads as a healthy week.
vocabulary is the map you need before you can ask anything else: the
project's feedback score names, its token usage keys, and the automation rules
scoring its traces. These are the names that go into a filter or into
series= below, and guessing them returns an empty page that reads like good
news. Score names and rules are capped, always report the true total, and name
the call that returns the rest; usage keys are listed in full, since nothing
else enumerates them. contains names the freshest experiment, dataset, prompt
version and optimization run, so "what has been happening here" does not need
four more calls. A part that failed to load says so instead of looking empty,
and an empty one is omitted.
An agent_insights_issue read returns {issue, example_trace_ids, details}:
the Diagnostics issue record (name, description, cause, suggested fix,
severity, status), the deduplicated ids of the traces that exhibit it (the
same sample the Diagnostics page shows — open one with read("trace", id)),
and the per-day breakdown. Trace bodies are not inlined, so the read stays one
backend call. since / until narrow the per-day rows; the default is
all-time. When the server knows the Opik URL and the session's workspace, the
read also carries url (the issue's Diagnostics page) and trace_url_template
(a deep link for any of the example traces), so the assistant can hand you
something clickable; under an OAuth session whose workspace could not be
resolved the links are omitted rather than guessed.
Traces themselves carry no URL — a link for one is not derivable from the
fields a read or list returns, and a guessed shape 404s. The session
instructions name a template for it instead,
.../v1/session/redirect/projects/?trace_id={trace_id}&path=..., so the
assistant fills in an id and hands you a link. It goes through opik-backend's
redirect, which resolves the project and the workspace from the trace, so it
works where a direct project URL cannot, an OAuth session with an unresolved
workspace included. It is the same link the Python SDK prints for a trace.
list
Browse or search a collection with pagination. Project-scoped types (trace,
span, thread, agent_insights_issue, dataset_item, prompt_version)
need their parent: a project UUID or name, a dataset UUID, or a prompt UUID.
Filters. trace, span, thread, experiment and dataset_item take an
OQL string, the same grammar as the SDK's search_traces(filter_string=…):
Strings go in double quotes, numbers are bare, duration is in milliseconds,
dates are ISO-8601 instants with a timezone ("2026-09-08T10:00:00Z").
Scores and dictionaries take a key: feedback_scores.accuracy < 0.5,
metadata.environment = "prod". AND is the only connector.
Like the UI's Logs page, trace, span and thread lists add source = "sdk" so
evaluator, playground and experiment traces stay out of the way; name source
yourself to see them. The first output line echoes the filter that was applied.
A bad filter fails before reaching the backend with what is needed to fix it:
the position of a syntax error, the closest field name, the valid operators for
the field's type, or the expected value format. Fields with a closed set of
values (source, span type, thread status, visibility_mode) are checked
against it too, every element of an in list included. source is the one the
backend validates itself, and it answers an unknown value with a 500 rather
than a 400, so source = "SDK" would otherwise be an opaque server error for a
capital letter. The rest are compared as strings and answer with an empty page,
which reads as "no matches" when it means "no such value". Ask
schema("list.trace") (or list.span, list.thread, list.experiment) for
the full field reference, accepted values included.
Finding one case in a dataset. list(entity_type="dataset_item", dataset_id=…) filters on the case itself: data.<key> for the keys the
dataset was built with, full_data for a substring of the whole payload (a
full scan — name a key when you can), plus id, tags, source, trace_id,
span_id and the timestamps. data.<key> takes the six string operators only
(=, !=, contains, not_contains, starts_with, ends_with); the
backend answers a comparison with a 400, so this one is refused before the
call. The endpoint has no sorting and no free-text search — sort is refused
rather than dropped. read(entity_type="dataset_item", id=…) returns one case
whole, which is how a value the table cut is read back.
With experiment_ids the same list is the comparison instead — the cases with
each run attached — and it filters on the runs (feedback_scores.<name>,
output, duration). The two are different field sets on two backend
endpoints: schema("list.dataset_item_case") is the dataset's own cases,
schema("list.dataset_item") the comparison.
Sort. trace, span, thread and experiment take
sort="<field> [asc|desc]", desc by default and one field only:
sort="duration desc", sort="total_estimated_cost",
sort="feedback_scores.accuracy asc", sort="usage.total_tokens". The field is
checked against the entity's sortable list before the call, because the backend
silently ignores fields it cannot sort by. On very large workspaces the backend
drops sorting altogether; the header says so when that happens.
dataset_item sorts only as a comparison (with experiment_ids): the items
endpoint takes no sorting parameter, so a sort on a plain listing is refused
rather than dropped.
Time window and search. trace, span and thread take since and
until, each a relative span ("30m", "1h", "7d") or an ISO-8601 instant
with a timezone, so "the last hour" needs no clock arithmetic. The window is by
record creation time, which is cheap for the backend and agrees with
start_time within seconds for live traffic. For an exact bound, put
start_time in filters. The same three types take search, free text matched
anywhere in id, name, input, output, metadata, tags and thread id. Search scans
the whole project on the backend, so the first call on a large project can take
tens of seconds. Those calls get a 60-second timeout. Adding since makes them
fast again.
Reading the table. Durations are labelled duration_ms / ttft_ms and
shown as whole milliseconds; the field stays duration in filters and
sort. Timestamps are shown to the second and costs as plain decimals.
Project rows carry last_updated_trace_at so you can see which project has
live traffic; thread rows carry the first message. An empty page under a time
window says when the project's last trace landed, and an empty page under the
default source = "sdk" says how to see the other sources. A misspelled
project_name comes back with the closest existing name.
Diagnostics issues. agent_insights_issue is the Diagnostics page over
the MCP: the recurring failures Opik's Diagnostics job grouped for a project,
ranked as the UI ranks them (most recently seen first). Columns are severity,
status, total_occurrences (all-time sum), latest_count (the most recent
report day, the number the issue's own description refers to) and last_seen.
Open issues are listed by default; pass status="resolved" or "closed" for
the rest. read and list also answer to issue, which is what the UI calls
these; the long name is the one in the entity_type enum, so that one entity
does not appear there twice. Counts are all-time so they match the UI; the same since / until
as for traces narrow the window, truncated to UTC report days because
Diagnostics aggregates per day.
An empty list says why it is empty, because "nothing is broken" and "nobody turned Diagnostics on" read the same otherwise. There are five states: Diagnostics is unavailable on this deployment, not enabled for this project, turned off, enabled but not scanned recently, or enabled and clean with the time of the last scan. The ones you can act on name the call to make, and every state links the project's Diagnostics page.
A non-empty list dates itself. The issues are whatever the last scan grouped,
so the reply ends with Report covers data through <time>, and when the window
you asked about runs past that, it names the uncovered tail and how to close
it: a trigger when a rescan reaches back far enough, otherwise raw traces with
the since it gives you. Ask for a week on a project scanned nightly and the
last day is missing from the grouped answer; this is what says so.
write("agent_insights_job.enable", {"project_name": "demo"}) turns Diagnostics
on. It scans daily from then on, and calling it again is safe.
write("agent_insights_job.trigger", …) scans the last 24 hours now, without
waiting for the nightly run. Both take the permission that reading issues takes,
and both refuse where the deployment has no Diagnostics.
An issue moves through its lifecycle with
write("agent_insights_issue.resolve", {"issue_id": "<uuid>", "project_name": "demo"})
— dealt with — or …close for one not worth acting on, and …reopen to put
either back on the open list. All three take the same permission and answer
with a link to the view the issue moved to, since a resolved issue is no longer
on the default page. Whether a failure is fixed is a judgment call, so these
are for when you ask: the assistant has no business tidying the list while
triaging it.
Metrics over time. project_metric charts one metric for a project as a
table of time buckets: trace, span and thread counts, durations, error rates,
costs, token usage and feedback scores. It answers the question that follows
the overview, which is when something changed.
Rows are time buckets, not records, so page, size and sort are refused
rather than ignored. interval is hourly, daily, weekly or total;
left out, it follows the window the way the Metrics tab does — hourly up to 3
days, daily up to 30, weekly beyond — so a default chart is a few dozen rows
whatever the range, and an hourly month (721 rows) is something you ask for.
since / until take the same forms as everywhere else and default to the
last 7 days. filters uses the fields of whichever entity the metric is
about, so a span metric is filtered by span fields.
breakdown splits each bucket by tags, name, error_info, error_type,
model, provider, span_type, guardrail_name or metadata.<key>. Not
every metric accepts every one of those, and seven accept none at all; the tool
knows which and says so before calling the backend, naming a metric that does
answer the same question where one exists. Three families come back as several
series at once (a duration as p50/p90/p99, a feedback score per name, token
usage per key), and the backend charts one of them at a time when grouping, so
series= picks it: a percentile, a score name, or a usage key. Duration
defaults to p50 and token usage to total_tokens, and whichever was used is
echoed on the first line.
Empty buckets are left out and counted underneath, so a quiet month is a few rows instead of a column of zeros, and a rate over a bucket with no traces is absent rather than reported as zero.
Ask schema("list.project_metric") for the metric table, the intervals and the
per-metric grouping matrix.
A project's names. score_name lists the feedback score names recorded in
a project and online_rule the automation rule evaluators configured on it,
which is where most of those names come from. Both are the same lists
read("project", …) carries, in full and paginated, for when the capped
version in the overview is not enough.
write
Universal write dispatcher. Pass operation + data and the dispatcher
validates the payload, applies the right REST verb, and returns the
backend response.
Operations:
schema
Inspect the exact JSON shape and required fields of any write operation before
you call it — useful when you're not sure what data should look like. Returns
the schema, OAuth scope, and one validated example. Pure lookup, no backend
call.
The same tool answers list.trace, list.span, list.thread and
list.experiment with the list tool's reference for that entity: every
filterable field with its type and valid operators, the sortable fields, whether
a time window and free-text search apply, and two example filters.
Configuration
These configure the local server; every setting is an environment variable. The hosted server on Opik Cloud takes none of them.
Identity / endpoint
Server / transport
Choosing a transport
Two bearer shapes, two contracts on HTTP transport. An opik_mcp_at_… OAuth
access token is validated on every request against opik-backend's token
introspection endpoint (cached, see OPIK_MCP_OAUTH_VALIDATION_CACHE_TTL_S);
an expired or revoked token gets an HTTP 401 with
WWW-Authenticate: Bearer error="invalid_token", which is what MCP hosts key
their silent refresh_token grant on. An Opik API key is not validated
locally: it is forwarded verbatim to opik-backend, which is its single point
of enforcement. Pick the transport by deployment shape:
Note for local OSS installs: the OSS backend does not authenticate requests,
so an HTTP opik-mcp in front of it is as open as the OSS REST API itself.
Keep the default 127.0.0.1 bind (and prefer stdio) on shared networks.
Telemetry
Known host limits
Hosts differ in how long they let a single tool call run:
- Claude Code — no documented tool-call timeout. Recommended.
- Cursor — hard 60s timeout that does not reset on progress (upstream bug).
- MCP Inspector —
MAX_TOTAL_TIMEOUTbounds total duration (default 60s). Raise it in the Inspector UI for long operations.
If a call gets stuck, set OPIK_MCP_LOG_LEVEL=DEBUG for the full request log.
Troubleshooting
Does the setup work? Run the server with the env from its client config and
--check: OPIK_URL=http://localhost:5173/api uvx opik-mcp@latest --check. It
names the workspace and the projects it sees, or says what to fix. The server's
own errors also say what to change, and link the docs page for it.
OPIK_API_KEY isn't picked up — the var isn't reaching the server
process. In Claude Code / Cursor / VS Code, env vars only apply when inside
the env block of the MCP server config, not your shell; Codex also forwards
the names listed in env_vars. Start a new session after editing, since
clients read the config when a session starts.
Requests go to /opik/api on an open-source Opik — COMET_URL_OVERRIDE is
for a self-hosted Comet platform. Open source serves its API at /api: set
OPIK_URL=http://localhost:5173/api (or https://<host>/api) instead. The
server warns about this at startup when the host is this machine, and --check
answers "No Opik API at …".
Cursor call times out at 60s — Cursor's known bug, not opik-mcp. Either
narrow the call (smaller size, a tighter window), or run the same operation
on Claude Code which has no hard cap.
Server not showing, sign-in not opening, wrong workspace, uvx not found.
These are covered in the troubleshooting section of the docs.
uvx opik@latest mcp status lists every client that has the server configured
and whether its config has drifted.
Development
Common targets:
Repo layout:
Get help
- Open an issue for bugs and feature requests
- Opik docs for SDK / backend documentation
- Comet community Slack for questions
License
Apache-2.0.
来源:README.md,提交 50d750f
工具
0版本历史
9- v3.0.9最新Nov 7, 2026
- v3.0.8Oct 29, 2026
- v3.0.7Oct 23, 2026
- v3.0.6Oct 19, 2026
- v3.0.5Oct 8, 2026
- v3.0.4Oct 8, 2026
- v3.0.1Oct 7, 2026
- v3.0.0Oct 5, 2026
- v2.0.2Sep 16, 2026
评分
已满足适用检查项的 85%
该评分衡量此收录条目的完整程度,依据注册中心条目、端点与公开来源计算得出。它不是对服务器本身的评价,也不表示服务器安全或当前可用:可连通性是带日期的检查结果,评分也不包含安装量或用户评价。
- 近 30 天内可连通必需25 分
- 已声明认证方式必需10 分
- 已列出工具15 分
请让服务器在无凭据时响应 tools/list,或发布可在沙箱中无凭据启动的软件包。
- 描述必需15 分
- 图标10 分
- 文档15 分
- 许可证10 分