← Discover MCPs and Agents
s
MCPAI & MLGitHub

slopcatch

Flags AI-hallucinated package names in manifests and imports before you pip or npm install.

Links

README

From the repo.

slopcatch

English | 中文 | 日本語

License: MIT Version Python ≥3.9 Tests PRs welcome

Open-source slopsquat guard — flags AI-hallucinated package names in manifests and imports before you pip or npm install. Offline, zero dependencies.

Demo

git clone https://github.com/JaydenCJ/slopcatch && cd slopcatch && pip install -e .

Pre-release: slopcatch is not yet published to PyPI. Until the first release, clone JaydenCJ/slopcatch and run pip install -e . from the repository root.

Why slopcatch?

Slopsquatting is the 2025-vintage supply-chain attack with the simplest possible mechanic: code assistants hallucinate package names, the hallucinations recur across prompts and models, and attackers register them before you read the diff. Researchers measured roughly a fifth of AI-recommended packages resolving to nothing — or worse, to whoever claimed the name first. The existing tooling attacks the wrong half of the problem: typosquat scanners score keyboard distance to popular names, but a model never fat-fingers reqeusts — it composes openai-sdk, transplants axios into requirements.txt, or upgrades pip install cv2 from import name to install command. slopcatch is a single-purpose checker aimed at exactly those generation patterns: seven rules, an embedded corpus, no network, no account, exit code 2 before the installer runs.

slopcatchSocketGuardDogtyposquat scanners
Detects hallucination patterns (composition, not typos)yes — 7 dedicated rulesnonono
Import-name vs install-name traps (cv2, yaml, PIL)yes, with the real namenonono
Cross-ecosystem transplants (axios in requirements.txt)yesnonono
Works fully offlineyes (embedded corpora)no (SaaS API)no (fetches packages + rules)mostly
Flags names that do resolve on the registryyes — registered slop is worsereputation-basedscans the tarballno (existence = pass)
Runtime dependencies0app + CLI + API keyPython, Semgrep, pip treevaries

Column facts checked against Socket and GuardDog public docs, 2026-07. Both do far more than name checks — slopcatch deliberately does this one thing, before anything is downloaded.

Features

  • Exit code as a gateslopcatch check requirements.txt exits 2 the moment any finding reaches --fail-level (default: high), so a one-line hook blocks pip install; 0 means go, 1 means you held it wrong.
  • Hallucination patterns, not string distance — suffix echoes (openai-sdk), prefix echoes (python-requests), version drift (beautifulsoup), ecosystem transplants (express on PyPI), template names (smart-json-parser-tools), and a seed list of documented slop.
  • The pip trap, named — 35 import-name→distribution mappings turn pip install cv2 into "did you mean: opencv-python" instead of a mystery package.
  • Scans what you actually have — package.json (all four dependency sections), requirements/constraints files, pyproject.toml (PEP 621, poetry, build-system; works without tomllib on 3.9), plus ast-parsed Python and JS/TS import scanning.
  • Allowlist, not gag order--allow/--allow-file suppress a finding but report the name as allowed, so the JSON stays honest about why nothing fired; unknown names are reported, never flagged.
  • Zero everything — zero runtime dependencies, zero network calls, zero telemetry; the corpora ship inside the wheel and results are deterministic byte-for-byte.

Quickstart

Install:

git clone https://github.com/JaydenCJ/slopcatch && cd slopcatch && pip install -e .

Save this as requirements.txt — two of these five packages are real:

fastapi
openai-sdk
python-dotenv
beautifulsoup
smart-json-parser-tools

Check it before installing (output copied from a real run):

$ slopcatch check requirements.txt
requirements.txt (pypi, 5 names)
  HIGH    openai-sdk                   suffix-echo: real package "openai" + generated suffix "-sdk" — the real project publishes as "openai"  [line 2]
                                       did you mean: openai
  MEDIUM  beautifulsoup                version-drift: the registered package is "beautifulsoup4" — the un-versioned "beautifulsoup" is a common model mis-remembering  [line 4]
                                       did you mean: beautifulsoup4
  MEDIUM  smart-json-parser-tools      template-name: assembled entirely from generic filler words (smart, json, parser, tools) — a template-shaped name typical of generated code  [line 5]

