Comet Opik
offiziellFragen Sie Ihre Opik-Logs, Traces, Prompts und alle anderen Telemetriedaten Ihrer LLMs in natürlicher Sprache ab und analysieren Sie diese.
Was kann man mit Comet Opik MCP machen?
- Abfragen von Traces nach Projekt — Frage, welche Traces in einem Projekt heute fehlgeschlagen sind, mit Filtern für Fehlerinformationen, Dauer oder Tokenverbrauch.
- Beliebige Opik-Entität lesen — Rufe ein Projekt, einen Trace, einen Span, ein Dataset, ein Experiment, einen Prompt, einen Thread oder ein Diagnostics-Problem anhand der ID, des Namens oder der
opik://-URI ab. - Scores und Kommentare protokollieren — Bewerte einen Trace anhand einer Feedback-Metrik mit einer Begründung oder füge über das Schreibtool Kommentare hinzu.
- Prompt-Versionen speichern — Erstelle und speichere neue Prompt-Versionen zusammen mit Datasets und Experimenten.
- Schreibschemas prüfen — Frage nach dem Schema eines Schreibvorgangs, um vor dem Senden eine gültige Payload zu erstellen.
- Projektstatus prüfen — Lies ein Projekt aus, um Trace-Anzahl, Fehlerrate, durchschnittliche Dauer und Gesamtkosten der letzten 7 Tage abzurufen.
Dokumentation
Opik MCP Server
Der offizielle Model Context Protocol (MCP)-Server für Opik, die Open-Source-Plattform für LLM-Beobachtbarkeit und -Evaluierung, entwickelt von Comet. Verbinde deinen KI-Host (Claude Code, Cursor, VS Code Copilot, Codex, opencode oder einen beliebigen MCP-Client) direkt mit deinem Opik-Arbeitsbereich: Lies Traces, protokolliere Scores und speichere Prompt-Versionen – alles direkt im Chat.
Entwickelt für LLM-Entwickler, die Opik bereits nutzen und es über denselben KI-Assistenten steuern möchten, mit dem sie programmieren.
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
Schnellstart
Mit einem Befehl richtest du Opik in den KI-Clients auf deinem Rechner ein, einschließlich Claude Code.
Der Befehl findet deine Opik-Instanz (die in ~/.opik.config gespeicherte, eine auf
localhost laufende oder fragt dich, welche du verwenden möchtest), registriert den MCP-Server,
installiert das Opik-Skill-Paket und überprüft die Verbindung. Bei Opik Cloud musst du keinen API-Schlüssel
verwalten: Dein Client meldet dich im Browser an. Benötigt werden uv
und kein Opik SDK:
uvx opik@latest mcp configure
Ohne Terminal, etwa über einen Coding-Agenten oder ein Skript, gib den Client an:
uvx opik@latest mcp configure --ai-client claude-code --skills
--ai-client akzeptiert außerdem codex, cursor, vscode und opencode. Bei dieser
Ausführung wird die in ~/.opik.config gespeicherte Opik-Instanz samt API-Schlüssel verwendet oder eine
auf localhost erreichbare. Andernfalls wird abgebrochen und nach --deployment gefragt.
Ein Coding-Agent, der mit „install opik mcp“ beauftragt wird, erhält unter
uvx opik-mcp@latest --help die vollständigen Schritte, einschließlich der Fragen an den Benutzer.
Sie entsprechen den Anweisungen unter
Installation mit einem Coding-Agenten.
Wenn du den Server manuell mit den Client-Befehlen unter Manuelle Einrichtung registrierst, werden die verwendete Opik-Instanz nicht überprüft und das Skill-Paket nicht installiert. Das ist daher für Clients gedacht, die vom Installer nicht unterstützt werden.
| Deine Opik-Instanz | Server | Transport | Anmeldung |
|---|---|---|---|
Opik Cloud (www.comet.com) | der gehostete Server, betrieben von Comet | Streamable HTTP | im Browser (OAuth); kein API-Schlüssel |
| Selbst gehostete Comet-Plattform, Open-Source-Opik | der lokale Server, dieses Paket | stdio | Umgebungsvariablen; ein API-Schlüssel nur, wenn die Bereitstellung ihn benötigt |
Clients laden MCP-Server beim Start einer Sitzung. Starte daher anschließend eine neue Sitzung.
Einrichtungsanleitung, Fehlerbehebung und FAQ: comet.com/docs/opik/mcp-server.
Opik Cloud: der gehostete Server
Comet betreibt den Server unter https://www.comet.com/opik/api/v1/mcp. Dein Client
verbindet sich über HTTP und öffnet bei der ersten Verwendung ein Browserfenster zur Anmeldung. Es muss nichts
installiert und kein API-Schlüssel oder Arbeitsbereich eingerichtet werden: Der Server verwendet den
Arbeitsbereich, den du bei der Anmeldung auswählst. Füge ihn hinzu, starte eine neue Sitzung und
frage: „list my Opik projects“.
Mit dem Befehl unter Schnellstart richtest du den Server für Claude Code, Codex, Cursor, VS Code Copilot und opencode samt Skill-Paket ein. In Claude Code erledigt das Plugin dasselbe mit einem Befehl. Über die Schaltflächen unten kannst du ihn mit einem Klick zu Cursor oder VS Code hinzufügen. Weitere Möglichkeiten zur manuellen Registrierung findest du unter Manuelle Einrichtung.
Claude Code-Plugin
Das Plugin opik installiert die Opik-Skills und registriert den gehosteten MCP-Server
für Opik Cloud:
/plugin install opik --marketplace comet-ml/opik-mcp
Bei Claude Code vor Version 2.1.275 führe /plugin marketplace add comet-ml/opik-mcp und anschließend
/plugin install opik@opik aus. Die Skills werden als opik:<skill> geladen, zum Beispiel
opik:opik-instrument, und /mcp zeigt den Server als plugin:opik:opik-cloud an.
Der Server gehört zu Opik Cloud. Starte eine neue Sitzung und melde dich dann über /mcp →
Authenticate an. Für eine selbst gehostete Comet-Plattform, auf der der MCP-OAuth-Server läuft, füge
ihn mit claude mcp add --transport http opik-mcp https://<host>/opik/api/v1/mcp hinzu.
Für alle anderen selbst gehosteten oder Open-Source-Opik-Instanzen verwende den Befehl unter
Schnellstart. Deaktiviere anschließend plugin:opik:opik-cloud in
/mcp. Claude Code aktualisiert ein Plugin aus diesem Marketplace nicht automatisch:
Führe /plugin marketplace update opik und anschließend /plugin update opik@opik aus oder aktiviere die automatische
Aktualisierung des Marketplaces unter /plugin. Dieser Marketplace stellt main bereit,
das der letzten Veröffentlichung voraus sein kann. Ein Update wird erst bei einer Versionsänderung des Plugins
bereitgestellt, also mit jeder Veröffentlichung.
Wenn du zuvor opik-mcp unter derselben URL hinzugefügt hast, behält Claude Code deinen Eintrag
und überspringt den des Plugins. Wenn dein Eintrag ein anderer Server ist, etwa der lokale
uvx opik-mcp, werden beide geladen. Führe claude mcp remove opik-mcp aus, um nur den
des Plugins zu behalten. Die Skills aus dem Skill-Paket werden zusätzlich zu den Kopien des Plugins geladen.
Entferne sie mit npx skills remove --global --agent claude-code; dabei wirst du gefragt, welche Skills entfernt werden sollen.
Selbst gehostetes und Open-Source-Opik: der lokale Server
opik-mcp läuft auf deinem Rechner: Der Client startet ihn mit uvx opik-mcp und
kommuniziert über stdio mit ihm. Mit dem Befehl unter Schnellstart richtest du ihn
über dein ~/.opik.config oder eine lokale Opik-Instanz ein. Informationen zur manuellen Registrierung findest du unter
Manuelle Einrichtung. Installiere uv einmalig.
Beim ersten Start lädt es das Paket und bei Bedarf Python 3.13 herunter:
curl -LsSf https://astral.sh/uv/install.sh | sh # macOS / Linux
# or: brew install uv
uvx opik-mcp verwendet die von uv zwischengespeicherte Kopie erneut und startet daher schnell.
uv cache clean opik-mcp sorgt dafür, dass beim nächsten Start die neueste Version heruntergeladen wird.
uvx opik-mcp@latest fragt bei jedem Start PyPI ab, was etwa anderthalb Sekunden zusätzlich dauert.
Codex wartet mcp_optional_startup_grace_ms (standardmäßig 1 s) auf Server, bevor es die erste Tool-Liste erstellt.
Ein langsamerer Start kann dazu führen, dass die Tools im ersten Durchlauf fehlen.
Die einmaligen Befehle in dieser README (opik mcp configure,
opik mcp status, --help, --check) enthalten @latest.
Dadurch wird nie eine Kopie verwendet, die uv vor Monaten zwischengespeichert hat.
Umgebungsvariablen verweisen den Server auf deine Opik-Instanz:
| Deine Opik-Instanz | Umgebungsvariablen |
|---|---|
| Open-Source-Opik auf diesem Rechner | OPIK_URL=http://localhost:5173/api |
| Open-Source-Opik auf einem Server | OPIK_URL=https://<host>/api, außerdem OPIK_API_KEY nur, wenn die Bereitstellung eine Authentifizierung hinzufügt |
Selbst gehostete Comet-Plattform (die Opik-Benutzeroberfläche befindet sich unter https://<host>/opik) | COMET_URL_OVERRIDE=https://<host>, OPIK_WORKSPACE, OPIK_API_KEY |
- Open Source stellt seine API unter
/apibereit und hat einen Arbeitsbereich,default. Daher ist keinOPIK_WORKSPACEerforderlich.COMET_URL_OVERRIDEwürde den Server auf/opik/apiverweisen, das Open Source nicht bereitstellt. - Eine selbst gehostete Comet-Plattform hat benannte Arbeitsbereiche. Setze
OPIK_WORKSPACEauf das Segment nach/opik/in deiner Opik-URL. Wenn du es weglässt, werden Lesezugriffe aus dem Standardarbeitsbereich deines Kontos ausgeführt, ohne dass ein Fehler darauf hinweist. - Eine selbst gehostete Comet-Plattform, auf der der MCP-OAuth-Server läuft (standardmäßig deaktiviert), kann
stattdessen den gehosteten Ablauf unter
https://<host>/opik/api/v1/mcpverwenden. - Ersetze alle Werte. Der Server lehnt Platzhalter für Arbeitsbereiche wie
<your-workspace>oder${input:OPIK_WORKSPACE}ab. Eine Platzhalter-URL wird unverändert gesendet und die Verbindung schlägt fehl. OPIK_MCP_ANALYTICS_SOURCE=""im Blockenvverhindert, dass eine selbst gehostete Installation bei Telemetrieereignissen als Cloud-Comet gekennzeichnet wird.
Prüfe die Einstellungen, bevor du den Server zu einem Client hinzufügst: Starte ihn mit denselben
Umgebungsvariablen und --check. Dabei wird Opik einmal aufgerufen und der Arbeitsbereich sowie die Anzahl
der gefundenen Projekte ausgegeben. Bei Problemen wird angezeigt, was zu korrigieren ist, samt Link zur Dokumentation.
Der Befehl wird mit Exit-Code 0 oder 1 beendet. Ein Client kann das nicht vor einer neuen Sitzung überprüfen:
Claude Code zeigt auch bei einem falschen Schlüssel „Connected“ an, und Codex startet bis dahin nichts.
OPIK_URL=http://localhost:5173/api uvx opik-mcp@latest --check
Registriere ihn anschließend bei deinem Client: der lokale Server, manuell.
Installation mit einem Coding-Agenten
Für einen KI-Agenten, der mit der Installation des Servers beauftragt wird, etwa mit „install opik mcp“.
Ziel ist es, den Server für die Opik-Instanz des Benutzers zu registrieren, das Opik-Skill-Paket zu installieren
und den Benutzer anzumelden. Ermittle, welche Opik-Instanz auf diesem Rechner verwendet wird, und frage den Benutzer
nur nach Informationen, die du nicht selbst herausfinden kannst: eine Frage pro Nachricht und jede Antwort abwarten,
bevor du die nächste Frage stellst. Der Installer in Schritt 3 erledigt die gesamte Einrichtung in einem Durchlauf.
Kläre daher die Schritte 1 und 2, bevor du ihn ausführst. uvx opik-mcp@latest --help gibt diese Schritte aus.
-
Prüfe, was bereits vorhanden ist.
uvx opik@latest mcp statusDer Befehl zeigt die in
~/.opik.configgespeicherte Opik-Instanz (URL und Arbeitsbereich, niemals den Schlüssel) sowie die Clients, bei denen der Server bereits eingerichtet ist. Führe in Claude Code außerdemclaude mcp listaus: Der Befehl zeigt claude.ai-Connectoren und Einträge unter anderen Namen an. Er gibt auch den Befehl jedes Eintrags aus. Bei einem alten npx-Eintrag kann dieser einen API-Schlüssel enthalten: Gib ihn nicht weiter.- Ein Server für
https://www.comet.com/opik/api/v1/mcpunter einem beliebigen Namen, etwa als claude.ai-Connector, bedeutet, dass er bereits registriert ist. Füge keinen zweiten hinzu. Installiere nur das Skill-Paket mitnpx skills add comet-ml/opik-skills -g --all. Fahre mit Schritt 4 fort, wenn der Server als! Needs authenticationangezeigt wird. - Der Installer ersetzt einen vorhandenen Eintrag für
opik-mcpohne Rückfrage, etwa einen für den alten npx-Server. Frage den Benutzer, bevor du ihn ausführst.
- Ein Server für
-
Ermittle die Opik-Instanz des Benutzers.
- In
~/.opik.configgespeichert: Verwende sie und teile dem Benutzer mit, welche Instanz du einrichtest. Der Installer liest sie einschließlich des API-Schlüssels aus. Frage also nicht nach einem Schlüssel. - Kein
~/.opik.config:curl -s http://localhost:5173/api/is-alive/ping. Eine Antwort bedeutet, dass auf diesem Rechner eine Open-Source-Opik-Instanz läuft. In einer abgeschotteten Shell, etwa der von Codex, kann eine ausbleibende Antwort bedeuten, dass die Shell keinen Netzwerkzugriff hat und nicht, dass keine Opik-Instanz vorhanden ist. - Beides trifft nicht zu: Frage nach und wähle nicht selbst eine Instanz aus. Eine Opik-URL im Projekt,
etwa
OPIK_URL_OVERRIDEin.env, macht daraus eine Ja-Nein-Frage. Andernfalls frage: „Welche Opik-Instanz verwendest du: Opik Cloud (www.comet.com), eine Open-Source-Opik-Instanz (ihre URL) oder eine selbst gehostete Comet-Plattform (ihre URL und ihr Arbeitsbereich)?“
- In
-
Führe den Installer für den Client aus, in dem du arbeitest. Er installiert das Opik-Skill-Paket zusammen mit dem Server, mit oder ohne
--skills. Lass das Flag in einem Befehl stehen, den du dem Benutzer zur späteren Ausführung gibst. Bei Opik Cloud öffnet sich der Browser zur Anmeldung; der Installer wartet eine Minute darauf. Informiere den Benutzer daher vorher.uvx opik@latest mcp configure --ai-client claude-code --skills--ai-clientakzeptiert außerdemcodex,cursor,vscodeundopencode. Wenn eine Opik-Instanz in~/.opik.configgespeichert ist oder auf localhost läuft, führe den Befehl unverändert aus:--deploymentlegt die gespeicherte Konfiguration einschließlich des API-Schlüssels beiseite. Andernfalls füge das Flag für die in Schritt 2 genannte Opik-Instanz hinzu:Opik-Instanz des Benutzers Hinzufügen Opik Cloud, www.comet.com--deployment cloudOpen-Source-Opik --deployment local, und--url <url>, wenn sie nicht auf localhost läuftSelbst gehostete Comet-Plattform, /opik/in ihrer URL--deployment self-hosted --url <url> --workspace <workspace>, mitOPIK_API_KEYin der ShellSchlägt der Befehl fehl, etwa weil die Opik-Instanz nicht erreichbar ist, teile dem Benutzer die ausgegebene Meldung und die zu prüfenden Punkte mit, zum Beispiel VPN oder URL. Wechsle nicht zu einer anderen Opik-Instanz.
-
Anmeldung bei Opik Cloud. Wenn der Installer meldet, dass der Server noch nicht angemeldet ist, bitte den Benutzer,
claude mcp login opik-mcpoder in einer Claude Code-Sitzung/mcpauszuführen, statt den Befehl selbst auszuführen: Er wartet auf den Browser. Bei einem claude.ai-Connector erfolgt die Anmeldung über/mcp. Bei der Anmeldung wird nach einem Arbeitsbereich gefragt. Nenne den in~/.opik.configgespeicherten, falls vorhanden. -
Abschließen. Teile mit, was installiert wurde und was noch zu tun ist. Nenne das Skill-Paket: die Opik-Skills, die für jedes Projekt installiert werden und dem Agenten beibringen, Opik zur Instrumentierung, Evaluierung und Fehlersuche zu verwenden. Clients laden MCP-Server und Skills beim Start einer Sitzung. Bitte den Benutzer, eine neue Sitzung zu starten und anschließend „list my Opik projects“ auszuprobieren.
Für alle Fälle gilt:
-
Bitte den Benutzer nicht, einen API-Schlüssel in den Chat einzufügen. Der gehostete Server benötigt keinen. Andernfalls verwende den Schlüssel aus der Shell-Umgebung (
"$OPIK_API_KEY") oder lass den Benutzer den Befehl selbst ausführen. -
Rate nicht, welcher Arbeitsbereich verwendet wird. Er ist das Segment nach
comet.com/opik/(oder/opik/bei einer selbst gehosteten Comet-Plattform) in der Opik-URL des Benutzers. -
Gib
~/.claude.jsonoder~/.opik.confignicht aus: Beide können API-Schlüssel enthalten.uvx opik@latest mcp statusundclaude mcp listzeigen die benötigten Informationen an, und der Installer liest die Konfiguration selbst aus. -
Wenn eine Berechtigungsprüfung einen Befehl blockiert, umgehe sie nicht. Gib dem Benutzer den auszuführenden Befehl (in Claude Code muss er vor der Ausführung in der Eingabeaufforderung
!). Für einen Client, den das Installationsprogramm nicht kennt, registrieren Sie ihn manuell mit den Befehlen unter Manuell einrichten: den gehosteten Server für Opik Cloud, den lokalen Server für alle anderen. -
Bevor Sie den lokalen Server registrieren, führen Sie ihn mit der Umgebung aus, die Sie übergeben werden, und
--check, wobeiOPIK_API_KEYin der Shell exportiert und nicht im Befehl angegeben wird:OPIK_URL=http://localhost:5173/api uvx opik-mcp@latest --check. Der Prozess wird mit Exitcode 0 beendet und nennt den erkannten Workspace oder gibt an, was korrigiert werden muss. Nach der Registrierung meldet Claude Code „Connected“, selbst wenn der Schlüssel falsch ist, und Codex bietet keine Prüfung. -
Claude Code weigert sich, einen vorhandenen Eintrag
opik-mcpzu überschreiben. Entfernen Sie ihn daher zuerst mitclaude mcp remove opik-mcp --scope user; Codex'addersetzt ihn. -
Lesen Sie nach der Registrierung in Claude Code nur die Statuszeile:
claude mcp get opik-mcp | grep Status. Die vollständige Ausgabe gibt den Blockenvaus, einschließlich des API-Schlüssels. Beim gehosteten Server wird! Needs authenticationangezeigt, bisclaude mcp login opik-mcpausgeführt wurde. Bei Codex gibt es nichts, womit der Server vor einer Sitzung gestartet wird;codex mcp get opik-mcpzeigt die gespeicherten Werte an, wobei Umgebungsvariablen maskiert sind.
Manuell einrichten (ohne Opik-Prüfung, ohne Skill-Paket)
Der Befehl Schnellstart erledigt all dies für Claude Code, Codex, Cursor, VS Code Copilot und opencode und prüft außerdem, welches Opik Sie verwenden, und installiert das Skill-Paket. Registrieren Sie den Server nur für einen anderen Client manuell oder wenn Sie sehen möchten, was das Installationsprogramm schreibt. Ein Coding-Agent, der für einen Benutzer installiert, führt das Installationsprogramm aus: siehe Mit einem Coding-Agent installieren.
Gehosteter Server (Opik Cloud)
Claude Code, manuell
claude mcp add --scope user --transport http opik-mcp https://www.comet.com/opik/api/v1/mcp
Melden Sie sich anschließend in einer Claude-Code-Sitzung über /mcp → Authenticate an. Dabei wird
ein Browser geöffnet, sodass die Person an der Tastatur den Vorgang ausführt. Im eigenen Terminal
führt claude mcp login opik-mcp dasselbe aus. Mit --scope user ist der Server in jedem Projekt verfügbar; ohne
diese Option registriert Claude Code ihn nur für das aktuelle Verzeichnis. Über SSH
gibt claude mcp login opik-mcp --no-browser die Anmelde-URL aus, die Sie auf Ihrem
eigenen Rechner öffnen. Für den letzten Schritt ist ein interaktives Terminal erforderlich (ssh -t).
Codex, manuell
codex mcp add opik-mcp --url https://www.comet.com/opik/api/v1/mcp
add öffnet die Anmeldung; codex mcp login opik-mcp öffnet sie erneut. In
~/.codex/config.toml sieht derselbe Server so aus:
[mcp_servers.opik-mcp]
url = "https://www.comet.com/opik/api/v1/mcp"
Cursor, manuell
Verwenden Sie die Schaltfläche unter dem gehosteten Server oder fügen Sie Folgendes zu
~/.cursor/mcp.json hinzu:
{
"mcpServers": {
"opik-mcp": {
"url": "https://www.comet.com/opik/api/v1/mcp"
}
}
}
VS Code Copilot, manuell
Verwenden Sie die Schaltfläche unter dem gehosteten Server oder fügen Sie Folgendes zu
.vscode/mcp.json in Ihrem Workspace oder zu Ihrer
Benutzerkonfiguration mcp.json hinzu (MCP: Open User Configuration):
{
"servers": {
"opik-mcp": {
"type": "http",
"url": "https://www.comet.com/opik/api/v1/mcp"
}
}
}
Andere Clients
Jeder Client, der eine URL akzeptiert, kann den gehosteten Server verwenden:
npx add-mcp https://www.comet.com/opik/api/v1/mcp --name opik-mcp
Ein Client, der nur lokale Befehle starten kann, erreicht ihn über
npx -y mcp-remote https://www.comet.com/opik/api/v1/mcp.
Opik Cloud mit einem API-Schlüssel
Wenn niemand die Browser-Anmeldung abschließen kann, etwa wenn ein Agent unbeaufsichtigt
über ein Skript ausgeführt wird oder ein Client MCP OAuth nicht unterstützt, verwenden Sie stattdessen einen API-Schlüssel von
comet.com/api/my/settings/,
und richten Sie den lokalen Server
auf Opik Cloud aus:
claude mcp add --scope user opik-mcp \
--env OPIK_API_KEY="$OPIK_API_KEY" \
--env OPIK_WORKSPACE=<workspace> \
-- uvx opik-mcp
Die anderen Clients verwenden dieselben beiden Variablen in ihrem Block env. Setzen Sie
OPIK_WORKSPACE auf den Abschnitt nach comet.com/opik/ in Ihrer Opik-URL
(https://www.comet.com/opik/acme-ai/projects → acme-ai). Wenn der Wert fehlt, sendet der
Server default, das Comet dem Standard-Workspace Ihres Kontos zuordnet. Dadurch können Lesevorgänge ohne Fehlermeldung aus dem falschen Workspace stammen.
Lokaler Server (selbst gehostetes und Open-Source-Opik)
Die Beispiele verwenden ein lokales Open-Source-Opik. Bei einem selbst gehosteten Comet ersetzen Sie die drei Variablen durch die Werte aus der Tabelle. Starten Sie nach dem Hinzufügen des Servers eine neue Sitzung und fragen Sie: „list my Opik projects“.
Claude Code, manuell
claude mcp add --scope user opik-mcp --env OPIK_URL=http://localhost:5173/api -- uvx opik-mcp
Bei einem selbst gehosteten Comet mit dem Schlüssel in der Shell-Variablen OPIK_API_KEY:
claude mcp add --scope user opik-mcp \
--env COMET_URL_OVERRIDE=https://<host> \
--env OPIK_WORKSPACE=<workspace> \
--env OPIK_API_KEY="$OPIK_API_KEY" \
-- uvx opik-mcp
Oder bearbeiten Sie ~/.claude.json direkt:
{
"mcpServers": {
"opik-mcp": {
"type": "stdio",
"command": "uvx",
"args": ["opik-mcp"],
"env": {
"OPIK_URL": "http://localhost:5173/api"
}
}
}
}
claude mcp get opik-mcp zeigt ✔ Connected an, sobald der Server startet. Das
beweist nicht, dass URL oder Schlüssel korrekt sind, denn nur ein Tool-Aufruf erreicht Opik;
--check (der lokale Server) tut dies. Außerdem gibt der Befehl den Block env aus, einschließlich des API-Schlüssels.
Codex, manuell
codex mcp add opik-mcp --env OPIK_URL=http://localhost:5173/api -- uvx opik-mcp
Oder bearbeiten Sie ~/.codex/config.toml:
[mcp_servers.opik-mcp]
command = "uvx"
args = ["opik-mcp"]
env = { OPIK_URL = "http://localhost:5173/api" }
# On a self-hosted Comet, forward the key from the environment Codex starts in,
# so it stays out of this file:
# env_vars = ["OPIK_API_KEY"]
# Time allowed for the server to start (default 10 s); the first start
# downloads the package.
startup_timeout_sec = 30
Codex übergibt einem lokalen Server nur die Variablen in env und die Namen in
env_vars. Ein in Ihrer Shell exportierter Schlüssel wird daher andernfalls nicht an den Server weitergegeben.
Cursor, manuell
Fügen Sie Folgendes zu ~/.cursor/mcp.json (global) oder .cursor/mcp.json (Projekt) hinzu oder verwenden Sie
Cmd+Shift+J → Features → Model Context Protocol:
{
"mcpServers": {
"opik-mcp": {
"type": "stdio",
"command": "uvx",
"args": ["opik-mcp"],
"env": {
"OPIK_URL": "http://localhost:5173/api"
}
}
}
}
Cursor-Zeitlimit von 60 Sekunden. Cursor erzwingt ein hartes Zeitlimit für Tool-Aufrufe, das bei Fortschrittsmeldungen nicht zurückgesetzt wird. Siehe Bekannte Host-Limits.
VS Code Copilot, manuell
Fügen Sie Folgendes zu .vscode/mcp.json in Ihrem Workspace oder zu Ihrer Benutzerkonfiguration mcp.json
hinzu (MCP: Open User Configuration):
{
"servers": {
"opik-mcp": {
"type": "stdio",
"command": "uvx",
"args": ["opik-mcp"],
"env": {
"OPIK_URL": "http://localhost:5173/api"
}
}
}
}
MCP Inspector (manuelle Tests)
OPIK_URL=http://localhost:5173/api npx @modelcontextprotocol/inspector uvx opik-mcp
Sie kommen von npx opik-mcp?
Der TypeScript-Server (npm opik-mcp@2) ist veraltet und stellt am 2026-11-15 den Dienst ein. Führen Sie für eine Neuinstallation den Befehl
Schnellstart aus; uvx opik-mcp ist der Befehl, mit dem ein Client
den Server startet, kein Installationsprogramm. Um eine vorhandene Konfiguration für Opik Cloud zu migrieren,
wechseln Sie zum gehosteten Server und entfernen Sie den API-Schlüssel. Ersetzen Sie andernfalls in Ihrer MCP-Clientkonfiguration
npx -y opik-mcp durch uvx opik-mcp. Einige Umgebungsvariablen wurden umbenannt und Befehlszeilenoptionen werden nicht mehr
ausgelesen: siehe den Migrationsleitfaden
.
Support-Richtlinie: DEPRECATED.md.
Der TypeScript-Quellcode befindet sich im Git-Tag legacy-typescript-final.
Tools
opik-mcp stellt eine kleine, ergebnisorientierte Oberfläche bereit, die den gesamten
Lebenszyklus abdeckt (lesen → annotieren → kuratieren → erstellen → iterieren).
| Tool | Zweck |
|---|---|
read | Universelles Lesen nach ID / Name / opik://-URI |
list | Universelle Liste mit optionalem Namensfilter und Paginierung |
write | Universelles Schreiben — Traces/Spans protokollieren, bewerten, kommentieren, Prompts speichern, Datasets und Experimente verwalten |
schema | Schemas für Schreibvorgänge untersuchen (wird vom LLM verwendet, um gültige Payloads zu erstellen) |
read_skill | Einen der mit diesem Server gebündelten Opik-Agent-Skills lesen |
read
Ein Tool für jede Frage der Art „Zeig mir X“. Es akzeptiert ein entity_type sowie eine id
(UUID oder bei benennbaren Typen einen Namen) oder eine vollständige opik://-URI. Zusammengesetzte Lesevorgänge
(trace, prompt, thread, agent_insights_issue) betten ihre untergeordneten Elemente ein, sodass
ein einzelner Aufruf das vollständige Bild liefert.
Der angeforderte Datensatz wird vollständig zurückgegeben. Eingebettete untergeordnete Elemente hingegen nicht: Ihre Inhalte
werden mit truncate=true vom Backend abgerufen. Daher wird ein Feld mit mehr als etwa 10 KB in ClickHouse abgeschnitten
und Base64-Bilder werden durch "[image]" ersetzt — andernfalls würde ein Anhang, der in 200 Spans wiederholt wird, mehr kosten als alles andere beim
Lesen. Die Antwort weist unter spanBodies / messageBodies darauf hin. Jedes untergeordnete Element ist
über seinen eigenen read("span", id) oder read("trace", trace_id) wieder vollständig abrufbar.
Diese Aufrufe verwenden Endpunkte, die überhaupt keinen Parameter truncate haben.
Auch die Länge eingebetteter Sammlungen ist begrenzt: 200 Spans, 200 Turns, 100
Prompt-Versionen. Darüber hinaus ist spansTruncated / messagesTruncated /
versionsTruncated gleich true, und eine danebenstehende Zeile moreSpans / moreMessages /
moreVersions enthält die Anzahl sowie den genauen Aufruf von list(...), mit dem ab der Stelle fortgefahren wird, an der der eingebettete Teil endet.
Unterstützte Entitäten: project, trace, span, dataset, dataset_item,
experiment, prompt, thread, agent_insights_issue. Die Suche nach Namen ist für
project, experiment, prompt, dataset verfügbar (langsamer — zwei API-Aufrufe — und kann mehrere Treffer zurückgeben). thread und agent_insights_issue
sind projektbezogen: Übergeben Sie project_id oder project_name oder einen Link/eine URI,
die das Projekt enthält. dataset und dataset_item hießen früher test_suite und
test_suite_item. Die alten Namen funktionieren weiterhin, werden aber nicht mehr empfohlen; neuer Code sollte die neuen Namen verwenden.
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>",
)
Ein aus der Opik-Benutzeroberfläche kopierter Link funktioniert als id: Ein Thread-Link oder ein
Link zur Diagnostics-Seite enthält das Projekt, sodass project_id nicht erforderlich ist und der Entitätstyp aus dem Link übernommen wird.
Ein Lesevorgang für project beantwortet mit einem einzigen Aufruf die Frage „Wie läuft mein Projekt?“. Er gibt
{project, summary, vocabulary, contains, url} zurück: den Datensatz und anschließend die vier
Kennzahlen, die auf der Logs-Seite als Karten angezeigt werden (Trace-Anzahl, Fehlerrate, durchschnittliche
Dauer, Gesamtkosten) für die letzten 7 Tage im Vergleich zu den 7 Tagen davor, nur SDK-Traffic,
wie auf dem Bildschirm. since / until verschieben dieses Zeitfenster; since="30d" ist der
Standardwert der Benutzeroberfläche. Eine Rate oder ein Durchschnitt für einen Zeitraum ohne Traces wird als
null zurückgegeben, denn 0 % Fehler in einer Woche ohne Traffic würden fälschlich wie eine erfolgreiche Woche wirken.
vocabulary ist die Übersicht, die Sie brauchen, bevor Sie andere Fragen stellen können: die Namen der Feedback-Scores des
Projekts, seine Token-Nutzungsschlüssel und die Automatisierungsregeln, die seine Traces bewerten. Diese Namen werden in Filtern oder in
series= weiter unten verwendet. Wenn Sie sie erraten, erhalten Sie eine leere Seite, die wie eine gute Nachricht aussieht.
Die Anzahl der Score-Namen und Regeln ist begrenzt; die tatsächliche Gesamtzahl wird immer angegeben und der Aufruf zum Abrufen der übrigen Einträge genannt. Die Nutzungsschlüssel werden vollständig aufgelistet, da es keine andere Möglichkeit gibt, sie abzurufen. contains nennt das neueste Experiment, Dataset, die neueste Prompt-Version und den neuesten Optimierungslauf, sodass die Frage „Was ist hier passiert?“ nicht vier weitere Aufrufe erfordert. Wenn ein Teil nicht geladen werden konnte, wird dies angegeben, statt ihn leer erscheinen zu lassen; leere Teile werden ausgelassen.
Ein Lesevorgang für agent_insights_issue gibt {issue, example_trace_ids, details} zurück:
den Diagnostics-Eintrag (Name, Beschreibung, Ursache, Lösungsvorschlag,
Schweregrad, Status), die deduplizierten IDs der Traces, bei denen das Problem auftritt (dieselbe Stichprobe, die auf der Diagnostics-Seite angezeigt wird — öffnen Sie einen davon mit read("trace", id)),
sowie die Aufschlüsselung nach Tagen. Trace-Inhalte werden nicht eingebettet, sodass der Lesevorgang bei einem Backend-Aufruf bleibt. since / until grenzen die Tageszeilen ein; standardmäßig wird der gesamte Zeitraum verwendet. Wenn dem Server die Opik-URL und der Workspace der Sitzung bekannt sind, enthält der Lesevorgang außerdem url (die Diagnostics-Seite des Problems) und trace_url_template
(einen Deeplink zu einem beliebigen Beispiel-Trace), sodass der Assistent Ihnen einen anklickbaren Link geben kann. Bei einer OAuth-Sitzung, deren Workspace nicht ermittelt werden konnte, werden die Links weggelassen, statt geraten.
Traces selbst enthalten keine URL — ein Link zu einem Trace lässt sich nicht aus den Feldern ableiten, die ein read oder list zurückgibt, und eine erratene URL führt zu einem 404-Fehler. Die Sitzungsanweisungen geben stattdessen eine Vorlage dafür an,
.../v1/session/redirect/projects/?trace_id={trace_id}&path=..., sodass der Assistent eine ID einsetzt und Ihnen einen Link bereitstellt. Der Link führt über die Weiterleitung von opik-backend, die Projekt und Workspace anhand des Traces ermittelt. Daher funktioniert er auch dort, wo eine direkte Projekt-URL nicht funktioniert, einschließlich einer OAuth-Sitzung mit nicht aufgelöstem Workspace. Es ist derselbe Link, den das Python-SDK für einen Trace ausgibt.
list
Eine Sammlung mit Paginierung durchsuchen oder filtern. Projektbezogene Typen (trace,
span, thread, agent_insights_issue, dataset_item, prompt_version)
benötigen ihr übergeordnetes Element: eine Projekt-UUID oder einen Projektnamen, eine Dataset-UUID oder eine Prompt-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"')
Filter. trace, span, thread, experiment und dataset_item akzeptieren einen
OQL-String mit derselben Grammatik wie search_traces(filter_string=…) des SDK:
<field>[.<key>] <op> <value> [AND ...]
ops: = != > >= < <= contains not_contains starts_with ends_with is_empty is_not_empty in not_in
Zeichenfolgen stehen in doppelten Anführungszeichen, Zahlen ohne Anführungszeichen, duration wird in Millisekunden angegeben,
Datumsangaben sind ISO-8601-Zeitpunkte mit Zeitzone ("2026-09-08T10:00:00Z").
Scores und Dictionaries benötigen einen Schlüssel: feedback_scores.accuracy < 0.5,
metadata.environment = "prod". AND ist der einzige Connector.
Wie auf der Logs-Seite der UI fügen Trace-, Span- und Thread-Listen source = "sdk" hinzu, damit
Evaluator-, Playground- und Experiment-Traces nicht im Weg sind; benenne source
selbst, um sie zu sehen. Die erste Ausgabezeile gibt den angewendeten Filter wieder.
Ein ungültiger Filter schlägt fehl, bevor er das Backend erreicht, und nennt, was zu seiner Korrektur nötig ist:
die Position eines Syntaxfehlers, den ähnlichsten Feldnamen, die gültigen Operatoren für
den Feldtyp oder das erwartete Werteformat. Auch Felder mit einer abgeschlossenen Wertemenge
(source, Span type, Thread status, visibility_mode) werden
dagegen geprüft, einschließlich jedes Elements einer in-Liste. source ist das einzige Feld, das
das Backend selbst validiert. Bei einem unbekannten Wert antwortet es mit 500 statt
mit 400, sodass source = "SDK" bei einem Großbuchstaben andernfalls einen undurchsichtigen Serverfehler verursachen würde. Der Rest wird als Zeichenfolge verglichen und liefert eine leere Seite,
was wie „keine Treffer“ aussieht, obwohl es „kein solcher Wert“ bedeutet. Frage
schema("list.trace") (oder list.span, list.thread, list.experiment) nach
der vollständigen Feldreferenz, einschließlich der akzeptierten Werte.
Einen Fall in einem Dataset finden. list(entity_type="dataset_item", dataset_id=…) filters on the case itself: data.<key> für die Schlüssel, mit denen
das Dataset erstellt wurde, full_data für eine Teilzeichenfolge der gesamten Nutzlast (ein
vollständiger Scan — gib nach Möglichkeit einen Schlüssel an), außerdem id, tags, source, trace_id,
span_id und die Zeitstempel. data.<key> akzeptiert nur die sechs Zeichenfolgenoperatoren
(=, !=, contains, not_contains, starts_with, ends_with); das
Backend antwortet auf einen Vergleich mit 400, daher wird dieser vor dem
Aufruf abgelehnt. Der Endpunkt bietet weder Sortierung noch Freitextsuche — sort wird abgelehnt,
statt ignoriert zu werden. read(entity_type="dataset_item", id=…) gibt einen Fall
vollständig zurück. So lässt sich ein Wert wieder abrufen, den die Tabelle abgeschnitten hat.
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
Mit experiment_ids ist dieselbe Liste stattdessen der Vergleich — die Fälle mit
angehängtem Lauf — und sie filtert nach den Läufen (feedback_scores.<name>,
output, duration). Es handelt sich um unterschiedliche Feldmengen auf zwei Backend-
Endpunkten: schema("list.dataset_item_case") sind die eigenen Fälle des Datasets,
schema("list.dataset_item") der Vergleich.
Sortierung. trace, span, thread und experiment akzeptieren
sort="<field> [asc|desc]", standardmäßig desc, und jeweils nur ein Feld:
sort="duration desc", sort="total_estimated_cost",
sort="feedback_scores.accuracy asc", sort="usage.total_tokens". Das Feld wird vor dem Aufruf
mit der sortierbaren Liste der Entität abgeglichen, da das Backend Felder, nach denen es nicht sortieren kann,
stillschweigend ignoriert. In sehr großen Workspaces lässt das Backend die Sortierung vollständig weg; die Kopfzeile weist darauf hin, wenn das passiert.
dataset_item sortiert nur als Vergleich (mit experiment_ids): Der Items-Endpunkt akzeptiert keinen Sortierparameter, daher wird eine Sortierung in einer einfachen Auflistung abgelehnt,
statt ignoriert zu werden.
Zeitfenster und Suche. trace, span und thread akzeptieren since und
until, jeweils eine relative Zeitspanne ("30m", "1h", "7d") oder einen ISO-8601-Zeitpunkt
mit Zeitzone, sodass „die letzte Stunde“ keine Zeitberechnung erfordert. Das Zeitfenster richtet sich nach
dem Erstellungszeitpunkt des Datensatzes. Das ist für das Backend kostengünstig und stimmt bei Live-Traffic innerhalb von Sekunden mit
start_time überein. Für eine exakte Grenze setze
start_time in filters. Dieselben drei Typen akzeptieren search, Freitext, der
an beliebiger Stelle in ID, Name, Eingabe, Ausgabe, Metadaten, Tags und Thread-ID gefunden wird. Die Suche
durchsucht das gesamte Projekt im Backend, daher kann der erste Aufruf bei einem großen Projekt
mehrere zehn Sekunden dauern. Für diese Aufrufe gilt ein Timeout von 60 Sekunden. Mit since werden sie
wieder schnell.
Tabelle lesen. Dauern sind mit duration_ms / ttft_ms beschriftet und
werden als ganze Millisekunden angezeigt; das Feld bleibt duration in filters und
sort. Zeitstempel werden sekundengenau und Kosten als einfache Dezimalzahlen angezeigt.
Projektzeilen enthalten last_updated_trace_at, damit du siehst, in welchem Projekt
Live-Traffic eingeht; Thread-Zeilen enthalten die erste Nachricht. Eine leere Seite innerhalb eines Zeitfensters gibt an, wann der letzte Trace des Projekts eingegangen ist. Eine leere Seite unter dem Standardwert source = "sdk" erklärt, wie du die anderen Quellen anzeigen kannst. Ein falsch geschriebenes
project_name wird mit dem ähnlichsten vorhandenen Namen zurückgegeben.
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")
Diagnoseprobleme. agent_insights_issue ist die Diagnostics-Seite über
MCP: die wiederkehrenden Fehler, die der Diagnostics-Job von Opik für ein Projekt gruppiert hat,
sortiert wie in der UI (zuletzt aufgetretene zuerst). Die Spalten sind severity,
status, total_occurrences (Gesamtsumme), latest_count (der jüngste
Berichtstag, auf den sich die Beschreibung des Problems selbst bezieht) und last_seen.
Standardmäßig werden offene Probleme aufgelistet; übergib status="resolved" oder "closed" für
die übrigen. read und list werden auch als issue bezeichnet, wie die UI diese
nennt; der lange Name ist der Eintrag in der entity_type-Enum, damit diese Entität
dort nicht zweimal erscheint. Die Zählungen beziehen sich auf den gesamten Zeitraum, damit sie mit der UI übereinstimmen; dieselben since / until
wie bei Traces grenzen das Zeitfenster ein, das auf UTC-Berichtstage gekürzt wird, da
Diagnostics nach Tagen aggregiert.
Eine leere Liste erklärt, warum sie leer ist, denn „nichts ist kaputt“ und „niemand hat Diagnostics aktiviert“ sehen andernfalls gleich aus. Es gibt fünf Zustände: Diagnostics ist in dieser Bereitstellung nicht verfügbar, für dieses Projekt nicht aktiviert, ausgeschaltet, aktiviert, aber seit Kurzem nicht gescannt, oder aktiviert und fehlerfrei, mit dem Zeitpunkt des letzten Scans. Die Zustände, bei denen du etwas tun kannst, nennen den erforderlichen Aufruf, und jeder Zustand verlinkt auf die Diagnostics-Seite des Projekts.
Eine nicht leere Liste gibt ihren Zeitraum selbst an. Die Probleme entsprechen den Gruppen des letzten Scans,
daher endet die Antwort mit Report covers data through <time>. Wenn das angefragte Zeitfenster darüber hinausreicht,
wird die nicht abgedeckte Zeitspanne genannt und erklärt, wie sie abgedeckt werden kann:
durch einen Trigger, sobald ein erneuter Scan weit genug zurückreicht, andernfalls durch rohe Traces mit dem
angegebenen since. Wenn du für ein Projekt, das jede Nacht gescannt wird, eine Woche anfragst, fehlt der letzte Tag in der gruppierten Antwort; hier wird darauf hingewiesen.
write("agent_insights_job.enable", {"project_name": "demo"}) aktiviert Diagnostics.
Ab dann werden täglich Scans ausgeführt, und ein erneuter Aufruf ist unbedenklich.
write("agent_insights_job.trigger", …) scannt jetzt die letzten 24 Stunden, ohne
auf den nächtlichen Lauf zu warten. Beide erfordern dieselbe Berechtigung wie das Lesen von Problemen,
und beide werden abgelehnt, wenn Diagnostics in der Bereitstellung nicht verfügbar ist.
Ein Problem durchläuft seinen Lebenszyklus mit
write("agent_insights_issue.resolve", {"issue_id": "<uuid>", "project_name": "demo"})
— erledigt — oder …close für eines, bei dem sich Maßnahmen nicht lohnen, und mit …reopen, um
beide wieder in die Liste der offenen Probleme aufzunehmen. Alle drei erfordern dieselbe Berechtigung und antworten
mit einem Link zur Ansicht, in die das Problem verschoben wurde, da ein gelöstes Problem nicht mehr
auf der Standardseite erscheint. Ob ein Fehler behoben ist, ist eine Ermessensentscheidung. Daher sind diese Aktionen für den Fall gedacht, dass du sie anforderst: Der Assistent sollte die Liste nicht eigenmächtig aufräumen, während er Probleme untersucht.
Metriken im Zeitverlauf. project_metric stellt eine Metrik für ein Projekt als
Tabelle mit Zeitintervallen dar: Trace-, Span- und Thread-Anzahlen, Dauern, Fehlerraten,
Kosten, Token-Nutzung und Feedback-Scores. Damit beantwortet es die Frage, die sich an die Übersicht anschließt: wann sich etwas geändert hat.
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
Die Zeilen sind Zeitintervalle, keine Datensätze. Daher werden page, size und sort abgelehnt,
statt ignoriert zu werden. interval ist hourly, daily, weekly oder total;
wenn nicht angegeben, richtet es sich wie im Metrics-Tab nach dem Zeitfenster — stündlich bis zu 3
Tagen, täglich bis zu 30, wöchentlich darüber hinaus. So umfasst ein Standarddiagramm unabhängig vom Zeitraum einige Dutzend Zeilen, während ein stündlicher Monat (721 Zeilen) ausdrücklich angefordert werden muss.
since / until akzeptieren dieselben Formate wie überall sonst und verwenden standardmäßig die letzten 7 Tage. filters verwendet die Felder der Entität, auf die sich die Metrik bezieht. Eine Span-Metrik wird also nach Span-Feldern gefiltert.
breakdown unterteilt jedes Zeitintervall nach tags, name, error_info, error_type,
model, provider, span_type, guardrail_name oder metadata.<key>. Nicht
jede Metrik akzeptiert alle diese Optionen, und sieben akzeptieren gar keine. Das Tool
weiß, welche Optionen gültig sind, und teilt dies vor dem Aufruf des Backends mit. Falls vorhanden, nennt es eine Metrik, die dieselbe Frage beantwortet. Drei Familien liefern mehrere Zeitreihen auf einmal zurück (eine Dauer als p50/p90/p99, einen Feedback-Score pro Name, Token-Nutzung pro Schlüssel). Beim Gruppieren stellt das Backend jeweils nur eine davon dar, daher wählt series= sie aus: ein Perzentil, einen Score-Namen oder einen Nutzungsschlüssel. Für die Dauer gilt standardmäßig p50, für die Token-Nutzung total_tokens; der jeweils verwendete Wert wird in der ersten Zeile wiedergegeben.
Leere Zeitintervalle werden ausgelassen und darunter gezählt. So besteht ein ruhiger Monat aus wenigen Zeilen statt einer Spalte voller Nullen, und eine Rate für ein Zeitintervall ohne Traces fehlt, statt als null angegeben zu werden.
Frage schema("list.project_metric") nach der Metriktabelle, den Intervallen und der Gruppierungsmatrix pro Metrik.
Die Namen eines Projekts. score_name listet die in einem Projekt erfassten Feedback-Score-Namen auf und online_rule die dafür konfigurierten Evaluatoren für Automatisierungsregeln,
aus denen die meisten dieser Namen stammen. Beide entsprechen denselben Listen, die read("project", …) vollständig und paginiert bereitstellt, falls die begrenzte Version in der Übersicht nicht ausreicht.
list(entity_type="score_name", project_name="demo")
list(entity_type="online_rule", project_name="demo")
write
Universeller Dispatcher für Schreibvorgänge. Übergib operation + data, und der Dispatcher
validiert die Nutzlast, wendet die passende REST-Methode an und gibt die
Backend-Antwort zurück.
Operationen:
| Operation | Beschreibung |
|---|---|
trace.create | Einen einzelnen Trace (oder einen Batch) protokollieren. Übergeordneter Eintrag für Spans / Scores / Kommentare. |
trace.update | Einen vorhandenen Trace abschließen oder ändern. |
span.create | Einen Span in einem vorhandenen Trace protokollieren (oder einen Batch). |
score.create | Einen numerischen Feedback-Score an einen Trace, Span oder Thread anhängen. |
comment.create | Einen Freitextkommentar an einen Trace, Span oder Thread anhängen. |
prompt_version.save | Eine neue Prompt-Version speichern (erstellt den Prompt anhand des Namens, falls er fehlt). |
dataset.create | Ein Dataset erstellen — type: "test_suite" macht daraus eine Testsuite für Evaluierungen. |
dataset_item.upsert | Items in ein Dataset einfügen oder aktualisieren (immer im Envelope-Format). |
experiment.create | Ein auf ein Dataset beschränktes Experiment erstellen. |
experiment_item.create | Trace- und dataset_item-Zeilen an ein Experiment anhängen. |
thread.close | Einen Thread schließen (als inaktiv markieren). Übergib thread_id und das Projekt. |
thread.open | Einen geschlossenen Thread wieder öffnen. Übergib thread_id und das Projekt. |
agent_insights_job.enable | Diagnostics für ein Projekt aktivieren (tägliche Scans, wiederholter Aufruf unbedenklich). |
agent_insights_job.trigger | Jetzt einen Diagnostics-Scan über die letzten 24 Stunden ausführen. |
agent_insights_issue.resolve | Ein Diagnostics-Problem als erledigt markieren (zuerst den Benutzer fragen). |
agent_insights_issue.close | Ein Diagnostics-Problem als nicht handlungsrelevant markieren (zuerst den Benutzer fragen). |
agent_insights_issue.reopen | Ein gelöstes oder geschlossenes Diagnostics-Problem wieder in die Liste der offenen Probleme aufnehmen. |
annotation_queue.create | Die Annotationswarteschlange eines Projekts erstellen, optional mit einer benutzerdefinierten Annotator-Ansicht. |
annotation_queue.update | Eine Annotationswarteschlange ändern; ihre Annotator-Ansicht festlegen, ersetzen oder löschen. |
write(
operation="score.create",
data={
"target": "trace",
"target_id": "7f2e3c8a-…",
"name": "helpfulness",
"value": 0.9,
"reason": "great recovery",
},
)
schema
Prüfe vor dem Aufruf die genaue JSON-Struktur und die erforderlichen Felder eines beliebigen Schreibvorgangs — nützlich, wenn du dir nicht sicher bist, wie data aussehen sollte. Gibt das Schema, den OAuth-Scope und ein validiertes Beispiel zurück. Reine Abfrage, kein Backend-Aufruf.
schema(operation="score.create")
schema(operation="prompt_version.save")
Dasselbe Tool beantwortet list.trace, list.span, list.thread und
list.experiment mit der Referenz des Tools list für diese Entität: alle
filterbaren Felder mit ihrem Typ und den gültigen Operatoren, die sortierbaren Felder, ob
ein Zeitfenster und eine Freitextsuche unterstützt werden, sowie zwei Beispielfilter.
schema(operation="list.trace")
Konfiguration
Diese Einstellungen konfigurieren den lokalen Server; jede Einstellung ist eine Umgebungsvariable. Der gehostete Server auf Opik Cloud verwendet keine davon.
Identität / Endpunkt
| Variable | Standardwert | Hinweise |
|---|---|---|
OPIK_API_KEY | — | API-Schlüssel für ein selbst gehostetes Comet oder für Opik Cloud ohne den gehosteten Server. Für Open-Source-Opik ist keiner erforderlich, sofern die Bereitstellung keine Authentifizierung hinzufügt. |
OPIK_WORKSPACE | nicht gesetzt | Workspace-Name. Wird der Wert in der Cloud mit einem API-Schlüssel nicht gesetzt, sendet der Server default, wodurch der Standard-Workspace deines Kontos ermittelt wird — setze den Wert explizit, wenn du in einem anderen Workspace arbeitest, andernfalls werden Lesezugriffe unbemerkt aus dem falschen Workspace ausgeführt. Bei OAuth nicht setzen (der Token enthält den Wert) und auch nicht lokal/bei OSS (default ist dort der einzige Workspace). |
COMET_WORKSPACE | — | Veralteter Alias für OPIK_WORKSPACE (Abwärtskompatibilität). Wenn beide gesetzt sind, hat OPIK_WORKSPACE Vorrang. |
COMET_WORKSPACE_ID | nicht gesetzt | Optionale Workspace-UUID. Wird bei gesetztem Wert in Analytics-Ereignisse eingetragen und hat Vorrang vor der ermittelten UUID. Selten erforderlich — OAuth-Installationen erhalten die UUID automatisch aus dem Token. |
COMET_URL_OVERRIDE | https://www.comet.com | Auf den Host deines selbst gehosteten Comet oder für Staging auf https://dev.comet.com setzen. |
OPIK_URL | abgeleitet aus COMET_URL_OVERRIDE + /opik/api | Für Open-Source-Opik setzen, das seine API unter /api bereitstellt (http://localhost:5173/api lokal). Auf einer Comet-Plattform nur überschreiben, wenn Opik auf einem anderen Host/Pfad als die Comet-Benutzeroberfläche liegt. |
OPIK_DEFAULT_PROJECT_NAME | nicht gesetzt | Wenn gesetzt, weist der sitzungsbezogene instructions-Blob das LLM an, diesen Wert bei jedem Tool-Aufruf als project_name zu übergeben, sofern der Benutzer kein anderes Projekt angibt. |
Server / Transport
| Variable | Standardwert | Hinweise |
|---|---|---|
OPIK_MCP_TRANSPORT | stdio | stdio für den Start durch einen Host, streamable-http zum Lauschen an einem Port. |
OPIK_MCP_HOST | 127.0.0.1 | Bind-Host von uvicorn (nur streamable-http). |
OPIK_MCP_PORT | 8080 | Bind-Port von uvicorn (nur streamable-http). |
OPIK_MCP_RELOAD | false | Auf true setzen, um uvicorn --reload zu aktivieren (nur für die Entwicklung). |
OPIK_MCP_AS_URL | nicht gesetzt | URL des OAuth Authorization Servers, angegeben in /.well-known/oauth-protected-resource (RFC 9728) und als Proxy-Ziel für AS-Erkennungsabfragen verwendet. Erforderlich, damit MCP-Hosts den OAuth-Ablauf über HTTP starten können. |
OPIK_MCP_RESOURCE_URI | nicht gesetzt | Kanonische öffentliche URI dieses Servers, angegeben als resource in den Metadaten der geschützten Ressource und zur Ableitung des Hinweises WWW-Authenticate verwendet. |
OPIK_MCP_OAUTH_VALIDATION_CACHE_TTL_S | 30 | Gibt an, wie lange einer „gültigen“ Antwort der Token-Introspektion von opik-backend vertraut wird, bevor die nächste Anfrage mit demselben OAuth-Token erneut nachfragt. Begrenzt die zusätzliche Backend-Last durch die Validierung jeder Anfrage und den Zeitraum, in dem ein abgelaufener Token noch weitergeleitet wird (dieser Zeitraum endet ebenfalls mit der ersten 401-Antwort des Backends). Wird durch den eigenen expires_at des Tokens begrenzt, sofern das Backend einen solchen meldet. |
OPIK_MCP_LOG_LEVEL | INFO | Schwellenwert für stderr-Logger. |
Transport auswählen
Zwei Bearer-Formate, zwei Verträge für den HTTP-Transport. Ein OAuth-
Zugriffstoken opik_mcp_at_… wird bei jeder Anfrage über den Token-
Introspektionsendpunkt von opik-backend validiert (zwischengespeichert, siehe OPIK_MCP_OAUTH_VALIDATION_CACHE_TTL_S);
ein abgelaufener oder widerrufener Token erhält eine HTTP-401-Antwort mit
WWW-Authenticate: Bearer error="invalid_token", woran MCP-Hosts ihren stillen refresh_token-Grant erkennen.
Ein Opik-API-Schlüssel wird nicht lokal validiert: Er wird unverändert an opik-backend
weitergeleitet, wo die Durchsetzung zentral erfolgt. Wähle den Transport passend zur Bereitstellung:
| Szenario | Transport |
|---|---|
| Opik Cloud | Nichts auszuführen: der gehostete Server ist dieser Server über HTTP, betrieben von Comet |
| MCP-Client und Opik auf demselben Rechner (lokale OSS-Installation) | stdio (empfohlen — am einfachsten, kein Port, keine OAuth-Einrichtung) |
| Lokaler MCP-Client → selbst gehostetes Opik | stdio mit den Umgebungsvariablen für die Bereitstellung oder HTTP mit OAuth (OPIK_MCP_AS_URL verweist auf das Backend) |
| opik-mcp wird hinter demselben Edge wie opik-backend bereitgestellt | HTTP — Bearer-Tokens werden vom Backend bei jeder Anfrage validiert |
Hinweis zu lokalen OSS-Installationen: Das OSS-Backend authentifiziert keine Anfragen,
daher ist ein davor geschaltetes HTTP-opik-mcp genauso offen wie die OSS-REST-API selbst.
Behalte in gemeinsam genutzten Netzwerken die standardmäßige Bindung 127.0.0.1 bei
(und bevorzuge stdio).
Telemetrie
| Variable | Standardwert | Hinweise |
|---|---|---|
OPIK_MCP_ANALYTICS_ENABLED | true | Auf false setzen, um die gesamte Telemetrie außer Sentry zu deaktivieren. |
| `OPIK_MCP_SENTRY_ENABLED | true | Set to false zum Deaktivieren der gesamten Sentry-Telemetrie. |
| ======= |
Bekannte Host-Limits
Hosts unterscheiden sich darin, wie lange sie einen einzelnen Tool-Aufruf laufen lassen:
- Claude Code — kein dokumentiertes Timeout für Tool-Aufrufe. Empfohlen.
- Cursor — hartes Timeout von 60 s, das sich bei Fortschritt nicht zurücksetzt (Upstream-Bug).
- MCP Inspector —
MAX_TOTAL_TIMEOUTbegrenzt die Gesamtdauer (Standard: 60 s). Erhöhe den Wert in der Inspector-Benutzeroberfläche für längere Vorgänge.
Wenn ein Aufruf hängen bleibt, setze OPIK_MCP_LOG_LEVEL=DEBUG, um das vollständige Anfrageprotokoll zu erhalten.
Fehlerbehebung
Funktioniert die Einrichtung? Starte den Server mit den Umgebungsvariablen aus der Client-Konfiguration und
--check: OPIK_URL=http://localhost:5173/api uvx opik-mcp@latest --check. Der Befehl
nennt den Workspace und die darin gefundenen Projekte oder gibt an, was zu korrigieren ist. Auch die
Fehlermeldungen des Servers nennen die erforderlichen Änderungen und verweisen auf die entsprechende Dokumentationsseite.
OPIK_API_KEY wird nicht übernommen — die Variable erreicht den Serverprozess nicht.
In Claude Code / Cursor / VS Code gelten Umgebungsvariablen nur innerhalb des
env-Blocks der MCP-Serverkonfiguration, nicht in deiner Shell; Codex leitet außerdem
die in env_vars aufgeführten Namen weiter. Starte nach Änderungen eine neue Sitzung,
da Clients die Konfiguration beim Sitzungsstart einlesen.
Anfragen gehen bei Open-Source-Opik an /opik/api — COMET_URL_OVERRIDE ist
für eine selbst gehostete Comet-Plattform vorgesehen. Open Source stellt seine API unter /api bereit: Setze stattdessen
OPIK_URL=http://localhost:5173/api (oder https://<host>/api). Der
Server warnt beim Start davor, wenn der Host dieser Rechner ist, und --check
antwortet mit „No Opik API at …“.
Cursor-Aufruf läuft nach 60 s ab — ein bekannter Cursor-Bug, kein Problem mit opik-mcp. Entweder
den Aufruf eingrenzen (kleineres size, kürzeres Zeitfenster) oder denselben Vorgang
in Claude Code ausführen, das kein hartes Limit hat.
Server wird nicht angezeigt, Anmeldung öffnet sich nicht, falscher Workspace, uvx nicht gefunden.
Diese Fälle werden im Abschnitt zur Fehlerbehebung in der Dokumentation behandelt.
uvx opik@latest mcp status listet alle Clients auf, bei denen der Server konfiguriert ist,
und zeigt an, ob ihre Konfiguration abweicht.
Entwicklung
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
Häufige Ziele:
| Ziel | Funktion |
|---|---|
make install | uv sync --locked --extra dev |
make run | MCP-Server ausführen (standardmäßig stdio). |
make run-dev | Mit DEBUG-Protokollierung + uvicorn --reload ausführen. |
make dev | Über mcp dev ausführen (Inspector-Wrapper für den Entwicklungsmodus). |
make inspect | MCP Inspector mit einem laufenden Server starten. |
make test | uv run pytest -q. |
make lint | ruff check + Formatprüfung. |
make format | ruff format + ruff check --fix. |
make typecheck | mypy. |
make check | lint + typecheck + test. |
Repository-Struktur:
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
Hilfe erhalten
- Issue eröffnen für Fehler und Funktionswünsche
- Opik-Dokumentation für SDK- / Backend-Dokumentation
- Comet-Community auf Slack für Fragen
Lizenz
Apache-2.0.