mcp-langfuse
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@mcp-langfuseshow me failed traces in the sales project from the last 24h"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
@mgcrea/mcp-langfuse
A Model Context Protocol server for Langfuse, built for Langfuse v4 deployments in events-only mode: traces, sessions, observations, scores, metrics and prompts.
It is read-only. The only path that can mutate anything is the langfuse_request escape
hatch, and it is GET-only unless LANGFUSE_ALLOW_WRITES=1.
Why another Langfuse MCP
Two failures with the existing Python langfuse-mcp prompted this one.
Events-only mode. Langfuse v4 can run in an "events only" mode where
GET /traces,/traces/{id},/sessions,/observations(v1) and/scores(v1 and v2) all answer404 — not available on deployments running in Langfuse v4 events_only mode. Every older client is built on those endpoints. This server reads only what survives:/v2/observations,/v2/metrics,/v3/scoresand/v2/prompts. It rebuilds a trace from its observations and a session from its traces.The wrong project, silently. Langfuse keys are project-scoped, so the key alone decides which project answers. A key copied from the wrong project answers every query with plausible data from that project. This server checks every key against the project it is filed under before reading anything, names the project in its startup log and in
langfuse_auth_status, and stampsprojecton every data response.
One server reads many projects: it holds one key per project, and every data tool takes
a project argument. On an OSS Langfuse there is no API that mints those keys (it is the EE
admin-api), so pnpm provision writes them into Langfuse's own Postgres — see
Provisioning keys.
Related MCP server: Langfuse MCP Server
Features
Traces as a depth-first tree with total token usage, cost,
ERRORsteps, and the trace's input/output. That input/output comes from the first observation that has one, because the root span is often an AGENT that carries none.Sessions as their traces in chronological order, each with its input and output.
Observation search by type, level, model, name, latency, metadata (raw filters) and indexed literal text search over input/output.
level: "ERROR"is how to find failed runs.Server-side aggregates through
/v2/metrics: counts, cost, token sums and latency percentiles, grouped and bucketed over time.Output is shaped for the context window. Empty fields and per-row pricing echoes are dropped, and so are the OpenTelemetry
scope.*/resourceAttributes.*metadata keys that every span repeats (one of them is the project's public key). LLM inputs, often 20 KB each, are cut to a budget you choose, with an honest[truncated: N chars total]marker.Relative time windows (
since: "24h","7d"), because a model rarely knows today's date.Native
fetch, no runtime dependencies beyond the MCP SDK and Zod.
Configure
Keys come from three places, merged by project name, earlier wins:
LANGFUSE_PUBLIC_KEY+LANGFUSE_SECRET_KEY, filed underLANGFUSE_PROJECT.LANGFUSE_PROJECTS, a JSON map:{"sales": {"publicKey": "pk-lf-…", "secretKey": "sk-lf-…", "id": "…"}}.The keys file,
~/.config/langfuse-mcp/keys.json— whatpnpm provisionwrites.
Variable | Description |
| Instance URL, e.g. |
| Keys file path. Defaults to |
| JSON map of project name → key pair, as above. |
|
|
|
|
| The name (or id) that single key is filed under, and checked against. |
|
|
| Retry budget for 429/5xx. Defaults to 3. |
|
|
LANGFUSE_BASE_URL is accepted as an alias of LANGFUSE_HOST, and the names match the
Langfuse SDKs and the Python langfuse-mcp, so an existing single-project .mcp.json entry
switches over by changing its command.
The project check. Every key in LANGFUSE_PROJECTS or the keys file must resolve to the
project it is filed under — by name ignoring case, or by its recorded id — or every call to
that project is refused before anything is read. A lone LANGFUSE_PUBLIC_KEY pair without
LANGFUSE_PROJECT is served unchecked as default, as before; alongside other projects it
is ignored until LANGFUSE_PROJECT names it.
One project or several. With one project configured, project may be omitted. With
several it is required on every data tool, with no default — a silently chosen project is
the failure this server exists to prevent.
With no keys at all the server still starts and serves langfuse_auth_status, which says
what to set. It does not exit, because a server that exits shows up in the client only as
Connection closed. A malformed keys file is reported the same way.
Provisioning keys
Langfuse keys are project-scoped, and the API that mints them —
POST /api/public/projects/{id}/apiKeys — needs an organization key and the EE
admin-api entitlement (self-hosted Enterprise, or Cloud Team/Enterprise). On an OSS
instance every organization endpoint answers 403 "not available on your current plan". The
data plane is fully OSS, so a key written straight into Langfuse's Postgres, exactly as its
own UI writes it, authenticates like any other. That is what pnpm provision does:
kubectl port-forward -n langfuse svc/langfuse-postgresql 15432:5432 &
LANGFUSE_HOST=https://langfuse.example.com \
LANGFUSE_DB_URL=postgres://langfuse:…@127.0.0.1:15432/langfuse \
LANGFUSE_SALT=… \
pnpm provision # dry run: prints the plan, changes nothing
pnpm provision --apply # mint, verify, saveLANGFUSE_SALTmust be theSALTof the runninglangfuse-web. Read it from the deployment, not a local copy of the secrets, which can be stale. A wrong salt — or the wrong database — still inserts a row whose key never authenticates.Every minted key is verified against
GET /api/public/projectsafter its row commits, and must resolve to the right project. A key that fails is deleted again and the run stops.Safe to re-run. A recorded key that still works is kept. One that returns 401 is replaced, and only then revoked. One that reads a different project is replaced but left in place, since something else may use it. New projects get keys; entries for deleted projects leave the file (no row is touched).
The file is written after each key, mode
0600, so a crash never leaves a key in Langfuse whose secret exists nowhere.--only a,b/--exclude a,b(names or ids) limit a run.Keys carry the note
mcp-langfuse (read)in Langfuse's UI. Langfuse has no read-only key type: they can ingest too.Coupling. This reproduces Langfuse's internal
api_keysstorage scheme, verified on 4.63.0. The script probes the columns it needs and stops if they moved; re-checksrc/provision/keys.tson a Langfuse upgrade.
pg and bcryptjs are dev dependencies used only by the script. The published server
keeps its two runtime dependencies.
Tools
Every data tool takes project: one of the configured names.
Tool | What it does |
| Every configured project and what its key resolves to; version, events-only mode |
| Traces newest first (root observations), filtered by name/user/session/tags/time |
| One trace as a tree, with usage, cost, errors and input/output |
| A session's traces in order, each with its input/output |
| Search observations: type, level, model, latency, text in input/output, metadata |
| One observation in full; |
| Scores via |
| Aggregates via |
| Managed prompts, versions and labels |
| One prompt version in full |
| Raw |
Traps worth knowing
Units differ. Observation rows report
latencyin seconds, but/v2/metricsreportslatencyandtimeToFirstTokenin milliseconds.filtersilently overrides plain query params on/v2/observations. This server always sends the JSONfilterand never the plain params. Keep that in mind if you call the endpoint throughlangfuse_request.A failed trace's root is usually still
DEFAULT. Find failures withlangfuse_list_observationsandlevel: "ERROR", not by listing traces.App roots. An SDK-marked root can carry a
parentObservationIdthat points outside the trace. The tree treats it as a root.Observation ids are scoped to a trace. Pass
traceIdtolangfuse_get_observationwhenever you have it.High-cardinality fields (
traceId,userId,sessionId,id) cannot be metric dimensions. Filter on them instead.
Quick start
pnpm install
pnpm buildThen copy .mcp.json.example to .mcp.json and fill it in.
Inspect the tools
printf '%s\n' \
'{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2024-11-05","capabilities":{},"clientInfo":{"name":"cli","version":"0"}}}' \
'{"jsonrpc":"2.0","method":"notifications/initialized"}' \
'{"jsonrpc":"2.0","id":2,"method":"tools/list"}' \
| node dist/cli.js 2>/dev/null | jq -r '.result.tools[]?.name'Develop
pnpm dev # tsdown --watch
pnpm test # vitest, offline: fetch is mocked
pnpm typecheck
pnpm lint
pnpm formatTo check against a real instance, start the built server with real keys, then call
langfuse_auth_status first. It confirms the host, the project and events-only mode before
you read any data.
Publish
pnpm dlx release-it # bump, commit, tag
git push --follow-tags # CI publishes to npm + GHCR from the tagLicense
MIT
Available Tools
1 toollangfuse_auth_statusLangfuse: Auth StatusARead-only
List the Langfuse projects this server can read — the names the other tools' project argument takes — and check each key against the project it is filed under. Keys are project-scoped, so this is the first thing to check when data looks wrong or missing. Also reports the Langfuse version, whether it runs in v4 events-only mode (no /traces or /sessions), whether writes are enabled, and, when something is not configured, exactly what to set. Makes one small API call per project, plus two.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations only declare readOnlyHint=true; the description goes well beyond that. It discloses the cost profile ('one small API call per project, plus two'), the full set of things reported (version, v4 events-only mode with no /traces or /sessions, whether writes are enabled), and that remediation hints are returned when configuration is missing. That is exactly the extra context an agent needs to decide whether to call it and how to interpret the result.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The core purpose and the 'check this first' trigger are front-loaded, and every clause (version, v4 mode, write flag, remediation, API call count) carries distinct information rather than restating the title. It is dense and dash-heavy, which makes it slightly harder to scan than a shorter version would be, but no sentence is waste.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
There is no output schema, so the description must describe the return shape, and it does: project names, per-key validation results, version, events-only mode, write-enabled flag, missing-config guidance, and request cost. For a zero-parameter read-only diagnostic tool, an agent has everything needed to call it and interpret the response.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The tool takes zero parameters, so there is no input semantics to explain and the baseline applies. The description also usefully clarifies that the returned project names are what other tools' `project` argument accepts, which is value beyond this tool's own empty schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
Uses a specific verb-plus-resource pair: it lists the Langfuse projects this server can read, validates each key against the project it is filed under, and reports configuration state. An agent immediately knows this is a discovery/diagnostic tool rather than a data-fetching one, and the description explicitly links its output ('the names the other tools' `project` argument takes') to how sibling tools are invoked.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives an explicit trigger: 'Keys are project-scoped, so this is the first thing to check when data looks wrong or missing.' That is clear situational guidance an agent can act on. It stops short of naming when not to call it or an alternative, but with no sibling tools there is little left to route between.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
1 tool update
v0.1.0- First observed
langfuse_auth_status
TDQS
Scored across 1 tool
With only one tool exposed there is no possible confusion between tools, so selection is unambiguous. However, the description repeatedly refers to "the other tools' `project` argument," which do not exist in this set, so an agent may waste effort looking for tools that aren't there.
The single name `langfuse_auth_status` is clear, prefixed, and uses consistent snake_case. There is no multi-tool set to verify a pattern against, so consistency can only be judged on readability.
A Langfuse observability server exposing exactly one diagnostic/status tool is far too thin for the apparent scope (projects, traces, sessions, scores). The description itself implies a larger intended surface, making this a notable under-scoping rather than a deliberately minimal server.
There are no tools to actually read Langfuse data — no trace, session, observation, score, or project listing operations — despite the tool describing itself as the entry point to a broader set. An agent can check auth status and then hit a dead end for every real workflow.
Maintenance
Related MCP Connectors
Read-only MCP server for The Quiet Protocol's engines, benchmarks, proof, and business data.
Model Context Protocol server for the Apideck Unified API. Connect any MCP-compatible agent framework to 100+ accounting systems, HRIS platforms, file storage providers, and more through one integration. More information https://www.apideck.com/mcp-server
Read-only Google Analytics 4 MCP server for AI assistants.
OAuth-protected, read-only-by-default MCP server for provenance-labeled QuillCaddie project memory.
Related MCP Servers
- AlicenseCqualityAmaintenanceMCP server for Langfuse observability. Query traces, debug exceptions, analyze sessions, and manage prompts and datasets for your LLM applications.483,600 PyPI112MIT
- AlicenseBqualityDmaintenanceModel Context Protocol server for Langfuse observability. Query traces, analyze accuracy, detect failures, track costs, debug latency, manage prompts and datasets.582MIT
- AlicenseBqualityCmaintenanceA portable, read-only Model Context Protocol server for turning observability data into bounded evidence that AI agents can inspect safely.7Apache 2.0
- FlicenseNot gradedqualityAmaintenanceEnables AI agents and developers to query Langfuse telemetry locally, fetching traces, sessions, observations, and exceptions, inspecting route decisions, and running metrics, prompt, dataset, and annotation-queue operations. Supports selective tool-group loading and a read-only mode for token-efficient debugging from Claude Code, Codex, Cursor, or any MCP client.-