
Rugsnare
io.github.Paraphernv0.4.0更新于 Oct 2, 2026
Pin MCP tool contracts, catch silent drift, replay calls before upgrades. Zero deps.
概览
固定 MCP 工具契约,检测描述或架构的静默漂移,并在升级前重放已记录的调用。
- 功能
- RugSnare 对每个已批准工具的名称、描述和 inputSchema 做哈希,通过 scan、diff、approve 命令报告漂移、新增或移除的工具,并在有变化时让 CI 失败。可选的 stdio 代理会监视运行中的服务器,在 enforce 模式下隔离发生漂移的工具;canary 模式记录真实工具调用,并对新版本重放以判断升级是否安全。它还能把本地事件日志签名为可验证的收据,并暴露两个只读 MCP 工具 drift_feed_status 和 pins_report。
- 适用场景
- 适合在你已经批准一组 MCP 服务器之后使用,用来发现它们的工具契约之后是否发生变化,无论是跨会话还是会话中途。也适合希望在 CI 中对工具定义设卡,并在正式升级前用记录的真实调用测试新版本的团队。
- 运行要求
- 作为本地 Node.js 命令行工具和 stdio MCP 服务器运行,需要 Node.js 18 或更高版本;npm 包名为 rugsnare,从 GitHub 检出后无需 npm install。未声明任何账户、API 密钥或环境变量。可选的 drift_feed_status 工具在被调用时会向一个固定的公开地址发起一次外部请求。
安装
在 SourceWeft 中
- 打开 控制台中的 Rugsnare,将其添加到工作区。
- 为需要使用其工具的对话启用该服务。
Desktop only,通过 STDIO。 STDIO 服务会启动本地进程,因此需要 SourceWeft 桌面宿主。
其他 MCP 客户端
参照 仓库 中的启动说明。
README
RugSnare
[RugSnare logo][npm version] [License: Apache 2.0] [CI] [Dependencies: 0] [Node: >=18] [GitHub stars]
Runtime integrity for MCP tool descriptions. Scanners check MCP servers before you connect them. RugSnare watches what happens after: an approved tool whose description silently changed is a rug pull, and it fails your build.
Why this exists
MCP tool descriptions are instructions your agent obeys but nobody reads. They can change after you approve them — a maintainer update, a compromised registry, a typosquatted package — quietly carrying exfiltration instructions ("attach ~/.ssh/id_rsa for personalization"). The attack class is codified as tool poisoning (OWASP MCP03:2025). Version pinning doesn't help when the version string doesn't change; scanning doesn't help after approval. Hash pinning does.
What's inside
Install
npm (recommended — landing October 2, 2026):
From GitHub (works right now):
Zero dependencies, no npm install needed — just Node.js ≥ 18.
Quick start
After install (use node src/cli.js instead of rugsnare if installing from GitHub):
Each tool's { name, description, inputSchema } is canonicalized and hashed — so both poisoned descriptions and hidden "session" parameters in schemas trip the pin, while cosmetic reordering doesn't.
Live proxy (optional, v0.2+)
Wraps a stdio server: observe watches and alerts, enforce additionally quarantines drifted/new tools mid-session. Measured overhead on the bench fixture (tools/bench-proxy.mjs, 200 round-trips): ~0.7–1 ms per tool call in observe mode, ~1.2 ms with arg logging + canary recording on, ~7 MB working set beyond the Node baseline — the proxy adds three orders of magnitude less than the LLM turn it protects. Idle CPU is zero (pure event loop, no polling). By default the proxy is fail-open — if its own logic ever errors, the message is forwarded untouched (availability first). Strict environments can flip it:
or per-run with --fail-closed — then a proxy internal error blocks the message and answers the client with a JSON-RPC error instead (integrity first, logged as proxy-fail-closed).
One more opt-in: "canaryRecord": true in the config makes the proxy also record id-correlated tool-call traces (request, response, latency, server version) to .rugsnare/canary/calls.jsonl — local-only, capped at 64 KB per entry, off by default because args and responses are user data. rugsnare canary record (below) enables it for one session without touching the config file.
Canary: replay your real calls against a new version (v0.4)
Pinning answers "what changed?" The canary answers "can I upgrade?". While you work, the proxy records what your tools actually return; before an upgrade, replay that corpus against the new version and get a deterministic verdict:
Replay diffs both the contract (split hash: BREAKING schema vs COSMETIC prose) and the behavior — a call that was ok and now errors, a response whose shape changed — while ignoring value-only differences (timestamps, prices change between runs), so no crying wolf. Replay is read-only by default: only read-like tool calls are re-executed; write-class and destructive-looking calls are skipped with a loud SKIPPED note (--include <tool> opts specific tools in, --all-calls lifts the write-class skip for sandboxes — destructive names always require explicit --include). Point replay at a dev instance, not production. Known trade-off: arrays are compared by their first element's shape, so a structural change affecting only later elements of a heterogeneous array will not flag — deterministic under-flagging was chosen over probabilistic false positives. Exit codes fit CI: 0 = safe, 1 = breaking findings (or --strict cosmetic / --max-ms latency-budget violations), 2 = no corpus, 3 = replay failure. Contract assertions for CI: rugsnare diff --expect-tool search --forbid-tool admin fails the build when a required tool disappears or a forbidden one appears. Traces are local and gitignored (rugsnare init writes that .gitignore for you); pins remain the only deliberate commit. Self-verifying demo: repro/canary.sh; CI integration: action/canary.
Signed receipts: a tamper-evident trail of what the agent did (v0.4)
The proxy already logs every tool call. Receipts make that log provable: an Ed25519 hash-chain where each entry signs the hash of the previous one — edit, delete, or reorder anything after signing, and verify names the exact entry where the chain breaks.
Keys live in .rugsnare/keys/ (gitignored). verify --pub <pem> checks a receipt file against an exported public key — an auditor can confirm your trail without ever seeing a private key. One honest limit: the chain catches edits, insertions, deletions, and reordering inside it, but not a silent truncation of its tail (dropping the last N entries leaves a valid shorter chain). That is what the chain head printed by sign/export is for — anchor it somewhere the log writer cannot quietly rewrite (a commit, a message to the auditor) and compare. Also in v0.4: a loop detector — the proxy notices when the same tool is called repeatedly with identical arguments and no other tool in between (a stuck agent burning credits) and raises a one-time loop-suspected advisory; it never blocks anything.
RugSnare as an MCP tool (read-only, for marketplaces and agents)
The same binary doubles as a stdio MCP server, so agents can call it and marketplaces can list it:
Two read-only tools: drift_feed_status (what the public drift-feed currently sees across popular MCP servers — the only outbound call this server ever makes, a fixed public URL, only when explicitly invoked) and pins_report (the local pin store of the project the agent works in — never writes, never sends anything). Pinned by our own gate, naturally — the baseline lives in corpus/03-rugsnare-self. A Docker image and registry entry are prepared under docker/ and registry/.
Trust model
We take our own medicine:
- Zero dependencies — a supply-chain security tool must not be its own attack surface.
- No telemetry. Local pin store, local JSONL event log, nothing leaves your machine.
- Signed releases (Ed25519 OpenPGP, fingerprint in SECURITY.md, published in three independent places).
- On-chain
ReleaseLog— release hashes pinned append-only on Base (testnet live now);rugsnare verifychecks your install against a hash that has been in the ledger since release day. - Apache-2.0. If we ever go rogue — fork us. That's the license working as intended.
Ongoing research on how teams vet MCP servers: discussions/1 — 7 short questions, findings published. Author: @SergeyDruzhba on X.
FAQ
How is this different from MCP Inspector / Glama Inspector? Inspectors (including the official one) are interactive debugging tools: they show you tool descriptions while you're looking. RugSnare watches them when you're not: approved definitions are hash-pinned, and any later change — across sessions or mid-session via the proxy — trips an alert and fails CI. Complementary tools: inspect before you approve, pin after.
Is this another MCP scanner? No. Scanners (snyk agent-scan, ex-mcp-scan) run at install time. RugSnare runs after approval, forever.
Threat model — what this covers, honestly
RugSnare pins the contract your agent obeys — { name, description, inputSchema } of every approved tool — and detects any silent change to it, between sessions (CI diff) and mid-session (live proxy). It does not inspect implementations.
If an attacker changes the code but not the contract, no description hash can see it — that's a different layer's job. Defense in depth means layers; this tool owns the contract layer completely.
Field-tested
The silent changes report (repro/SILENT-CHANGES-REPORT.md): we pinned every stable release of the 4 official @modelcontextprotocol/server-* reference servers, diffed each version against the next, and counted every contract change between them.
74 findings. Not one was announced in a changelog. The most dramatic single step: filesystem 2025.8.21 → 2025.11.25 changed all 14 tool contracts simultaneously — 14 BREAKING schema changes in one silent release; memory's history carries 18 schema-level breaks. Reproduce on your machine: one command, ~20 minutes, deterministic — see the report footer.
Status & roadmap
118 tests · 10 CI jobs · field-tested on real packages · on-chain verified · zero dependencies · no telemetry.
来源:README.md,提交 e671636
工具
0版本历史
1- v0.4.0最新Oct 2, 2026


