Lazaretto

io.github.jamesdfinance-devPublished by GitHub account jamesdfinance-devv1.3.6Updated Nov 4, 2026

Supply chain security: free npm lockfile malware check, paid scan of packages, skills, MCP servers.

VerifiedStreamable HTTPWeb executableDeveloper ToolsSecurity & MonitoringAI & ML

Overview

Lazaretto's hosted MCP server (lazaretto.dev); optional API key; Streamable HTTP; 10 tools.

No AI overview yet: these facts come from the registry entry and the server itself.

Endpoint
lazaretto.dev
Last checked

Installation

In SourceWeft

  1. Open Lazaretto in the dashboard and add it to a workspace.
  2. Enable the server for the chats that should use its tools.

Web executable via Streamable HTTP. Remote servers run from the web runtime once configured in a workspace.

Use with an agent

Paste this prompt into Claude Code, Codex, Cursor or another agent — or into SourceWeft chat. The agent reads this server's install guide, shows you its publisher, endpoint and sign-in, and adds it to your client once you agree. Keys never go into a command.

Read https://sourceweft.com/mcp/io.github.jamesdfinance-dev%2Flazaretto/install.md and connect the MCP server it describes to my client. Before changing any config, show me its publisher, endpoint and sign-in method and wait for my OK. Never put an API key in a command or in a file I would commit; ask me where it should come from.

Read the install guide the agent follows

Other MCP clients

Add this to your client's mcpServers config.

{
  "mcpServers": {
    "lazaretto": {
      "type": "http",
      "url": "https://lazaretto.dev/mcp"
    }
  }
}

README

lazaretto-mcp

[Lazaretto on the x402 List] [Lazaretto on Wellknown]

Know what a package does before you install it.

Quick start

No account and no key. In Claude Code:

bash
claude mcp add --transport http lazaretto "https://lazaretto.dev/mcp?ref=npm"

Then, in a project with a lockfile, ask your agent for the free check:

Use the lazaretto check_lockfile tool to check this project's dependencies.

In any other client, add https://lazaretto.dev/mcp?ref=npm as a remote MCP server. If your client only runs local servers, make npx -y lazaretto-mcp the command, which needs Node 20 or newer. Set it up has the exact steps for Cursor, Gemini CLI and Cline, and lazaretto.dev/add covers more clients.

ref=npm only tells us this page is where you found it. Leave it off and nothing changes.

What it is

An MCP server for Lazaretto: deterministic pre-install verification for npm packages, AI agent skills and MCP tools. The free lockfile check matches every exactly pinned dependency against OSV and OpenSSF malicious-package advisories, with no account. A metered scan adds behavioral analysis with file-and-line evidence.

This package is a thin front end for the Lazaretto API. It ships no detection logic and does nothing but make HTTPS requests, so it is short enough to read end to end. Each request names this package in its User-Agent header, so we can tell how much use comes through it.

Setting this up as an agent, with no other context? Read llms-install.md instead. It is the same information as a straight-line procedure.

Two ways to run it

Hosted (recommended)stdio package
Endpointhttps://lazaretto.dev/mcp?ref=npmnpx -y lazaretto-mcp
InstallnothingNode 20 or newer
Key goes inthe X-API-Key headerthe LAZARETTO_API_KEY env var
Get a free key in-sessionyes, the get_free_key toolno, curl the trial endpoint
Find a server for a jobyes, the find_mcp_servers toolno
Reads your lockfile off diskno, you pass the textyes, from the working directory
Needs a client that speaks Streamable HTTPyesno

Eight tools are on both. Their arguments match except for these:

Toolstdio packageHosted
check_lockfile, scan_lockfile_deepalso take path, a lockfile on diskno path
scan_artifacttarget_typetype, plus name for inline content

The stdio package refuses an argument a tool does not take, and says what it does take.

The hosted server adds two free tools: find_mcp_servers, which finds a server for a job in the official MCP registry, and get_free_key, which mints a free developer key in the session. Pick the hosted one unless your client has no remote-server support, or you want check_lockfile to read the lockfile off disk so a large tree never passes through the model context.

Set it up

Claude Code

Hosted, one command:

bash
claude mcp add --transport http lazaretto "https://lazaretto.dev/mcp?ref=npm"

With a key for the metered tools:

