Install
$ agentstack add mcp-fardenghi-pkg-guard-mcp Open-source listing — not yet scanned by AgentStack. Follow the source repository for install instructions.
Security review
⚠ Flagged1 finding(s); flagged for manual review. · v0.1.0 How review works →
- • Prompt-injection patterns
- • Secret / credential exfiltration
- • Dangerous shell & filesystem operations
- • Untrusted network calls
- • Known-malicious package signatures
- high Destructive filesystem operation.
What it can access
- ✓ Network access No
- ✓ Filesystem access No
- ● Shell / process execution Used
- ✓ Environment & secrets No
- ✓ Dynamic code execution No
From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.
About
pkg-guard
[](https://www.npmjs.com/package/@pkg-guard/mcp) [](LICENSE) [](https://nodejs.org)
> pkg-guard is an alerting layer — a day-zero supply-chain checker for npm + PyPI, distributed as a local MCP server for AI coding agents. > > pkg-guard runs locally via npx. When your AI agent (Claude Code, Cursor, Claude Desktop) is about to install a package, it calls check_package first and surfaces structured evidence — publish-time anomalies, lifecycle script changes, Scorecard signal, OSV advisories — so the agent (and you) can stop and look before installing. > > It is not a package-manager enforcement gate, a malware scanner, a sandbox, or a guarantee. See [Limitations](#limitations).
What it does
Most supply-chain incidents have a small day-zero window: the malicious version lives for hours before defenses catch up. Confidence-based signals (provenance, signatures) and slow-feedback signals (CVEs, advisory databases) usually arrive too late.
pkg-guard looks for contextual anomalies that don't need to know the specific malware:
- A1 — Version age: package published moments ago
- A2 — New lifecycle scripts /
.pthfiles: install-time code injection - A3 — Size delta: unusual jump in published artifact size
- A4 — Maintainer change: new publisher this version
- A5 — Author change: new author this version
- B1-B4 — Baseline signals: Scorecard, OSV advisories, popularity, age
Signals combine with AND rules (not additive weights). A package with a single anomalous A-signal still gets flagged when paired with a low-popularity baseline. Returns a structured Verdict with level: "ok" | "warn" | "critical", the signal IDs, and the sources consulted.
What it isn't
- Not an enforcement gate — it surfaces evidence; your agent decides
- Not a malware scanner — no static or dynamic analysis of package contents
- Not a sandbox — packages still install with their normal permissions if you proceed
- Not a guarantee — heuristics can produce both false positives and false negatives; treat results as one input, not a verdict
Install in your MCP client
pkg-guard is a stdio MCP server. Your AI client launches it as a subprocess. No hosted service, no OAuth, no account required.
Step 1 — Install the package globally (recommended)
npm install -g @pkg-guard/mcp
> Why global install? MCP clients (Claude Code, Cursor, Claude Desktop) spawn the MCP subprocess without inheriting your shell's PATH. If you use nvm or any non-system Node install, the npx binary may not be on the subprocess's PATH, and the MCP connection fails with -32000. A global install puts pkg-guard-mcp on a stable path that subprocess-spawned MCP servers can find. > > You can use npx -y @pkg-guard/mcp instead if your node + npx are at predictable system paths (Homebrew Node, system Node) — see [Troubleshooting](#troubleshooting) if your client reports -32000 or "Failed to connect."
Step 2 — Configure your MCP client
Claude Code (CLI)
# After global install
claude mcp add --transport stdio pkg-guard pkg-guard-mcp
# Alternative: via npx (use absolute paths if your client reports -32000)
claude mcp add --transport stdio pkg-guard "$(which node)" "$(which npx)" -y @pkg-guard/mcp
Cursor (.cursor/mcp.json)
{
"mcpServers": {
"pkg-guard": {
"command": "pkg-guard-mcp"
}
}
}
Claude Desktop (claude_desktop_config.json)
{
"mcpServers": {
"pkg-guard": {
"command": "pkg-guard-mcp"
}
}
}
Restart your MCP client after editing the config. The check_package tool should appear in the tool list.
Troubleshooting
| Symptom | Cause | Fix | |---------|-------|-----| | -32000 / "Failed to connect" | MCP client can't find npx or node because the subprocess doesn't inherit your shell PATH (common with nvm) | Use the global-install path above, or pass absolute paths: `claude mcp add --transport stdio pkg-guard which node which npx -y @pkg-guard/mcp | | sh: pkg-guard-mcp: command not found (when calling npx) | Stale npx cache holding a broken older version | rm -rf ~/.npm/npx && npm cache clean --force | | Tool list missing checkpackage | Bin started but the MCP protocol handshake failed | Test directly: echo '{"jsonrpc":"2.0","method":"initialize","params":{"protocolVersion":"2024-11-05","capabilities":{},"clientInfo":{"name":"test","version":"1"}},"id":1}' \| pkg-guard-mcp should print a JSON-RPC response with serverInfo and tools.listChanged: true` |
Example
After install, drop the [adoption snippet](#adoption-snippet) below into your agent's system prompt (Claude Code's CLAUDE.md, Cursor rules, Claude Desktop system prompt). A typical exchange:
You: install left-pad
Agent: Let me check left-pad first via pkg-guard.
[calls check_package({ ecosystem: "npm", name: "left-pad" })]
Verdict: ok
Signals: []
Sources: registry, deps-dev, osv
The package looks fine. Proceeding with `npm install left-pad`.
When something's wrong:
You: install some-suspicious-package
Agent: [calls check_package, gets level: critical]
pkg-guard returned a CRITICAL signal:
- A1 (version_age): published 2 hours ago
- A2 (new_lifecycle_script): new preinstall script in v1.2.4
I am not going to install this without explicit confirmation.
Please review the evidence and tell me if you want to proceed.
Adoption snippet
Paste this verbatim into your agent's system prompt (Claude Code's CLAUDE.md, Cursor rules, Claude Desktop system message, or any other MCP-capable AI coding agent). It makes the agent call check_package before any npm or PyPI install, block on warn / critical until you explicitly confirm, and ask before proceeding if pkg-guard is unavailable.
## pkg-guard package install safety
Before installing or adding any npm or PyPI package, call the `check_package`
MCP tool from the pkg-guard server.
This applies before commands including `npm install`, `npm add`, `pnpm add`,
`yarn add`, `bun add`, `pip install`, `pipx install`, `uv pip install`,
`poetry add`, and edits to files that introduce new npm/PyPI dependencies
(`package.json`, `pyproject.toml`, `requirements.txt`, `Pipfile`).
Call `check_package` with:
- `ecosystem: "npm"` for npm/pnpm/yarn/bun packages.
- `ecosystem: "pypi"` for pip/pipx/uv/poetry packages.
- `name`: the package name.
- `version`: the exact version if known. Omit only when the install
command would use the default/latest version.
If pkg-guard returns `level: "ok"`, proceed normally and keep the
explanation brief.
If pkg-guard returns `level: "warn"` or `level: "critical"`, do **not**
install yet. Show the user:
- `level`
- `summary_hint`
- `signal_ids`
- `signals[].evidence`
- `sources_failed`
Then ask the user for explicit confirmation before installing. Do not
infer that they want to proceed.
If the pkg-guard tool is unavailable, errors, or times out (or returns a
non-empty `sources_failed`), do **not** silently proceed. Tell the user
the supply-chain check could not be completed and ask whether they want
to proceed without pkg-guard. Do not run the install command before they
answer.
If `level: "ok"` but `sources_failed` includes `"registry"`, the
requested version probably does not exist on the registry. Treat this
as a phantom-version risk: tell the user the version was not found,
and ask before installing. (v1.0.x has a known gap where this is not
yet a first-class signal; v1.1 will add an explicit `A6:
version_not_found` heuristic.)
Do not reinterpret a `warn` or `critical` result as safe because OSV has
no advisory, because the project is popular, or because the maintainer
is well-known. The pkg-guard `level` is the authoritative alert for this
workflow.
> Note: MCP tool selection is model-controlled. The snippet strongly instructs the agent but does not enforce — a user who tells the agent to install anyway can still install anyway. pkg-guard is an alerting layer, not a hard gate.
Configuration
All optional. Set as environment variables (or via your MCP client's env config).
| Variable | Default | What it does | |----------|---------|--------------| | HMAC_LOG_SECRET | dev-default | Per-process secret used to HMAC-hash package names in structured logs. Set to a stable random value if you want consistent hashes across npx invocations. | | PKG_GUARD_AUDIT_LOG | 0 (off) | Set to 1 to append hash-only audit lines to ~/.pkg-guard/audit.jsonl. Useful for analyzing your own check history; default is off so nothing touches disk. |
How it works
For each check_package call, pkg-guard:
- Resolves the package and version against the registry (npm or PyPI)
- Fetches in parallel: registry metadata, deps.dev (Scorecard + popularity), OSV.dev (advisories), and for PyPI, the wheel
RECORDfile for.pthfiles - Runs 9 heuristics (A1-A5 acute + B1-B4 baseline)
- Combines signals with AND rules into a
Verdict - Returns:
{ level, signals[], transitive_flagged[], sources_consulted[], sources_failed[], summary_hint }
Failed sources degrade gracefully — the call still returns a Verdict computed from whatever resolved within the timeout budget, and sources_failed[] tells the caller what was missing.
Privacy: structured logs and the optional audit file are hash-only. Package names are HMAC-SHA256'd; raw package names and versions never appear in logs or files.
Limitations
- Heuristic, not deterministic. Can produce both false positives (legitimate packages with surprising release patterns) and false negatives (carefully-staged attacks that match a normal release pattern).
- Phantom-version gap (v1.0.x). If you query a version that doesn't exist on the registry (e.g.
react@99.0.0), the engine currently returnslevel: "ok"withsources_failed: ["registry"]rather than treating "version not found" as its own signal. Always checksources_failedbefore acting on a level: ok verdict — ifregistryis insources_failed[]for a real-world (not test) query, the version probably doesn't exist and you should not install it. Tracked for v1.1+ as a newA6: version_not_foundheuristic. - English-only signal labels. Signal descriptions are English; integrate via signal IDs (
A1,A2, …) for client UIs that localize. - No package contents inspection. We read metadata and (for PyPI wheels) the RECORD; we don't unpack tarballs or run dependency installers.
- Source availability. When deps.dev or OSV is degraded, signals that depend on them are unavailable.
sources_failed[]reports this. - Stdio only in v1.0. Hosted/multi-tenant mode (HTTP + OAuth) was scoped out for v1; see CONTRIBUTING.md if you want to help bring it back.
Contributing
See [CONTRIBUTING.md](CONTRIBUTING.md) for dev setup, test requirements, and how to add a new heuristic or MCP tool. Issues and PRs welcome.
Security
Vulnerability reports: see [SECURITY.md](SECURITY.md). Use GitHub Security Advisories for private disclosure.
License
[MIT](LICENSE). Copyright 2026 Filipo Ardenghi.
Source & license
This open-source MCP server is cataloged on AgentStack and links to its original source — we do not rehost the code.
- Author: fardenghi
- Source: fardenghi/pkg-guard-mcp
- License: MIT
- Homepage: https://www.npmjs.com/package/@pkg-guard/mcp
Install and usage instructions live in the source repository linked above.
Reviews
No reviews yet — be the first.
Write a review
Versions
- v0.1.0 Imported from the upstream source.