Stop your AI assistant from installing packages that don't exist
DepMesh checks every package your coding assistant wants to add — before it gets installed. It catches made-up ("hallucinated") package names, abandoned projects, and risky licenses, and answers one plain question: should you use this or not?
Free, and no account is needed to use DepMesh — signing in adds a dashboard of what it caught for you.
What's the problem? (the 30-second version)
AI coding assistants sometimes invent a package name that sounds real
but isn't. Attackers watch for those invented names, register them for
real, and fill them with malware. So when your assistant confidently
runs npm install or pip install on a name it
made up, it can pull in someone else's trap. This even has a name:
slopsquatting.
Even when a package is real, it might be abandoned, deprecated, or under a license your company can't use.
What does DepMesh do about it?
DepMesh is a tiny helper your assistant can ask, "is this package safe to adopt?" It looks the package up on the real registry and gives a one-word verdict with reasons:
- ADOPT real, healthy, well-maintained — go ahead.
- CAUTION exists, but something's off (gone quiet, one maintainer, odd license).
- REJECT doesn't exist, or is deprecated/risky — don't install it.
“Gone quiet” is judged against the project’s own rhythm rather than a fixed number of months: a library that shipped every week and then stopped for six is flagged, while one that has always released once a year is not.
It runs entirely on your machine and adds no dependencies of its own. Nothing is sent anywhere unless you connect it to a hosted DepMesh account (optional — set up after you sign in).
Which package registries does it check?
Each one is read from the registry your build tool actually resolves from, so "does this package exist?" is answered by the source of truth rather than guessed at.
Anything else, DepMesh says it does not know that ecosystem — it never passes a package it could not check.
It checks the version you pinned, not just the package
Your build file never asks for a package — it asks for one
exact version, and that is where a lot of the risk actually sits. An
advisory applies to a range of releases, a license can change between
them, a single version gets yanked, and a pin can sit years behind a
project that is otherwise perfectly healthy. Asked about
express, DepMesh says CAUTION; asked about
express@4.18.2, it says REJECT — two advisories apply to
that release and not to the current one.
Paste the coordinate your build file already contains. Each ecosystem is read the way its own tooling writes it, so there is no DepMesh spelling to learn:
depmesh-ai vet npm express@4.18.2 depmesh-ai vet pypi requests==2.31.0 depmesh-ai vet maven org.springframework.boot:spring-boot-starter-parent:3.2.2 depmesh-ai vet go github.com/BurntSushi/toml@v1.3.2 depmesh-ai vet packagist monolog/monolog:2.0.0 depmesh-ai vet npm express --version 4.18.2 # or say it explicitly
The verdict then tells you which half the problem is in, because the fix is not the same: a healthy package with a stale pin means upgrade it, while an abandoned package with a current pin means drop it. Ask without a version and nothing changes — you get exactly the package-level answer you got before.
Your assistant gets the same argument. The MCP tool takes an optional
version, and is told to pass it whenever it is about to
pin one — so the check happens at the coordinate that ends up in your
project, not at the name.
A range is refused rather than resolved: ^4.18.0,
[1.0,2.0) and latest all come back asking
for the version your build tool settled on. It has already done that
work, and guessing at it would answer a different question than the
one your project contains.
A version nobody ever published is a REJECT, the same as a made-up
name — an assistant will invent express@4.18.99 as
readily as it invents package names. It is not counted in your
dashboard, though: nobody can register version 4.18.99 of someone
else’s package, so there is nothing there for an attacker to
squat.
What signing in gives you
DepMesh does its job without an account, and the verdicts are the same either way. What an account adds is memory: every made-up package name it turned down for you, kept and counted instead of scrolling past in a terminal.
- Your numbers. How many invented package names DepMesh stopped — all-time, and day by day across the last 30 days.
- The names themselves. Which hallucinations keep coming back in your work. Those are the exact names an attacker would register to catch you, so a repeat offender is worth knowing by name.
- Everyone's, in one place. Every install reporting with your key rolls into the same dashboard, so a pattern spread thin across people and machines becomes visible.
- A key you control. Copy it into your setup once, and rotate it yourself whenever you want — the old one stops working immediately.
A report is sent only when DepMesh rejects a package because the registry has never heard of it — real packages, low scores and policy rejections are never reported. It carries the ecosystem, the name, and the version of the tool. Deliberately not sent: usernames, hostnames, repository or project names, file paths, or IP-derived data. Your code never leaves your machine.
Dashboards belong to an account rather than to a person, since reports carry no identity to tell your colleagues apart. If you sign in before yours has been set up, DepMesh will say so rather than show you an empty chart.
Set it up in two minutes
-
Step 1 — install DepMesh. One command (needs
Go installed):
go install github.com/jhberges/depmesh-ai/cmd/depmesh-ai@latest
Check it worked:depmesh-ai vet npm expressshould print a green✓ ADOPT. - Step 2 — connect it to your assistant. Pick the tool you use:
Run this once, anywhere:
claude mcp add depmesh -- depmesh-ai serve
That's it. Claude Code now has a vet_dependency tool and
will check packages before adding them. (Prefer a file? Put this in
.mcp.json at your project root instead:)
{
"mcpServers": {
"depmesh": { "command": "depmesh-ai", "args": ["serve"] }
}
}
Start Copilot CLI, then add DepMesh interactively:
copilot # then, at the prompt: /mcp add
Fill in the fields: name depmesh,
type Local, command
depmesh-ai, arguments serve.
The config is saved to ~/.copilot/mcp-config.json — you
can also edit that file directly:
{
"mcpServers": {
"depmesh": {
"type": "local",
"command": "depmesh-ai",
"args": ["serve"],
"tools": ["*"]
}
}
}
Verify with /mcp show depmesh.
Create a file called .vscode/mcp.json in your project
(note: the key is servers, not mcpServers):
{
"servers": {
"depmesh": {
"type": "stdio",
"command": "depmesh-ai",
"args": ["serve"]
}
}
}
Open the Copilot Chat panel, switch it to Agent mode,
and DepMesh's vet_dependency tool is available. VS Code
shows a "Start" button on the server the first time.
What happens after that?
Nothing to remember day-to-day. Whenever your assistant is about to add
a dependency, it can ask DepMesh first and see the verdict — so a
made-up or risky package gets stopped before it ever reaches your
project. You can also run a check by hand any time:
depmesh-ai vet pypi requests.
For teams: a policy file
The verdict says whether a package is healthy. A
policy file says whether your organization
allows it — a minimum score, which licenses are acceptable,
and named, expiring exceptions. Drop a
depmesh.policy.json in your project and every check —
from the command line, your assistant, or the internal API — obeys it:
{
"min_score": 70,
"fail_on": "caution",
"licenses": { "allow": ["MIT", "Apache", "BSD", "ISC"], "deny": ["AGPL", "SSPL"] },
"exceptions": [
{ "ecosystem": "maven", "package": "org.apache.commons:commons-lang3",
"reason": "Apache-2.0 via parent POM, approved by security architecture",
"expires": "2027-06-30" }
],
"audit_log": "depmesh-decisions.jsonl"
}
Licenses match case-insensitively and deny beats
allow. Every exception is justified and carries an
expires date — an expired or malformed exception fails
closed rather than silently allowing the package.
The audit trail
Set audit_log (or pass --audit-log) and every
decision — from the CLI, your assistant, or the API — appends one JSON
line: who asked, on which surface, the package, the verdict, the score,
and what policy decided. It is append-only
JSON Lines, ready to ship to
Splunk or ELK. If the audit write ever fails, the decision is withheld
(fail closed).
{"time":"2026-07-24T09:12:44Z","actor":"alice","surface":"mcp","ecosystem":"npm","package":"reqwest-http","advice":"REJECT","score":0,"policy":{"allowed":false,"violations":["verdict is REJECT","score 0 is below the policy minimum 70"]},"tool_version":"0.2.0"}
Turn it on for your assistant
A depmesh.policy.json in your project root is picked up
automatically, so the setup from Step 2 already enforces it. To point
at a policy elsewhere — or to be explicit — add the flags to the same
serve command your assistant runs:
claude mcp add depmesh -- depmesh-ai serve --policy depmesh.policy.json --audit-log depmesh-decisions.jsonl
In a .mcp.json (Claude Code / Copilot CLI) or
.vscode/mcp.json (VS Code), that is the same
args array with the flags appended:
"args": ["serve", "--policy", "depmesh.policy.json", "--audit-log", "depmesh-decisions.jsonl"]
Open source at github.com/jhberges/depmesh-ai. The policy file and audit trail above run entirely on your own machines. Sign in with GitHub to add a hosted dashboard of every hallucinated name your team caught.
Signed in
Your account () is not assigned to a customer tenant yet. Contact your DepMesh representative.
Dashboard
Most-caught package names
| Package | Caught |
|---|
Setup & configuration
Point your depmesh-ai installations at this endpoint:
Ingest key:
Rotating invalidates the old key immediately.
Admin — all tenants
Tenants
| Tenant | Owners | Events | Last event |
|---|