statusas docs
Guides

How to Monitor an MCP Server

Monitor an MCP server with statusas - JSON-RPC health checks, tools/list assertions, authenticated endpoints, and uptime alerts from 28 regions.

Just want to test a server once? Run it through the free MCP server health check — full JSON-RPC handshake from your browser, no account. This guide is for monitoring it continuously.

Problem

Running a Model Context Protocol (MCP) server is critical for your AI applications, but traditional HTTP monitoring often falls short. MCP servers communicate using the JSON-RPC 2.0 protocol, requiring specific request/response patterns that standard health checks don't cover. A server can return 200 OK with an HTML error page, stop echoing the JSON-RPC id, or quietly return an empty tools/list — and every one of those looks healthy to a status-code pinger while breaking every AI client that connects.

How can you confidently ensure your MCP server is healthy and responsive at all times, without custom scripts or complex setups?

Solution

statusas monitors MCP servers by sending JSON-RPC ping requests to your endpoint from multiple global locations. This verifies not only network reachability but also the correct functioning of your server's JSON-RPC interface. This guide declares those monitors with the statusas Terraform provider, so your monitoring lives in version control alongside the rest of your infrastructure.

Prerequisites

Step-by-step guide

1. Declare the monitor

Add an openstatus_http_monitor resource, adapting it for your own MCP endpoint. This example targets a Hugging Face MCP server.

resource "openstatus_http_monitor" "mcp_server" {
  name        = "HF MCP Server"
  description = "Hugging Face MCP server monitoring"
  url         = "https://hf.co/mcp"
  method      = "POST"
  periodicity = "1m"
  active      = true
  retry       = 3
  regions     = ["fly-iad", "fly-ams", "fly-lax"]

  body = jsonencode({
    jsonrpc = "2.0"
    id      = "statusas"
    method  = "ping"
  })

  headers {
    key   = "Content-Type"
    value = "application/json"
  }

  headers {
    key   = "Accept"
    value = "application/json, text/event-stream"
  }

  status_code_assertions {
    target     = 200
    comparator = "eq"
  }

  body_assertions {
    target     = "{\"result\":{},\"jsonrpc\":\"2.0\",\"id\":\"statusas\"}"
    comparator = "eq"
  }
}

2. Understand the configuration

The fields that matter for an MCP check:

  • name and description — human-readable name and explanation for your monitor.
  • url — the full URL of your MCP server's JSON-RPC endpoint.
  • method — must be POST for JSON-RPC requests.
  • periodicity — how often statusas runs the check (30s, 1m, 5m, 10m, 30m, 1h).
  • regions — the locations the check runs from. Monitoring from several catches localised issues. Terraform uses the prefixed region codes (fly-iad), unlike the dashboard — see the location reference.
  • retry — how many times a failed check is retried before the monitor is marked down.
  • body — the JSON-RPC ping payload. jsonencode keeps it readable and correctly escaped.
  • headers — one block per header. statusas already sends User-Agent: Statusas/1.0; override it only if your server cares.
  • status_code_assertions — ensures the HTTP response is 200 OK.
  • body_assertions — verifies the response payload matches the expected JSON-RPC ping result.

3. Test your MCP server online first

Before deploying a monitor, confirm the server actually speaks MCP. The quickest way is the MCP server health check — paste your URL and it runs the full handshake (initialize, ping, tools/list) from the browser, shows the per-step latency, and tells you whether the endpoint is Healthy, Partial, Auth Required, or Unreachable. Use it to read off the exact response your assertion needs to match.

You can also test the ping endpoint manually with curl. This helps verify the target value for your body assertion.

curl -X POST \\
  -H "Content-Type: application/json" \\
  -d '{"jsonrpc": "2.0", "id": "statusas", "method": "ping"}' \\
  https://hf.co/mcp # Replace with your MCP server URL

A healthy server should return a JSON response like {"result":{},"jsonrpc":"2.0","id":"statusas"}.

