datarobot_genai.drmcpbase.tool_metrics
tool_metrics
OTel metrics for MCP tool calls (shared by User MCP and Global MCP servers).
Until now tool calls were observable through spans only — per-tool call counts, latency, and failure taxonomy had to be re-derived by scanning traces. This module adds SLI instruments plus the OTel-recommended server operation duration histogram:
mcp.server.operation.durationhistogram (OTel GenAI MCP semconv)datarobot.mcp.tool.calls_totalcounter, by tool + outcomedatarobot.mcp.tool.call_failure_totalcounter, by tool + error.kind + error.type
Latency follows OpenTelemetry GenAI MCP semantic conventions
<https://github.com/open-telemetry/semantic-conventions-genai/blob/main/docs/gen-ai/mcp.md>_
(mcp.server.operation.duration with mcp.method.name=tools/call,
gen_ai.tool.name, gen_ai.operation.name=execute_tool, and error.type
on failure). MCP attribute registry:
https://opentelemetry.io/docs/specs/semconv/registry/attributes/mcp/
error.kind on the failure counter carries the
:class:~datarobot_genai.drmcputils.exceptions.ToolErrorKind value. The
middleware sees failures AFTER log_execution converted them to FastMCP
ToolError strings, so the kind is recovered from the exception's kind
attribute when present, else parsed from the "[kind] …" message prefix, else
recorded as "unknown".
Metrics ship through the OTLP MeterProvider bootstrap_metrics_provider installs
during initialize_telemetry; without OTLP env it resolves to a no-op provider. That
makes recording cheap, not infallible, so :func:record_tool_call swallows its own
errors — it runs on the success path before the tool's result is returned.
ToolCallInstruments
dataclass
OTel instruments backing per-tool MCP SLIs and semconv latency.
Source code in datarobot_genai/drmcpbase/tool_metrics.py
build_instruments
Create the tool-call instruments on meter (an OTel Meter).
Source code in datarobot_genai/drmcpbase/tool_metrics.py
get_instruments
Build (and cache) instruments from the global meter.
Source code in datarobot_genai/drmcpbase/tool_metrics.py
resolve_error_kind
Resolve the error.kind label value for a tool failure.
Prefers the exception's own kind (drmcputils ToolError); falls
back to the "[kind] …" message prefix log_execution puts on the
FastMCP-facing error; else "unknown".
Source code in datarobot_genai/drmcpbase/tool_metrics.py
record_tool_call
record_tool_call(tool_name: str, duration_s: float, error: BaseException | None, *, instruments: ToolCallInstruments | None = None) -> None
Emit the SLI and semconv metrics for one MCP tools/call.
Never raises. The success path calls this before returning the tool's result, so an exception escaping here would turn a tool call that worked into a client-visible error — telemetry is not worth that. "No-op without OTLP env" is not the same guarantee: it only holds in the configuration where nothing is recorded at all.