Skip to main content
Workflows Library MCP Directory Realtime AI News Sponsor Tier Subscribe
Front Page / AI Tools / Deep Dive

Langfuse AgentOps MCP Server with OpenTelemetry Instrumentation & Session Replay for Claude Desktop

Run Langfuse as an AgentOps observability plane reachable from Claude Desktop: OpenTelemetry GenAI semantic conventions, gen_ai.* trace ingestion, dual-device session replay, and per-trace cost tracking over a native MCP server at /api/public/mcp.

Deepak Bagada

Deepak Bagada

CEO, SaaSNext

Aug 07, 2026 Published
|
Aug 07, 2026 Updated
|
11 Minutes Reading Time
Core Takeaways for Founders & Builders
  • Langfuse is a warehouse-first (ClickHouse) observability layer with a native MCP server and an OpenTelemetry OTLP ingestion endpoint.
  • The OpenTelemetry GenAI semantic conventions are the unified wire format; Langfuse is an OTLP destination, not a proprietary SDK lock.
  • Session replay of traces grouped by session ID is what turns vague feedback into pinpointed actions at a specific step.

Langfuse AgentOps MCP Server with OpenTelemetry Instrumentation & Session Replay for Claude Desktop

Ship an agent in 2026 and you inherit a distributed tracing problem dressed up as a feature. Every LLM call, retrieval step, tool invocation, and provider round-trip emits telemetry, and unless you standardize how that telemetry is encoded, you cannot replay a session, explain a failure, or answer the only question your CFO cares about: which conversations are burning the budget.

This guide builds a production-grade Langfuse AgentOps MCP server — observability functions exposed as Model Context Protocol tools that a Claude Desktop client can invoke directly — with three non-negotiable pillars: OpenTelemetry GenAI semantic conventions for the wire format, session replay so your debugger can step through what an agent actually did, and cost tracking normalized at ingest time.

By Deepak Bagada, CEO at SaaSNext & Principal AI Architect.

Key insight: Langfuse is now the deep storage layer, not the dashboard. ClickHouse completed its acquisition in January 2026, and the platform is warehouse-first. The agent-facing surface is a native MCP server at /api/public/mcp plus an OpenTelemetry OTLP ingestion endpoint at /api/public/otel. Your job is to make traces speak the same vocabulary on both sides.

Why AgentOps MCP, and why Langfuse

Model Context Protocol is the interface between models and tools. A2A is the interface between agents. Observability sits underneath both, and the fastest way to give your Claude Desktop, Cursor, or Claude Code session a lever on your production agent estate is to expose observability as tools. Instead of alt-tabbing to a dashboard when a run fails, an assistant asks which session failed, why was it slow, which user journey regressed, how much did our refund agent cost last week?

Langfuse is the reference destination for this because of four concrete properties:

  1. OpenTelemetry-native ingestion. Traces arrive over OTLP at /api/public/otel, mapped to the Langfuse data model. You instrument once with the standard SDK and repoint exporters without rewriting agent code.
  2. Warehouse-first storage on ClickHouse. Cost per trace is joined with token usage at ingest, so budget queries become column filters, not table scans.
  3. Replayable sessions. Every run is grouped by a session identifier and can be stepped through as a trace, with input, output, and reasoning at each observation.
  4. A first-class MCP server. The native Langfuse endpoint at /api/public/mcp (streamable HTTP) exposes trace, generation, session, prompt, dataset, and scoring tools to any MCP client.

The observability market consolidated sharply: ClickHouse took Langfuse in January 2026 and Cisco closed Galileo (folded into Splunk) in May 2026. Mature backends now ingest OpenTelemetry-shaped traces as their primary wire format, so choosing a non-OTel format in 2026 means opting out of the two largest acquisitions in the category.

Add to that the momentum of the AgentOps tooling ecosystem: the decorator-style AgentOps Python SDK ships with more than 400 integrations and a single decorator that covers most agent frameworks, making it a natural companion for whichever tracing backend you pick.

The two-layer model: transport and meaning

OpenTelemetry solves transport. It handles span creation, batching, context propagation, OTLP export, and sampling — the same plumbing your REST microservices already use. Semantic conventions solve meaning: the attribute vocabulary that lets a backend render a conversation view, compute per-call cost, and group agent runs without custom parsing.

There are two serious vocabularies, and your pick changes how much a rendered trace can tell you:

Dimension OpenTelemetry GenAI conventions OpenInference
Namespace gen_ai.* openinference-oriented span kinds
Span vocabulary Model + agent spans, gen_ai.operation.name LLM, TOOL, AGENT, CHAIN, RETRIEVER spans
Auto-instrumentation Growing community support Broad (LangChain, LlamaIndex, OpenAI, CrewAI, Mastra, ADK)
Maturity in 2026 Pre-stable, Development status Established, active releases
Wire format OpenTelemetry OTLP OpenTelemetry OTLP

