Skip to content

mcp: classify tool-call errors and attribute unknown tools to a server #362

Description

@MitulShah1

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.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions