MCP Monitoring: Why Your Agents Fail Silently and How to Catch It
Your MCP server is returning 200s. Your uptime dashboard is green. And an agent somewhere just told a user "I couldn't complete that request" for the fortieth time today. That gap is what MCP monitoring is about. When a
Your MCP server is returning 200s. Your uptime dashboard is green. And an agent somewhere just told a user "I couldn't complete that request" for the fortieth time today.
That gap is what MCP monitoring is about. When an MCP server breaks, a person rarely sees an error page. An agent reads a failure, retries, picks a different tool, or gives up and summarizes the problem in natural language. None of that shows up in a classic HTTP monitor.
This guide covers why MCP needs its own monitoring, which signals are worth capturing, the main tools you can use today, and a walkthrough of one hosted option.
Why MCP monitoring is different from API monitoring
Classic API monitoring assumes a request, a status code, and a human or a service that notices when things go wrong. MCP breaks most of those assumptions.
Failures can be invisible at the transport layer. In MCP, a tool that fails can return a normal JSON-RPC result with isError: true in the body. The HTTP response is still a success. If you only count 5xx responses, you will miss every tool-level error.
Agents don't file tickets. A human who hits a broken endpoint tries once and complains. An agent may retry in a loop, burn tokens, and move on. The only witness is the traffic itself.
Tool misuse looks like success. An agent can call the wrong tool, or the right tool with poorly chosen arguments, and get a valid response. Usually the cause is a vague description or two tools that look alike. Your server did its job. The user still got a bad answer.
Latency compounds. One agent task can chain several tool calls. A tool with a slow p95 doesn't just slow one request. It stretches the whole task, and clients may time out partway through.
Schemas drift. Agents read your tools/list output and take input schemas literally. Rename a parameter or remove a tool, and clients that cached the old shape start failing. Nothing on the server side registers it as an error.
The handshake can break while the host is up. A server can answer a ping and still fail initialize, return an HTML error page where JSON-RPC should be, or reject credentials after an OAuth change.
What signals to capture
Whatever tool you pick, aim to capture these:
-
Handshake health: whether
initializesucceeds, how long it takes, and which protocol version and transport were negotiated. -
Tool inventory: the current
tools/listoutput, compared against the previous one, so added, removed, or changed tools are visible. -
Per-tool error rate: including results with
isError: true, not just protocol or HTTP errors. - Latency percentiles per tool: p50 and p95 at minimum, since averages hide the slow tail agents time out on.
- Caller identity: which client or agent made the call (Claude, Cursor, a partner's bot), and which key or user it used.
- Token or payload size: large, unpaginated responses are expensive for the agent even when they succeed.
- Retries and loops: repeated calls to the same tool with similar arguments in a short window.
- Trace context: a trace ID that links the agent's LLM call to the tool call to your backend, so you can follow one task end to end.
Approaches and tools
There is no single right layer. Some teams instrument the server code, some trace the client, some put a gateway in front, and some run synthetic checks from outside. Most production setups combine at least two of these.
OpenTelemetry with the MCP semantic conventions
OpenTelemetry now has semantic conventions for MCP, currently marked as in development. They define client and server spans named {mcp.method.name} {target}, for example tools/call get-weather, with attributes such as mcp.method.name, mcp.protocol.version, and gen_ai.tool.name. They also define duration metrics like mcp.server.operation.duration.
Trace context travels inside the MCP request's params._meta rather than only in HTTP headers, which SEP-414 documents in the MCP spec. That matters because one MCP request can span several HTTP requests, and one HTTP stream can carry several MCP messages.
The official Python and TypeScript MCP SDKs emit these spans once you register an OpenTelemetry SDK. Per the Python SDK docs, a tool result with is_error=True sets the span status to error, which covers the silent-failure case above. The TypeScript docs note that spans don't record tool arguments or results by default.
From there you can send traces to any OpenTelemetry-compatible backend, such as Grafana Tempo, Jaeger, or a vendor platform. This is the most portable approach and works for self-hosted servers. You build the dashboards and alerts yourself.
Datadog Agent Observability
Datadog's MCP client guide covers automatic instrumentation for the official Python and JavaScript MCP SDKs, and manual instrumentation for other clients, including Java. For Python, the setup from their docs is:
pip install ddtrace
export DD_LLMOBS_ENABLED=true
export DD_LLMOBS_ML_APP=<YOUR_ML_APP_NAME>
export DD_LLMOBS_AGENTLESS_ENABLED=true
export DD_API_KEY=<YOUR_API_KEY>
ddtrace-run <YOUR_APP_STARTUP_COMMAND>
According to Datadog's auto-instrumentation docs, the Python integration also instruments the server side (initialize and tools/call), tagging spans with the client name and version. The manual instrumentation example explicitly marks a span as an error when result.isError is true. Their announcement post describes linking MCP spans to the LLM span that chose the tool, with aggregated p95 latency and error rates per tool and server.
This fits best if you already run Datadog and want MCP traces next to the rest of your APM data.
Speakeasy Gram tool logs
If your servers are hosted on Speakeasy's platform, the Tool Logs page is a raw log of every tool call. Its docs list filters for server, client (as reported at the MCP handshake), status, agent, and user, plus a summary strip with failure rate and blocked rate. MCP Insights rolls this up into call volumes and the tools with the most errors. Logs can also be exported to a collector, and there's an API for searching them.
MCP Inspector
The MCP Inspector is the official interactive tool for connecting to a server, listing its tools, and calling them by hand. It isn't a monitoring system, since nothing runs on a schedule and nothing alerts you. It's still the quickest way to reproduce a failure once your monitoring has flagged one.
Elva MCP Monitor and MCP logs
Elva, which builds hosted MCP servers from APIs, takes two angles. Elva-hosted servers come with call logs and insights. A newer feature, MCP Monitor, runs scheduled synthetic checks against any remote MCP server, including ones not hosted on Elva. The walkthrough below follows Elva's documentation.
Walkthrough: setting up an MCP monitor in Elva
Everything in this section comes from the MCP Monitor docs.
What each check does
Every check runs up to three steps:
-
Handshake: runs the MCP
initializehandshake and records latency, transport, and protocol version. - Tool inventory: lists the tools and compares names and input schemas with the previous check. This is the schema drift signal from earlier.
- Read-only tool call (optional): calls one read-only tool with arguments you choose, as a synthetic test.
The result is one of four statuses:
- Up: the handshake succeeded and every enabled check passed.
-
Degraded: the server answered, but
tools/listfailed, the tool call failed, or latency went over your threshold. - Down: no valid MCP response, for example DNS or TLS failure, timeout, 5xx, an HTML page instead of JSON-RPC, or rejected credentials.
- Auth required: the server needs a credential or an OAuth reconnect before it can be checked.
A 429 is reported as rate limited, not as down.
Step 1: Add the server
Open MCP Monitor and enter the server URL, or pick one of your Elva-hosted servers.
Step 2: Authenticate
Choose None, Bearer token, API key header, Custom header, or OAuth. Per the docs, saved headers are encrypted at rest and not shown again.
Step 3: Choose what to check
Set the interval (every 1, 5, 15, 30, or 60 minutes), an optional latency threshold in milliseconds, and optionally one read-only tool to call. Free workspaces can check every 5 minutes or slower.
Step 4: Set alerts
Choose how many consecutive failed checks open an incident (2 by default), whether degraded checks count, and whether to notify when the tool inventory changes. Alerts can go to a Slack incoming webhook, up to five email recipients, or a signed webhook. Each monitor has Checks, Incidents, Tools, Alerts, and Settings tabs, and Send test on the Alerts tab tries every configured channel.
An incident opens when the failure threshold is reached and resolves on the next healthy check.
Handling webhook alerts
Webhook events are mcp_monitor.incident.opened, mcp_monitor.incident.resolved, mcp_monitor.tools.changed, and mcp_monitor.test. Here's the example incident payload from the docs:
{
"event": "mcp_monitor.incident.opened",
"occurredAt": "2026-11-02T10:00:00.000Z",
"monitor": {
"name": "Orders MCP",
"url": "https://mcp.example.com/mcp",
"status": "down",
"slug": "orders-mcp",
"statusPageUrl": "https://app.getelva.ai/status/orders-mcp"
},
"incident": {
"startedAt": "2026-11-02T09:58:00.000Z",
"cause": {
"status": "down",
"failureCode": "timeout",
"message": "Handshake timed out"
}
}
}
Tool-change events include a toolsDiff with added, removed, and changed tools. Deliveries are signed with the same scheme as Elva's MCP webhooks, using the X-Elva-Signature and X-Elva-Timestamp headers, so verify them before acting on an event.
Status pages and one-off checks
You can publish a public status page at app.getelva.ai/status/<slug> and embed an SVG badge in a README. There's also a one-off check you can run without signing in, which produces a shareable report on the handshake, protocol version, transport, tools, and OAuth discovery.
On plan limits, the docs say Free workspaces can save 10 monitors with a 5-minute minimum interval.
Looking at real traffic
Synthetic checks tell you whether a server works. They don't tell you what agents actually do with it. For Elva-hosted servers, the MCP insights and logs page covers the traffic side: total requests, response-time percentiles, error rate, and token estimates over a date range, plus per-agent cards. Calling clients such as Claude, Cursor, Windsurf, and MCP Inspector are detected automatically from their requests. You can also follow logs from the terminal with elva-cli 1.2.0 or later:
elva mcp logs orders-mcp --follow
I covered Elva briefly in an earlier post, Postman Alternatives in 2026, from the API testing side. This post looks at the monitoring side.
How to choose
- You run your own server and want portability: use the OpenTelemetry MCP conventions through the official SDKs, then send the data to the backend you already use.
- You're already on Datadog: its MCP integration puts tool calls inside the same traces as the LLM calls that triggered them.
- Your servers live on a hosted platform: start with that platform's logs (Gram's Tool Logs, Elva's MCP logs), then add external checks.
- You need to know when a server breaks for agents, wherever it's hosted: add a synthetic monitor that runs the handshake and checks the tool list on a schedule. Elva's MCP Monitor is one option. A scheduled script using an official MCP SDK client is another.
- You're debugging one failure right now: open MCP Inspector.
MCP monitoring checklist
- [ ] Count tool results with
isError: trueas errors, not just HTTP and JSON-RPC errors. - [ ] Track p50 and p95 latency per tool, not per server.
- [ ] Record which client or agent made each call.
- [ ] Snapshot
tools/listand alert when names or input schemas change. - [ ] Run a scheduled
initializehandshake from outside your network. - [ ] Include at least one read-only synthetic tool call.
- [ ] Propagate trace context through
params._metaso agent, tool, and backend spans connect. - [ ] Watch response size and token usage for unpaginated tools.
- [ ] Alert on repeated retries of the same tool from the same caller.
- [ ] Treat auth and OAuth failures as their own status, separate from downtime.
- [ ] Keep MCP Inspector handy for reproducing what your monitors find.
Originally published by Dev.to AI. Aggregated on AIWithGhost for educational purposes — full credit and traffic to the original publisher.