如何使用 OpenTelemetry 和 Elastic APM 追踪 MCP 服务器工具调用

作者:来自 Elastic Jeffrey Rengifo

为 MCP 服务器添加 OpenTelemetry 追踪,在 Elastic APM 中可视化工具调用性能,并通过 Agent Builder MCP 从 Claude Desktop 查询追踪数据。

MCP 服务器本质上只是一个 Node 进程,这意味着只需要一个 --import 标志就可以启用 OpenTelemetry 插桩。真正的新变化发生在追踪数据进入 Elastic APM 之后。同一个生成这些追踪数据的 Claude Desktop 会话,可以通过 Elastic Agent Builder MCP 再次查询这些数据。agent 可以分析自己的工具调用延迟、识别慢工具,并在不离开聊天窗口的情况下解释失败原因。可观测性不再只是人类事后查看的 dashboard,而是 agent 在工作过程中使用的上下文。本文将介绍 MCP 的 OTel 语义约定、工具 span 的包装模式,以及在 Elastic 侧如何闭环。

前提条件

  • Elastic Cloud Hosted( 9.3+ )或 Serverless
  • Claude Desktop
  • 一个使用 Elastic Distribution of OpenTelemetry( EDOT )进行 instrumentation 的 MCP 服务器。下文会介绍如何进行 instrumentation 。

MCP 服务器中的可观测性缺口

MCP 服务器默认不带任何内置可观测性,这意味着工具调用延迟、错误和性能基线对开发者来说是不可见的。MCP( Model Context Protocol )服务器正越来越多地作为 AI 驱动应用的基础设施,为 AI 模型提供数据库、API、内部工具和业务数据访问能力。而 MCP SDK 本身并不会对这些进行插桩。

这个缺口主要体现在三个具体方面:

  • 当一次工具调用耗时 3 秒时,你不知道瓶颈是在业务逻辑、下游 API 还是数据层。
  • 当工具调用失败时,你只能看到错误消息,却不知道服务器在失败之前正在执行什么。
  • 当你新增一个工具时,你没有任何性能基线可以进行对比。

这些问题和任何后端服务面临的问题完全相同。解决方案也与后端开发者多年来一直使用的方法相同:使用 OpenTelemetry 进行分布式追踪。

MCP 服务器本质上是标准的程序化进程。从插装的角度来看,它们并没有什么特殊之处。你只需要添加 OTel SDK,在工具处理器周围定义 spans,并将 traces 发送到你的后端。唯一新的部分,是需要知道应该使用哪些 span 名称和属性,才能让你的 traces 具有意义并保持一致。

我们构建了什么

在本文中,我们使用 [@modelcontextprotocol/server-everything](https://www.npmjs.com/package/@modelcontextprotocol/server-everything "@modelcontextprotocol/server-everything") 包,这是 Anthropic 发布的官方参考 MCP 服务器。它内置了一组工具,覆盖了你在真实世界 MCP 服务器中会遇到的常见模式:简单请求/响应、带参数调用、长时间运行操作,以及返回结构化数据的调用。

该服务器暴露了多个工具。在本文中,我们使用其中三个:

  • echo:接收一个字符串并原样返回。一个最小化的请求/响应工具,用于验证插桩流水线是否端到端正常工作。
  • get-sum:接收两个数字并返回它们的和。代表一个带参数的工具,并包含简单业务逻辑。
  • trigger-long-running-operation:启动一个需要数秒才能完成的多步骤操作。用于模拟调用下游 API 或执行高开销计算的工具。

我们使用 EDOT Node.js@elastic/opentelemetry-node)对它进行了插桩,这是 Elastic 提供的 OpenTelemetry SDK 发行版。EDOT 替代了你原本需要单独安装的五六个 OTel 包,并额外提供了 elasticapm connector,这是 Kibana APM UI 构建服务拓扑图、事务分组和延迟图表所必需的。如果没有这个 connector,原始 OTLP 数据虽然会进入 Elasticsearch,但 APM 视图将没有可用于构建的数据。

整体架构如下:

这就是整个闭环:Claude 执行工具、生成遥测数据,然后再通过第二个 MCP 分析这些遥测数据。可观测性数据不再只是静静待在 dashboard 中等待人类查看的东西,而是 AI 可以主动推理的上下文。

这两个 MCP 服务器会同时在 Claude Desktop 中运行。已插桩的 MCP 负责生成遥测数据,而 Agent Builder MCP 负责让我们查询这些数据。

