Sign In

fencescan

Package Overview
Dependencies
Maintainers
1
Versions
5
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

fencescan

Find tool calls that could fire the same effect twice. Reports evidence, renders no verdict. Zero dependencies.

latest
Source
npmnpm
Version
0.1.4
Version published
Maintainers
1
Created
Source

fencescan

Find tool calls that could fire the same effect twice.

npx fencescan

No install, no dependencies, no network, no config. Scans the current directory and prints what's worth a second look.

What it does

An agent that retries a tool call after a timeout doesn't know whether the first attempt landed. The request reached the server, the work happened, the response never came back. Nothing failed loudly — it succeeded twice.

fencescan reads your code and lists the tools where that would cost you something, alongside what else it found: write call sites, anything that looks like an idempotency guard, and retry logic.

fencescan /your/mcp-server
  42 files · 11 tool declarations found

Tools worth checking  (candidates, not verdicts)
  money   createCampaign   src/tools/ads.py:609 · 12 write call(s) in this file
  money   chargeAccount    src/tools/billing.py:88
  effect  sendTemplate     src/tools/whatsapp.py:151

What else is in this codebase
  59 write call site(s)
  0 idempotency-looking guard(s)  ← none found in this repo
  14 retry site(s)

Worth a close look: retry logic and no visible dedup key.

What it deliberately does not do

It renders no verdict. There is no risk score, no "AT RISK", no severity. An outsider reading a codebase usually cannot prove a double-fire: the guard often lives in a service the code calls or a sibling package, and a function whose name sounds like a write may only build a payload for someone else to sign. Every run prints what it cannot see.

This isn't modesty. An earlier version did print verdicts, and hand-verification killed 4 of its first 7. Each of those failures is now a fixed behaviour with a test:

It got this wrongWhyFixed by
Said a repo had no idempotency when it shipped a whole module\b(idempot…) cannot match deriveIdempotencyKey — no word boundary before a mid-word capital. Same blindness hid requestId, clientTokenanchors removed
Flagged read-only toolsA flat window after a tool name ran into the next declaration, so reads inherited writes' vocabularybrace-matched to the tool's own block; a read verb in the name vetoes
Found no writes at allWrites live in shared helpers, not in the tool declarationcollected per file as corroboration, never claimed as "this tool writes"
Missed method: body ? "POST" : "GET"String literals were stripped before matching — but the HTTP verb is a literalmatched on the raw line

If it flags something and you're sure it's wrong, that's worth an issue. A false positive here costs more than a miss.

Usage

npx fencescan              # scan the current directory
npx fencescan ./server     # scan a path
npx fencescan --json       # machine-readable

Exit codes: 0 scanned, 2 bad path. It never exits non-zero for findings — findings are for a human to read, not for a build to fail on.

Recognises MCP-style tool declarations (registerTool, @mcp.tool, Tool(...), @tool) across TypeScript, JavaScript, Python, Go, Rust, Java and Ruby.

If it finds something

Open each candidate and ask one question: if this ran twice, would anyone notice?

If the answer is no, that's the bug — not the crash you'd have caught.

For fixes: once is an exactly-once kernel for TypeScript and Python, and effectfence is an MCP server that fences tool calls. Both free. If you'd rather someone did the work, the Fence Audit.

Licence

MIT

Keywords

mcp

FAQs

Package last updated on 11 Aug 2026

Related posts