Key insight: The choice is vocabulary, not wire format. Both ride the same OpenTelemetry transport, so either vocabulary keeps you portable across backends. As of core semconv v1.42.0 (June 2026), the entire gen_ai.* namespace was moved into a dedicated repository and remains Development status with no 1.0 — emit the five agent spans now to insulate your code from churn, but do not treat the convention as a stability promise yet.

Architecture: instruments, collector, Langfuse

Here is the shape you are building:

+-----------------------------+              OTLP (gRPC 4317 / HTTP 4318)
|  Claude Desktop / Cursor    | -------------------------------+
|  (MCP client, stdio / HTTP) |                                  |
+-------------+---------------+                                  v
              |  MCP streamable HTTP    +-----------------------+--------------------------+
+-------------v---------------+         |   OpenTelemetry Collector              |
|  Langfuse AgentOps MCP       | ------->|   receivers: otlp                       |
|  Server (Node FastMCP)      |  OTLP    |   processors: batch + attribute upsert  |
|  - telemetry / tools / rest | expos.   |   exporters: otlphttp -> langfuse        |
+-----------------------------+         +-----------------------------------------+-----+
                                                                                   |
   Agent runtime  --- LLM providers ----                                         v
   (LangGraph,                                       +---------------------------+
   CrewAI, Mastra)                                     |  Langfuse (ClickHouse)    |
                                                        |  traces / sessions / obs |
                                                        |  cost + usage at ingest   |
                                                        +---------------------------+

The split is deliberately redundant at the client edge. The collector receives both MCP-specific analytics (user intentions, session replay) and framework-generated spans, and it forwards a normalized stream to Langfuse (and optionally a second backend for alerts). Nothing slow runs in the MCP path; Langfuse remains a destination, not a hop.

Step 1 — Environment and export

Start from an env file referenced by both the collector and the MCP server so secrets live in one place per environment:

# Langfuse cloud (EU region shown)
LANGFUSE_HOST=https://cloud.langfuse.com
LANGFUSE_OTLP_ENDPOINT=https://cloud.langfuse.com/api/public/otel
LANGFUSE_PUBLIC_KEY=pk-lf-xxxxxxxx
LANGFUSE_SECRET_KEY=sk-lf-xxxxxxxx

# OpenTelemetry
OTEL_EXPORTER_OTLP_ENDPOINT=http://otel-collector:4318
OTEL_EXPORTER_OTLP_PROTOCOL=http/protobuf
OTEL_SERVICE_NAME=langfuse-agentops-mcp

# AgentOps companion
AGENTOPS_API_KEY=xxxxxxxx
AGENTOPS_AUTO_START_SESSION=true

Key insight: Langfuse authenticates via an Authorization basic header composed from public key and secret key. Keep only environment tokens server-side; never let a Claude Desktop config carry a secret past a pointer to a remote connector that performs OAuth.

Step 2 — OpenTelemetry Collector config

The collector adds production fidelity: batch buffers and a clean route to Langfuse.

receivers:
  otlp:
    protocols:
      http:
        endpoint: 0.0.0.0:4318
      grpc:
        endpoint: 0.0.0.0:4317

processors:
  batch:
    timeout: 5s
    send_batch_size: 1024
  attributes:
    actions:
      - key: environment
        value: production
        action: upsert

exporters:
  otlphttp/langfuse:
    endpoint: "https://cloud.langfuse.com/api/public/otel"
    headers:
      Authorization: "Basic ${LANGFUSE_BASIC_AUTH}"
      x-langfuse-ingestion-version: "4"

connectors:
  spanmetrics:
    dimensions:
      - name: gen_ai.operation.name
      - name: gen_ai.request.model

service:
  pipelines:
    traces:
      receivers: [otlp]
      processors: [batch]
      exporters: [otlphttp/langfuse]

Langfuse aims to be compliant with the OpenAI telemetry conventions and maps attributes in the langfuse.* namespace onto its data model. The usual production trap is turning off the batch processor under load, which floods the endpoint; keep it on.

Step 3 — A TypeScript FastMCP observability server

Rather than scrape the platform API, implement a FastMCP server that exposes observability as tools a Claude Desktop session can call. Each tool declares its inputSchema as plain JSON so the model can build well-shaped invocations.

import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js'
import { trace } from '@opentelemetry/api'

const tracer = trace.getTracer('langfuse-agentops-mcp')

