将 Cursor 连接到生产日志:通过 Elastic MCP 服务器

概述

1. 两个世界的断裂:日志与代码的脱节

在传统开发过程中,应用运行时的生产日志和本地的源代码是两座孤岛。

当需要根据日志中的报错或用户行为来优化代码时,开发者必须反复切换上下文:先到 Kibana 或日志平台分析数据,记住关键信息,再回到编辑器中修改代码。这个过程不仅低效,还容易遗漏细节,决策依赖猜测而非生产真相。

模型上下文协议 (Model Context Protocol, MCP) 的出现彻底改变了这一局面。它是一种开放标准,让 AI 客户端(如 Cursor)能够通过统一的接口连接到外部工具和数据源。这意味着 IDE 不仅能理解本地代码,还能同步查询 Elasticsearch 集群中的 APM 数据,并直接在编辑器中对生产行为进行推理。

Elastic 在其 Agent Builder 功能中内置了 MCP 服务器端点。你在 Kibana 中定义好查询工具,暴露到 MCP 端点,任何兼容 MCP 的客户端(包括 Cursor)都能调用它们。整个过程只需几分钟。

2. 我们要构建什么

以一个使用 Elastic APM 进行前端监控的电商搜索应用为例:

  • 前端 :通过 RUM JS Agent 捕获用户的筛选点击交互,数据存储在 traces-apm-default 索引中。
  • 后端 :Node.js APM Agent 捕获后端错误,数据存储在 logs-apm.error-default 索引中。

开发中面临两个典型场景:

  1. 数据驱动的 UI 优化:产品团队想精简搜索页面,但目前对六个筛选器(品类、品牌、价格区间、用户性别、星期几、地区)的使用情况一无所知,需要生产数据支撑决策。
  2. 生产环境报错调试:用户反馈搜索接口间歇性返回 500 错误,且从两天前开始出现,没有规律,需要快速定位异常细节和根源。

我们将通过 Agent Builder 创建两个工具并连接到 Cursor:

  • get_filter_usage:查询 traces-apm-default 中筛选器点击事件,按筛选器名称返回使用频次。
  • get_recent_errors:查询 logs-apm.error-default 中指定服务最近的错误分组,包括异常消息和堆栈根源代码位置。

整体架构

Elastic Stack 环境
MCP 客户端协议
SSE 长连接
执行 ES|QL 查询
APM 数据索引
Cursor IDE
mcp-remote

桥接进程
Kibana Agent Builder

MCP 端点
Elasticsearch

集群

Cursor 通过 mcp-remote 作为本地代理,使用 Server‑Sent Events (SSE) 传输协议连接到 Kibana 暴露的 MCP 端点。工具定义和实际的 ES|QL 查询均在 Kibana 侧维护,Cursor 仅在需要时发起远程调用,数据按需返回。

3. 准备工作

开始之前,请确保具备下列环境:

  • Elasticsearch 9.3+ 或 Elastic Cloud Serverless 实例
  • Kibana URL 及拥有适当权限的 API Key(需要能读取 APM 相关索引)
  • 一个使用 Elastic APM 进行探针注入的前后端应用(RUM Agent 生成交互追踪,APM Agent 记录错误)
  • Cursor 2.6+ 已安装

安全最佳实践

API Key 应遵循最小权限原则,仅授予 read 权限访问 traces-apm-*logs-apm.error-* 索引,不要使用超级用户密钥。

4. 创建 Agent Builder 工具

在 Kibana 中通过 Agent Builder API 定义工具。每个工具本质上是一条 ES|QL 查询,附带名称和描述,Cursor 根据描述自动决定何时调用该工具。

4.1 工具一:get_filter_usage

该工具针对前端交互事件,按 labels.filter_name 分组统计每种筛选器的点击次数。

json 复制代码
{
  "id": "get_filter_usage",
  "type": "esql",
  "description": "返回 ecommerce-search-ui 服务中各搜索筛选器的使用次数,按频次由高到低排序。",
  "configuration": {
    "query": "FROM traces-apm-default | WHERE service.name == \"ecommerce-search-ui\" | WHERE transaction.type == \"user-interaction\" | WHERE labels.filter_name IS NOT NULL | STATS count = COUNT(*) BY labels.filter_name | SORT count DESC"
  }
}

