Skip to content

MCP server monitoring

Agents trust whatever an MCP server says in tools/list. Tool descriptions and server instructions go straight into the model’s context, so a changed description is a changed instruction to every agent connected to that server. Servers also break quietly: a spec revision or an auth change, and new clients stop connecting while nothing in your logs looks wrong. The mcp monitor type watches a remote MCP server the way an HTTP monitor watches a website - is it up, does the handshake still work - and adds the part an uptime check cannot see: did the tools it advertises change since a person last approved them.

It suits two jobs:

  • You publish an MCP server. Uptime, auth-chain health, protocol version, and tool changes you did not expect after a deploy.
  • You depend on someone else’s MCP server. Pin the approved tool surface and get paged when it changes.

Monitors, then Add Monitor, type MCP server.

FieldNotes
MCP endpoint URLThe server endpoint, e.g. https://mcp.example.com/mcp
TransportStreamable HTTP (default) or Legacy SSE
AuthenticationNone, Header (API key or bearer token), or OAuth - check discovery chain only
HeadersHeader mode only: name and value pairs such as Authorization or X-API-Key, up to 10
Drift policyAlert on changes (default) or Record changes only
Expected toolsOptional, comma-separated tool names that must be present
Max toolsFail when the server lists more tools than this; 0 means no cap
Check intervalDefault 10 minutes
TimeoutDefault 20 seconds
Escalation policyWhere a failure pages

Everything else is the same as other monitors - locations, escalation policy binding, pausing - and is described in Monitor types. AI assistants can create one with the create_mcp_monitor tool; see the MCP tool reference.

StepWhat happens
HandshakeConnects over the chosen transport and runs initialize, recording the negotiated protocol version, server name and version, capabilities, and a hash of the server instructions
Protocol versionA server that negotiates a version older than 2025-06-18 gets a warning; the check still passes
Tool listCalls tools/list and follows nextCursor across pages, up to 20 pages or 500 tools. A truncated list is a warning
FingerprintsEach tool is hashed as canonical JSON of its name, title, description, input and output schema, and annotations, with separate hashes for the text, the schema, and the annotations so a change can be named. The whole surface gets one digest
DriftThe fingerprints are compared with the approved baseline (below)
LintEvery tool title and description, and the server instructions, are scanned for suspicious patterns
AssertionsExpected tools must be present, and the tool count must not exceed the max
LatencyHandshake time and list time are recorded on every successful check

The check only lists. It never calls a tool, so it is safe to point at any server.

ChangeEventFails the check by default
Tool removedmcp_tool_removedYes - clients that call it break
Tool addedmcp_tool_addedYes - the server’s reach grew
Input or output schema changedmcp_tool_schema_changedYes
Description or title changedmcp_tool_description_changedYes - the text a model reads changed
Server instructions changedmcp_instructions_changedYes - same reason
Annotations: a read-only tool is no longer read-only, or a tool becomes destructivemcp_tool_annotations_changedYes
Any other annotation changemcp_tool_annotations_changedNo, event only
Server version or protocol version changedmcp_server_version_changedNo, event only
OAuth discovery metadata changedmcp_auth_metadata_changedNo, event only
New suspicious pattern foundmcp_poison_findingYes

With Record changes only, nothing in this table fails the check: every change is still recorded as an event, which suits a development server that changes several times a day. Missing expected tools and a tool count over the max fail under either policy.

The lint is a set of heuristics. False positives happen; a finding is accepted the same way as any other change.

RuleLooks for
Hidden characters (hidden_unicode)Zero-width, bidirectional control, invisible operator, byte-order mark, and Unicode tag characters: text a model reads but a person reviewing the list does not see
Instruction markers (instruction_marker)Tags such as <IMPORTANT> or <SYSTEM>, “ignore previous instructions”, “do not tell the user”, “before using this tool, read…”
Sensitive paths (sensitive_path)~/.ssh, id_rsa, .env, .aws/credentials, mcp.json, .cursor/, .claude/, /etc/passwd, .npmrc, .git-credentials, .kube/config
Cross-tool steering (cross_tool)“When calling the X tool” where X is not a tool this server lists
Encoded blobs (encoded_blob)Base64-like runs over 200 characters or hex runs over 128
Oversized (oversized)A description over 16 KB. Over 4 KB is a warning only