bash
claude mcp add --transport http lazaretto "https://lazaretto.dev/mcp?ref=npm" \  --header "X-API-Key: YOUR_KEY"

stdio instead:

bash
claude mcp add lazaretto --env LAZARETTO_API_KEY=YOUR_KEY -- npx -y lazaretto-mcp

Drop --env LAZARETTO_API_KEY=YOUR_KEY if you only want the free tools.

To check it in for the whole team, put this in .mcp.json at the repo root instead of running the command:

json
{  "mcpServers": {    "lazaretto": {      "type": "http",      "url": "https://lazaretto.dev/mcp?ref=npm"    }  }}

One catch with .mcp.json: a project-scoped server needs a person to approve it once. Until they do, claude mcp list says Pending approval (run claude to approve) and the tools are not there. The claude mcp add commands above take effect immediately, with nothing to approve, so use those if you want it working in this session.

Confirm with claude mcp list. The entry should say Connected.

Cursor

One click, free tools: Add to Cursor. To add a key, or to set it up by hand, edit ~/.cursor/mcp.json for every project, or .cursor/mcp.json for one:

json
{  "mcpServers": {    "lazaretto": {      "url": "https://lazaretto.dev/mcp?ref=npm",      "headers": {        "X-API-Key": "YOUR_KEY"      }    }  }}

Drop the headers block if you only want the free tools. For stdio, replace url and headers with:

json
{  "mcpServers": {    "lazaretto": {      "command": "npx",      "args": ["-y", "lazaretto-mcp"],      "env": { "LAZARETTO_API_KEY": "YOUR_KEY" }    }  }}

Cursor reloads the file on save. Settings, MCP should list lazaretto with its tools.

Gemini CLI

Install it as an extension. This adds the hosted server with its free tools and a short GEMINI.md telling the agent when to check:

sh
gemini extensions install https://github.com/jamesdfinance-dev/lazaretto-mcp

The metered tools need a key, which the extension does not send. For those, add the server directly instead:

sh
gemini mcp add -s user --transport http --header "X-API-Key: YOUR_KEY" lazaretto "https://lazaretto.dev/mcp?ref=npm"

Use the key itself, not $LAZARETTO_API_KEY: Gemini CLI redacts environment variables whose names contain KEY or TOKEN.

Google moved individual accounts from Gemini CLI to Antigravity CLI on June 18, 2026. Gemini CLI still serves paid API keys and Code Assist Standard or Enterprise. We have not tested Antigravity CLI. lazaretto.dev/add has its steps.

Cline

Open the MCP Servers panel, then Configure MCP Servers, which opens cline_mcp_settings.json. Add the block below, keeping "type": "streamableHttp": without it Cline falls back to the legacy SSE transport, which this server does not offer.

json
{  "mcpServers": {    "lazaretto": {      "type": "streamableHttp",      "url": "https://lazaretto.dev/mcp?ref=npm",      "headers": { "X-API-Key": "YOUR_KEY" },      "disabled": false,      "autoApprove": ["check_lockfile", "known_bad_lookup", "find_attestation", "verify_attestation"]    }  }}

autoApprove lists only free tools on purpose, so nothing that spends credits runs without you seeing it. The hosted server has two more free tools, find_mcp_servers and get_free_key. They are left out so that a search or a new key is something you see happen. Drop the headers block if you only want the free tools. For stdio, swap url and headers for command, args and env exactly as in the Cursor example above.

Any other MCP client

Remote (Streamable HTTP):

json
{  "mcpServers": {    "lazaretto": {      "url": "https://lazaretto.dev/mcp?ref=npm",      "headers": { "X-API-Key": "YOUR_KEY" }    }  }}

stdio:

json
{  "mcpServers": {    "lazaretto": {      "command": "npx",      "args": ["-y", "lazaretto-mcp"],      "env": { "LAZARETTO_API_KEY": "YOUR_KEY" }    }  }}

Both key fields are optional. Without one, the free tools work (four on the stdio package, six on the hosted server, which adds get_free_key and find_mcp_servers) and the four metered ones return a message telling you how to get credits.

The first call to try

From a project that has a lockfile, ask your agent:

Use the lazaretto check_lockfile tool to check this project's dependencies.

