Follow-up to #356, which proposed six items and shipped four in v1.3.2.
What shipped
gateway_mcp_server_up — per-server readiness gauge
gateway_mcp_server_init_failures_total — initialization failure counter
- OTel spans covering server initialization and tool discovery
- A registry status accessor exposing readiness and last error
Two correctness fixes landed alongside, which #356 had not identified: a tool returning an error result was being metered, audited, and traced as a success, and an unknown tool name taken from model output was an unbounded Prometheus label.
What did not, and why
Two proposed items would have changed existing metric series:
- an error-class label (
timeout / transport / server_error) on ferrogw_mcp_tool_calls_total
server_name on ferrogw_mcp_unknown_tool_calls_total
Prometheus identifies a series by its full label set. Adding a label replaces every existing series and resets it to zero, so rate() and increase() produce garbage across the rollover and anything matching on an exact label set breaks. That is a consumer-visible change and does not belong in a patch.
Proposed
Add a new series rather than relabelling an existing one:
gateway_mcp_tool_call_errors_total{server_name, tool_name, error_class}
with error_class one of timeout, transport, server_error. This leaves ferrogw_mcp_tool_calls_total untouched, so existing dashboards keep working, and gives operators the distinction they actually need — a hung subprocess versus a broken tool.
The unknown-tool case is better served the same way, since the current metric's tool_name is model-supplied and already collapsed to a bounded value.
Naming note
New metrics added in v1.3.2 use the repository convention of a bare gateway_ prefix. The three original MCP metrics use ferrogw_mcp_ and are the outlier; renaming them would itself be a breaking metric change and is deliberately not proposed here.
Also outstanding from #356
AttrFerroMCPDepth is declared in observability/attributes.go and documented as planned, but still not emitted. Its value exists as a local in the routing path; emitting it requires threading depth into the executor.
Follow-up to #356, which proposed six items and shipped four in v1.3.2.
What shipped
gateway_mcp_server_up— per-server readiness gaugegateway_mcp_server_init_failures_total— initialization failure counterTwo correctness fixes landed alongside, which #356 had not identified: a tool returning an error result was being metered, audited, and traced as a success, and an unknown tool name taken from model output was an unbounded Prometheus label.
What did not, and why
Two proposed items would have changed existing metric series:
timeout/transport/server_error) onferrogw_mcp_tool_calls_totalserver_nameonferrogw_mcp_unknown_tool_calls_totalPrometheus identifies a series by its full label set. Adding a label replaces every existing series and resets it to zero, so
rate()andincrease()produce garbage across the rollover and anything matching on an exact label set breaks. That is a consumer-visible change and does not belong in a patch.Proposed
Add a new series rather than relabelling an existing one:
with
error_classone oftimeout,transport,server_error. This leavesferrogw_mcp_tool_calls_totaluntouched, so existing dashboards keep working, and gives operators the distinction they actually need — a hung subprocess versus a broken tool.The unknown-tool case is better served the same way, since the current metric's
tool_nameis model-supplied and already collapsed to a bounded value.Naming note
New metrics added in v1.3.2 use the repository convention of a bare
gateway_prefix. The three original MCP metrics useferrogw_mcp_and are the outlier; renaming them would itself be a breaking metric change and is deliberately not proposed here.Also outstanding from #356
AttrFerroMCPDepthis declared inobservability/attributes.goand documented as planned, but still not emitted. Its value exists as a local in the routing path; emitting it requires threading depth into the executor.