Two kinds of incidents, one alerting system
MCP servers fail in two fundamentally different ways, and treating them as the same alert is how teams end up either ignoring their monitoring or drowning in noise.
Downtime is the failure your instincts already know: the server doesn't respond, the handshake times out, the transport drops connections. This needs fast, high-confidence alerts — if an MCP server is down, every client depending on it is degraded right now.
Drift is quieter and arguably more common: the server is up, the handshake completes, tools/list returns a 200 — but the tool schemas inside it have changed since the last known-good check. A parameter got renamed, a required field was added, a tool disappeared. No client necessarily fails immediately, but the next agent that calls that tool with its old assumptions will.
Good alerting for MCP servers treats these as separate signals with separate urgency, not one merged "healthy/unhealthy" boolean.
What to actually alert on
For downtime:
- Handshake failure —
initializedoesn't complete within a reasonable timeout. tools/listfailure — the handshake succeeds but the follow-up call errors or times out.- Elevated latency on either, past a threshold that reflects real user impact rather than an arbitrary round number.
- Repeated transport-level errors (connection resets, TLS failures) across consecutive checks — one blip usually isn't worth a page, three in a row usually is.
For drift:
- Any tool removed from
tools/listthat was present in the last baseline. - A required parameter added, or a previously optional parameter made required.
- A parameter type change or enum value removed.
- Output schema changes for tools your clients actively parse.
- Description changes above some threshold of edit distance, if you want to catch behavior-altering rewording (this one is optional and noisier — tune it to your tolerance).
Avoid one-alert-does-everything
A common mistake is wiring both categories into a single Slack channel with identical formatting. Within a week, everyone mutes it. A better structure:
- Downtime alerts go to whatever your team already uses for incidents — PagerDuty, Opsgenie, an on-call rotation — because they're time-sensitive and actionable immediately.
- Drift alerts go somewhere reviewable but lower-urgency — a dedicated channel, a ticket, a PR comment if it's caught pre-deploy — because the response is usually "review this diff and decide if it's intentional," not "drop everything."
Include enough context in the alert to triage without opening a dashboard: which tool changed, what the field was before and after, and a link to the last known-good baseline.
A basic alerting config, conceptually
Whether you build this with a cron job and a webhook or a dedicated tool, the shape is the same:
checks:
- name: handshake
interval: 60s
timeout: 5s
on_fail: page # immediate, high urgency
consecutive_failures: 2
- name: tools_list_schema
interval: 5m
on_change:
removed_tool: page
required_field_added: page
new_optional_field: notify # low urgency, informational
description_changed: log # visible, not alerted
The exact thresholds matter less than the principle: severity should match blast radius. A removed tool or a newly required field can break every client calling it. A new optional field usually can't.
Don't forget the public signal
Internal alerting handles your team. If other people integrate against your MCP server — internal teams, external partners, or the broader MCP ecosystem — a public status badge showing current uptime and schema stability saves everyone a support ticket. It also gives you a lightweight audit trail: "was the server healthy at 3pm yesterday" becomes a link, not a Slack archaeology exercise.
This is the specific combination MCP Vitals is built around: it runs the real handshake and tools/list check on a schedule, separates downtime alerts from schema-drift alerts, and gives you a public badge so integrators don't have to take your word for it.
Closing
Alerting on MCP servers works best when it mirrors how they actually fail: fast, unambiguous pages for downtime, and reviewable, context-rich notices for drift. Merge the two and you'll either miss real incidents in the noise or stop trusting the alerts altogether. Split them, tune the thresholds to blast radius, and make the current state visible to anyone who depends on the server — not just the team getting paged.