原理解析

  • FROM traces-apm-default 指向 APM 的前端追踪索引;
  • service.name 限定服务名,transaction.type == \"user-interaction\" 确保只统计用户交互类事务;
  • labels.filter_name 是一个自定义标签,记录了被点击的筛选器名称;过滤掉空值后,用 STATS ... BY 分组计数。

4.2 工具二:get_recent_errors

该工具从错误日志中提取最近高频错误的分组信息,包含异常消息和错误发生处的代码源码行(culprit)。

json 复制代码
{
  "id": "get_recent_errors",
  "type": "esql",
  "description": "返回 ecommerce-search-ui 服务最近的高频错误分组(按出现次数排名),包含异常消息和代码位置。",
  "configuration": {
    "query": "FROM logs-apm.error-default | WHERE service.name == \"ecommerce-search-ui\" | WHERE processor.name == \"error\" | STATS count = COUNT(*) BY error.grouping_key, error.exception.0.message, error.culprit | SORT count DESC | LIMIT 5"
  }
}

原理解析

  • 错误数据存储在 logs-apm.error-* 索引中,error.grouping_key 是 Elastic APM 自动生成的错误指纹,相同类型的错误会归为一组;
  • error.exception.0.message 提取第一个异常的消息;
  • error.culprit 记录触发错误的源码位置(如函数或文件行号);
  • 按出现次数倒序,限制返回 top 5。

4.3 工具创建与优化替代方案

通过 POST /api/agent_builder/tools 接口向 Kibana 注册工具。更详细 API 文档可参见 Kibana Agent Builder API

潜在问题与优化建议

  1. 缺少时间过滤
    上述查询会扫描整个索引,可能导致性能问题且数据量膨胀。优化方案是为工具添加可选的时间范围参数,在 ES|QL 中追加 WHERE @timestamp >= ?start AND @timestamp <= ?end。MCP 工具支持参数化,可以在工具定义中增加 parameters 配置,让用户在 Cursor 中自然语言指定"过去 24 小时"并映射为时间戳。
  2. 服务名称硬编码
    目前固定为 "ecommerce-search-ui",工具复用性差。可以将服务名定义为一个参数(service_name),由对话上下文动态传入,使工具可用于多个微服务。
  3. 错误日志中 processor.name == \"error\" 可能冗余
    logs-apm.error-default 索引已默认只包含错误事件,但为防止索引内混入其他处理器数据,加上过滤条件也可以接受。从逻辑严谨性考虑,这条条件可以保留,但应补充注释说明防御性用途。

改进后的 get_recent_errors 工具示例(参数化版本)

json 复制代码
{
  "id": "get_recent_errors",
  "type": "esql",
  "description": "返回指定服务最近的高频错误分组。支持通过服务名和时间范围筛选。",
  "parameters": [
    {"name": "service_name", "type": "string", "description": "APM 服务名", "required": true},
    {"name": "hours_ago", "type": "number", "description": "从多少小时前开始统计,默认 24", "default": 24}
  ],
  "configuration": {
    "query": "FROM logs-apm.error-default | WHERE service.name == ?service_name | WHERE @timestamp >= NOW() - ?hours_ago HOUR | STATS count = COUNT(*) BY error.grouping_key, error.exception.0.message, error.culprit | SORT count DESC | LIMIT 5"
  }
}

这种设计让工具更加通用,同时避免检索海量历史数据。

5. 将 Cursor 连接到 Elastic MCP 服务器

Cursor 通过 ~/.cursor/mcp.json 文件注册 MCP 服务器。打开此文件并添加配置(首次使用需手动创建):

json 复制代码
{
  "mcpServers": {
    "elastic-agent-builder": {
      "command": "npx",
      "args": [
        "-y",
        "mcp-remote",
        "https://YOUR_KIBANA_URL/api/agent_builder/mcp",
        "--header",
        "Authorization: ApiKey YOUR_API_KEY"
      ]
    }
  }
}

连接原理

Cursor 本身并不直接支持 SSE 网络连接,而是通过启动一个本地子进程 mcp-remote(一个轻量级 MCP‑to‑SSE 桥接)来实现。mcp-remote 作为 MCP 客户端,接收 Cursor 的请求,并通过 HTTP SSE 长连接与 Kibana 的 MCP 端点通信,从而安全地将远程工具暴露给 Cursor。

