Same idea, different consumer
An MCP server and a REST API are both a boundary that exposes capabilities over a network (or a local pipe) to a caller. That similarity makes it tempting to apply REST-era reliability practices to MCP unchanged. Most of them translate, but a few core assumptions don't, and the gaps show up specifically around reliability.
Discovery: OpenAPI vs tools/list
A REST API is typically documented with an OpenAPI or Swagger spec that's mostly read by humans and code generators at build time. It rarely changes the runtime behavior of a client that was already built against it.
An MCP server's equivalent, the tools/list response, is fetched at runtime and read directly by the model deciding what to call. There's no build step in between. That means the documentation is live and load-bearing in a way an OpenAPI file usually isn't: change it, and you change behavior immediately, for every connected agent, without anyone shipping new client code.
Versioning: explicit vs implicit
REST APIs generally version deliberately, with /v1/ vs /v2/ in the path or a version header, and a breaking change is, by convention, supposed to arrive under a new version identifier. Consumers that don't want the change simply don't move.
MCP has no equivalent built-in mechanism for versioning individual tools. A tool's schema can change in place, under the same name, with no forced migration path. (The protocol itself is versioned via protocolVersion, negotiated during the handshake, but that covers the wire protocol, not the tools an individual server chooses to expose.) In practice, this pushes the burden of not breaking existing consumers from the protocol onto each server operator's own discipline.
Statefulness
REST is, by design, stateless per request: each call carries what it needs, and any session state lives in a token or cookie the client manages. Traditional MCP sessions have been more stateful: a connection persists, capabilities are negotiated once at initialize, and the server can push notifications like tools/list_changed to a still-open connection. That's convenient, but it also means a server upgrade or restart can disrupt long-lived agent sessions in ways a stateless REST call wouldn't.
Notably, the MCP specification finalized in mid-2026 moves the protocol toward statelessness, dropping the persistent handshake in favor of per-request metadata, specifically to make horizontal scaling and plain load balancing easier, much closer to how REST already behaves. That shift is very new and will take time to show up in the servers most teams actually run against.
Error handling: status codes vs JSON-RPC plus isError
REST has a well-worn vocabulary: 4xx for client mistakes, 5xx for server failures, and a body developers are used to parsing. MCP runs over JSON-RPC, which has its own error object for protocol-level failures (bad method, bad params), plus a tool-call-specific convention: a tool result can come back with isError: true and an error message in its content, which is a successful JSON-RPC response describing a failed tool execution. Getting this distinction wrong, treating a tool-level error as a protocol success or vice versa, is a common source of agents that don't notice they failed.
The consumer is probabilistic
This is the biggest reliability difference, and it isn't about the protocol at all; it's about who's calling. A REST client is code: deterministic, and it fails the same way every time given the same bad input. An MCP tool's caller is a language model reading a description and a schema and deciding, probabilistically, what to send. The same drift that a REST client would reject outright, a missing required field, say, an LLM might work around with a plausible guess, which can be worse, because it fails silently instead of loudly.
What this means in practice
For teams running MCP servers, the reliability checklist looks like REST's, plus a few MCP-specific items:
- Standard uptime and latency monitoring still applies to the transport layer.
- Add schema-level monitoring on top: track
tools/listoutput over time the way you'd track an API contract, since nothing else enforces it for you. - Treat description text as part of the contract, not just documentation.
- Watch the handshake itself, not just the server process; a process can be up while
initializeortools/listquietly breaks.
This is the specific niche MCP Vitals fills: running the real MCP handshake against your servers, watching for schema and behavior drift that plain uptime checks can't see, and giving you (or your users, via a public status badge) a signal that's actually about MCP-level health, not just whether the port is open.
Closing thought
MCP borrows enough from REST's shape that REST instincts get you most of the way to a reliable server. The remaining distance, live model-read schemas with no built-in versioning and a probabilistic consumer that fails quietly, is exactly where MCP-specific monitoring earns its keep.