const server = new McpServer({
  name: 'langfuse-agentops-mcp',
  version: '1.0.0',
})

server.tool(
  'get_trace',
  'Fetch a single Langfuse trace with its full span tree and cost',
  {
    inputSchema: {
      type: 'object',
      properties: {
        trace_id: { type: 'string', description: 'Langfuse trace identifier' },
        include_events: {
          type: 'boolean',
          default: false,
          description: 'Expand events under the trace',
        },
      },
      required: ['trace_id'],
    } as any,
  },
  async ({ trace_id, include_events }) => {
    const span = tracer.startSpan('mcp.get_trace')
    span.setAttribute('mcp.tool.name', 'get_trace')
    try {
      const data = await langfuseClient.fetchTrace(trace_id)
      span.setAttribute('gen_ai.usage.input_tokens', data.inputTokens)
      span.setAttribute('gen_ai.usage.output_tokens', data.outputTokens)
      return {
        content: [{ type: 'text', text: JSON.stringify(data, null, 2) }],
      }
    } finally {
      span.end()
    }
  },
)

server.tool(
  'list_session_traces',
  'Return all traces grouped under a session ID (session replay entry point)',
  {
    inputSchema: {
      type: 'object',
      properties: {
        session_id: { type: 'string' },
        limit: { type: 'number', default: 50 },
      },
      required: ['session_id'],
    } as any,
  },
  async ({ session_id, limit }) => {
    const traces = await langfuseClient.listSession(session_id, limit)
    return {
      content: [{ type: 'text', text: JSON.stringify(traces, null, 2) }],
    }
  },
)

server.tool(
  'agent_cost_by_agent',
  'Aggregate cost and token usage grouped by agent for a time window',
  {
    inputSchema: {
      type: 'object',
      properties: {
        from: { type: 'string', format: 'date-time' },
        to: { type: 'string', format: 'date-time' },
        group_by: { type: 'string', enum: ['agent_id', 'model'] },
      },
      required: ['from', 'to'],
    } as any,
  },
  async ({ from, to, group_by }) => {
    const agg = await langfuseClient.aggregateUsage({ from, to, groupBy: group_by })
    return {
      content: [{ type: 'text', text: JSON.stringify(agg, null, 2) }],
    }
  },
)

const transport = new StdioServerTransport()
await server.connect(transport)

This is deliberately minimal but model-usable: each tool carries a reference inputSchema, the model sees well-named tools, and cost columns flow because Langfuse stores the per-call usage joined at ingest.

The Python FastMCP equivalent

If your observability glue lives in Python, the same tools are a few lines with the official SDK and a native tracing story:

from langfuse import get_client
from mcp.server.fastmcp import FastMCP

mcp = FastMCP("langfuse-agentops")
langfuse = get_client()


@mcp.tool()
def get_trace(trace_id: str, include_events: bool = False) -> dict:
    '''Return a full trace including cost and any events.'''
    return langfuse.fetch_trace(trace_id, include_events=include_events)


@mcp.tool()
def list_session_traces(session_id: str, limit: int = 50) -> dict:
    '''Replay a session by listing all traces in order.'''
    return langfuse.list_traces({"session_id": session_id, "limit": limit})


@mcp.tool()
def agent_cost(from_ts: str, to_ts: str, group_by: str = "agent") -> dict:
    '''Cost and token aggregate per agent for a window.'''
    return langfuse.aggregate_usage(from_ts=from_ts, to_ts=to_ts, group_by=group_by)


mcp.run(transport="streamable-http")

Key insight: Because Langfuse stores the joined cost on every observation, the "which conversations are burning the budget" query is a ClickHouse select ... group by agent_id order by cost_usd with no price-table join at query time.

Step 4 — Connect Claude Desktop / Cursor

For a server the client launches in-process, add it to the config. For a remote streamable-HTTP server behind OAuth, prefer the Connectors UI.

{
  "mcpServers": {
    "langfuse": {
      "command": "node",
      "args": [],
      "env": {
        "LANGFUSE_HOST": "https://cloud.langfuse.com",
        "LANGFUSE_PUBLIC_KEY": "pk-xxxx",
        "LANGFUSE_SECRET_KEY": "sk-xxxx",
        "OTEL_EXPORTER_OTLP_ENDPOINT": "http://otel-collector:4318"
      }
    }
  }
}

Cursor uses the same top-level mcpServers key in .cursor/mcp.json. Local servers use command and args and env; remote (OAuth) servers use a url and are wired through the streamable-HTTP transport, which replaced the deprecated SSE transport in clients like Desktop, Claude Code, and VS Code.

OAuth 2.0 / Security guide