安全加固与优化

  1. API Key 不应硬编码在配置文件

    将 API Key 明文写在 args 中存在泄露风险,尤其当配置文件被提交到版本控制系统时。应使用环境变量注入:

    json 复制代码
    {
      "command": "npx",
      "args": [
        "-y",
        "mcp-remote",
        "https://${env:KIBANA_URL}/api/agent_builder/mcp",
        "--header",
        "Authorization: ApiKey ${env:ELASTIC_API_KEY}"
      ]
    }

    然后在系统环境变量或 Cursor 的环境变量配置块中设置 KIBANA_URLELASTIC_API_KEY

  2. 持久化守护进程替代 npx -y

    每次 Cursor 重启都会重新下载和启动 mcp-remote,可能影响响应速度。可考虑全局安装 mcp-remote 包,并直接使用 mcp-remote 路径作为命令,避免重复下载。

  3. 连接健康检查

    配置完成后,在 Cursor 的 Agent 面板中应能看到 get_filter_usageget_recent_errors 两个工具。如果未出现,检查 Kibana 日志和网络连接,确保 API Key 具有访问 Agent Builder 端点的权限。

Elasticsearch Kibana MCP 端点 mcp-remote 子进程 Cursor Agent Elasticsearch Kibana MCP 端点 mcp-remote 子进程 Cursor Agent 调用工具 (toolCall) SSE 发送工具执行请求 执行 ES|QL 查询 返回查询结果 SSE 流式返回数据 MCP 响应格式化结果

图:工具调用的完整请求‑响应流

6. 使用案例 1:数据驱动的 UI 简化

在 Cursor 的 Agent 对话中,只需用自然语言提问:"显示每个搜索筛选器的使用频次 "。Cursor 会自动匹配 get_filter_usage 工具并触发调用。返回结果类似:

筛选器 点击次数
category 15203
manufacturer 14120
price_range 5211
customer_gender 342
day_of_week 198
region 87

显然,customer_genderday_of_weekregion 三个筛选器几乎无人使用。

接着,对 Cursor 提出修改要求:"根据这些数据简化 SearchFilters 组件,将使用量最低的三个筛选器收起到'更多筛选'开关下,保持品类、品牌、价格范围直接可见。"

Cursor 会打开 src/components/SearchFilters.jsx,分析现有代码结构,并生成精确的代码更改建议。整个过程无需人工切换上下文,修改依据直接来自生产数据,而非主观假设。

交互流程示例

开发者提问:显示筛选器使用频次
Cursor 识别意图并调用 get_filter_usage
返回生产统计数据
开发者分析数据并给出修改指令
Cursor 读取本地组件代码
提出 UI 重构方案
开发者审阅并应用更改

7. 使用案例 2:生产错误调试

报错场景:搜索接口间歇性 500 错误,近日出现且并不稳定。开发者直接在 Cursor 中询问:"显示 ecommerce-search-ui 最近抛出了哪些错误 "。Cursor 调用 get_recent_errors,返回结果示例如下:

出现次数 异常消息 错误来源 (culprit)
47 "category" is a text field, cannot be used in terms aggregation SearchService.aggregate:42
9 Connection refused to Elasticsearch ElasticsearchConnector.connect:18

错误信息直截了当:category 字段是 text 类型,不能直接用于 terms 聚合,应使用 category.keyword 。同时 culprit 指明了出错位置 SearchService.js:42

于是可以直接要求 Cursor:"修复这个错误,把 category 改为 category.keyword"。Cursor 会在文件定位到相关代码,给出修改前后对比并自动应用补丁。

自动化调试链

询问最近错误
获取APM数据
人类+AI协同
报告错误
Cursor对话
调用get_recent_errors
返回异常分组
分析根源
提出代码修复
应用修复

这种闭环将"发现问题 → 拉取生产证据 → 定位代码 → 实施修复"完整的流程缩短到同一个编辑界面内,大幅降低调试认知负荷。

8. 纠正原文中的不准确与改进点

在实现该方案时,原文中存在一些易于误解或可提升之处,现详细分析并提供纠正和替代方案。

8.1 关于"Elastic ships a built-in MCP server as part of Agent Builder"

问题 :原文易使读者误认为 Agent Builder 是一个独立产品或组件。事实上,Agent Builder 是 Elastic Security 中的一个功能模块,运行在 Kibana 内部,允许用户创建和管理自定义集成。它内置了一个 MCP 端点,通过该端点暴露用户定义的工具。因此,不存在一个叫做 "Elastic Agent Builder MCP Server" 的独立进程,它本质上是 Kibana 的一个 HTTP 端点。

纠正表述