On the stdio server, call it with no arguments: it finds package-lock.json, npm-shrinkwrap.json, yarn.lock or pnpm-lock.yaml in the working directory by itself. The hosted server cannot read your disk, so pass the lockfile text as lockfile. On either server, pass a list of "name@version" strings as packages to ask about specific versions, or when a whole tree would not fit in context. Give one or the other, never both.

A result with one known-malware version in the tree looks like this (the stdio server adds source, naming the file it read; the hosted one has no source because it never touched your disk):

json
{  "source": "package-lock.json",  "checked": 2,  "format": "package-lock",  "malicious": [    { "name": "debug", "version": "4.4.2", "ids": ["MAL-2025-46974"], "advisory_url": "https://osv.dev/vulnerability/MAL-2025-46974" }  ],  "unverified": [],  "truncated": false,  "skipped": { "count": 0, "reason": "..." },  "note": "1 pinned package version is listed as malware. Remove or upgrade before installing.",  "disclaimer": "..."}

An empty malicious list is a real all-clear only when unverified is also empty and truncated is false. Anything under unverified was not checked and must not be reported as clean.

truncated: true is the case with no list to read. A lockfile longer than the per-request package limit is clipped, and the packages past the limit land in neither malicious nor unverified: they were never looked at, and checked counts only the ones that were. Check it once per workspace, or pass the rest of the tree, before calling the dependencies clean.

skipped is an object, not a list: it counts entries with no published registry identity and says why they have none.

No lockfile handy? known_bad_lookup needs nothing but a hash:

known_bad_lookup with sha256 = e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855

That is the hash of the empty file, so a miss is the expected answer. It proves the connection works.

You can also check the service without an MCP client at all:

bash
curl -s https://lazaretto.dev/check --data-binary @package-lock.json

We keep no copy of your lockfile.

Free and metered

Free, no key, no account:

  • check_lockfile
  • known_bad_lookup
  • find_attestation
  • verify_attestation

Free, hosted server only:

  • find_mcp_servers, which finds remote servers in the official MCP registry for a job ("postgres", "send slack messages"), each with its endpoint, tools, the command to add it, and our latest read (we re-read each server about every two weeks). Servers we flagged or could not reach are left out.
  • get_free_key, which mints a developer key with a small daily allowance that refills each day. No payment, no account, no card. It is shown once, so store it. Throttled to one key per source per window.

Metered, needs credits on a key:

  • scan_artifact (one credit per artifact)
  • scan_lockfile_deep (one credit per package that returns a verdict)
  • scan_mcp_server (one credit)
  • check_mcp_tools (one credit)

One credit is consumed per verdict and nothing on an error. Three ways to get credits:

  1. Free developer key: call get_free_key on the hosted server, or curl -sX POST https://lazaretto.dev/v1/trial for the stdio package.
  2. Buy a pack at https://lazaretto.dev/buy.
  3. An agent holding a wallet can buy credits itself over x402 at POST https://lazaretto.dev/v1/credits/topup.

Without credits a metered tool changes nothing and spends nothing. It returns a message saying how to get a key.

How payment works, exactly

The stdio package pays one way only: prepaid credits on LAZARETTO_API_KEY. It has no x402 client inside it. A paywalled result from this package therefore carries no x402 payment challenge for your agent to answer, and there is no way to make it pay per call. If you want per-call x402 payment, your own HTTP client has to make it against https://lazaretto.dev/v1/scan directly, not through this package.

The hosted endpoint is the same: the X-API-Key header spends prepaid credits.

Tools

check_lockfile (free)

Checks every exactly pinned dependency in your lockfile against published malicious-package advisories. One call covers the whole tree. Only exact versions can be answered: a range like ^5.0.0 has no definitive answer, because a compromised release usually sits between clean ones. Entries with no published registry identity (file:, link:, workspace:, git) are counted under skipped rather than dropped.

Give packages, a list of name@version strings, to ask about specific versions instead. A result with anything under malicious comes back marked as an error, so an agent acts on it rather than summarising it.

An empty malicious list is an all-clear only when unverified is also empty and truncated is false. A truncated result dropped everything past the per-request package limit into neither list, so those packages are unchecked rather than clean: split the tree and check the rest.

known_bad_lookup (free)

Is a sha256 content hash a known-bad artifact? Exact-hash match against an indicator store refreshed daily.

