How We Built Drift Detection for MCP Server Tool Changes
Fingerprinting every MCP server at registration and continuously monitoring for new tools, changed tool signatures, and modified endpoints. The diffing algorithm and alert pipeline.
You approved an MCP server last week with three tools: search_docs, summarize, and list_files. This week, that server silently added a fourth tool: delete_all_documents. Your agent discovered it and used it before you knew it existed. This is drift — and without detection, it is a blind spot in every MCP deployment. Here is how we built the drift detection system.
What drift looks like
Drift comes in three forms:
- Tool addition: the server adds new tools after initial registration. Most dangerous when the new tool has destructive capabilities the admin did not review.
- Schema change: an existing tool's input/output schema changes. A tool that previously accepted only a document ID now accepts arbitrary SQL — the surface area expanded silently.
- Endpoint change: the upstream URL changes, potentially redirecting tool calls to a different server entirely.
Fingerprinting at registration
When an admin registers an MCP server, the gateway performs a list_tools call and captures a fingerprint — a signed snapshot of the server's complete tool catalog:
interface McpServerFingerprint {
serverId: string
capturedAt: string
endpoint: string
tools: ToolFingerprint[]
hash: string // SHA-256 of the entire fingerprint payload
}
interface ToolFingerprint {
name: string
description: string
inputSchema: JSONSchema // full JSON Schema of expected arguments
hash: string // SHA-256 of name + inputSchema
}The fingerprint is stored alongside the server registration and becomes the "approved" baseline. Any deviation from this baseline triggers an alert.
Continuous monitoring
A scheduled Lambda function (wired to EventBridge, running every 5 minutes) re-fingerprints every registered MCP server and diffs against the approved baseline:
async function detectDrift(server: RegisteredMcpServer): Promise<DriftReport> {
const approved = await getFingerprint(server.id)
const current = await captureFingerprint(server.id, server.endpoint)
const added = current.tools.filter(t => !approved.tools.find(a => a.name === t.name))
const removed = approved.tools.filter(a => !current.tools.find(t => t.name === a.name))
const changed = current.tools.filter(t => {
const a = approved.tools.find(a => a.name === t.name)
return a && a.hash !== t.hash
})
return { serverId: server.id, added, removed, changed, timestamp: new Date().toISOString() }
}Alerting pipeline
When drift is detected, the system generates an alert with severity based on the type of change:
- Critical: new tool added with destructive verbs in the name or description (delete, drop, revoke, purge, wipe). Immediate notification to all workspace admins.
- Warning: existing tool schema changed. Notification to the admin who registered the server.
- Info: tool removed or endpoint changed. Logged to audit trail; displayed in the dashboard for review.
The auto-block option
For high-security environments, drift detection can be configured to auto-block: when new tools are detected, the server is immediately quarantined — tool calls return errors until the admin re-approves the updated fingerprint. This is a tenant-level configuration, defaulting to "alert only" to avoid breaking legitimate server updates.
What we learned
The biggest surprise was how frequently legitimate MCP servers update their tool schemas. Servers add optional parameters, improve descriptions, and fix schema bugs — all of which look like drift. We added a "diff threshold": schema changes that only add optional fields or modify descriptions are classified as "info" level, not "warning." Only changes that remove required fields, add required fields, or change field types trigger warnings.