Guide
How to Check if Your MCP Server Is Up
August 18, 2026 · 6 min read
"Is my MCP server up?" is not answered by opening the URL in a browser — most MCP endpoints return an error page or 405 to a plain GET even when they're perfectly healthy. The honest answer requires speaking the protocol: an initialize handshake and a tools/list call. Both are plain JSON-RPC over HTTP, so curl can do it. Here's the complete walkthrough for a Streamable HTTP server.
Step 1: the initialize request
Send a JSON-RPC initialize to your endpoint. The -i flag matters — you'll need a response header in step 2. The Accept header must offer both content types or compliant servers will refuse with 406:
curl -si -X POST https://your-server.com/mcp \
-H 'Content-Type: application/json' \
-H 'Accept: application/json, text/event-stream' \
-d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{
"protocolVersion":"2025-06-18",
"capabilities":{},
"clientInfo":{"name":"health-check","version":"1.0"}}}' A healthy server responds 200 with either a JSON body or an SSE-framed message (event: message followed by a data: line — same JSON, different wrapper). What you want to see in it:
{"jsonrpc":"2.0","id":1,"result":{
"protocolVersion":"2025-06-18",
"capabilities":{"tools":{}},
"serverInfo":{"name":"my-server","version":"1.4.2"}}} Check three things: it's a result (not an error), the protocolVersion is one your clients can accept, and capabilities includes tools if you expect tools. Also look at the response headers for Mcp-Session-Id — if present, copy it; every following request must carry it.
Step 2: the initialized notification
Before making requests, a client is supposed to confirm the handshake. Notifications have no id and expect no body back — a 202 Accepted is the normal response:
curl -si -X POST https://your-server.com/mcp \
-H 'Content-Type: application/json' \
-H 'Accept: application/json, text/event-stream' \
-H 'MCP-Protocol-Version: 2025-06-18' \
-H 'Mcp-Session-Id: PASTE-YOUR-SESSION-ID' \
-d '{"jsonrpc":"2.0","method":"notifications/initialized"}' Omit the Mcp-Session-Id line if step 1 didn't return one. Lenient servers work without this step; strict ones reject tools/list until they've seen it, so a thorough check includes it.
Step 3: list the tools
curl -si -X POST https://your-server.com/mcp \
-H 'Content-Type: application/json' \
-H 'Accept: application/json, text/event-stream' \
-H 'MCP-Protocol-Version: 2025-06-18' \
-H 'Mcp-Session-Id: PASTE-YOUR-SESSION-ID' \
-d '{"jsonrpc":"2.0","id":2,"method":"tools/list"}' The result contains a tools array with each tool's name, description, and inputSchema. This is the step that separates "the process is running" from "the server is actually serving": count the tools and eyeball the names. An empty array on a server that should have tools is an outage in every way that matters, whatever the status code says.
Reading the failures
406— yourAcceptheader doesn't offer both content types.401/403— auth. Add yourAuthorization(or custom) header to every request above.400on step 2 or 3 — usually a missingMcp-Session-IdorMCP-Protocol-Versionheader.404— wrong path, or an expired session id; re-run step 1.405on POST — possibly a legacy HTTP+SSE server that wants a GET to/ssefirst; see the transport guide.- A hang with no response — almost always a buffering proxy or a cold start; the initialize failure guide covers both.
Checking a legacy HTTP+SSE server
If the POST in step 1 comes back 404 or 405, you may be talking to a server on the old transport. Those expect you to open the SSE stream first:
curl -sN https://your-server.com/sse -H 'Accept: text/event-stream' A healthy legacy server immediately emits an endpoint event whose data: line is a URL, usually containing a session token. Keep that curl running in one terminal, POST the same initialize body from step 1 to the endpoint URL in another, and watch the response arrive on the stream rather than in the POST reply — the POST itself just returns 202. If the stream opens but no endpoint event ever arrives, a buffering proxy is holding it back. The -N flag disables curl's own buffering so you can tell the difference.
Making it repeatable
Once the three requests work, wrap them in a script and pipe the results through jq so a human doesn't have to read raw JSON-RPC:
curl -s ... -d "$TOOLS_LIST_BODY" \
| sed -n 's/^data: //p' \
| jq -r '.result.tools[].name' The sed line strips SSE framing when present and passes plain JSON through untouched, so the same pipeline handles both response styles. A one-line cron job comparing that output against yesterday's copy is already a primitive drift detector.
From one check to continuous checks
This walkthrough proves your server is up right now. The failures that hurt are the ones that happen at 3am after a deploy, and the ones a handshake alone can't see — a tool list that quietly shrank, a tool whose upstream dependency died. That's a monitoring problem: the same sequence, every minute, with the tool list diffed between runs and an alert when anything changes. The complete monitoring guide covers the full setup — or paste your URL into the free checker below and get this entire walkthrough run for you in about two seconds.