find_attestation (free)

Has anyone already attested this artifact? Give a package identity like [email protected], an MCP server URL, or a sha256 content hash, and get the signed verdict if one exists, with its age, whether it was made under an older rules version, and contradicted if the subject is now known-bad. A miss means no attestation is on record for this subject. It is not a verdict either way.

When nobody has attested an npm package identity, the answer falls back to a free identity check against published advisories: answer: "identity_check" with an identity_check object, and found still false, because an identity check is unsigned, looks at the identity rather than the code, and absence from the corpus is not a verdict. Both transports mark identity_check.listed_as_malware: true as an error result, so a known-malware version cannot be summarised as "nothing found".

verify_attestation (free)

A scan verdict ships with a signed attestation (compact JWS). Hand this tool one that another agent, a README, or a lockfile gave you: it confirms the signature is Lazaretto's, returns the attested claims, and flags contradicted if a once-clear subject is now known-bad, so a verdict can be used without re-scanning or paying again. Still confirm the artifact you will run matches claims.sub.

get_free_key (free, hosted server only)

Mints a developer key for the metered tools without leaving the session. No payment, no account, no card. The key holds a small daily allowance that refills every day. Present it as the X-API-Key header on the connection, or hand it to whoever configures the client. It is shown once and cannot be recovered, so store it before doing anything else. Calling again shortly after is refused rather than minting a second key. The stdio package has no such tool: use curl -sX POST https://lazaretto.dev/v1/trial instead.

scan_artifact (metered)

Fetches a target (npm or PyPI package, GitHub repo, ClawHub skill, raw URL, or inline text) without running it and returns a deterministic verdict (malicious, flagged, clear, error) with the file, line and evidence behind each finding.

scan_lockfile_deep (metered)

The behavioral counterpart to check_lockfile: reads the code of every exactly pinned dependency, up to 25 per call, instead of matching names and versions only. Trust complete_coverage. false means something was capped, errored or was only partly read, so the run is not a clean bill of health for the tree.

Calling again with the same lockfile rescans, and bills again, the same first packages. The result lists what it left in not_scanned.packages, as name@version strings. To continue a run, pass those as packages instead of the lockfile:

  • Hosted server: pass the whole not_scanned.packages list back as packages. It scans the first 25 and lists the rest in not_scanned.packages again.
  • stdio package: packages takes up to 25 per call, so work through not_scanned.packages 25 at a time. The tool adds next_call to the result, and next_call.packages holds the first 25 of that list.

check_mcp_tools (metered)

For a server that runs over stdio, which is most of them, nothing can connect to it from outside, so there is no endpoint to check. Your client already read its tool list at startup though: paste that JSON and we analyze the same text with the same rules, contacting no server at all.

scan_mcp_server (metered)

Point it at an MCP endpoint before you connect to it. It asks the server to introduce itself and list its tools, then analyzes the text that server hands an agent: tool names, descriptions, parameter schemas, and its instructions. That text is documentation a model obeys, so it is an instruction channel the server controls. Catches tool poisoning (hidden directives to read ~/.ssh/id_rsa or an agent config file), parameters whose purpose is to carry secrets or your conversation out, and standing orders about another server's tools. Evidence names the exact tool. It calls only initialize and tools/list, never the server's own tools.

Reading a result

Reports are signals with evidence, not a warranty. clear means no known-bad match and no rule fired. It is not a statement about risk.

Environment variables (stdio only)

VariableRequiredWhat it does
LAZARETTO_API_KEYnoA key holding prepaid credits, sent as X-API-Key. Only the metered tools use it.
LAZARETTO_BASE_URLnoOverrides the API host. Default https://lazaretto.dev.

When it does not work

  • The client shows no tools. For stdio, run npx -y lazaretto-mcp in a terminal. It should print a short note saying it is an MCP server, then wait. If npx cannot find it, check node --version is 20 or newer.
  • Every metered tool says it needs credits. The key is missing or was not accepted. Check the env var name is exactly LAZARETTO_API_KEY, or the header is exactly X-API-Key.
  • check_lockfile says it could not read a lockfile. It only reads package-lock.json, npm-shrinkwrap.json, yarn.lock and pnpm-lock.yaml, relative to the working directory. Pass path explicitly for a monorepo, for example apps/web/pnpm-lock.yaml.
  • A rate-limit message. The free check allows a small number per minute per IP. Wait and call it again. Do not read the failure as an all-clear.