4. Deploy your monitor

Review the plan, then apply it:

terraform plan    # confirm the monitor is what you expect
terraform apply

Monitoring begins as soon as the apply completes.

Monitoring an MCP server that requires authentication

Most production MCP servers are not public. An unauthenticated ping against one returns 401 Unauthorized, usually with a WWW-Authenticate: Bearer header, so a monitor without credentials will report your healthy server as down.

Add the same Authorization header your AI clients use:

variable "mcp_token" {
  type      = string
  sensitive = true
}

resource "openstatus_http_monitor" "mcp_server" {
  # ...

  headers {
    key   = "Authorization"
    value = "Bearer ${var.mcp_token}"
  }
}

Two things to plan for:

  • Token rotation is the most common false alarm. When the token expires, the monitor goes down while the server is perfectly healthy. Assert on the status code being 200 so a 401 fails loudly and is easy to recognise, rather than debugging it as an outage.
  • Keep the credential out of your repository. Mark the variable sensitive and pass it in with TF_VAR_mcp_token or from a secrets manager. Use a token scoped to read-only health checks — not a production credential — and rotate it on a schedule you control.

If you are unsure which authorization server issues your token, the health check tool parses the WWW-Authenticate challenge and surfaces the OAuth resource metadata for you.

Monitoring tool availability and latency

A ping proves the server is answering. It does not prove the server still exposes the tools your agents call — an empty tools/list is the failure mode that breaks AI clients while every uptime dashboard stays green.

Add a second monitor that calls tools/list and asserts a known tool name is present:

resource "openstatus_http_monitor" "mcp_tools" {
  name        = "MCP tools/list"
  description = "Verify the MCP server still exposes its tools"
  url         = "https://hf.co/mcp"
  method      = "POST"
  periodicity = "5m"
  active      = true
  retry       = 3
  regions     = ["fly-iad", "fly-ams", "fly-sin"]

  body = jsonencode({
    jsonrpc = "2.0"
    id      = "statusas"
    method  = "tools/list"
  })

  headers {
    key   = "Content-Type"
    value = "application/json"
  }

  headers {
    key   = "Accept"
    value = "application/json, text/event-stream"
  }

  status_code_assertions {
    target     = 200
    comparator = "eq"
  }

  body_assertions {
    target     = "your_tool_name"
    comparator = "contains"
  }
}

Assert on the bare tool name, not on "name":"your_tool_name". contains matches literally, and servers differ in whether they emit a space after the JSON key — an assertion written against the compact form fails the moment a server pretty-prints its response.

tools/list is also the more honest latency signal. ping usually returns an empty result and measures little more than the network round trip, whereas tools/list exercises the server's actual request path — which is what an agent waits on. Run it at a lower frequency than ping if you want to keep request volume down.

What to alert on

Not every MCP failure deserves the same response:

  • ping failing across all regions — the server is down. Alert immediately.
  • ping failing in one region — usually a network path problem rather than your server. Retries handle most of these, which is what retry = 3 is for.
  • 401 after a period of 200s — a rotated or expired token. This is a credentials problem, not an outage.
  • tools/list succeeding but missing a tool — a deploy removed or renamed a tool. Nothing is "down", but your agents are already broken.
  • Latency climbing on tools/list while ping stays flat — the server is under load in its application layer rather than its network layer.

What you've accomplished

  • Configured a JSON-RPC based monitor for your MCP server
  • Implemented precise assertions to validate ping responses
  • Handled authenticated endpoints without turning token rotation into a false outage
  • Added a tools/list check so a missing tool is caught before your agents hit it
  • Set up global monitoring to detect localised or widespread issues
  • Declared both monitors in Terraform, so they are reviewable and reproducible

Both monitors run on statusas uptime monitoring from up to 28 regions, with alerting and history — so a broken handshake reaches you before it reaches the agents depending on it.

What's next

Learn more

On this page