# Your MCP server can change what it does between versions — and you won't know

> Source: <https://dev.to/cleiton_augusto_/your-mcp-server-can-change-what-it-does-between-versions-and-you-wont-know-37dn>
> Published: 2026-11-03 11:42:25+00:00

MCP exploded: by mid-2026 there are **10,000+ public servers**. But trust in the ecosystem is **name-based**, and that is the problem.

The official registry **does not review code or scan for malware** — it checks that you own the GitHub repo or domain, and leaves scanning to "downstream aggregators." So "it's in the registry" means almost nothing for safety.

Worse, servers **drift**. An August 2026 census of 21,643 registry servers found:

And star counts barely help (popularity was a weak safety signal). So you vet a server once, pin trust to its name, and a later version quietly does something else. Static scanners check a snapshot; **drift happens after the scan.**

Two properties, at runtime, on every call:

That's what I built into [CleiMesh](https://github.com/cleitonaugusto/cleimesh). You put any MCP server behind it:

```
cleimesh mcp wrap --token fetch.json -- uvx mcp-server-fetch
```

Now:

`run_shell`? It's never exposed. An argument reaching outside the grant? Refused — and the refusal is receipted too.
Unlike a scanner, this is **continuous and after-the-fact provable**: you don't trust a one-time scan, you get a signed record of what every call did, run after run.

`wrap` does **not** sandbox a native server's own process — it reaches whatever its OS user can. What `wrap` gives you is a **pinned, receipted surface**: the tools/arguments the token allows, and a signed record naming the server. If you want the tool itself physically contained (default-deny, can't touch `~/.ssh` no matter what), that's `cleimesh mcp serve`, which runs tools in a WebAssembly sandbox. Use `wrap` for native servers you don't control; `serve` for tools you run under CleiMesh.

A vetted MCP server advertises one tool, `search`. A later version keeps the same identity but silently adds a dangerous `run_shell`. Behind `cleimesh mcp wrap`, with a token that grants only `search`:

```
Token grants exactly one tool: search.

== v1  (vetted server: advertises only 'search') ==
  client sees tools: ['search']
  search -> ok

== v2  (SILENT DRIFT: same identity, now also advertises 'run_shell') ==
  client sees tools: ['search']
  search -> ok
  run_shell -> REFUSED

== What the signed receipts recorded ==
  tool       decision  server_sha256 (names which server ran)
  search     allowed   4ae7d7e537ca9144...
  search     allowed   edcfb70e2b2e9ada...
  run_shell  denied    - (denied before dispatch)
```

Three things the signed receipts prove: the drifted `run_shell` was **never exposed** (the grant pins the tool surface); the attempt was **refused and recorded**; and the `server_sha256` **changed between versions** — so the drift is in the log, not silent. (`wrap` does not sandbox the native server, and the receipt says so: `confined: false`. For a tool you want physically contained, run it under `cleimesh mcp serve`, in WASM.)

MCP trust today is "I vetted the name once." That doesn't survive 40% silent drift. The fix isn't another catalog or another one-time scan — it's **enforcing the grant and proving every call at runtime**, so a server that changes what it does is *bounded* and *caught*.

Free and open (MIT/Apache-2.0): **[https://github.com/cleitonaugusto/cleimesh](https://github.com/cleitonaugusto/cleimesh)** — the `cleimesh-mcp` skill on ClawHub sets it up. Point it at the MCP servers your agent already uses and look at the receipts.

— Cleiton Augusto Correa Bezerra ([github.com/cleitonaugusto](https://github.com/cleitonaugusto))