"Elastic 在 Kibana 的 Agent Builder 功能中提供了一个内置的 MCP 端点。你在 Kibana 中定义工具后,该端点会自动以 MCP 标准格式暴露这些工具。"

8.2 工具查询缺少时间范围,生产环境风险高

原文两则 ES|QL 查询都没有时间过滤子句。在生产环境下,traces-apm-* 索引可能累积数月至数年的数据,全表扫描将导致严重的性能问题和超长查询时间,且返回的数据对"最近"的使用频率分析毫无意义。

替代方案

  • 在 Agent Builder 工具中加入时间参数,例如自动取"最近 7 天"作为默认窗口。
  • 或者利用 ES|QL 的 WHERE @timestamp >= NOW() - 7 DAY 作为硬性安全限制,防止查询过早数据。
  • 推荐让工具支持自然语言时间参数,如"过去 24 小时""上周",由 LLM 转换成相对时间表达式。

8.3 连接配置中 API Key 明文风险

原文直接将 API Key 写在命令行参数中,这会暴露给进程列表和系统审计日志。更佳实践已在第 5 节中给出:使用环境变量或专门的密钥管理服务注入。

8.4 错误工具中 error.culprit 字段的可靠性说明

error.culprit 是 APM Agent 尝试推断的源代码位置,但并非所有语言/框架都能准确填充(例如经过压缩的 JavaScript 或缺乏调试符号的服务)。当该字段为空或模糊时,开发者仍需要结合堆栈跟踪查看。因此,优化版工具应当考虑加入 error.exception.0.stacktrace 的前几帧,或者提供链接跳转到 Kibana APM 错误详情页,让用户能获得完整上下文。

建议补充字段

esql 复制代码
| STATS count = COUNT(*) BY error.grouping_key, error.exception.0.message, error.culprit, error.exception.0.stacktrace

但堆栈字段较大,直接分组可能导致过多唯一组合。可改为返回前几条错误样本的 ID 或链接。

8.5 单点故障与高可用优化

当前架构下,Kibana 成为所有 MCP 查询的必经之路,且 Kibana 本身并非为高频率的程序化查询而设计。若 Cursor 频繁调用工具,可能给 Kibana 带来压力。替代方案是将 MCP 服务器实现为一个轻量级的独立服务,直接与 Elasticsearch 通信,绕过 Kibana 的 MCP 端点,以此获得更好的性能和可伸缩性。

高级架构
MCP
Elasticsearch HTTP
预定义查询模板
Cursor
自定义 MCP Server

Elastic Proxy
Elasticsearch

这个自定义 MCP 服务器可以使用 TypeScript 或 Python 编写,内部封装查询并支持参数验证,安全性和性能都优于通用端点。

9. 小结

本文不仅演示了如何将 Elastic APM 数据带入 Cursor,更深入优化了整个连接链路的安全、性能和工具设计。

  • 数据驱动的决策:通过 MCP,生产环境的使用频率直接决定了 UI 组件的去留,避免了主观猜测。
  • 无缝的调试体验:错误细节和源代码并置,使修复过程一气呵成。
  • 可复用的模式:这种方法适用于 Elasticsearch 中的任何数据------性能指标、A/B 测试结果、审计日志、功能开关、用户会话等。你只需定义对应的 Agent Builder 工具,或搭建专用的 MCP 服务器,即可让任何数据源成为 Cursor 上下文的一部分。
相关推荐
计算机安禾7 小时前
【Linux从入门到精通】第41篇:Linux内核编译初体验——裁剪属于你自己的内核
linux·运维·服务器
Elastic 中国社区官方博客7 小时前
2026 年金融服务可观测性现状:从实施到业务影响
大数据·运维·人工智能·elasticsearch·搜索引擎·金融·自动化
谷哥的小弟7 小时前
(最新版)腾讯云服务器项目部署教程(4)— 部署项目
linux·运维·服务器·云计算·腾讯云·云服务器·项目部署
楼田莉子7 小时前
仿muduo库的高并发服务器——buffer缓冲区模块、socket模块
运维·服务器
starvapour8 小时前
INTEL-C621A芯片组服务器主板如何修改pcie等级
运维
酸钠鈀8 小时前
AI M61SDK Ubuntu 环境搭建
linux·运维·ubuntu
2601_949817928 小时前
nginx 代理 redis
运维·redis·nginx
JiaWen技术圈8 小时前
netfiler 协议栈钩子
linux·运维·服务器·安全
橙子也要努力变强8 小时前
进程与信号
linux·服务器·c++