Metadata-Version: 2.5
Name: langfuse-trace-mcp
Version: 0.1.0.post1
Summary: Read-only stdio MCP server for Langfuse traces
License-Expression: MIT
License-File: LICENSE
Keywords: langfuse,mcp,observability,traces
Classifier: Environment :: Console
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3 :: Only
Classifier: Programming Language :: Python :: 3.12
Classifier: Topic :: Utilities
Requires-Python: >=3.12
Requires-Dist: anyio<5,>=4.9
Requires-Dist: httpx<0.29,>=0.28.1
Requires-Dist: jsonschema[format]<5,>=4.25
Requires-Dist: mcp==1.27.0
Requires-Dist: pydantic<3,>=2.11
Description-Content-Type: text/markdown

# langfuse-trace-mcp

用于分析 Langfuse Trace、Session 和 badcase 的只读 Python MCP 服务，通过 stdio 提供六个工具。服务负责查询、分页和正文切片，分析由 Codex、Claude 等调用方完成；工具内部不调用大模型。

支持按 Trace ID、Session ID 或时间范围查询，先返回摘要，再按需分页读取节点和正文，减少一次查询带来的 token 消耗。

Python 分发包名为 `langfuse-trace-mcp`，命令行入口为 `langfuse-mcp`，Python 模块名为 `langfuse_mcp`。

## 1. 从 PyPI 安装

准备好以下内容：

