Most "uptime" tooling was built for HTTP services: ping an endpoint, check for a 200, alert if it times out. That works fine for a REST API. It doesn't work for an MCP server, because an MCP server can return 200 on every request and still be completely broken for the clients depending on it.
Why MCP uptime is a different problem
A Model Context Protocol server isn't just an HTTP process that needs to be "up." It's a stateful JSON-RPC peer that has to complete a specific handshake and then keep an accurate, stable contract with every client connected to it. A load balancer or uptime pinger checking GET /health has no idea whether:
- the
initializehandshake actually succeeds tools/listreturns the tools the server is supposed to expose- those tool schemas match what clients last saw
That last point is the one classic monitoring completely misses, and it's the one that actually breaks agents in production.
What "up" should mean for an MCP server
Real MCP uptime checking means simulating what a client does: open a connection, send initialize, negotiate capabilities, then call tools/list and inspect the result. If any of those steps fail, or the response doesn't match the previous known-good schema, the server should be considered down or degraded — even if the process is technically running and answering requests.
The silent failure: schema drift
The most common way an MCP server "fails" without anyone noticing is schema drift: a tool's input parameters, required fields, or descriptions change between deploys, but nothing crashes. The server keeps answering tools/list calls fine. Meanwhile, any agent that cached the old schema, or any client with brittle argument-building logic, starts sending calls that get silently rejected or misinterpreted. There's no 500 error to alert on — just wrong behavior downstream. Catching this requires diffing the actual tool schema over time, not just checking that the endpoint responds.
Status pages: making uptime visible
Once you're actually checking handshake success and schema stability, the natural next step is surfacing that history somewhere your users (or your own team) can see it. A public status page for an MCP server typically shows:
- current handshake status (can a client connect and initialize right now?)
- recent incident history
- whether the tool schema has changed recently, and when
- historical uptime over the last 24 hours, 7 days, 30 days
This matters more for MCP servers than for typical APIs because the people integrating with you are often building autonomous or semi-autonomous agents. They can't always watch a dashboard in real time — they need a source of truth they can check programmatically or link to when something in their pipeline starts acting up.
Health badges: the low-friction version
Not every MCP server needs a full status page from day one. A public health badge — the kind of small SVG image you already see on thousands of GitHub READMEs for build status or test coverage — is a lighter way to communicate the same signal. Drop it at the top of your README and anyone evaluating or depending on your server gets an instant, always-current answer to "is this thing actually working right now, with the schema I expect?"
The badge itself is just the visible tip. What matters is what's behind it: an actual handshake check running on a schedule, not a static image someone forgot to update.
Setting this up without building it yourself
You can build this monitoring in-house — a cron job that runs initialize and tools/list against your server, stores the results, diffs schemas, and renders a badge — but it's a fair amount of undifferentiated plumbing for something that isn't your product. Tools built specifically for this, like MCP Vitals, run the real MCP handshake against your server on a schedule, detect tool schema drift automatically, alert you when something breaks, and give you a public status page and badge to share — so you're not reinventing handshake-aware monitoring from scratch.
Whichever route you take, the underlying principle is the same: for an MCP server, "up" means the handshake succeeds and the tool contract hasn't silently changed underneath your users. Anything less is just checking that a process is running.