opik
Log Claude Code sessions to Opik for LLM observability, plus skills and agents for building observable AI applications. Opik is the open-source LLM observability and evaluation platform, built by Comet.
The official Model Context Protocol (MCP) server for Opik, the open-source LLM observability and evaluation platform, built by Comet.
> /plugin marketplace add comet-ml/opik-mcp> /plugin install opik@opik
Repo: comet-ml/opik-mcp
What's inside
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.
Migrating from the old
npx opik-mcp? The TypeScript server is deprecated and sunsets on 2026-11-15. Swapnpx -y opik-mcpforuvx opik-mcp@latestin your MCP client config. Full guide: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
One command registers the server with the AI clients on your machine, installs
the Opik skill pack, and verifies the connection. It needs uv
and no Opik SDK:
uvx opik mcp configure
It detects Claude Code, Cursor, VS Code Copilot, Codex and opencode, and uses the hosted server on Opik Cloud (browser sign-in, no API key stored) or this local server elsewhere. Any other MCP client can take the hosted URL directly:
npx add-mcp https://www.comet.com/opik/api/v1/mcp --name opik-mcp
Setup guide, troubleshooting and FAQ: comet.com/docs/opik/mcp-server. The rest of this README covers the local server, which the command above sets up for self-hosted and open-source Opik, and which you can also configure by hand.
opik-mcp is a Python package (requires Python 3.13+). The recommended way to
run it is uvx, which fetches and runs the latest published version on demand —
no global install, no virtualenv juggling.
Install uv once:
curl -LsSf https://astral.sh/uv/install.sh | sh # macOS / Linux
# or: brew install uv
You'll need two things from your Opik workspace:
OPIK_API_KEY — get it from comet.com/api/my/settings/.OPIK_WORKSPACE — your workspace name (lowercase, as it appears in the URL). E.g. https://www.comet.com/acme-ai/... → OPIK_WORKSPACE=acme-ai. COMET_WORKSPACE is accepted as a deprecated alias.Cloud, with an API key: set it unless your account default is the one you want. Left out, the server sends
default, which Comet resolves to your account's default workspace. That works, but if you actually work in a named workspace you will be pointed at a different one with nothing to tell you — your reads come back from the wrong place rather than failing.Cloud, over OAuth: leave it unset. The workspace comes from the token you authorized, and the server ignores this setting entirely.
Local / open source: leave it unset. Open source Opik has a single workspace named
defaultand no way to create others, which is exactly what the fallback gives you.Self-hosted Comet: set it. Unlike open source, these deployments have real named workspaces, and the same silent-wrong-workspace risk applies.
Whichever applies, make sure the value is actually substituted. Snippets in the wild ship placeholders like
<your-workspace>or${input:OPIK_WORKSPACE}; pasted as-is, those are not workspace names. The server now refuses them outright rather than letting the backend answer with an auth error that explains nothing.
Add the server with one command:
claude mcp add --transport stdio opik-mcp \
--env OPIK_API_KEY=<your-key> \
--env OPIK_WORKSPACE=<your-workspace> \
-- uvx opik-mcp
Or edit ~/.claude.json directly:
{
"mcpServers": {
"opik-mcp": {
"type": "stdio",
"command": "uvx",
"args": ["opik-mcp"],
"env": {
"OPIK_API_KEY": "<your-key>",
"OPIK_WORKSPACE": "<your-workspace>"
}
}
}
}
Restart Claude Code. Verify with /mcp — opik-mcp should appear as connected.
Then, in the chat, ask: "list my Opik projects" — Claude will call the list
tool and you'll see your workspace's projects.
Edit ~/.cursor/mcp.json (global) or .cursor/mcp.json (project), or open
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>"
}
}
}
}
Reload Cursor; the green dot next to opik-mcp in the MCP panel confirms the
connection. Ask in chat: "list my Opik projects".
Cursor 60s timeout. Cursor enforces a hard tool-call timeout that doesn't reset on progress notifications. See Known host limits.
.vscode/mcp.json in your workspace (or User Settings JSON):
{
"servers": {
"opik-mcp": {
"type": "stdio",
"command": "uvx",
"args": ["opik-mcp"],
"env": {
"OPIK_API_KEY": "<your-key>",
"OPIK_WORKSPACE": "<your-workspace>"
}
}
}
}
Reload the window; the Copilot Chat MCP indicator shows opik-mcp once
the server is reachable. Ask in chat: "list my Opik projects".
OPIK_API_KEY=<your-key> OPIK_WORKSPACE=<your-workspace> \
npx @modelcontextprotocol/inspector uvx opik-mcp
Add COMET_URL_OVERRIDE (and OPIK_URL if Opik lives at a non-default path) to
the same env block in your host config:
{
"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": ""
}
}
}
}
Omit OPIK_WORKSPACE on an open-source deployment, where default is the only
workspace; keep it on a self-hosted Comet, which has real named ones.
Setting OPIK_MCP_ANALYTICS_SOURCE="" opts your install out of the
cloud-Comet source label on telemetry events.
opik-mcp exposes a small, outcome-oriented surface that covers the full
lifecycle (read → annotate → curate → author → iterate).
| Tool | Purpose |
|---|---|
read | Universal read by id / name / opik:// URI |
list | Universal list with optional name filter + pagination |
write | Universal write — log traces/spans, score, comment, save prompts, manage datasets & experiments |
schema | Introspect write-operation schemas (used by the LLM to construct valid payloads) |
read_skill | Read one of the Opik agent skills bundled with this server |
readOne 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, 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.
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>")
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
Log Claude Code sessions to Opik for LLM observability, plus skills and agents for building observable AI applications. Opik is the open-source LLM observability and evaluation platform, built by Comet.
FAQ
opik-mcp is a Claude Code plugin with 9 hand-picked skills for development work, indexed on Flowy. Install it with the command on its page. It includes opik-compare, opik-diagnose, opik-evaluate. Its skills do not fire on their own yet. Request auto-invocation to have Flowy route them as you prompt. Free and open source.
Is this plugin yours?
Claim it with GitHubSubmit a pluginPromote it