Never run the Langfuse secret in an MCP stdio child shipped to a shared desktop. The secure pattern is remote MCP plus OAuth, and Claude Desktop auto-discovers the standard metadata endpoint:

  1. Expose .well-known/oauth-authorization-server and a metadata document describing your issuer and token endpoint.
  2. The client fetches the issuer, then runs the authorization-code flow with PKCE; the client never sees the secret.
  3. Your MCP server validates the bearer JWT (check iss, aud, and exp) per request and returns RFC 6750-compliant 401s when the token is missing or invalid.
  4. Issue scopes such as langfuse:read:traces and langfuse:read:cost and assert them before each tool answers.
{
  "mcpServers": {
    "langfuse": {
      "url": "https://mcp.example.com/mcp"
    }
  }
}

Claude Desktop fetches the well-known metadata, walks the user through OAuth, and stores the token itself — the client never holds your key. Keep real secrets out of tracked config files and inject them at runtime.

Session replay in practice

Replay is the difference between "the site is broken" and "the agent called the refund tool twice at 03:14 because the tool response was empty". Because each run carries a session identifier and ordered observations, you can walk input-to-output per step, diff two runs to surface behavioral regressions, and pinpoint the exact divergence step — which is what production MCP replay suites now benchmark.

FAQ

Does Langfuse require the Langfuse SDK to benefit from MCP plus OTel? No. The OTLP endpoint at /api/public/otel ingests any OTel-compliant exporter, and Langfuse maps gen_ai.* and langfuse.* attributes onto its model. SDKs are an easier path, not a hard requirement.

Is the OpenTelemetry GenAI semantic convention stable? As of mid-2026 it is Development status only; the whole namespace moved to a dedicated semantic-conventions-genai repository and no 1.0 is published. Emit the five agent spans with gen_ai.operation.name set and track the migration notes.

Can the MCP server write back, for example submit scores or edit prompts? Yes. The native Langfuse MCP server exposes dataset, prompt, annotation, and scoring tools; your own FastMCP server can wrap writes too, but gate them behind read-only versus write OAuth scopes.

Do session replay and cost land for every framework? Langfuse surfaces pre-aggregated cost per trace and reads traces from LangChain, LlamaIndex, CrewAI, Mastra, and any OpenTelemetry-compatible runtime, so replay and cost work for all of them.

For more server recipes, browse the MCP directory, apply these patterns in real workflow examples, and follow the protocol roadmap on our latest AI news.

By Deepak Bagada, CEO at SaaSNext & Principal AI Architect.

Executive Briefing

Enjoyed this breakdown? Get our morning dispatch in your inbox.

Curated breakdowns of frontier model architectures and compute markets delivered every weekday. Zero fluff.

Frequently Asked Questions
No. Langfuse ingests OpenTelemetry traces over its /api/public/otel endpoint and maps gen_ai.* and langfuse.* attributes onto its data model, so any OTel-compliant exporter works. SDKs simply make the path easier.
They remain Development status with no 1.0 release as of mid-2026, living in a dedicated semantic-conventions-genai repository. Emit the five core agent spans and track migration notes.
Yes, the native MCP server exposes dataset, annotation, prompt, and scoring tools over streamable HTTP. Gate destructive write tools behind read-only versus write OAuth scopes.
Connect via a remote streamable-HTTP MCP server with OAuth, or run the FastMCP server locally as stdio with env variables pointing at /api/public/otel. Cost is pre-aggregated per trace at ingest.
Deepak Bagada
Author Profile

Deepak Bagada

CEO, SaaSNext

Deepak Bagada is the CEO of SaaSNext and founder of Daily AI World. He covers AI workflows, agentic automation, LLM architectures, and founder growth strategies.

Related Intelligence Analysis

Briefing AI Tools

Vercel AI SDK Tool Calling React: 5 Steps (2026)

Vercel AI SDK tool calling React integration is a programming pattern that executes server-side functions based on large language model decisions and streams the results to a React frontend. By combining streamText with...

Deepak Bagada Deepak Bagada
12m read
Breaking AI Tools

Fact-Density vs. Word Count: The New SEO for 2026

Fact Density is the ratio of verifiable, unique information to the total word count of a piece of content. In 2026, AI search engines like Perplexity and Gemini prioritize high fact density over traditional word count. A...

Deepak Bagada Deepak Bagada
4m read
Audio Briefing
Accessibility Preferences
High Contrast Mode
Accessible Reading Font

Keyboard Shortcuts

Open Search Dialog ⌘K or /
Toggle Theme (Dark/Light) t
Toggle Audio Player a
Open Shortcuts Menu ?
Close Active Dialog Esc