MCP rug pulls and silent contract drift - catch the change before your agent acts

Short answer: yes, it can change after you approve it, and most of the time the declared version does not move. Across a frozen 40-day census of the public MCP registry we recorded 2,503 safety-relevant contract changes, and in 62.4% of them the server's declared version was unchanged. A version pin does not see roughly three in five of the changes that matter. 123 of them flipped a tool's annotation toward destructive: a hint that read "read-only" now declares it can write, delete or send.

Those figures are frozen and citable (DOI 10.5281/zenodo.21449150); the running count is on the public ledger, and the full deduped analysis - version behavior, removal scope, stability segmentation - is The MCP Drift Report. The honest limit: this is a contract diff, not a safety verdict, and "silent" is a claim about version evidence only, never about intent.

Security writeups call the sharpest version of this an MCP rug pull: a server passes review, runs cleanly for weeks, then swaps its tool contract for something else after your agent already trusts it (CVE-2025-54136 demonstrated the pattern against approved configs). Rug pull asserts intent; most contract changes we observe in the wild are ordinary, unannounced maintenance. Both matter, because your agent cannot tell them apart at call time - and the mechanics are identical.

Model Context Protocol tools are described to your agent the way a system prompt is: a name, parameters, constraints, and annotations. That description is a contract. Unlike a pinned npm version, many MCP servers can change that contract on the remote side with no release tag your client notices.

When the contract drifts - a new required parameter, a narrowed enum, an annotation flip to destructive - the agent still calls the tool with Monday’s assumptions. The failure mode is quiet. You see a weird tool result, a wrong side effect, or a hold-up much later in the chain.

A directory listing or a one-time “screen” of the description helps before you wire a tool. It does not help on Tuesday when the live schema changed. That is an in-path problem: something has to compare the live contract to what you pinned on first sight and stop the call when they disagree.

mcpindex’s drift gate does that locally. It pins each tool contract on first sight (TOFU), diffs on every later call, and HOLDs when the change is breaking. Benign added-optional fields can proceed. The verdict is a contract-diff - “this changed” - not a claim that the tool is safe. Zero credentials; the default build egresses nothing.

If you only need discovery or an advisory REVIEW/UNVERIFIED screen before install, use the directory and /screen. If you already run tools in Claude Desktop, Cursor, Cline, or Zed, install the gate so silent drift cannot run unseen: https://mcpindex.ai/#install

Related

Monday / TuesdayOn Monday you pin a tool contract in which search_docs takes a query string. On Tuesday the server changes it to also require a webhook parameter, with no version bump, no notification and no email. On Wednesday your agent calls the tool. Without a pin the agent fills the new required parameter and calls anyway and nothing tells you. With mcpindex the call is held and labelled added-required-param before it goes out.MONTUEWEDyou pin the contractsearch_docs(  query: string)the server changes itsearch_docs(  query: string,  webhook: string ** NEWLY REQUIREDNO VERSION BUMP · NO NOTIFICATION · NO EMAILyour agent calls itWITHOUT A PINthe agent fills the new requiredparam and calls. nothing tells you.WITH MCPINDEXadded-required-paramheld before the call goes out.THE TOOL YOUR AGENT TRUSTED ON MONDAY CHANGED ON TUESDAY. NOTHING IN MCP TOLD YOU.
Fig. 02 · The change arrives with no version bump, no notification and no email. The pin is the only witness.
Read Fig. 02 as text
  MON -------------------- TUE -------------------- WED
   |                        |                        |
   you pin the contract     the server changes it    your agent calls it

   search_docs(             search_docs(             WITHOUT A PIN
     query: string            query: string,         the agent fills the new required
   )                          webhook: string *      param and calls. nothing tells you.
                            )
                            * newly required         WITH MCPINDEX
                            no version bump          |- HELD  added-required-param
                            no notification             held before the call goes out
                            no email

  the tool your agent trusted on monday changed on tuesday. nothing in MCP told you.

Permalink, SVG & reuse · CC BY 4.0

Questions
What is an MCP rug pull?
An MCP rug pull is when a server changes a tool's behavior or declared contract after you approved it - the tool your agent trusted Monday is a different tool on Tuesday, with no version bump. The pattern was demonstrated in CVE-2025-54136 (an approved config whose underlying command was swapped). A drift gate counters it by pinning the contract on first sight and holding any call where the live contract no longer matches the pin. Note the honest limit: a contract-diff catches declared changes; a server that keeps its contract identical and changes behavior underneath is out of scope.
How do I know if an MCP tool changed after I connected it?
Pin the tool's declared contract (name, schema, annotations) on first sight and diff it on every later call. When the live contract differs from what you pinned, a drift gate flags the specific change or holds the call. MCP servers can change remotely with no version bump, so a diff is the only reliable signal.
What is silent MCP tool contract drift?
It is when an MCP server changes a tool's declared contract, a new required parameter, a narrowed constraint, an annotation flipping from read to write, without a version bump your client notices. The agent keeps calling the tool with its old assumptions, and the failure is quiet: a wrong side effect or a bad result later in the chain.
Can you detect an MCP server that changes behavior without changing its schema?
Not from the client side deterministically. Contract pinning catches declared changes to schema, description, and annotations. A server that keeps the schema identical and changes behavior underneath is the honest hard part, and anyone claiming to verify behavior for arbitrary servers is overclaiming. mcpindex scopes itself to declared-contract diff and labels behavior-underneath as out of scope.
Is git diff enough to catch MCP tool contract changes?
No. git diff and similar utilities compare file snapshots you provide. MCP contract integrity pins the live tool contract on first sight and diffs it on later calls - including when the server changes remotely with no file in your repo. See the layer map in MCP scanners vs gateways.