checked 5 names: 2 known, 0 unknown, 0 allowed, 3 flagged (1 high, 2 medium, 0 low)

Exit code 2 — wire it straight into a pre-install hook. Single names work too, including the classic pip trap:

$ slopcatch name cv2
<names> (pypi, 1 name)
  HIGH    cv2                          import-alias: "cv2" is the *import* name; the installable distribution is "opencv-python"  [argument]
                                       did you mean: opencv-python

checked 1 name: 0 known, 0 unknown, 0 allowed, 1 flagged (1 high, 0 medium, 0 low)

Or scan the generated source directly — slopcatch check bot.py app.ts evaluates every third-party import as if it were about to be installed. A full "vibe-coded" project lives in examples/.

Detection rules

RuleSeverityCatchesExample
known-slophighDocumented assistant hallucinations (seed list)huggingface-cli
import-aliashighImport name used as install namecv2opencv-python
cross-ecosystemhighReal package from the other registryaxios in requirements.txt
prefix-echohighEcosystem prefix on a real namepython-requests
suffix-echohigh / mediumReal package / brand + glue suffixopenai-sdk, supabase-utils
version-driftmediumVersion digits dropped or inventedbeautifulsoup, psycopg3
template-namemedium3+ tokens, all generic fillersmart-json-parser-tools

A name found in the embedded real-package corpus is never flagged, and a name matching no rule is reported as unknown, never flagged — absence from a bundled list is not evidence. Full semantics, severity rationale, and tuning notes are in docs/detection-rules.md.

FlagDefaultEffect
--fail-levelhighLowest severity that makes the exit code 2
--formattexttext or json (versioned schema, sorted keys)
--allow / --allow-fileSuppress findings for vetted names; reported as allowed
--ecosystempypiRegistry for bare name checks (pypi, npm)
--show-alloffAlso list known/unknown/allowed names in text output

Verification

This repository ships no CI; every claim above is verified by local runs. Reproduce them from a checkout of this repository:

pip install -e '.[dev]' && pytest && bash scripts/smoke.sh

Output (copied from a real run, truncated with ...):

89 passed in 0.58s
...
SMOKE OK

Architecture

flowchart LR
    M[package.json / pyproject.toml / requirements.txt] --> P[Manifest parsers]
    S[.py / .ts sources] --> I[Import scanners]
    P --> E[Rules engine<br/>7 hallucination patterns]
    I --> E
    D[(Embedded corpora<br/>real pkgs · aliases · slop seed)] --> E
    E --> R[Reports: text + JSON]
    R --> X{exit 0 / 2}

Roadmap

  • Seven-rule engine, embedded corpora, four manifest formats, Python/JS import scanning, allowlists, text+JSON reports, CLI (v0.1.0)
  • Lockfile scanning (package-lock.json, poetry.lock, uv.lock) with dependency provenance
  • Go, Rust, and Ruby ecosystems (go.mod, Cargo.toml, Gemfile)
  • Optional registry cross-check mode (opt-in network) reporting registration dates for flagged names
  • PyPI release with pip install slopcatch

See the open issues for the full list.

Contributing

Contributions are welcome — start with a good first issue or open a discussion. See CONTRIBUTING.md for the development setup.

License

MIT

Collected info

  • 0 stars
  • Language: Python
  • Source updated: 8/8/2026

Config for your environment

Replace {MCP_ENDPOINT_URL} with this MCP’s endpoint URL (from its repo or docs above). No API key — you connect directly.

Tool

OS

Config file: ~/.cursor/mcp.json

{
  "mcpServers": {
    "mcp-server": {
      "url": "{MCP_ENDPOINT_URL}"
    }
  }
}

Paste into mcpServers in the config file. Restart Cursor after saving.

If this MCP is also published on mcpchannel.ai, you can subscribe from Browse and use the gateway config there instead.