Detect WebMCP Toolset Drift on the Client
Short answer: @mcptrail/webmcp-attest computes a stable, order-independent hash of the tools a page has registered, lets you freeze that hash as a baseline, and fires an onDrift callback the instant the toolset changes — a tool added, renamed, or its schema altered. It’s the client-side signal that the site your agent trusted yesterday is exposing something different today.
WebMCP tools are declared by the site and can change at any time, with no notice. The tool your agent called safely this morning might have a new schema — or new behavior behind the same name — this afternoon. Toolset attestation gives you a fingerprint you can watch. (For the protocol basics, see What is WebMCP?)
Install and create an attestor
The package is MIT open source on GitHub at github.com/ElBartoTn/webmcp-attest. Install it wherever your agent-side code observes the page’s tools:
npm install @mcptrail/webmcp-attest
Create an attestor, freeze the current toolset as your baseline, and register a drift handler:
import { createAttestor } from "@mcptrail/webmcp-attest";
const a = createAttestor();
a.setBaseline(); // snapshot the tools as they are now
a.onDrift((info) => warn(info)); // fires whenever the toolset changes
From here, any change to the registered tools that differs from the baseline invokes your handler with details about what moved.
Why the hash is order-independent
Drift detection is only useful if it flags meaningful changes and ignores noise. A naive approach that hashed the raw list would fire every time tools happened to register in a different order — a false alarm on every page load.
@mcptrail/webmcp-attest computes a stable, order-independent hash: it normalizes each tool (name, description, input schema) and combines them so the same set of tools produces the same hash regardless of registration order. The result is a fingerprint that changes only when the substance of the toolset changes.
| Change | Does the hash change? |
|---|---|
| Tools register in a different order | No |
| A tool’s description is reworded | Yes |
| A tool’s input schema gains a field | Yes |
| A new tool appears | Yes |
| A tool is renamed or removed | Yes |
What onDrift tells you
When the toolset diverges from the baseline, your handler receives an info object describing the drift — which tools were added, removed, or changed, and the old and new hashes. That’s enough to decide what to do:
a.onDrift((info) => {
console.warn("WebMCP toolset drifted", info.added, info.changed);
pauseAgent(); // stop calling tools until a human looks
showReviewBanner(info); // surface the change to the user
});
A common pattern is to treat drift as a hard stop: freeze agent tool calls, show the user exactly what changed, and only resume once someone re-approves the new shape. That prevents a silent redefinition of a tool from sailing through on trust you granted to the old one.
Re-baselining after a legitimate change
Not every drift is an attack — sites ship updates. When a change is expected and reviewed, you re-baseline to accept the new toolset as the trusted one:
a.onDrift((info) => {
if (userApproves(info)) {
a.setBaseline(); // the new toolset becomes trusted
} else {
pauseAgent();
}
});
This keeps the signal honest: the baseline always reflects a toolset a human has actually looked at, and any future divergence from it fires again. Drift detection isn’t a one-time check — it’s a running comparison against the last shape you signed off on.
Client signal vs server-verified attestation
The client attestor is fast and local: it runs in the page, needs no account, and catches drift the moment it happens in that session. Its limit is trust boundary — it lives in the same browser as the tools it’s watching, and it can’t prove to anyone else that the toolset hasn’t changed.
When you need drift caught server-side, enforced across sessions, and written to an audit trail, that’s the hosted version. Turn a WebMCP site into a guarded MCP server explains how MCP Trail snapshots the approved toolset at the proxy and blocks calls until you re-approve when a site’s tools change — so a page update cannot quietly expand what an agent is allowed to do, and the block is recorded. Use the library as the in-page early warning; use MCP Trail when drift needs to be an enforced, audited gate.
FAQ
What is WebMCP toolset drift?
Drift is when a WebMCP site changes the tools it exposes — adding, removing, renaming, or altering the schema or behavior of a tool — without notice. Because tools are declared by the site and callable by your agent, a silent change means the agent may now be calling something different from what you trusted. @mcptrail/webmcp-attest detects it by comparing a hash of the current toolset against a frozen baseline.
Does re-ordering tools trigger a false alarm?
No. The hash is order-independent: it normalizes and combines tools so the same set produces the same fingerprint regardless of the order they registered in. It changes only when the substance changes — a new tool, a renamed tool, a reworded description, or an altered input schema.
How is this different from MCP Trail’s drift attestation?
The library is a client-side signal that runs in the browser for a single session, with no proof to any outside party. MCP Trail’s server-verified drift attestation snapshots the approved toolset at the proxy and blocks calls until a human re-approves the new shape, with the whole event in the audit log. Use the library for an in-page warning; use the hosted version when drift must be an enforced gate.
Explore features · Open MCP Trail
Related articles
- What is WebMCP? — the plain-English introduction to the protocol whose tools can drift.
- Turn a WebMCP site into a guarded MCP server — the hosted version: server-verified drift attestation that blocks calls until re-approved, plus audit logs.
- Client-side approvals for WebMCP tool calls — pair drift detection with a per-tool confirmation step in the browser.
- How to test WebMCP tools — verify a toolset behaves as expected before you trust its baseline.