With OAuth - check discovery chain only, the monitor walks the same discovery a new client would, without logging in:

  1. An unauthenticated request to the endpoint must get HTTP 401. The resource_metadata URL is taken from the WWW-Authenticate header; if it is missing, the monitor falls back to the well-known location and records a warning.
  2. The protected-resource metadata (RFC 9728) must load and name at least one authorization server.
  3. The authorization-server metadata (RFC 8414, then OpenID configuration) must load, and its issuer must match the authorization server URL (the RFC 9207 mix-up defence).
  4. PKCE S256 must be advertised, and the authorization and token endpoints must be present.
  5. A client registration path must exist: client ID metadata documents, or dynamic client registration. Relying on dynamic registration alone is a warning, since the 2026-07-28 spec deprecates it; having neither fails.

Any break in the chain fails the check. Because there is no login yet, the tool list is not checked in this mode: use None or Header when the server lets you list tools that way.

  • The first successful check sets the baseline. The first tool list the monitor sees becomes the approved one, and the monitor records a mcp_baseline_set event. Review it on the monitor’s page.
  • Findings are not accepted automatically. If the first check finds a suspicious pattern, the check fails until a person accepts it. A server that was already poisoned when you added it still gets flagged.
  • Changes keep failing until someone accepts them. Drift is not a one-off event: the check stays failing, and the alert stays open, until a person reviews the diff and chooses Accept changes on the monitor’s page. That copies the current tools, instructions, and findings into the baseline, records who accepted it, and logs a mcp_baseline_accepted event.
  • Accepting is human-only. It works only from a signed-in session in the AlertKick web app. The API refuses it for API keys and for the MCP connector, and there is no MCP or WebMCP tool for it: an agent must not be able to approve the tool changes that would steer it.
  • Changing the URL resets the baseline. A different endpoint is a different tool surface, so the next check starts over.
SettingDefaultNotes
Transport (mcp_transport)streamable-httpsse for servers that only speak the legacy HTTP+SSE transport
Authentication (mcp_auth_mode)noneheader sends fixed headers with every request; oauth checks the discovery chain only
Headers (mcp_headers)-Header mode only. Values are stored encrypted and never returned by the API; the web app shows header names only, and leaving a value blank on edit keeps the stored secret. Switching away from header mode deletes them
Drift policy (mcp_drift_policy)alertrecord turns every drift row and finding into an event only
Expected tools (mcp_expected_tools)-Up to 100 names. A missing one fails the check under either policy
Max tools (mcp_max_tools)0 (no cap)Up to 10,000
Check interval10 minutesTool lists change with deploys, not by the second
Timeout20 secondsCovers the handshake and every page of the tool list

The monitor identifies itself honestly: client name alertkick-monitor and the user agent AlertKick-MCP-Monitor/1.0, with a link to this page.

  • It never calls a tool. It lists, fingerprints, and compares.
  • No OAuth login yet. OAuth mode checks the discovery chain; it cannot list tools behind a login.
  • Remote servers only. Servers that run locally over stdio, such as npm or PyPI packages started by a desktop client, cannot be reached by a poller.
  • It cannot see per-user cloaking. A server that shows clean tool text to monitors and something else to specific users or clients is invisible to any outside check. A server that returns different tools per account will also show drift if the monitor’s key changes.
  • Resources and prompts are not fingerprinted, only tools and the server instructions.

Tool descriptions and server instructions come from the server being watched, so AlertKick treats them as untrusted input. The monitor’s page shows short excerpts as plain text. Events, alerts, and AI triage carry tool names and change kinds only, never the text itself. The MCP tools get_monitor and list_monitors omit descriptions, titles, instructions, and finding excerpts and return a compact mcp_summary instead, so a poisoned description cannot reach an assistant through AlertKick.

Every event in the drift table above, plus mcp_baseline_set and mcp_baseline_accepted, appears on the monitor’s timeline. Drift and finding events fire once, when the change first appears, while the check keeps failing until it is accepted.

MetricMeaning
mcp_tool_countTools listed by the server
mcp_init_msHandshake time in milliseconds
mcp_list_msTime to list every page of tools, in milliseconds

The monitor’s response time is the whole check, handshake plus tool list.