Monitor your MCP server the way agents use it
MCP server monitoring that speaks the protocol. Every check completes the handshake, lists the tools and can call one, and tells you when a tool your agents depend on changed its schema. An HTTP 200 on the URL proves none of that.
What one check does
Three protocol steps, each timed on its own. The timings are stored with every check, and GET /monitors/:id/metrics returns their p50 and p95, so a slow tools/list shows up before it becomes a timeout.
- 01
initialize
notifications/initialized
The handshake an agent makes before anything else. Streamable HTTP first; the older HTTP+SSE transport when that is all the server offers.
timed as initMs
- 02
tools/list
nextCursor until complete
The full tool list, and with listPrompts or listResources also the prompts and resources the server advertises.
timed as listMs
- 03
tools/call
optional probe
One call to a tool you choose. The check fails when the tool is missing, returns isError, or its text does not satisfy expectContains or expectRegex.
timed as callMs
Tool schema drift, classified
The first successful check records the tool list as the baseline. Every later check compares what the server serves with it. Nested object parameters are compared by path, so a new required field inside an optional object is not breaking. Key order and a server version bump are never drift.
| Severity | Changes | What happens |
|---|---|---|
| breaking | Tool removed · parameter removed · new required parameter · optional parameter became required · parameter type changed · enum value removed · prompt removed | An event, and the monitor goes to driftStatus (degraded by default) with the diff as its error, which alerts your channels. |
| non_breaking | Tool added · optional parameter added · parameter became optional · enum value added · constraint or output schema changed · resources changed | An event only. The baseline moves to the new schema. |
| description | Only the wording of a tool or parameter description changed | An event only. Listed on its own because a quietly edited description is how tool poisoning reaches an agent. |
After a breaking change
- You accept it. "Accept as new baseline" on the monitor page, or
monitors_schema_acceptfrom your agent, once your agents work with the new schema. - The server rolls it back. The tool list matches the baseline again and the monitor recovers by itself.
- The hold runs out. After
driftHoldHours(24 by default, up to 720) the change is accepted automatically, so a monitor is never degraded forever.
Subscribe a webhook to monitor.schema_changed to get all three severities as a tool changelog. It is not in the default set of alert events, so it adds no noise: breaking changes already alert through the monitor going degraded or down.
{
"type": "monitor.schema_changed",
"data": {
"monitor": { "name": "Acme MCP", "kind": "mcp", "target": "https://mcp.acme.com/mcp" },
"schemaChange": {
"severity": "breaking",
"pending": true,
"summary": "tool `search` lost required param `query`",
"changes": [
{ "severity": "breaking", "type": "param_removed", "tool": "search", "param": "query" }
]
}
}
}One call to start
The kind is inferred when you send an mcp object. The same monitor can be created from the dashboard under Monitors → New monitor, or by your agent with the monitors_create tool of the UpButler MCP server.
From there it behaves like every other monitor: failures are confirmed before anyone is alerted, an incident opens, your status page component follows, and the AI incident report names the failing step and the tools and parameters that changed.
curl -X POST https://upbutler.com/api/v1/monitors \
-H "Authorization: Bearer $UPBUTLER_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "Acme MCP",
"kind": "mcp",
"url": "https://mcp.acme.com/mcp",
"headers": { "Authorization": "Bearer <token>" },
"mcp": {
"probe": { "tool": "ping", "args": {}, "expectContains": "ok" },
"driftStatus": "degraded",
"driftHoldHours": 24
}
}'What a failure means
Every failed check carries a class in evidence.mcp.failure, so an alert says "the token expired" or "the probe tool is gone" and not "the check failed".
| Class | Meaning | Monitor state |
|---|---|---|
| auth | HTTP 401 or 403 at any step. The server is reachable; the credential is wrong or expired. | down |
| unreachable | The connection failed, DNS failed, or the server answered HTTP 5xx. | down |
| timeout | The check ran out of time. The error names the step it was in. | down |
| protocol | The endpoint answered, but not with valid MCP: a JSON-RPC error, a missing tools array, an HTML page. | down |
| probe | The probe tool is gone, returned an error, or failed your assertion. | down |
| drift | The server works, but its tool schema changed in a breaking way. | driftStatus |
Limits, plainly
Free$0
1
MCP and LLM monitor, checked as often as every 5 min
Starter$12/mo
5
MCP and LLM monitors, checked as often as every 1 min
Pro$29/mo
25
MCP and LLM monitors, checked as often as every 30 s
Business$99/mo
100
MCP and LLM monitors, checked as often as every 30 s
They count toward the plan's monitor total. Related: LLM API monitoring for the model behind the server, and the live status of the providers you depend on. Full list on pricing.
MCP monitoring questions
What is MCP server monitoring?
MCP server monitoring checks a Model Context Protocol server the way an agent uses it: it completes the handshake, lists the tools, optionally calls one, and compares the tool schema with the last known one. An ordinary uptime check only sees that the URL answers; it does not notice that a tool lost a parameter or that tools/list returns an error.
How is this different from an HTTP check on the MCP URL?
An MCP endpoint can answer HTTP 200 while the handshake fails, the token has expired, the tool list is empty or a tool your agents call was renamed. UpButler runs initialize, tools/list and, if you set one, a tools/call probe on every check, and reports which step failed.
What counts as a breaking schema change?
A tool or prompt that was removed, a parameter that was removed, a new required parameter, an optional parameter that became required, a changed parameter type and a removed enum value. Added tools, added optional parameters and description edits are recorded as events but do not change the monitor state.
What happens after a breaking change?
The monitor stays in its drift state (degraded by default) until you accept the new schema as the baseline, the server rolls the change back, or driftHoldHours pass (24 by default, up to 720), after which the change is accepted automatically. Set driftStatus to down to open an incident, or none to record changes without alerting.
Can I monitor an MCP server that needs authentication?
Yes. Send the headers the server expects when you create the monitor. Header values are encrypted at rest (AES-256-GCM) and are never returned by the API, the dashboard, events or webhooks; you get the header names back.
Can I monitor an internal MCP server that is not on the public internet?
Yes, with a private probe that you run inside your own network. It makes outbound HTTPS requests only, so nothing has to be opened to the internet. See private monitoring.
How often is the server checked, and what does a probe call cost?
Every 5 minutes by default, down to the fastest interval of your plan (30 s on Pro). At a 5-minute interval a probe tool is called about 8,600 times a month per region, so pick a read-only tool that costs nothing.
How many MCP monitors are included?
MCP and LLM monitors share one allowance: 1 on Free, 5 on Starter, 25 on Pro, 100 on Business. They also count toward the plan's monitor total.
Know before your agents do.
One MCP monitor is free, with drift detection and a status page. 100 on Business.