Run it from a clone (optional)

bash
git clone https://github.com/jamesdfinance-dev/lazaretto-mcpcd lazaretto-mcp && npm ciread -rs LAZARETTO_API_KEY && export LAZARETTO_API_KEYnode index.mjs

License

MIT. The Lazaretto service and its detection engine are separate and proprietary.

Source: README.md at commit fe23677

Tools

10

known_bad_lookup

Known-bad hash lookup (free)

Check a SHA-256 against Lazaretto's known-bad indicator set (refreshed daily from abuse.ch). Free and anonymous. A miss only means this exact hash is not in the indicator set; it is not a clean verdict on the artifact.

Parameterssha256required

check_lockfile

Lockfile malware check (free, whole tree)

Check EXACTLY-PINNED npm dependencies against published malicious-package advisories (OSV/OpenSSF). Free, anonymous, one call for the whole set. Give EITHER `lockfile`, the full text of a package-lock.json, yarn.lock or pnpm-lock.yaml, OR `packages`, a list of "name@version" strings, which is the one to reach for when you only care about a few dependencies or when an 800-package tree would not fit in your context. Give one or the other, never both. Only exact versions can be answered: a range like ^5.0.0 has no definitive answer because a compromised release usually sits between clean ones. Fail-closed: anything that could not be checked is returned in `unverified`, so an empty `malicious` list is an all-clear only when `unverified` is empty too AND `truncated` is false. `truncated: true` means the lockfile ran past the per-request package limit and the packages past it went into NEITHER list: they were never looked at, `checked` counts only the ones that were, and the rest are unchecked rather than clean. When that happens, send the remainder as `packages` (name@version strings) in a second call, or split the lockfile by workspace, before telling anyone the tree is clean.

Parameterslockfilepackages

scan_artifact

Full behavioral scan (metered)

Deterministically analyze a package, repo, AI model, skill, or file for malicious behavior (credential theft, data exfiltration, obfuscation, prompt injection aimed at the agent, install scripts, model files that run code on load) and return a verdict (malicious, flagged, clear, error) with the exact evidence and a hash of what was scanned. Metered: present an X-API-Key holding credits. If you hold a wallet instead of an account, pay per call over x402 at POST https://lazaretto.dev/v1/scan ($0.03 USDC on Base, no signup). A free key with a daily allowance is available at POST https://lazaretto.dev/v1/trial. For checks that are always free, use check_lockfile or known_bad_lookup.

Parametersrefnametyperequireddepthcontent

scan_lockfile_deep

Deep scan a whole lockfile (metered, one credit per package)

Behaviorally scan the exactly-pinned dependencies in a lockfile, not just their identities: reads the code of each package and screens for credential theft, exfiltration, obfuscation, prompt injection and install-time droppers. Each result carries a verdict, a risk level, the ids of the rules that fired and a risk summary. It does not carry file-and-line evidence: for that, run scan_artifact on the package you want to look at. This is the paid counterpart to check_lockfile, which only matches names and versions against advisories. Metered: one credit per package that returns a verdict, nothing for one that errors. Capped at 25 packages per call, in lockfile order, so calling it again with the same lockfile rescans the same first 25. To continue, pass the not_scanned.packages list from the result (name@version strings) as `packages` instead of `lockfile`. Use it before installing a tree you have not vetted.

Parameterslockfilepackages

scan_mcp_server

Scan an MCP server before connecting (metered)

Check an MCP server BEFORE you connect to it. Asks the server to introduce itself and list its tools, then analyzes the text it hands an agent: tool names, descriptions, parameter schemas and server instructions. Catches tool poisoning (hidden directives that point the agent at private keys or at an agent config file), parameters whose real purpose is to carry secrets or your conversation out, standing orders about ANOTHER server's tools (cross-server shadowing), and invisible-unicode payloads. Returns a verdict with the exact tool and line as evidence, plus a hash of what was advertised, so a server that changes its tools later does not inherit the old verdict. Metered like scan_artifact: an X-API-Key with credits, or pay per call over x402 at POST https://lazaretto.dev/v1/scan with target type mcp_server ($0.03 USDC on Base, no signup).

