# Show HN: I ran 70 MCP servers in a sandbox and logged what they do

> Source: <https://github.com/BhaveshThapar/mcp-audit>
> Published: 2026-07-08 22:44:41+00:00

A harness that runs MCP servers in an instrumented sandbox and records what they
**actually do at runtime** — every network connection they open and every file
they touch — so you can see a server's real behavior instead of trusting its
description.

The official MCP registry verifies *who published* a server (namespace
authentication tied to a GitHub account or domain). It does not verify *what a
server does once you run it*. The existing trust tooling in the ecosystem is
almost entirely **static analysis** — scanning source code and metadata. Static
scans miss an entire class of risk that only shows up at runtime:

- a server that connects somewhere unrelated to its stated purpose
- a server that reads credentials or files outside its lane
- a "rug pull": a server whose behavior changes in a later version,
*after*you've already reviewed and trusted it

This project captures runtime behavior directly, which is the part almost nobody is watching yet.

Each server is launched inside a disposable Linux container (Docker) under
`strace`

, with syscalls for file access (`openat`

) and network connections
(`connect`

) logged. A fake credential is seeded into the environment as a canary,
so any attempt to read or transmit it is visible in the trace. The container is
throwaway; nothing the server does touches the host.

```
docker + strace  ──►  per-server syscall trace  ──►  behavior manifest
```

Everything runs locally. No server code executes on the host machine.

**70 MCP servers** audited: the 20 most-downloaded on npm, plus 50 from the long
tail. Full per-server summaries are in [ manifests/](/BhaveshThapar/mcp-audit/blob/main/manifests); the headline
findings are in

[.](/BhaveshThapar/mcp-audit/blob/main/RESULTS.md)

`RESULTS.md`

**67 clean** at startup — no sensitive-file reads, no unexpected network.**3 made outbound HTTPS connections at startup**(`okx-trade-mcp`

,`razorpay/blade-mcp`

,`notebooklm-mcp-server`

) to external hosts consistent with each server's function (an exchange integration, a GitHub fetch, cloud/CDN endpoints). None read sensitive files or touched the seeded canary.**1**(`bullmq-mcp`

) reads`/etc/passwd`

at startup via a standard glibc user lookup — flagged by the harness, then**verified benign**: the contents never leave the process.** No server transmitted sensitive data.**

The value shown here isn't "everything was clean" — it's that the harness surfaced the three servers that phone home and the one that touches a sensitive file, and each could be run down to a verdict from the trace. That is behavior static scanners don't see.

Scope note:this capturesstartup and idlebehavior only — the server booting and waiting. It does not yet exercise individual tool calls, which is where more behavior lives. See roadmap.

**Tool-call tracing**— drive each server through its advertised tools and record behavior per call, not just at boot. (The 3 outbound servers above are the first place this matters.)**Version diffing**— re-run servers across releases and diff behavior to detect rug pulls — the highest-value, least-covered case.** Behavior manifests as a feed**— a stable, diffable per-server output that clients or registries could consume before install.** Wider coverage**— deeper into the long tail of single-maintainer servers.

```
# needs Docker
git clone <this repo> && cd mcp-audit
docker run --rm -v "$PWD":/audit -w /audit node:22 bash -c \
  'apt-get update -qq && apt-get install -y -qq strace && bash run.sh'   # batch 1
# (run2.sh for the long-tail batch)

# distil the traces into readable manifests
python3 summarize.py
```

Reading raw traces: a read inside the server's own dependencies is normal (it's
loading its own code); a failed open (`-1 ENOENT`

) is normal (a config file that
isn't there); DNS (`port 53`

) and package-download connections (Cloudflare
`104.16.x.x`

) are normal. You're looking for a server that reads a *sensitive*
file, or connects to a host with *nothing to do with its job*, once it's running.

Anything that looks like a genuine issue is reported privately to the server's maintainer first, with time to fix, before it appears in any public writeup. Observations here are characterized conservatively — a flagged behavior is not an accusation until it's confirmed with the maintainer.

*Built by Bhavesh Thapar*
