Model Context Protocol Monitoring: How to Observe MCP Servers and Tool Calls
Reliable Model Context Protocol (MCP) monitoring turns agentic workflows from a black box into an operation your team can trust. A single agent prompt can fan out into a chain of tool calls across multiple servers, where each call may query a database or hit an external application programming interface (API) before results return to the model’s context.
That chain works cleanly when every dependency responds, but a generic “Failed to connect to MCP server” message leaves teams without a trace or an error code that maps to a root cause, and no clear answer to whether the problem came from the model, the protocol, or the database behind the tool.
This guide covers the signals every MCP server should expose, the OpenTelemetry conventions for instrumenting them, and how to diagnose the failures that standard application performance monitoring (APM) tooling misses by default. It then extends the same telemetry to MCP cost, security, and agent usage, since the usual entry point to MCP is an AI coding agent.
Why MCP Monitoring Differs From API Monitoring
MCPs give large language models (LLMs) a standard way to discover and call tools, but the protocol itself does not mandate observability. Servers built on it often ship with no metrics endpoint, no structured logging, and no tracing, so tool-call latency, error rates, and performance baselines stay invisible even inside teams that run mature Prometheus and OpenTelemetry stacks.
The reason is that an MCP tool call spans several independent hops: the request runs from the user through agent reasoning, MCP tool selection, MCP server execution, and a downstream API or database query before the response aggregates back to the model. Each hop can fail on its own, and each needs its own telemetry to be diagnosable.
The protocol organizes those hops through a client-host-server architecture with three roles, each a distinct place to put instrumentation: the host aggregates context and controls security policy, each client maintains an isolated stateful session with a single server, and each server exposes tools, resources, and prompts.
That stateful session model, built on JSON Remote Procedure Call (JSON-RPC) 2.0, separates MCP from a stateless Representational State Transfer (REST) API, which is why naive monitoring misses the failures that bring a workflow down.
Why Standard API and APM Monitoring Misses MCP Failures
Standard API monitors alert on HTTP 4xx and 5xx status codes or top-level JSON-RPC error objects, but MCP routes its most common application failures around both of those signals. Three failure patterns slip past conventional monitoring:
- An HTTP 200 can hide a failed tool: A failed tool call returns a successful JSON-RPC response with an error flag set inside the result, so a status-code monitor reports a healthy server while your agent receives invalid output.
- Non-deterministic tool chains defeat span baselines: The same prompt can trigger different tool chains depending on how the model reasons, so span-based root cause analysis cannot separate a badly worded prompt from a hallucinated parameter or a real execution failure.
- The tool process is opaque to APM: APM sees requests entering the server and responses leaving it, but not what the tool did between those points, including which files it read or which outbound connections it opened.
Correlating those layers is where a unified pipeline earns its place. Coralogix, a full-stack observability platform, ingests MCP spans, metrics, and logs through the same OpenTelemetry pipeline as the rest of your stack, so the model reasoning, protocol negotiation, and downstream execution that APM collapses into one opaque hop arrive as separate, correlated signals in a single data plane.
The Core Signals to Monitor on Every MCP Server
Effective MCP monitoring starts with a fixed set of signals that map to the protocol lifecycle. Every MCP server should expose:
- Tool-call success and error rate: Track protocol errors (the JSON-RPC error object) and execution errors (the error flag inside a successful response) separately, since the MCP tools spec defines them as distinct mechanisms.
- Latency percentiles: Capture p50, p95, and p99 on tool-call duration, because averages hide the tail latency that actually breaks agent runs.
- Tool-listing latency and cache behavior: The time to list available tools grows with registry size, and gateways cache that response, so cache hit rate and staleness become real signals.
- Session-initialization failures: Errors during session setup, plus sessions that end almost as soon as they begin, indicate failed capability negotiations.
- Registry and token bloat: A tool count per registry and the token size of the tool-list response measure how much context the definitions consume before any query runs.
Server saturation: Rate-limit hits, request volume, and resource exhaustion surface capacity problems before they become outages, and a saturation spike across multiple tools points to shared infrastructure instead of one tool. - Downstream-API attribution: A measure of backend execution time on its own, excluding protocol overhead, lets you blame the database instead of the protocol.
Together these signals define what good looks like on an MCP server. The harder part is capturing them consistently across clients, servers, and transports, which is where OpenTelemetry’s conventions come in.
How to Instrument MCP Servers with OpenTelemetry
OpenTelemetry now publishes conventions for MCP that standardize how tool calls appear in your traces, the same OpenTelemetry approach you already use across the rest of your stack. They are still marked as in development, so expect some churn before they settle. Three principles matter more than any specific setup.
Instrument Both Sides of Every Call
Instrument both the client that issues a call and the server that runs it, and measure each from when the request goes out to when the response comes back. Keeping the two separate is what later lets you say whether a slow tool call was slow in the tool or slow on the wire.
Name Spans to Group Related Calls
Name each span after the operation and its target instead of the full arguments, so a weather lookup reads as a single repeatable name instead of a unique string for every request. That keeps related calls grouped together instead of scattered one span per request. The detail that trips teams up most is failure: a tool can fail while the call still returns a normal success response, with the error tucked inside the result as a flag, not surfaced as a failed response. Unless your instrumentation reads that flag and marks the span as failed, a broken tool looks healthy in every dashboard.
Propagate Trace Context Across the Boundary
MCP also has no built-in way to carry trace context from the client to the server, so the two halves of a call often end up as disconnected traces. The conventions fix this by passing the standard trace-context values in a metadata field on each request, which the server picks up as the parent of its own span. This gap is widest for local servers that talk over standard input and output, where there are no network headers to fall back on. Current libraries only do part of this automatically, though: FastMCP’s built-in instrumentation, for example, covers the common setup calls but not the tool calls that carry your reliability risk, so those still need spans of their own.
Common MCP Failure Modes and How to Diagnose Them
MCP failures cluster into a few repeatable patterns, mostly timeout and session-state problems, with registry size as another recurring source. Diagnose them by matching the symptom to its likely cause and the signal that confirms it.
| Failure Mode | Symptoms | Likely Cause | Detection Signal |
| Session never initializes | “Failed to connect to MCP server” in the user interface (UI); manual verify succeeds but chat calls fail | Hardcoded short cancel scope around session.initialize(); cold start exceeds budget | Timeout success rates improve from 20% at 10s to 80% at 30s and 100% at 60s across 15 trials |
| tools/list timeout | Server is healthy but the client cannot connect; other clients succeed | Hardcoded 5s limit ignores the user-configured timeout; default init timeout too short for npx-launched servers | Client error at exactly the hardcoded threshold; server logs show no error |
| Tool-call timeout | Call spins, client proceeds as failed; server logs a 200 after the client abandoned | Long-running tool limits fire before tools finish | Server logs show 200 OK after the client moved on; client shows no result |
| Stale session, no re-init | All calls fail permanently after session time-to-live (TTL) expiry; no recovery without restart | Client does not send a new InitializeRequest on HTTP 404 for an expired session ID | Repeated tools/call <stale-id> returns 404 with no InitializeRequest ever sent |
| Registry too large to parse | Wrong tools selected or hallucinated; context exhausted before the user message | list_tools returns everything at once; a documented setup hit 143K tokens, 72% of the context window | Token metrics show large definition overhead before the first message |
| stdio transport hang | Session blocks with no error; process appears running; no timeout fires | context.Background() with no timeout; a mutex serializes calls so one hang blocks every subsequent call | No client log output; server process still running in the operating system (OS) process list |
| Malformed or partial results | Truncated output; schema validation error; -32602 Invalid params | Parameters not conforming to schema; capability not declared during init | -32602 in the JSON-RPC response; compare params against the /tools/list schema in MCP debugging guidance |
The stdio cases deserve separate attention because they create true observability dead zones. With no HTTP headers for trace context and no timeout on the underlying call, a single hung stdio call can block every subsequent call with no protocol-level signal while the process still shows as running, so process-level monitoring of the OS process list becomes a necessary complement to your spans.
Diagnosing any of these means correlating signals that live in different places: client and server spans, token metrics, process state, and JSON-RPC error objects. DataPrime, the query engine inside Coralogix, queries logs, metrics, traces, and security events in a single expression, so you can match a symptom in the table above to its confirming signal without leaving one query.
How to Set Alerts and SLOs for MCP Reliability
Service level indicators (SLIs) for MCP map cleanly onto the rate, errors, and duration (RED) method: invocation rate, errors (protocol errors plus failed executions), and latency percentiles. A 99.9 percent success SLO over four weeks handling 3 million requests gives you an error budget of 3,000 errors, so one outage costing 1,500 of them burns half your budget at once.
Multi-window, multi-burn-rate alerting pages only when an event consumes a meaningful fraction of that budget, but an alert tied to indexed data fires after the indexing step, minutes behind a fast burn. Coralogix’s Streama analyzes MCP telemetry in flight and anomaly-baselines it before storage, so a burn-rate alert fires while the budget is still draining, and comparing the client-side call duration against the linked server span rules out network transit as a latency cause in seconds.
How to Monitor MCP Cost and Token Usage
By default, MCP clients load every tool definition into context before the user types a word, and that upfront cost is the dominant driver of MCP token spend. Connecting multiple servers can produce token overhead of 15,000 to 20,000 tokens before any query runs, and for identical operations MCP can cost several times more than the same command line interface (CLI) call, almost entirely from those definitions.
Attribution turns token usage from a monthly surprise into a signal a team can govern. Coralogix TCO Optimizer routes telemetry across the Frequent Search, Monitoring, Compliance, and Blocked pipelines, so high-volume MCP traces land in the lowest-cost pipeline that still supports the queries you run, and telemetry you never query drops into Blocked instead of incurring storage cost. Pairing that with per-call token usage, broken out by input, output, and cached tokens, gives you the granular driver of spend per registry, per tool, and per session without a pricing model that penalizes you for instrumenting every tool call.
That spend originates in the coding agents your developers already use, and each exposes a different slice of usage telemetry:
- Claude Code: emits OpenTelemetry metrics for cost and token usage broken out by model, attributes that spend to a developer or team, and records the MCP server and tool names in its tool-result logs once tool-detail logging is turned on.
- Copilot, Cursor, and Codex: report model, spend, or token data without documented MCP-specific tool fields, so the per-tool picture there needs explicit configuration.
Coralogix’s Code Agents Observability brings these signals into one view through native integrations for Claude Code, Codex, and Gemini CLI. It tracks model usage, token consumption, estimated cost, unique users, and pull request activity, giving platform teams a per-developer and per-team view of cost that sits alongside the pipeline-level attribution above.
How to Monitor and Govern MCP Security Risks
MCP tool decisions let the model choose which tools to invoke, when, and with what parameters, a class of risk traditional API security never had to handle. Teams review tool descriptions once when the agent connects, while tool responses flow straight into the model’s context with no equivalent check. Observability is how teams enforce policy on that unguarded runtime channel and catch anomalies with enough context for compliance review.
The Runtime Risks to Watch
The risks that recur in production each map to telemetry you can capture and act on:
- Personally identifiable information (PII) in tool inputs and outputs: Data loss prevention scanning should cover names, emails, Social Security numbers, credit cards, and credentials, since attackers can encode sensitive data into normal-looking tool calls.
- Prompt injection via tool results: A poisoned server can return a response embedding hidden instructions, as in a tool poisoning case where a tool’s output told the agent to read the system password file.
- Anomalous tool-call volume: A spike in a specific tool against its own rolling baseline can indicate an injection attempt exfiltrating data or an agent stuck in a loop.
- Authentication and authorization failures: A rise in permission-denied or 401 responses points to credential abuse or an agent probing resources outside its scope.
- Over-permissive tool chaining: Loosely defined permissions widen over time, and the confused-deputy problem means the server may act with its own broad privileges, disconnected from the user’s scope.
Each of these is only a signal on its own; the value comes from turning them into a policy your team can enforce while an interaction is still in flight.
Turning Risk Signals Into Policy
Catching those signals early turns security review into continuous monitoring, feeding dashboards that track sensitive-data exposure, injection attempts, and over-permissive behavior alongside reliability telemetry. The response should be tiered, not blanket: redact or block based on sensitivity, and alert when a risky interaction needs review, because blanket blocking stops legitimate work while pure logging catches nothing in time.
Coralogix’s AI Center treats these as runtime observability problems. Its AI Guardrails detect, block, or rewrite unsafe prompts and tool interactions in real time, stopping an in-progress interaction when an evaluator flags PII in the input, and its evaluators run custom domain-specific checks such as a financial application that prohibits stock advice. LLM Tracekit captures the prompts, tool inputs, and responses for each interaction into the same data plane as your reliability signals, which puts a governance record on the dashboard a site reliability engineer (SRE) already watches for MCP health.
How Coralogix Unifies MCP Monitoring in One Place
Monitoring MCP well means watching reliability, cost, security, and agent usage together, and splitting those across separate tools recreates the correlation problem MCP already made worse. Coralogix keeps all four in one data plane: Streama analyzes MCP telemetry in flight so burn-rate alerts fire before the data lands, and TCO Optimizer routes token-heavy traces into the pipeline that matches how you query them.
AI Guardrails block unsafe tool interactions in real time while LLM Tracekit records the prompts and tool calls behind them, and Code Agents Observability tracks agent spend across Claude Code, Codex, and Gemini CLI. DataPrime then queries those reliability, cost, and security signals in a single expression instead of leaving you to stitch them together by hand.
If you want to correlate MCP reliability, cost, and security signals in a single DataPrime query against your own production telemetry, start with a 14-day trial of Coralogix today.
Frequently Asked Questions About Model Context Protocol Monitoring
How much overhead does instrumenting every MCP tool call add?
Little runtime cost, because emitting a span for each tool call is cheap next to the model and network latency already in the path. What grows is telemetry volume, not execution time, so routing high-volume MCP traces into a lower-cost pipeline keeps full instrumentation affordable. The token overhead from tool definitions loaded into context is a separate and usually larger driver.
Should I instrument the MCP client or the server?
Both, because each answers a different question. Client-side spans capture the latency your agent experiences; server-side spans isolate execution time inside the tool. Linking the two through trace context carried on each request is what tells a slow tool apart from a slow network hop.
How do I monitor a third-party MCP server I don’t control?
From the client side, since you cannot instrument a server someone else runs. Client-side metrics like call duration and error rate, split between protocol errors and failed executions, plus session-initialization failures, give you a reliable health picture without touching the server. For a stdio server, add process-level monitoring of the child process, because a hung call there produces no protocol-level signal.
Does MCP monitoring fit into an existing OpenTelemetry pipeline?
Yes. MCP spans and metrics use standard OpenTelemetry semantic conventions, so they flow through the Collector and backend you already run over OpenTelemetry Protocol (OTLP) without a separate agent. Standard MCP attributes such as the method name ride the same pipeline as the rest of your telemetry, which is what lets you correlate tool calls with the services behind them. If you want to see MCP reliability, cost, and security correlated against your own production telemetry, start a Coralogix trial.