- [uv](https://docs.astral.sh/uv/getting-started/installation/)（包含 `uvx`）。已有 uv 时无需重新安装。
- 运行客户端的机器能够下载 PyPI 依赖，并访问 Langfuse。
- 同一个 Langfuse 项目的 Public Key 和 Secret Key，可从该项目的 API Keys 设置中获取。

在任意目录执行以下命令，从 [PyPI](https://pypi.org/project/langfuse-trace-mcp/) 安装并检查启动入口：

```bash
uvx --python 3.12 \
  --from langfuse-trace-mcp==0.1.0.post1 \
  langfuse-mcp --help
```

`uvx` 首次运行时会自动创建隔离环境、安装包及其依赖，后续复用缓存。`--python 3.12` 指定运行时；本机缺少该版本时，uv 默认会自动下载。运行依赖包含官方 MCP Python SDK 和 httpx，服务直接调用 Langfuse Public API。

正常输出应包含 `--base-url`、`--public-key`、`--secret-key` 三个参数。这个检查只启动命令行帮助，不连接 Langfuse。

包名与命令名不同：`--from langfuse-trace-mcp==0.1.0.post1` 指定安装来源，后面的 `langfuse-mcp` 是执行入口。客户端配置中也需要保留这一组合。

以下示例固定使用 `0.1.0.post1`。升级时，将配置中的版本号改为已发布的新版本，先运行对应版本的 `--help` 完成安装，再重启客户端。

## 2. 在客户端中配置

服务通过 **stdio** 通信，由客户端自动启动和管理进程，无需先手动启动或使用 `nohup` 常驻后台。它不提供可填写到远程 MCP 连接框的 HTTP 地址。

所有客户端使用相同的三个启动参数：

| 参数 | 填写内容 |
| --- | --- |
| `--base-url` | Langfuse 服务地址，如 `https://langfuse.example.com`；不要追加 `/api/public` |
| `--public-key` | Langfuse 项目的 Public Key |
| `--secret-key` | 同一项目的 Secret Key |

下面的地址和密钥都是占位符，使用前请替换。连接凭据在启动时传入，工具调用中无需传入凭据或 `environment`。

配置中的 `command` 使用 `uvx`。如果桌面客户端找不到它，请查出实际路径，并将 `command` 改为该绝对路径：

| 系统 | 查找 uvx 的命令 |
| --- | --- |
| macOS / Linux | `command -v uvx` |
| Windows PowerShell | `(Get-Command uvx).Source` |

Windows 的 JSON / TOML 配置中可用 `/` 表示路径分隔符，例如 `C:/Users/你的用户名/.local/bin/uvx.exe`。

### Codex 桌面客户端 / CLI

打开 `~/.codex/config.toml`，添加以下配置；若已有 `[mcp_servers.langfuse]`，修改原条目即可：

```toml
[mcp_servers.langfuse]
command = "uvx"
args = [
  "--python", "3.12",
  "--from", "langfuse-trace-mcp==0.1.0.post1",
  "langfuse-mcp",
  "--base-url", "https://langfuse.example.com",
  "--public-key", "<public_key>",
  "--secret-key", "<secret_key>",
]
```

保存后重启 Codex 桌面客户端，或重新启动 Codex CLI 会话。桌面客户端可在 **Settings → MCP servers** 中检查服务。

如果安装了 Codex CLI，也可在终端检查登记的配置：

```bash
codex mcp get langfuse
```

应显示 `enabled: true`、`transport: stdio` 及配置的启动命令。该命令只确认配置已登记，实际连接和查询可用下文的对话示例验证。

### Claude Desktop

打开 Claude 桌面应用的 **Settings → Developer → Edit Config**。配置文件通常位于：

| 系统 | 配置文件 |
| --- | --- |
| macOS | `~/Library/Application Support/Claude/claude_desktop_config.json` |
| Windows | `%APPDATA%\Claude\claude_desktop_config.json` |

将 `langfuse` 加入 `mcpServers`。已有其他服务时，保留原条目并合并此配置：

```json
{
  "mcpServers": {
    "langfuse": {
      "command": "uvx",
      "args": [
        "--python", "3.12",
        "--from", "langfuse-trace-mcp==0.1.0.post1",
        "langfuse-mcp",
        "--base-url", "https://langfuse.example.com",
        "--public-key", "<public_key>",
        "--secret-key", "<secret_key>"
      ]
    }
  }
}
```

保存后完全退出并重新打开 Claude Desktop。在 Developer 设置中检查连接状态，或从对话输入框的 **Connectors** 中查看 `langfuse` 和可用工具。

此配置用于本地桌面应用，Claude 网页版不能直接启动本机的 stdio 进程。

### Claude Code

已安装 Claude Code 时，在 macOS / Linux 终端执行：

```bash
claude mcp add --transport stdio --scope user langfuse -- \
  uvx --python 3.12 --from langfuse-trace-mcp==0.1.0.post1 langfuse-mcp \
  --base-url 'https://langfuse.example.com' \
  --public-key '<public_key>' \
  --secret-key '<secret_key>'
```

`--scope user` 表示该用户的所有项目均可使用；`--` 后面是 `uvx` 命令及其启动参数。

检查配置及连接：

```bash
claude mcp get langfuse
```

重新启动 Claude Code 会话，输入 `/mcp` 查看 `langfuse` 的连接状态和工具。Claude Code 与 Claude Desktop 分别管理 MCP 配置，使用哪个客户端就配置哪一个。

以上接入方式依据 [OpenAI 官方 Codex MCP 文档](https://developers.openai.com/codex/mcp)、[Claude Desktop 本地 MCP 指南](https://modelcontextprotocol.io/docs/develop/connect-local-servers)和 [Claude Code MCP 文档](https://code.claude.com/docs/en/mcp)。

## 3. 开始查询

连接成功后，直接在 Codex 或 Claude 中描述需求，例如：

> 使用 langfuse MCP 分析 trace_id 为 `<trace_id>` 的请求。先获取摘要和第一页 observations，定位可疑节点后再按需读取 input/output，不要一次读取全部正文。

> 查询 session_id 为 `<session_id>` 的 Trace，先返回 10 条，说明哪些请求可能需要进一步排查。

> 查询北京时间 2026-10-10 09:00 到 10:00 之间开始的 Trace，先返回 20 条摘要；需要查看更多时再续页。

> 查找北京时间 2026-10-10 09:00 到 10:00 之间有 Trace 开始的 Session，先返回第一页。

服务只返回事实数据，badcase 分析由调用方完成。下面列出工具和调用示例，方便明确控制查询范围。

### 六个工具

| 工具 | 首次调用的主要参数 | 用途 |
| --- | --- | --- |
| `list_traces` | session_id，或 from_time + to_time；可选 name、user_id、tags、order、view、limit | 查找 Trace，或分页读取一个 Session 的 Trace |
| `get_trace` | trace_id | 获取单条 Trace 的基本信息和指标 |
| `list_observations` | trace_id，或 from_time + to_time；可选 parent_observation_id、name、type、level、view、limit | 分页查看节点与错误状态 |
| `get_observation` | trace_id + observation_id | 查看单节点的耗时、模型、用量与错误信息 |
| `read_content` | trace_id、可选 observation_id、field；可选 path、format、offset、limit | 读取 input/output/metadata 等字段的结构或片段 |
| `list_sessions` | from_time + to_time；可选 time_basis、limit | 按 Trace 开始时间或 Session 创建时间发现 Session |

完整参数与返回值见包内的 `langfuse_mcp/contracts.json`，源码中对应 `src/langfuse_mcp/contracts.json`；详细设计位于源码仓库的 `docs/stdio-mcp-design.md`。工具发现只返回输入 Schema 和简短说明，工具结果为一个包含紧凑 JSON 的 TextContent。

### 按 Trace 查看节点和正文

常用调用顺序如下。这里表示 MCP 工具名和参数，不是 shell 命令：

1. `get_trace({"trace_id":"..."})` 获取概况。
2. `list_observations({"trace_id":"...","limit":20})` 查看一页节点。
3. `get_observation({"trace_id":"...","observation_id":"..."})` 定位可疑节点。
4. `read_content({"trace_id":"...","observation_id":"...","field":"input","path":"/messages","limit":10})` 查看一页消息预览。
5. 对需要分析的消息读取 `/messages/3/content`，按需续读正文。

### 按 Session 或时间查询

调用 `list_traces`，单独提供 `session_id` 即可查询 Session 内的 Trace：

```json
{"session_id": "<session_id>", "limit": 10}
```

调用 `list_traces` 查询指定时间范围，时间必须包含时区：

```json
{
  "from_time": "2026-10-10T09:00:00+08:00",
  "to_time": "2026-10-10T10:00:00+08:00",
  "limit": 20
}
```

调用 `list_sessions` 发现这个时间范围内有 Trace 开始的 Session：

```json
{
  "from_time": "2026-10-10T09:00:00+08:00",
  "to_time": "2026-10-10T10:00:00+08:00",
  "time_basis": "trace_started",
  "limit": 20
}
```

如果要按 Session 自身的创建时间查询，将 `time_basis` 改为 `created`。

### 获取下一页

当返回的 `next_cursor` 非空时，调用**同一个工具**，只传该 cursor：

```json
{"cursor": "<上一次返回的 next_cursor>"}
```

不要同时传 `limit`、ID 或时间条件；查询条件已保存在 cursor 中。`next_cursor: null` 表示结束。列表和 `read_content` 都使用这一续页方式。

## 4. 分页与内容读取

- 列表默认 20 条，最大 50 条。每次至多获取一个新的上游源页，不会自动遍历整个 Trace 或时间窗口。
- 后续调用同一个工具时只传 `{"cursor":"上次的 next_cursor"}`。cursor 与其他参数混用会报错；`next_cursor=null` 表示结束。
- 一页因输出长度限制分多次返回时，优先消费已读取的剩余记录。同一 cursor 重试会重放相同结果。
- Observation 的 level 筛选和 Session 去重可能产生空 items，但 next_cursor 仍有值；这时可以继续读取。
- 时间必须带时区，范围为 `[from_time,to_time)`。Trace、Observation、Session created 模式分别过滤 timestamp、startTime、createdAt。
- `read_content` 用 JSON Pointer 定位字段，再处理选中的内容。文本按 Unicode 字符分页；数组和对象按项/键分页。字符串化 JSON 可以按路径访问，`format=text` 可以连续读取其文本。
- 正文默认 4000 字符、最多 8000；数组/对象默认 20 项、最多 50。整个返回同时受 12,000 个 JSON 字符和 64 KiB 限制。
- 正文 cursor 固定已读取的内容；新建不同路径的请求不保证与旧快照同时刻。实体缓存有效 5 秒；cursor 空闲 15 分钟、最长 1 小时，进程重启或状态淘汰后需重新查询。
- 选中内容中的已知秘密字段、启动密钥及明确标记的 base64 会被处理，并附带 warnings；敏感字段不能通过子路径绕过脱敏。偏移量对应处理后的内容。不会执行正文指令或下载其中的 URL。

节点集合使用 Langfuse 原生分页。当前旧版 API 对单节点 I/O 不提供字符范围下载，因此首次读取仍可能下载整条节点；后续由 MCP 切片返回。单响应解压后最多 32 MiB，一次工具调用累计最多 64 MiB、最多 3 次请求（含重试），工具总时限 30 秒。

本版使用参考部署支持的 Trace 列表、Observation v1 和 Session 列表端点。官方已将它们标为 legacy，Langfuse v4 的兼容性需另行验证。页码分页受持续写入和晚到数据影响，不提供跨页强一致快照。

## 5. 验证与排查

先运行第一节的 `uvx ... --help`，确认包能下载安装。然后在客户端查看 `langfuse` 的连接状态和六个工具，并使用一个已知 Trace ID 查询摘要。

客户端显示已连接只代表 MCP 连接正常，Langfuse 地址和密钥会在第一次实际查询时验证。

| 现象 | 检查方法 |
| --- | --- |
| 客户端找不到命令、出现 `ENOENT` | 确认已安装 uv，将 `command` 改为查到的 `uvx` 绝对路径 |
| 首次连接启动超时 | 先在终端运行第一节的 `--help` 命令，完成 Python、包和依赖下载，再重启客户端 |
| 报找不到包或版本 | 确认 `--from` 为 `langfuse-trace-mcp==0.1.0.post1`，检查 PyPI 或所用镜像是否可以访问该版本 |
| 修改配置后未出现工具 | 检查 JSON / TOML 格式，保留其他配置条目，保存后重启相应客户端或 CLI 会话 |
| 显示已连接，但查询报 `AUTH_FAILED` | 检查地址和两个 Key 是否属于同一 Langfuse 项目 |
| 查询报连接错误或超时 | 确认运行客户端的机器能访问 Langfuse；内网部署需要相应网络连接 |
| 手动启动后终端没有输出 | stdio 服务在等待客户端消息，属于正常行为；通过 MCP 客户端调用工具，按 Ctrl+C 结束手动启动的进程 |
| 返回 `CURSOR_EXPIRED` | cursor 已过期、被淘汰或服务已重启，重新提交首次查询条件 |

服务 stdout 仅用于 MCP 消息，日志写入 stderr；客户端报告启动失败时，可在其 MCP 日志中查看原因。

## 6. 开发与相关文档

修改代码或运行测试时，下载源码并进入项目根目录：

```bash
cd /absolute/path/to/langfuse-mcp
uv sync --locked
uv run --no-sync langfuse-mcp --help
uv run ruff format --check .
uv run ruff check .
uv run pytest -m "not live"
uv build
```

测试使用人工数据和 httpx MockTransport；stdio 集成测试需要允许监听临时的 `127.0.0.1` 端口。覆盖源页拆分、游标重放与取消、Session 去重、正文切片、响应限额、协议错误、两个 MCP 协议版本和 EOF 退出。

源码附带的验收脚本可检查 stdio 握手和六个工具的发现，不访问 Langfuse：

```bash
uv run --no-sync python tests/smoke_stdio.py \
  --base-url http://127.0.0.1:1 \
  --public-key placeholder --secret-key placeholder \
  --discovery-only
```

预期输出 `PASS initialize tools/list`。要验证真实查询，传入连接参数和一个存在的 Trace ID：

```bash
uv run --no-sync python tests/smoke_stdio.py \
  --base-url https://langfuse.example.com \
  --public-key '<public_key>' --secret-key '<secret_key>' \
  --trace-id '<existing_trace_id>'
```

验收脚本只读取小页和一个正文片段，输出通过项与错误码。它不会自动加载其他项目的配置。没有节点的 Trace 会明确跳过单节点检查。源码安装和这些脚本用于验证本地代码；客户端的 `uvx --from` 配置运行的是 PyPI 发布版本。

构建出的 wheel 可以安装到独立 Python 环境，并直接运行该环境的 `langfuse-mcp` 可执行文件。源码仓库的 `docs/implementation-plan.md` 和 `docs/validation.md` 分别记录实施方案与验证结果；`docs` 不随发行包分发。

## 7. 构建与发布

发行包使用标准的 `pyproject.toml` 元数据和 Hatchling 构建后端。文件范围由构建配置明确限定：

- 源码发行包（`.tar.gz`）：源码、测试及人工数据、README、MIT 许可证、`pyproject.toml`、`uv.lock`、`.python-version`、`.gitignore`，以及构建工具生成的包元数据。
- wheel（`.whl`）：`langfuse_mcp` 运行模块、`contracts.json`、MIT 许可证和安装元数据。
- 两种发行包均排除整个 `docs`、`.git`、字节码和 `.DS_Store`；虚拟环境、缓存、旧构建产物及 ZIP 不在文件清单中。

构建并校验待发布文件：

```bash
uv build --no-sources
uvx --from 'twine>=7,<8' twine check --strict \
  dist/langfuse_trace_mcp-0.1.0.post1-py3-none-any.whl \
  dist/langfuse_trace_mcp-0.1.0.post1.tar.gz
```

准备好 PyPI 发布令牌并在本机设置 `UV_PUBLISH_TOKEN` 后，明确指定本次上传的两个文件，避免旧包或 ZIP 混入：

```bash
uv publish \
  dist/langfuse_trace_mcp-0.1.0.post1-py3-none-any.whl \
  dist/langfuse_trace_mcp-0.1.0.post1.tar.gz
```

构建和 `twine check` 不会上传文件；只有 `uv publish` 执行发布。每次新发布需递增版本号，同步 `pyproject.toml` 与 `src/langfuse_mcp/__init__.py`，运行 `uv lock` 并在命令中使用对应版本的文件名。

PyPI 项目页的说明来自发行包内的 README，修改后需随新版本发布才会更新。

## 8. 许可证

本项目采用 MIT 许可证，完整条款见 `LICENSE`。许可证随源码发行包及 wheel 一同分发。