Parametersurlrequired

check_mcp_tools

Check tool definitions you already have (metered, no network)

Check tool definitions you ALREADY HOLD, with no network call to anyone. Most MCP servers run locally over stdio and have no endpoint that can be reached, so this is the only way to check them, and your client already read their tool list at startup. Paste that JSON: a whole tools/list response, a {"tools":[...]} object, or a bare array. Analyzes the same text as scan_mcp_server and applies the same rules, so a payload cannot be caught over the wire and missed here. Detects tool poisoning (hidden directive blocks, orders pointing the agent at private keys or an agent config file), parameters whose real purpose is to carry secrets or your conversation out, standing orders about ANOTHER server's tools, and invisible-unicode payloads. Metered like scan_artifact.

Parameterstools_jsonrequired

find_mcp_servers

Find an MCP server for a job (free)

Find an MCP server for a job, free and with no key: describe what you need ("postgres", "send slack messages", "browser automation") and get matching servers from the official MCP registry, each with its endpoint, the command to add it to Claude Code, its tools, and what Lazaretto's latest read found. Only servers whose tools we read with nothing matching our tool-poisoning rules, or live servers that ask you to sign in before listing tools (said plainly), are returned; servers we flagged or could not reach are left out. Remote servers only: for a local stdio server, check its tool list with check_mcp_tools. Use it whenever you need a capability you do not have yet.

Parameterslimitqueryrequired

find_attestation

Find an existing attestation (free)

Ask whether anyone has already attested an artifact, BEFORE you install it or pay to scan it. Free and anonymous. Give a package identity like "[email protected]", an MCP server endpoint URL, or a sha256 content hash. Returns the signed verdict if one exists, which you can verify offline against https://lazaretto.dev/.well-known/jwks.json, plus freshness: whether the corpus has since contradicted it and whether it was attested under an older rules version. A miss is not a verdict, it only means nobody has scanned this yet. When nobody has attested an npm package identity, the answer falls back to an identity check against published advisories: `answer: "identity_check"` with an `identity_check` object, and `found` still false, because an identity check is unsigned, looks at the identity rather than the code, and absence from the corpus is not a verdict. `identity_check.listed_as_malware: true` comes back as an error result, so a published malware version cannot be read as "nothing found"; `null` there means the corpus could not be consulted, which is unchecked and never clear.

Parameterssubjectrequired

verify_attestation

Verify a scan attestation (free)

Verify a Lazaretto scan attestation that another agent (or a README, or a lockfile) handed you, WITHOUT re-scanning or paying. Free and anonymous. Returns signature validity and the signed claims, including verdict, risk and subject. For a clear or flagged SHA-256 subject only, checks the current known-bad indicator set and includes `contradicted` when it matches. That field is otherwise omitted; its absence is not a freshness or safety verdict. Package identities are not rechecked here. A valid signature authenticates an earlier claim, not current safety. The artifact's hash or package identity must match `claims.sub` for the claim to apply.

Parametersattestationrequired

get_free_key

Get a free developer key (free)

Get a free developer key for the metered tools on this server, without leaving this session. No payment, no account, no card. The key holds a small daily allowance that refills every day, and one credit is consumed per verdict, nothing on an error. Present it as the X-API-Key header on this MCP connection, or hand it to whoever configures your client. Throttled exactly as the equivalent HTTP endpoint is: one key per source per window, so calling this again shortly after will be refused rather than minting a second key. Store the key when you get it: it is shown once and cannot be recovered.

Takes no parameters.

Version history

6
  1. v1.3.6LatestNov 4, 2026
  2. v1.3.5Nov 3, 2026
  3. v1.3.4Nov 3, 2026
  4. v1.3.1Nov 1, 2026
  5. v1.3.0Sep 22, 2026
  6. v1.2.6Sep 16, 2026

Score

100% of the applicable checks met

How complete this listing is, computed from the registry entry, the endpoint and public sources. Not a rating of the server and not a statement that it is safe or working today: reachability is a dated check, and no installs or reviews go into the score.

  • Reached in the last 30 daysRequired25 pts
  • Auth declaredRequired10 pts
  • Tools listedRequired15 pts
  • DescriptionRequired15 pts
  • Logo10 pts
  • Documentation15 pts
  • License10 pts