为了让 Claude Desktop 同时连接到这两个服务器,claude_desktop_config.json 配置如下:

bash 复制代码
`

1.  {
2.    "mcpServers": {
3.      "everything": {
4.        "command": "node",
5.        "args": [
6.          "--import",
7.          "/path/to/node_modules/@elastic/opentelemetry-node/import.mjs",
8.          "/path/to/everything/dist/index.js",
9.          "stdio"
10.        ],
11.        "env": {
12.          "OTEL_SERVICE_NAME": "everything-mcp-server",
13.          "OTEL_EXPORTER_OTLP_ENDPOINT": "https://<your-otlp-endpoint>",
14.          "OTEL_EXPORTER_OTLP_HEADERS": "Authorization=ApiKey <your-api-key>",
15.          "OTEL_LOG_LEVEL": "none"
16.        }
17.      },
18.      "elastic-agent-builder": {
19.        "command": "npx",
20.        "args": [
21.          "mcp-remote",
22.          "https://<your-kibana-url>/api/agent_builder/mcp",
23.          "--header",
24.          "Authorization:ApiKey <your-api-key>"
25.        ]
26.      }
27.    }
28.  }

`AI写代码![](https://csdnimg.cn/release/blogv2/dist/pc/img/runCode/icon-arrowwhite.png)

--import /path/to/@elastic/opentelemetry-node/import.mjs 标志就是实现零代码自动插桩所需的全部内容。但自动插桩只能捕获 HTTP 调用、数据库查询以及其他 Node.js 已支持插桩的库。MCP 工具调用属于应用逻辑,而应用逻辑需要手动 spans。

MCP 工具调用会生成什么 traces

OpenTelemetry 规范已经包含了 MCP 的官方语义约定( semantic conventions )。遵循这些约定意味着你的 traces 在不同工具和团队之间具有一致性、可以按名称搜索,并兼容任何支持 OTel 的后端,包括 Elastic APM。

span 命名遵循 {mcp.method.name} {target} 模式。对于工具调用,这会变成 tools/call echotools/call get-sum 。这也是你在 Kibana APM 中看到的 transaction 名称。

每个 span 上的关键 attributes:

Attribute Value Purpose
mcp.method.name tools/call MCP 协议方法
gen_ai.tool.name echo 被调用的具体工具
gen_ai.operation.name execute_tool GenAI 语义约定
error.type 错误类名 仅在失败时设置

用于创建这些 spans 的 wrapper 模式如下所示:

javascript 复制代码
``

1.  const tracer = trace.getTracer('everything-mcp-server', '1.0.0');

3.  function withToolSpan(toolName, fn) {
4.    return tracer.startActiveSpan(`tools/call ${toolName}`, (span) => {
5.      span.setAttribute('mcp.method.name', 'tools/call');
6.      span.setAttribute('gen_ai.tool.name', toolName);
7.      span.setAttribute('gen_ai.operation.name', 'execute_tool');

9.      try {
10.        const result = fn();
11.        span.end();
12.        return result;
13.      } catch (err) {
14.        span.recordException(err);
15.        span.setStatus({ code: SpanStatusCode.ERROR, message: err.message });
16.        span.setAttribute('error.type', err.constructor.name);
17.        span.end();
18.        throw err;
19.      }
20.    });
21.  }

``AI写代码![](https://csdnimg.cn/release/blogv2/dist/pc/img/runCode/icon-arrowwhite.png)

每个 tool handler 都会用 withToolSpan 包裹其逻辑。结果是在 Elastic APM 中为每一次工具调用生成一个已命名的 span,其中包含持续时间、状态以及错误信息等。

安全注意事项:OTel 规范定义了两个用于工具调用的可选属性:gen_ai.tool.call.argumentsgen_ai.tool.call.result。这两个字段都可能包含敏感数据,因此被标记为潜在风险字段。以 everything server 中的 get-env 工具为例,它会返回所有环境变量,其中可能包含 API key 和凭证。因此,只有在确认数据可以安全存储在可观测性后端时,才应采集这些属性,并建议在 SDK 层进行脱敏或过滤后再导出。

Kibana APM:查看 MCP 服务器性能

在配置好 Claude Desktop 并启动两个 MCP 之后,触发几次工具调用后,everything-mcp-server 服务会出现在 Kibana 的 Observability > Applications > Services Inventory 中:

Transactions 视图

Kibana 会按照 transaction 名称对 traces 进行分组。由于我们遵循语义约定,每个工具都会拥有自己的一行:tools/call echotools/call get-sumtools/call trigger-long-running-operation。你可以无需任何配置,直接看到每个工具的延迟、吞吐量和错误率。

这正是统一 span 命名价值体现的地方。如果有五个不同开发者在 MCP 服务器中添加工具,并且大家都遵循 tools/call {toolName} 的规范,APM UI 就会自动保持整洁有序。

Trace waterfall(调用链瀑布图)

点击某个具体 trace 后会进入 waterfall 视图。对于单个工具调用来说,这个结构非常简单:一个 span 覆盖整个执行过程。如果你的 tool handler 调用了下游 HTTP 请求或数据库查询(这些通常会被自动插桩),它们会作为子 spans 显示出来。你可以清晰看到时间消耗是在业务逻辑中,还是在等待外部调用。

延迟分布(Latency distribution)

延迟图展示了 p50、p95 和 p99 的分布情况,覆盖某个工具的所有执行记录。这使你能够轻松区分"稳定快速"的工具和"偶发慢请求"的工具。例如 trigger-long-running-operation 会根据执行步骤数量显示较宽的分布,这是在设置告警前理解预期执行时间范围的有效基线。

错误追踪(Error tracking)

失败的工具调用会出现在 Errors 面板中,包含完整堆栈、失败时附带的 span attributes,以及该错误发生的次数。如果你使用 span.recordException(err) 记录异常,Kibana 会将该错误直接关联到对应的 trace。

用 Agent Builder MCP 闭环

Elastic Agent Builder MCP 允许 Claude 在生成 trace 的同一个聊天会话中,从 Elasticsearch 查询自己的 trace 数据。Agent Builder MCP 可以查询 API key 有权限访问的任何 Elasticsearch 索引,而 APM traces 存储在 .ds-traces-apm.otel-default-* 中。为 Agent Builder API key 授予这些索引的读取权限,就完成了这个闭环:执行工具调用的 agent 现在可以反过来理解这些调用的性能表现。

下面是实际效果。在 Claude Desktop 中生成 traces,可以这样提问:

"使用 echo 工具说 hello,然后使用 get-sum 计算 1337 加 42,最后运行一个包含 3 个步骤的 long-running operation。"

Claude 在已插桩的 MCP 上执行了三个工具调用。三个 spans 被写入 Elastic APM。

现在,不离开聊天窗口,我们尝试查询这些 traces,可以这样提问:

"搜索过去 10 分钟的 APM trace 数据。做了哪些工具调用?每个调用耗时多少?"

我们可以用服务数据来进行验证:

你可以继续用服务数据来验证这一点:

Claude 会通过 Agent Builder MCP 在 traces index 上执行查询。它返回真实 trace 数据中的工具名称、持续时间和状态,然后用自然语言综合生成答案。

你可以进一步提问,例如:

  • "这些工具调用中哪个的 p95 延迟最高?"
  • "有没有工具调用失败?如果有,错误信息是什么?"
  • "比较 echo 工具和 get-sum 在过去一小时内的延迟差异。"

这些问题都会通过 Agent Builder 的 platform.core.execute_esql 工具转换为 ES|QL 查询,并在 APM trace 索引上执行。

为什么选择 Elastic 做 MCP 可观测性

Agent Builder 实现了闭环:这是 Elastic 生态中特有的能力。由于 APM 数据存储在 Elasticsearch 中,而 Elasticsearch 又可以通过 Agent Builder MCP 直接查询,因此你可以把 AI agent 自己的可观测数据带回对话中。你的 AI 可以反思自身性能并识别异常。

分布式追踪设计的 APM UI:Kibana 的 APM 界面专为这类数据设计,包括命名 transactions、trace waterfall、延迟百分位、带 stack trace 的错误追踪以及服务拓扑图。

托管 OTLP 端点:Elastic APM 从 Elastic 8.x 起直接支持 OTLP。你只需将 OTEL_EXPORTER_OTLP_ENDPOINT 指向 APM server 即可使用。

EDOT 简化配置:内置 elasticapm connector,这意味着 APM UI 可以无需额外配置直接工作。

结论

MCP 服务器不需要特殊的可观测性工具。它们本质上是程序化进程,而 OpenTelemetry 正是为进程设计的标准 instrumentation 方式。OTel MCP 语义约定是稳定的,并提供了一套可在工具和团队间扩展的一致命名规范。

Elastic 方案的关键不在 instrumentation 本身,而在第二个 MCP。当你的可观测数据存储在 Elasticsearch 中时,你可以在同一个 AI 会话中查询它。这种反馈闭环是新的,它开启了仅靠 dashboard 无法实现的能力:实时异常分析、自动化排障,以及在团队已有聊天界面中进行 AI 辅助事故分析。

下一步

常见问题

**如何为 MCP 服务器添加 tracing?**使用 OpenTelemetry SDK 并遵循官方 MCP OTel 语义约定。通过 Elastic Distribution of OpenTelemetry(EDOT)Node.js 版本,一个 --import 标志即可启用 HTTP 和数据库的自动 instrumentation。工具调用 spans 需要手动添加 wrapper,并设置 mcp.method.namegen_ai.tool.namegen_ai.operation.name

**为什么我的 MCP 工具调用很慢,如何定位瓶颈?**没有 tracing 时,MCP 工具调用是黑盒:你只能看到结果,无法知道时间消耗在哪。使用 OpenTelemetry 对服务器进行 instrumentation,将 traces 发送到 Elastic APM,并在 Kibana 的 trace waterfall 中查看业务逻辑与下游 HTTP / 数据库调用的耗时分布。

**可以在不使用自定义 collector 的情况下发送 MCP traces 到 Elastic APM 吗?**可以。Elastic APM 直接支持 OTLP。设置 OTEL_EXPORTER_OTLP_ENDPOINTOTEL_EXPORTER_OTLP_HEADERS(包含 API key)即可。EDOT 还内置 elasticapm connector,用于支持 Kibana APM 的服务拓扑和 transaction 分组。

**MCP 工具调用应该使用什么 span 名称和属性?**遵循 OpenTelemetry MCP 语义约定:span 命名为 {mcp.method.name} {target}(例如 tools/call echo),并设置 mcp.method.namegen_ai.tool.namegen_ai.operation.name=execute_tool。失败时设置 error.type。统一命名可以让 Kibana APM 自动正确分组。

**这和 Datadog 或 Grafana 有什么不同?**任何 OTel 兼容后端都可以接收 traces。Elastic 的区别在于 Agent Builder MCP,它允许 AI agent 用自然语言查询自己生成的 traces。这种"AI 反思自身性能"的闭环能力,是不通过 MCP 暴露数据的系统所不具备的。

**是否应该在 trace 中记录 MCP tool 的参数和结果?**OTel 规范将 gen_ai.tool.call.argumentsgen_ai.tool.call.result 标记为可选字段,并提示可能包含敏感数据。例如 get-env 工具可能泄露 API key。只有在确认安全时才应记录,并建议在 SDK 层进行脱敏。

**这个方案是否支持 Node.js 以外的语言?**支持。MCP OTel 语义是语言无关的。EDOT 提供 Node.js、Java、Python、.NET 等版本,所有语言都可以发送 OTLP 到 Elastic APM。wrapper 模式是通用的:在 tool handler 外包一层 span,并设置标准 attributes,在失败时记录 exception。

原文:www.elastic.co/observabili...

相关推荐
Elastic 中国社区官方博客6 小时前
Elastic 开源社区行为准则
大数据·elasticsearch·搜索引擎·信息可视化·全文检索
逸Y 仙X9 小时前
文章二十九:ElasticSearch分桶聚合
android·大数据·elasticsearch·搜索引擎·全文检索
Highcharts.js10 小时前
Highcharts React 5.0 正式版:支持 ES 模块化、组件更精简、开发体验全面升级
前端·javascript·react.js·elasticsearch·前端框架·highcharts
Elastic 中国社区官方博客10 小时前
通过项目标签和路由,在 Elasticsearch Serverless 中实现更快的跨项目搜索
大数据·elasticsearch·搜索引擎·云原生·serverless·全文检索
海兰10 小时前
使用 OpenTelemetry 与 Elastic APM 追踪 MCP 服务器工具调用
运维·服务器·elasticsearch·wpf
逆境不可逃11 小时前
一篇速通互联网架构的不断升级过程:从单机到云原生
java·elasticsearch·搜索引擎·云原生·架构
明明跟你说过1 天前
Kafka 与 Elasticsearch 的集成应用案例深度解析
大数据·elk·elasticsearch·kafka·big data·bigdata
拾-光1 天前
【Git】命令大全:从入门到高手,100 个最常用命令速查(2026 版)
java·大数据·人工智能·git·python·elasticsearch·设计模式
醉颜凉1 天前
Elasticsearch 实战:数据自动化清理完全指南(ILM + 定时删除 + 最佳实践)
elasticsearch·自动化·jenkins