Endpoints: 30,862MCP servers: 18,583Payout addresses: 2,106Paid calls: 1,607Letters: 14Defects: 1,351counted 4 min ago
teppi

Server definition

Hash
sha256:5b4b70d16f42271e860a353a2852d230c1270482d92ddd1aaf64d64b76e0b9fc
What it is
What a remote MCP server returned when asked what it offers: 23 tools

The blob, as servednamed by its sha256

{ "instructions": "NPMScan tools for checking npm packages and their known vulnerabilities before recommending, installing, or upgrading a dependency. Prefer get_package/get_package_version over trusting a package's own README claims — install scripts (preinstall/postinstall) and dependency lists reflect what actually runs. When comparing or recommending among 2-5 known candidate packages for the same job (e.g. \"axios vs got vs node-fetch\"), use compare_packages instead of calling get_package N times and eyeballing the results yourself — it fans out the same enrichment in parallel and returns a structured side-by-side plus a deterministic pick with a rationale, so you don't have to build the comparison table by hand. Use search_packages first when you don't already have a shortlist of names to compare. Don't rank by name recognition alone: search_packages returns each candidate's weekly/monthly download counts, dependentsCount, and deterministic popularityTier/maintenanceTier labels, and get_package/compare_packages add GitHub stars, TypeScript support, days since last publish, and a maintenanceSummary sentence — a package that merely matches the query text can still be abandoned, squatted, or near-unused. Those tiers/summary are rule-based on the numbers, not a verdict — always check the explicit deprecated field too, and note that a long gap since the last release can mean \"stable and finished\" as easily as \"abandoned.\" Both tools also flag possibleTyposquatOf when a low-popularity result's name is one typo away from a top-5,000 package (e.g. \"raect\" vs \"react\") — call this out explicitly to the user rather than silently dropping the result, since it's a real supply-chain risk pattern. get_package additionally returns topPackagesRank and downloadTrend (growing/stable/declining vs. ~3 months ago) for deeper comparisons. If the package in question is deprecated, vulnerable, stale, or suspicious and the user needs an actionable replacement shortlist rather than raw search results, use suggest_alternative: it combines maintainer-provided deprecation hints with deterministic category matching, filters out typosquats/weak contenders, and returns plain-language whySuggested notes for each replacement. For a dependency audit (checking many packages at once), batch_query_vulnerabilities already returns severity/summary/fixed-version per finding — don't call query_vulnerabilities again per package unless the batch result's enrichmentNote says it was truncated. For a \"is this safe to use\" question about one package or one exact version, don't just list raw advisory IDs and make the user judge severity themselves: query_vulnerabilities, get_package_version, and get_package (scoped to the latest version) all return isVulnerable/isLatestVersionVulnerable and highestSeverity as a direct verdict, plus each finding's severity, a plain-language summary, and the fixedVersion to name in your recommendation. For a dependency audit that needs to catch vulnerabilities hiding in *transitive* dependencies (not just the direct ones you were given), use analyze_transitive_dependencies instead of batch_query_vulnerabilities — it walks each dependency's own dependency tree to a configurable depth and reports vulnerablePaths naming which direct dependency actually pulled in each vulnerable transitive package; batch_query_vulnerabilities alone only checks the exact packages you list. If the user gives you a GitHub repository URL instead of pasted package.json/lockfile content, don't ask them to paste it — call audit_github_repository directly: it fetches the manifest/lockfile from the repo's default branch itself and runs the vulnerability, license-compliance, and install-script checks in one call. If the user already has \"npm audit --json\" output in hand (npm 7+'s {vulnerabilities: {...}} format or legacy npm 6's {advisories: {...}}), don't ask them to paste package.json/lockfile content or manually rebuild a findings list for prioritize_remediation — call enrich_npm_audit directly with that JSON: it parses the report itself, resolves each GHSA advisory to a CVE alias via OSV first (npm audit JSON almost never includes a CVE id on its own, which would otherwise silently degrade most findings to severity-only ranking), and returns the same remove-now/patch-now/patch-soon/scheduled/monitor ranking prioritize_remediation exposes for hand-built finding lists (a MAL-* advisoryId is auto-detected as malware and forces remove-now), plus npm-specific context (isDirect, fixAvailable/fixTarget) prioritize_remediation has no field for. It does not support \"yarn audit --json\"/\"pnpm audit --json\" — fall back to batch_query_vulnerabilities with the project's manifest/lockfile for those. If check_maintainer_changes flags a newly added or fully turned-over maintainer on a package, don't stop at that one package — call check_maintainer_blast_radius with that maintainer's username to see whether the same account touched other packages around the same time; a tight cluster across several packages is the compromised-account supply-chain shape (the 2025 chalk/debug \"qix\" incident hit ~18 packages within about 2 hours), while a large-but-unclustered footprint is normal for a prolific maintainer and not itself a red flag. When you use one of these tools in a response to a user, include the npmscanUrl from the result so they can see the full analysis on npmscan.com.", "tools": [ { "description": "Statically scans a package's preinstall/install/postinstall/prepare lifecycle scripts AND the file(s) they reference — fetched directly from the published tarball, not just the command string in package.json — against npmscan's documented red-flags rubric (/docs/red-flags): child_process use, network calls, access to sensitive paths/env (.ssh, .aws, .npmrc, *TOKEN/*KEY), obfuscation, remote binaries hosted off trusted CDNs, writes to HOME, Discord/Telegram/Pastebin exfil endpoints, eval on decoded strings, chmod+exec of downloaded binaries, and CI-metadata telemetry — plus a possibleTyposquatOf name check. Returns a weighted totalScore and riskTier ('none'/'low'/'moderate'/'high'/'critical'). This is a heuristic static scan, not proof of malice or a guarantee of safety: it doesn't execute any code, can't see behavior gated on runtime conditions, and does NOT check maintainer/ownership history (a separate red-flags signal this tool doesn't cover). Use get_package/get_package_version first for the raw script listing; use this when you need to know what an install script actually does, not just that one exists.", "inputSchema": { "$schema": "http://json-schema.org/draft-07/schema#", "additionalProperties": false, "properties": { "name": { "description": "Exact npm package name, e.g. \"lodash\" or \"@scope/name\"", "maxLength": 214, "minLength": 1, "type": "string" }, "version": { "description": "Exact version to analyze; omit to use the latest published version", "maxLength": 128, "minLength": 1, "type": "string" } }, "required": [ "name" ], "type": "object" }, "name": "analyze_install_script", "outputSchema": { "$schema": "http://json-schema.org/draft-07/schema#", "additionalProperties": false, "properties": { "filesScanned": { "items": { "type": "string" }, "type": "array" }, "findings": { "items": { "additionalProperties": false, "properties": { "locations": { "items": { "additionalProperties": false, "properties": { "file": { "type": "string" }, "snippet": { "type": "string" } }, "required": [ "file", "snippet" ], "type": "object" }, "type": "array" }, "note": { "type": "string" }, "points": { "type": "number" }, "rule": { "type": "string" }, "text": { "type": "string" } }, "required": [ "rule", "text", "points", "note", "locations" ], "type": "object" }, "type": "array" }, "hasLifecycleScripts": { "type": "boolean" }, "lifecycleScripts": { "additionalProperties": { "type": "string" }, "type": "object" }, "name": { "type": "string" }, "npmscanUrl": { "type": "string" }, "possibleTyposquatOf": { "anyOf": [ { "additionalProperties": false, "properties": { "name": { "type": "string" }, "rank": { "type": "number" } }, "required": [ "name", "rank" ], "type": "object" }, { "type": "null" } ] }, "riskTier": { "enum": [ "none", "low", "moderate", "high", "critical" ], "type": "string" }, "scanNote": { "type": [ "string", "null" ] }, "totalScore": { "type": "number" }, "version": { "type": "string" } }, "required": [ "name", "version", "npmscanUrl", "hasLifecycleScripts", "lifecycleScripts", "filesScanned", "scanNote", "possibleTyposquatOf", "findings", "totalScore", "riskTier" ], "type": "object" } }, { "description": "Recursively resolves one or more direct/root packages' dependency graphs — e.g. the \"dependencies\" section of a package.json — up to maxDepth levels deep (default 2, max 3) and batch-checks every resolved package@version against OSV.dev, so vulnerabilities buried several levels down (which would never show up from checking direct dependencies alone) still surface. `summary` is a one-sentence, deterministic recap (packages scanned, unresolved count, vulnerable count and which roots pulled them in) — read it first. The `vulnerablePaths` field directly answers \"which of my dependencies pulled this in\" by naming the root package(s) responsible for each vulnerable transitive package; `nodes` has the full resolved graph (depth, parents, resolutionError) for deeper inspection. An npm alias (e.g. `\"totally-safe\": \"npm:[email protected]\"`) is followed to its real target — `actualName` names the real package that vulnerability data attaches to (`name` stays the declared/alias key) — this is NOT silently skipped, since doing so would mean a vulnerable package hides behind whatever name a project calls it. A node with `resolutionError` set (unsatisfiable range, 404, or a git/file/workspace/URL specifier — those still aren't followed, only npm: aliases are) has `isVulnerable: null`, not `false` — it was never actually scanned, so \"not vulnerable\" would be a fabricated clean bill of health; only trust `isVulnerable: true`/`false` once a real version was resolved and checked. Scope/limits worth knowing before trusting a \"clean\" result: only the \"dependencies\" field is followed (not devDependencies/peerDependencies/optionalDependencies); each range is resolved independently per branch via semver max-satisfying against published versions — this does NOT emulate npm/yarn's actual node_modules hoisting/dedup, so read results as \"which vulnerable versions are reachable in the graph,\" not the exact installed layout; and the whole traversal is capped at a total node budget — check `truncated`/`truncationNote` rather than assuming a large graph was scanned exhaustively. Prefer batch_query_vulnerabilities instead when you only need to check exact packages you already have a flat list for (faster, no graph walk).", "inputSchema": { "$schema": "http://json-schema.org/draft-07/schema#", "additionalProperties": false, "properties": { "maxDepth": { "description": "How many levels of transitive dependencies to expand beyond the given root packages (0 = only check the roots themselves). Default 2, capped at 3 to bound registry calls and stay within the request timeout.", "maximum": 3, "minimum": 0, "type": "integer" }, "packages": { "description": "1-15 direct/root packages to expand from, e.g. a package.json's \"dependencies\". version accepts an exact version or a semver range like \"^4.17.21\"; omitted = latest.", "items": { "additionalProperties": false, "properties": { "name": { "maxLength": 214, "minLength": 1, "type": "string" }, "version": { "maxLength": 128, "type": "string" } }, "required": [ "name" ], "type": "object" }, "maxItems": 15, "minItems": 1, "type": "array" } }, "required": [ "packages" ], "type": "object" }, "name": "analyze_transitive_dependencies", "outputSchema": { "$schema": "http://json-schema.org/draft-07/schema#", "additionalProperties": false, "properties": { "enrichmentNote": { "type": [ "string", "null" ] }, "maxDepth": { "type": "number" }, "nodes": { "items": { "additionalProperties": false, "properties": { "actualName": { "type": [ "string", "null" ] }, "depth": { "type": "number" }, "highestSeverity": { "type": [ "string", "null" ] }, "isRoot": { "type": "boolean" }, "isVulnerable": { "type": [ "boolean", "null" ] }, "name": { "type": "string" }, "npmscanUrl": { "type": "string" }, "parents": { "items": { "type": "string" }, "type": "array" }, "resolutionError": { "type": [ "string", "null" ] }, "rootPackages": { "items": { "type": "string" }, "type": "array" }, "version": { "type": [ "string", "null" ] }, "vulnerabilities": { "items": { "additionalProperties": false, "properties": { "aliases": { "items": { "type": "string" }, "type": "array" }, "fixedVersion": { "type": [ "string", "null" ] }, "id": { "type": "string" }, "npmscanUrl": { "type": "string" }, "publishedAt": { "type": [ "string", "null" ] }, "severity": { "type": [ "string", "null" ] }, "summary": { "type": [ "string", "null" ] } }, "required": [ "id", "summary", "severity", "aliases", "publishedAt", "fixedVersion", "npmscanUrl" ], "type": "object" }, "type": "array" } }, "required": [ "name", "actualName", "version", "depth", "isRoot", "rootPackages", "parents", "npmscanUrl", "resolutionError", "isVulnerable", "highestSeverity", "vulnerabilities" ], "type": "object" }, "type": "array" }, "roots": { "items": { "additionalProperties": false, "properties": { "name": { "type": "string" }, "requestedVersion": { "type": [ "string", "null" ] } }, "required": [ "name", "requestedVersion" ], "type": "object" }, "type": "array" }, "summary": { "type": "string" }, "totalPackagesScanned": { "type": "number" }, "totalVulnerabilities": { "type": "number" }, "truncated": { "type": "boolean" }, "truncationNote": { "type": [ "string", "null" ] }, "unresolvedCount": { "type": "number" }, "vulnerablePackageCount": { "type": "number" }, "vulnerablePaths": { "items": { "additionalProperties": false, "properties": { "highestSeverity": { "type": [ "string", "null" ] }, "name": { "type": "string" }, "npmscanUrl": { "type": "string" }, "pulledInBy": { "items": { "type": "string" }, "type": "array" }, "version": { "type": "string" }, "vulnerabilityCount": { "type": "number" } }, "required": [ "name", "version", "highestSeverity", "vulnerabilityCount", "pulledInBy", "npmscanUrl" ], "type": "object" }, "type": "array" } }, "required": [ "summary", "roots", "maxDepth", "nodes", "vulnerablePaths", "totalPackagesScanned", "unresolvedCount", "vulnerablePackageCount", "totalVulnerabilities", "truncated", "truncationNote", "enrichmentNote" ], "type": "object" } }, { "description": "Given a GitHub repository URL, fetches its package.json (and, if present, a pnpm-lock.yaml/package-lock.json/yarn.lock — first one found wins, in that priority order) straight from the repo's default branch and runs the same vulnerability, license-compliance, install-script, and ownership-risk pipelines batch_query_vulnerabilities/check_license_compliance/analyze_install_script/check_maintainer_changes/check_package_provenance expose individually, in one call — no copy-pasting file contents required. A monorepo (package.json#workspaces, Yarn's {packages:[...]} form, or pnpm-workspace.yaml) is detected automatically: pnpm-lock.yaml and yarn.lock already record every workspace member's dependencies directly, and for package.json-only or package-lock.json repos this additionally lists the repo's file tree, resolves the declared glob patterns to member directories, and merges each member's dependencies into the audit (capped at 50 member packages) — see isMonorepo/workspacePatterns/workspacePackageCount/workspaceNote in the result. Every direct dependency (up to 100 per call, across the root and any merged workspace members) gets: an OSV.dev vulnerability check, a license-compliance verdict against the given policy (same default as check_license_compliance: only copyleft/network-copyleft/proprietary are violations unless you pass one), and a tarball-free install-script risk signal (installScriptScanScope: 'lifecycle-scripts-only'). Up to 10 of the packages that actually declare a lifecycle script — prioritized by already-vulnerable, then possible-typosquat, then whatever's left — additionally get the full tarball-fetching deep scan analyze_install_script itself runs (installScriptScanScope: 'deep-tarball-scan', with a populated installScriptFindings array); any remaining flagged packages past that cap keep the lighter signal only, noted in deepScanNote. Any package that comes back vulnerable at high/critical severity, a possible typosquat, or deprecated (ownershipRiskEligible) additionally gets check_maintainer_changes and check_package_provenance run against it — up to 5 such packages per call (ownershipRiskChecked), prioritized the same way as the deep install-script scan, populating maintainerRiskTier/maintainerFindings and provenanceRiskTier/provenanceFindings; remaining eligible packages past that cap are named in ownershipCheckNote. This is the most expensive tool in the suite (a repo lookup, a handful of file fetches, up to 100 registry doc fetches, one OSV batch call, up to 10 tarball fetches, up to 5 packages each getting a maintainer-history check plus a provenance check — the latter alone can fan out to ~8 more registry fetches on its own — and, for a monorepo needing enumeration, one file-tree listing plus up to 50 more manifest fetches) — don't call it in a loop across many repos. `peerDependencies` (root and, for a monorepo, each workspace member's own manifest) are excluded from the audit by default, same as batch_query_vulnerabilities — pass `includePeerDependencies: true` to also check them; see `warnings` for which peers were excluded.", "inputSchema": { "$schema": "http://json-schema.org/draft-07/schema#", "additionalProperties": false, "properties": { "includeDevDependencies": { "description": "Include package.json devDependencies in the audit. Default false. Ignored when a lockfile is used instead (its own format decides direct-dependency scope), and yarn.lock can never distinguish dev from production dependencies regardless of this flag.", "type": "boolean" }, "includePeerDependencies": { "description": "Include package.json peerDependencies (root and, for a monorepo, each workspace member) in the audit. Default false — a peer is often intentionally left unresolved by the consumer. See warnings for which peers were excluded.", "type": "boolean" }, "policy": { "additionalProperties": false, "description": "License allow/deny policy, same shape as check_license_compliance. Omit for the default policy (only copyleft/network-copyleft/proprietary are violations).", "properties": { "allow": { "description": "SPDX ids, family prefixes (e.g. \"GPL\"), or category names. Anything not matching is a violation.", "items": { "maxLength": 100, "minLength": 1, "type": "string" }, "maxItems": 50, "type": "array" }, "deny": { "description": "SPDX ids, family prefixes, or category names. Always takes precedence over allow.", "items": { "maxLength": 100, "minLength": 1, "type": "string" }, "maxItems": 50, "type": "array" } }, "type": "object" }, "ref": { "description": "Branch, tag, or commit SHA to audit. Omit to use the repository's default branch.", "maxLength": 250, "minLength": 1, "type": "string" }, "url": { "description": "GitHub repository URL, e.g. \"https://github.com/owner/repo\".", "maxLength": 500, "minLength": 1, "type": "string" } }, "required": [ "url" ], "type": "object" }, "name": "audit_github_repository", "outputSchema": { "$schema": "http://json-schema.org/draft-07/schema#", "additionalProperties": false, "properties": { "deepScanNote": { "type": [ "string", "null" ] }, "deepScannedCount": { "type": "number" }, "defaultBranchUsed": { "type": "boolean" }, "findings": { "items": { "additionalProperties": false, "properties": { "deprecated": { "type": [ "string", "null" ] }, "hasLifecycleScripts": { "type": "boolean" }, "highestSeverity": { "type": [ "string", "null" ] }, "installScriptFindings": { "anyOf": [ { "items": { "additionalProperties": false, "properties": { "locations": { "items": { "additionalProperties": false, "properties": { "file": { "type": "string" }, "snippet": { "type": "string" } }, "required": [ "file", "snippet" ], "type": "object" }, "type": "array" }, "note": { "type": "string" }, "points": { "type": "number" }, "rule": { "type": "string" }, "text": { "type": "string" } }, "required": [ "rule", "text", "points", "note", "locations" ], "type": "object" }, "type": "array" }, { "type": "null" } ] }, "installScriptRiskTier": { "anyOf": [ { "enum": [ "none", "low", "moderate", "high", "critical" ], "type": "string" }, { "type": "null" } ] }, "installScriptScanScope": { "anyOf": [ { "enum": [ "lifecycle-scripts-only", "deep-tarball-scan" ], "type": "string" }, { "type": "null" } ] }, "installScriptScore": { "type": [ "number", "null" ] }, "isLicenseCompliant": { "type": [ "boolean", "null" ] }, "isVulnerable": { "type": [ "boolean", "null" ] }, "licenseCategory": { "enum": [ "permissive", "weak-copyleft", "copyleft", "network-copyleft", "proprietary", "public-domain", "unknown", "mixed" ], "type": "string" }, "licenseNeedsReview": { "type": "boolean" }, "licenseViolation": { "anyOf": [ { "additionalProperties": false, "properties": { "note": { "type": "string" }, "rule": { "type": "string" }, "text": { "type": "string" } }, "required": [ "rule", "text", "note" ], "type": "object" }, { "type": "null" } ] }, "maintainerFindings": { "anyOf": [ { "items": { "$ref": "#/properties/findings/items/properties/installScriptFindings/anyOf/0/items" }, "type": "array" }, { "type": "null" } ] }, "maintainerRiskTier": { "anyOf": [ { "$ref": "#/properties/findings/items/properties/installScriptRiskTier/anyOf/0" }, { "type": "null" } ] }, "name": { "type": "string" }, "npmscanUrl": { "type": "string" }, "ownershipRiskChecked": { "type": "boolean" }, "ownershipRiskEligible": { "type": "boolean" }, "ownershipRiskReason": { "anyOf": [ { "enum": [ "critical-or-high-severity-vulnerability", "possible-typosquat", "deprecated" ], "type": "string" }, { "type": "null" } ] }, "possibleTyposquatOf": { "anyOf": [ { "additionalProperties": false, "properties": { "name": { "type": "string" }, "rank": { "type": "number" } }, "required": [ "name", "rank" ], "type": "object" }, { "type": "null" } ] }, "provenanceFindings": { "anyOf": [ { "items": { "$ref": "#/properties/findings/items/properties/installScriptFindings/anyOf/0/items" }, "type": "array" }, { "type": "null" } ] }, "provenanceRiskTier": { "anyOf": [ { "$ref": "#/properties/findings/items/properties/installScriptRiskTier/anyOf/0" }, { "type": "null" } ] }, "rawLicense": { "type": [ "string", "null" ] }, "requestedVersion": { "type": [ "string", "null" ] }, "resolutionError": { "type": [ "string", "null" ] }, "resolvedVersion": { "type": [ "string", "null" ] }, "vulnerabilities": { "items": { "additionalProperties": false, "properties": { "aliases": { "items": { "type": "string" }, "type": "array" }, "fixedVersion": { "type": [ "string", "null" ] }, "id": { "type": "string" }, "npmscanUrl": { "type": "string" }, "publishedAt": { "type": [ "string", "null" ] }, "severity": { "type": [ "string", "null" ] }, "summary": { "type": [ "string", "null" ] } }, "required": [ "id", "summary", "severity", "aliases", "publishedAt", "fixedVersion", "npmscanUrl" ], "type": "object" }, "type": "array" } }, "required": [ "name", "requestedVersion", "resolvedVersion", "npmscanUrl", "deprecated", "possibleTyposquatOf", "isVulnerable", "highestSeverity", "vulnerabilities", "rawLicense", "licenseCategory", "isLicenseCompliant", "licenseNeedsReview", "licenseViolation", "hasLifecycleScripts", "installScriptRiskTier", "installScriptScore", "installScriptScanScope", "installScriptFindings", "resolutionError", "ownershipRiskEligible", "ownershipRiskReason", "ownershipRiskChecked", "maintainerRiskTier", "maintainerFindings", "provenanceRiskTier", "provenanceFindings" ], "type": "object" }, "type": "array" }, "inputFormat": { "enum": [ "package.json", "npm-lock", "yarn-lock", "pnpm-lock" ], "type": "string" }, "installScriptFlaggedCount": { "type": "number" }, "isMonorepo": { "type": "boolean" }, "licenseViolationCount": { "type": "number" }, "lockfilePath": { "type": [ "string", "null" ] }, "manifestPath": { "type": "string" }, "overflowPackages": { "items": { "additionalProperties": false, "properties": { "name": { "type": "string" }, "requestedVersion": { "type": [ "string", "null" ] } }, "required": [ "name", "requestedVersion" ], "type": "object" }, "type": "array" }, "owner": { "type": "string" }, "ownershipCheckNote": { "type": [ "string", "null" ] }, "ownershipCheckedCount": { "type": "number" }, "ownershipRiskFlaggedCount": { "type": "number" }, "policy": { "additionalProperties": false, "properties": { "allow": { "items": { "type": "string" }, "type": "array" }, "deny": { "items": { "type": "string" }, "type": "array" }, "mode": { "enum": [ "default", "allow", "deny", "allow+deny" ], "type": "string" } }, "required": [ "mode", "allow", "deny" ], "type": "object" }, "ref": { "type": "string" }, "repoName": { "type": "string" }, "summary": { "type": "string" }, "totalPackages": { "type": "number" }, "truncationNote": { "type": [ "string", "null" ] }, "vulnerablePackageCount": { "type": "number" }, "warnings": { "items": { "type": "string" }, "type": "array" }, "workspaceNote": { "type": [ "string", "null" ] }, "workspacePackageCount": { "type": "number" }, "workspacePatterns": { "items": { "type": "string" }, "type": "array" } }, "required": [ "summary", "owner", "repoName", "ref", "defaultBranchUsed", "manifestPath", "lockfilePath", "inputFormat", "isMonorepo", "workspacePatterns", "workspacePackageCount", "workspaceNote", "policy", "findings", "overflowPackages", "totalPackages", "vulnerablePackageCount", "licenseViolationCount", "installScriptFlaggedCount", "deepScannedCount", "ownershipCheckedCount", "ownershipRiskFlaggedCount", "warnings", "truncationNote", "deepScanNote", "ownershipCheckNote" ], "type": "object" } }, { "description": "Query OSV.dev for known vulnerabilities across a whole npm dependency inventory at once: either pass a flat {packages:[...]} list, or paste raw package.json / lockfile / CycloneDX JSON / SPDX JSON content via `content`. The tool normalizes npm dependencies first, then chunk-queries OSV behind the scenes so large SBOMs don't stop at the upstream 100-package batch limit. Each finding includes severity, a summary, CVE aliases, and the fixed version — not just a bare advisory ID — so a dependency audit answer doesn't need a follow-up call per flagged package. For an explicit `packages` list or raw `package.json` content — names that were never actually resolved against a registry, unlike a real lockfile/SBOM — package names are also cross-checked against the npm registry (capped at 200 unique names): a name that doesn't exist there would otherwise show a silent, indistinguishable `vulnerabilityCount: 0` — see `unresolvedPackages`/`existenceCheckNote` and do not read those entries as a clean bill of health. The same facts are attached to each result as `registryStatus` (\"found\" | \"package-not-found\" | \"version-not-found\" | \"unchecked\") — independent of `scanStatus`, which stays \"scanned\" for these because OSV IS still queried (a package unpublished for malware keeps its OSV/MAL- record, so treating registry absence as \"not scanned\" would hide exactly that case). A `packages[].version` that doesn't currently appear on the registry (a typo'd/fabricated version, OR a real version that was published and later removed, e.g. unpublished for containing malware) is cross-checked the same way — see `nonexistentVersions`; don't assume it never existed, and don't assume `vulnerabilityCount:0` for it means clean, since OSV can still carry findings for a version the registry no longer lists. A `packages[]` entry given with NO version at all (e.g. `{name:\"react\"}`) is intentionally queried unversioned against OSV — this returns advisories affecting ANY historical published version of that package, not just the latest or whatever a project actually has installed; see the corresponding `warnings` entry naming which packages this applied to, and don't report \"package X is vulnerable\" from an unversioned result without separately confirming against the specific version in use (get_package/get_package_version). Each result also carries `signals` (deprecated, hasInstallScripts for the specific requested/resolved version, popularityTier/maintenanceTier, and possibleTyposquatOf — same deterministic rule-based labels as get_package/search_packages, capped at the same 200 unique names): a clean `vulnerabilityCount:0` does NOT mean safe to use if `signals` flags a likely typosquat, an abandoned/stale package, or a deprecation notice — surface those explicitly rather than reporting only the vulnerability count. `signals` is `null` for a `scanStatus: \"not-scanned\"` entry, deliberately — a git/file/workspace/URL dependency can be declared under a name that collides with a real npm package (e.g. a git dependency literally named \"lodash\"), and that unrelated public package's popularity/maintenance signals must not be attached to it just because the name happens to resolve on the registry. A lockfile-resolved result also carries `source` (resolvedUrl/integrity straight from that lockfile entry, plus `nonRegistryHost`): `nonRegistryHost: true` means the tarball URL points somewhere other than the expected npm/yarn registry host — e.g. a compromised mirror or a hand-edited lockfile — which a name+version match against OSV cannot detect on its own, since a malicious tarball can share the same name/version as the real package and carry zero OSV findings. `source` is `null` when the input format doesn't record this (package.json content, an explicit `packages` entry, or pnpm-lock, which never records a resolvedUrl). `nonRegistryHost: false` alone is NOT proof the tarball is correct — `source.identityMismatch: true` catches a SAME-HOST swap that host-checking cannot: a lockfile entry can declare e.g. \"[email protected]\" while resolvedUrl actually points at the real registry.npmjs.org's own tarball for a completely different package/version, and `vulnerabilityCount` above was still computed for the DECLARED name/version, not whatever that resolved tarball actually is — treat `identityMismatch: true` as a lockfile-tamper finding, not a cosmetic mismatch, and see `source.resolvedName`/`resolvedVersion` for what the tarball actually names. `vulnerabilityCount`/`advisoryCount` are raw OSV/GHSA advisory counts and can over-count: OSV sometimes publishes more than one advisory record for the same underlying CVE — use `uniqueVulnerabilityCount` (deduped by shared CVE alias) when reporting 'how many distinct issues' rather than a raw advisory tally. When `content` is itself a package.json (not a lockfile/SBOM), `projectLifecycleScripts` surfaces that SCANNED PROJECT's own preinstall/install/postinstall/prepare scripts, if any — these run arbitrary code the moment someone runs `npm install` on the project itself, separate from anything a dependency does, and 'scan my package.json' should not silently skip the one script that actually executes for the project being scanned. An npm alias (e.g. `\"totally-safe\": \"npm:[email protected]\"`) is followed to its real target in every input format — `results[i].package.actualName` names the real package that vulnerability/signal data attaches to (`.name` stays the declared/alias key); this is NOT silently skipped, since doing so would let a vulnerable package hide behind whatever name a project calls it. A dependency whose spec points somewhere other than the registry (git/file/workspace/URL) or that never resolved to a version is excluded from vulnerability querying entirely rather than queried by name alone — `vulnerabilityCount: 0` for one of these would otherwise misleadingly attach an unrelated public npm package's entire vulnerability history to it. When `content` is a package.json, `peerDependencies` are excluded from scanning by default (a peer is often intentionally left unresolved by the consumer) — see `ignoredPeerDependencyNames`, and pass `includePeerDependencies: true` to also check them, since a vulnerable/malicious peerDependency is otherwise invisible to this scan. `results[i].package.declaredSpec` is set whenever `.version` was RESOLVED from a package.json semver range/tag (e.g. `\"^18.2.0\"` -> `\"18.2.0\"`) rather than being an already-exact pin or a lockfile-derived version — a range can silently pick up a new, possibly-compromised release the next time this project is installed, while an exact pin can't, so don't treat a range-resolved `isVulnerable:false` as equally durable to a pinned one just because they look identical today.", "inputSchema": { "$schema": "http://json-schema.org/draft-07/schema#", "additionalProperties": false, "properties": { "content": { "description": "Raw dependency inventory content: package.json, package-lock.json, yarn.lock, pnpm-lock.yaml, CycloneDX JSON, or SPDX JSON. Use this OR `packages`, not both.", "minLength": 1, "type": "string" }, "includeDevDependencies": { "description": "Ignored when using `packages`; only applies when `content` is a manifest/lockfile format that distinguishes dev dependencies.", "type": "boolean" }, "includePeerDependencies": { "description": "Ignored when using `packages`; only applies when `content` is a package.json. peerDependencies are excluded from scanning by default (see ignoredPeerDependencyNames) since a peer is often intentionally left unresolved by the consumer — set this to also check them.", "type": "boolean" }, "packages": { "description": "Explicit package list (1-1000 items). Use this OR `content`, not both.", "items": { "additionalProperties": false, "properties": { "name": { "maxLength": 214, "minLength": 1, "type": "string" }, "version": { "description": "One exact published version, e.g. \"18.2.0\" (not a range/tag like \"^18.2.0\" or \"latest\" — those are resolved against the registry first, at the cost of an extra lookup, rather than rejected)", "maxLength": 128, "type": "string" } }, "required": [ "name" ], "type": "object" }, "maxItems": 1000, "minItems": 1, "type": "array" } }, "type": "object" }, "name": "batch_query_vulnerabilities", "outputSchema": { "$schema": "http://json-schema.org/draft-07/schema#", "additionalProperties": false, "properties": { "enrichmentNote": { "type": "string" }, "existenceCheckNote": { "type": "string" }, "ignoredCount": { "type": "number" }, "ignoredPeerDependencyNames": { "items": { "type": "string" }, "type": "array" }, "inputFormat": { "type": "string" }, "nonexistentVersions": { "items": { "type": "string" }, "type": "array" }, "packagesWithVulnerabilities": { "type": "number" }, "parsedPackageCount": { "type": "number" }, "projectLifecycleScriptRisk": { "additionalProperties": false, "properties": { "hasLifecycleScripts": { "type": "boolean" }, "riskTier": { "enum": [ "none", "low", "moderate", "high", "critical" ], "type": "string" }, "totalScore": { "type": "number" } }, "required": [ "hasLifecycleScripts", "riskTier", "totalScore" ], "type": "object" }, "projectLifecycleScripts": { "anyOf": [ { "additionalProperties": { "type": "string" }, "type": "object" }, { "type": "null" } ] }, "queryFailureCount": { "type": "number" }, "results": { "items": { "additionalProperties": false, "properties": { "advisoryCount": { "type": "number" }, "npmscanUrl": { "type": "string" }, "package": { "additionalProperties": false, "properties": { "actualName": { "type": "string" }, "declaredSpec": { "type": "string" }, "name": { "type": "string" }, "version": { "type": "string" } }, "required": [ "name" ], "type": "object" }, "registryStatus": { "enum": [ "found", "package-not-found", "version-not-found", "unchecked" ], "type": "string" }, "scanStatus": { "enum": [ "scanned", "not-scanned" ], "type": "string" }, "signals": { "anyOf": [ { "additionalProperties": false, "properties": { "deprecated": { "type": [ "string", "null" ] }, "hasInstallScripts": { "type": [ "boolean", "null" ] }, "maintenanceTier": { "enum": [ "active", "aging", "stale", "unknown" ], "type": "string" }, "popularityTier": { "enum": [ "very-high", "high", "moderate", "low", "very-low", "unknown" ], "type": "string" }, "possibleTyposquatOf": { "anyOf": [ { "additionalProperties": false, "properties": { "name": { "type": "string" }, "rank": { "type": "number" } }, "required": [ "name", "rank" ], "type": "object" }, { "type": "null" } ] } }, "required": [ "deprecated", "hasInstallScripts", "popularityTier", "maintenanceTier", "possibleTyposquatOf" ], "type": "object" }, { "type": "null" } ] }, "source": { "anyOf": [ { "additionalProperties": false, "properties": { "identityMismatch": { "type": [ "boolean", "null" ] }, "integrity": { "type": [ "string", "null" ] }, "nonRegistryHost": { "type": [ "boolean", "null" ] }, "resolvedName": { "type": [ "string", "null" ] }, "resolvedUrl": { "type": [ "string", "null" ] }, "resolvedVersion": { "type": [ "string", "null" ] } }, "required": [ "resolvedUrl", "integrity", "nonRegistryHost", "identityMismatch", "resolvedName", "resolvedVersion" ], "type": "object" }, { "type": "null" } ] }, "uniqueVulnerabilityCount": { "type": "number" }, "vulnerabilities": { "items": { "additionalProperties": false, "properties": { "aliases": { "items": { "type": "string" }, "type": "array" }, "fixedVersion": { "type": [ "string", "null" ] }, "id": { "type": "string" }, "npmscanUrl": { "type": "string" }, "publishedAt": { "type": [ "string", "null" ] }, "severity": { "type": [ "string", "null" ] }, "summary": { "type": [ "string", "null" ] } }, "required": [ "id", "summary", "severity", "aliases", "publishedAt", "fixedVersion", "npmscanUrl" ], "type": "object" }, "type": "array" }, "vulnerabilityCount": { "type": "number" } }, "required": [ "package", "npmscanUrl", "scanStatus", "registryStatus", "vulnerabilityCount", "advisoryCount", "uniqueVulnerabilityCount", "vulnerabilities", "signals", "source" ], "type": "object" }, "type": "array" }, "totalUniqueVulnerabilities": { "type": "number" }, "totalVulnerabilities": { "type": "number" }, "unresolvedPackages": { "items": { "type": "string" }, "type": "array" }, "warnings": { "items": { "type": "string" }, "type": "array" } }, "required": [ "results", "totalVulnerabilities", "totalUniqueVulnerabilities", "packagesWithVulnerabilities" ], "type": "object" } }, { "description": "Given a list of packages (name + optional exact version or semver range — e.g. straight from a package.json \"dependencies\" object) and an optional allow/deny license policy, resolves each package's declared SPDX license and reports a compliance verdict per package. Classifies every license into one of permissive/weak-copyleft/copyleft/network-copyleft/proprietary/public-domain/unknown, and understands simple SPDX expressions: \"(MIT OR GPL-3.0)\" is compliant if EITHER side is permitted (a consumer may legally pick the clean alternative), \"MIT AND Apache-2.0\" requires both sides to pass, and \"X WITH exception\" is judged on X. A mixed/nested expression like \"(MIT OR ISC) AND Apache-2.0\" is reported as needsReview rather than guessed at. `policy.deny` entries always win over `policy.allow` (so a name can appear in both without a silent contradiction); with `policy.allow` set, anything not matching it is a violation (unproven is treated as non-compliant); with neither given, the default policy flags only copyleft/network-copyleft/proprietary (e.g. GPL/AGPL/UNLICENSED) — weak-copyleft (LGPL/MPL/EPL) and unrecognized license strings are surfaced but not auto-flagged. Policy entries accept an exact SPDX id, a family prefix (\"GPL\" catches GPL-2.0/GPL-3.0-only/etc.), or a category name. This reads only the registry-declared `license` field — it does not fetch or parse LICENSE file contents from the source repository.", "inputSchema": { "$schema": "http://json-schema.org/draft-07/schema#", "additionalProperties": false, "properties": { "packages": { "description": "1-100 packages to check. version accepts an exact version or a semver range like \"^4.17.21\"; omitted = latest.", "items": { "additionalProperties": false, "properties": { "name": { "maxLength": 214, "minLength": 1, "type": "string" }, "version": { "maxLength": 128, "type": "string" } }, "required": [ "name" ], "type": "object" }, "maxItems": 100, "minItems": 1, "type": "array" }, "policy": { "additionalProperties": false, "description": "Omit entirely to use the default policy: only copyleft/network-copyleft/proprietary are violations.", "properties": { "allow": { "description": "SPDX ids, family prefixes (e.g. \"GPL\"), or category names. Anything not matching is a violation.", "items": { "maxLength": 100, "minLength": 1, "type": "string" }, "maxItems": 50, "type": "array" }, "deny": { "description": "SPDX ids, family prefixes, or category names. Always takes precedence over allow.", "items": { "maxLength": 100, "minLength": 1, "type": "string" }, "maxItems": 50, "type": "array" } }, "type": "object" } }, "required": [ "packages" ], "type": "object" }, "name": "check_license_compliance", "outputSchema": { "$schema": "http://json-schema.org/draft-07/schema#", "additionalProperties": false, "properties": { "compliantCount": { "type": "number" }, "needsReviewCount": { "type": "number" }, "policy": { "additionalProperties": false, "properties": { "allow": { "items": { "type": "string" }, "type": "array" }, "deny": { "items": { "type": "string" }, "type": "array" }, "mode": { "enum": [ "default", "allow", "deny", "allow+deny" ], "type": "string" } }, "required": [ "mode", "allow", "deny" ], "type": "object" }, "results": { "items": { "additionalProperties": false, "properties": { "category": { "enum": [ "permissive", "weak-copyleft", "copyleft", "network-copyleft", "proprietary", "public-domain", "unknown", "mixed" ], "type": "string" }, "isCompliant": { "type": "boolean" }, "needsReview": { "type": "boolean" }, "npmscanUrl": { "type": "string" }, "package": { "additionalProperties": false, "properties": { "name": { "type": "string" }, "version": { "type": "string" } }, "required": [ "name" ], "type": "object" }, "rawLicense": { "type": [ "string", "null" ] }, "resolutionError": { "type": [ "string", "null" ] }, "resolvedVersion": { "type": [ "string", "null" ] }, "violation": { "anyOf": [ { "additionalProperties": false, "properties": { "note": { "type": "string" }, "rule": { "type": "string" }, "text": { "type": "string" } }, "required": [ "rule", "text", "note" ], "type": "object" }, { "type": "null" } ] } }, "required": [ "package", "npmscanUrl", "resolvedVersion", "rawLicense", "category", "isCompliant", "needsReview", "violation", "resolutionError" ], "type": "object" }, "type": "array" }, "summary": { "type": "string" }, "totalPackages": { "type": "number" }, "unresolvedCount": { "type": "number" }, "violationCount": { "type": "number" } }, "required": [ "policy", "summary", "results", "totalPackages", "compliantCount", "violationCount", "needsReviewCount", "unresolvedCount" ], "type": "object" } }, { "description": "Given an npm username, lists the packages npm's maintainer:<username> search index returns for that account and looks for a tight cluster of packages whose latest version was published within a short rolling window of each other — the shape of a compromised-account supply-chain attack, where a stolen credential is used on every package the account can publish to within hours (e.g. the September 2025 chalk/debug compromise, ~18 packages in ~2 hours). A large total package count is not itself a red flag; only a tight publish-time cluster is scored, weighted by its package count and combined weekly downloads/dependentsCount. Clusters mostly within one npm scope (a monorepo release) are dampened, and multiple clusters combine with diminishing returns. isCurrentMaintainer shows whether the account still maintains each package. avatarUrl is a proxied Gravatar image (null if no email is on record). Natural follow-up to check_maintainer_changes: call this with a newly added maintainer's username to see whether the same account touched other packages around the same time. Limitations: npm's search index can lag or omit packages; results are capped at 250 packages ranked by relevance, not recency (see resultsTruncated/totalPackagesFound); lastPublished reflects only each package's latest version. npmscanUrl is the account's npmscan profile; npmProfileUrl is its npmjs.com page.", "inputSchema": { "$schema": "http://json-schema.org/draft-07/schema#", "additionalProperties": false, "properties": { "maintainerUsername": { "description": "Exact npm username, e.g. \"sindresorhus\" — as shown at npmjs.com/~username. Not an email address, not a package name or scope.", "maxLength": 100, "minLength": 1, "type": "string" } }, "required": [ "maintainerUsername" ], "type": "object" }, "name": "check_maintainer_blast_radius", "outputSchema": { "$schema": "http://json-schema.org/draft-07/schema#", "additionalProperties": false, "properties": { "avatarUrl": { "type": [ "string", "null" ] }, "clusterWindowHours": { "type": "number" }, "clusters": { "items": { "additionalProperties": false, "properties": { "combinedDependentsCount": { "type": "number" }, "combinedWeeklyDownloads": { "type": "number" }, "packageCount": { "type": "number" }, "packageNames": { "items": { "type": "string" }, "type": "array" }, "stillCurrentMaintainerCount": { "type": "number" }, "windowEnd": { "type": "string" }, "windowStart": { "type": "string" } }, "required": [ "windowStart", "windowEnd", "packageNames", "packageCount", "combinedWeeklyDownloads", "combinedDependentsCount", "stillCurrentMaintainerCount" ], "type": "object" }, "type": "array" }, "findings": { "items": { "additionalProperties": false, "properties": { "locations": { "items": { "additionalProperties": false, "properties": { "file": { "type": "string" }, "snippet": { "type": "string" } }, "required": [ "file", "snippet" ], "type": "object" }, "type": "array" }, "note": { "type": "string" }, "points": { "type": "number" }, "rule": { "type": "string" }, "text": { "type": "string" } }, "required": [ "rule", "text", "points", "note", "locations" ], "type": "object" }, "type": "array" }, "maintainerUsername": { "type": "string" }, "note": { "type": [ "string", "null" ] }, "npmProfileUrl": { "type": "string" }, "npmscanUrl": { "type": "string" }, "packages": { "items": { "additionalProperties": false, "properties": { "dependentsCount": { "type": [ "number", "null" ] }, "isCurrentMaintainer": { "type": "boolean" }, "lastPublished": { "type": [ "string", "null" ] }, "name": { "type": "string" }, "npmscanUrl": { "type": "string" }, "version": { "type": "string" }, "weeklyDownloads": { "type": [ "number", "null" ] } }, "required": [ "name", "version", "lastPublished", "weeklyDownloads", "dependentsCount", "isCurrentMaintainer", "npmscanUrl" ], "type": "object" }, "type": "array" }, "packagesReturned": { "type": "number" }, "resultsTruncated": { "type": "boolean" }, "riskTier": { "enum": [ "none", "low", "moderate", "high", "critical" ], "type": "string" }, "totalPackagesFound": { "type": "number" }, "totalScore": { "type": "number" } }, "required": [ "maintainerUsername", "npmscanUrl", "npmProfileUrl", "avatarUrl", "totalPackagesFound", "packagesReturned", "resultsTruncated", "clusterWindowHours", "packages", "clusters", "findings", "totalScore", "riskTier", "note" ], "type": "object" } }, { "description": "Reconstructs a package's maintainer-change history straight from the npm packument — every published version carries the maintainers-list SNAPSHOT as it stood at that publish plus who actually ran `npm publish` (`_npmUser`), so diffing consecutive snapshots in publish-time order recovers exactly who was added or removed and when, with no extra API calls. Flags: (1) a maintainer added recently who then published a release shortly afterward on a package with real prior history — the account-takeover/hostile-handoff shape behind incidents like ua-parser-js, event-stream, and the 2025 chalk/debug ('qix') compromise; (2) a full, sudden replacement of the entire maintainer list; (3) a long-standing maintainer quietly dropped from the list; (4) a maintainer-list change that happened on npm's site AFTER the latest release — not yet tied to any published version, which is the more urgent case since it means access changed hands but nothing has shipped with it yet. Also cross-checks the declared GitHub repository: whether it still resolves to the same owner/name (a transfer/rename), whether it's reachable at all, and whether the latest npm release landed long after any real push activity there — repository.ownerLogin/ownerAvatarUrl name and show the CURRENT owning account (the new one after a transfer, not the one originally declared in package.json), with ownerAvatarUrl a proxied GitHub avatar image, both null whenever the repo check itself didn't reach GitHub. Use get_package/check_package_provenance first for the package's general health and publish-integrity signals; use this specifically for the 'who controls this package, and did that change recently' question. If this flags a newly added or fully turned-over maintainer, follow up with check_maintainer_blast_radius on that maintainer's username — it lists every other package the same account currently touches and flags a tight publish-time cluster across them, the 'did this compromise hit just one package or a dozen' question this tool can't answer on its own.", "inputSchema": { "$schema": "http://json-schema.org/draft-07/schema#", "additionalProperties": false, "properties": { "name": { "description": "Exact npm package name, e.g. \"lodash\" or \"@scope/name\"", "maxLength": 214, "minLength": 1, "type": "string" } }, "required": [ "name" ], "type": "object" }, "name": "check_maintainer_changes", "outputSchema": { "$schema": "http://json-schema.org/draft-07/schema#", "additionalProperties": false, "properties": { "currentMaintainers": { "items": { "additionalProperties": false, "properties": { "email": { "type": [ "string", "null" ] }, "name": { "type": "string" } }, "required": [ "name", "email" ], "type": "object" }, "type": "array" }, "findings": { "items": { "additionalProperties": false, "properties": { "locations": { "items": { "additionalProperties": false, "properties": { "file": { "type": "string" }, "snippet": { "type": "string" } }, "required": [ "file", "snippet" ], "type": "object" }, "type": "array" }, "note": { "type": "string" }, "points": { "type": "number" }, "rule": { "type": "string" }, "text": { "type": "string" } }, "required": [ "rule", "text", "points", "note", "locations" ], "type": "object" }, "type": "array" }, "history": { "additionalProperties": false, "properties": { "changes": { "items": { "additionalProperties": false, "properties": { "added": { "items": { "type": "string" }, "type": "array" }, "publishedAt": { "type": [ "string", "null" ] }, "removed": { "items": { "type": "string" }, "type": "array" }, "version": { "type": [ "string", "null" ] } }, "required": [ "version", "publishedAt", "added", "removed" ], "type": "object" }, "type": "array" }, "changesTruncated": { "type": "boolean" }, "firstTrackedVersion": { "anyOf": [ { "additionalProperties": false, "properties": { "publishedAt": { "type": "string" }, "version": { "type": "string" } }, "required": [ "version", "publishedAt" ], "type": "object" }, { "type": "null" } ] }, "latestTrackedVersion": { "anyOf": [ { "additionalProperties": false, "properties": { "publishedAt": { "type": "string" }, "version": { "type": "string" } }, "required": [ "version", "publishedAt" ], "type": "object" }, { "type": "null" } ] }, "latestVersionPublishedViaTrustedPublisher": { "type": "boolean" }, "note": { "type": [ "string", "null" ] }, "versionsConsidered": { "type": "number" } }, "required": [ "versionsConsidered", "firstTrackedVersion", "latestTrackedVersion", "latestVersionPublishedViaTrustedPublisher", "changes", "changesTruncated", "note" ], "type": "object" }, "lookbackDays": { "type": "number" }, "name": { "type": "string" }, "npmscanUrl": { "type": "string" }, "repository": { "additionalProperties": false, "properties": { "archived": { "type": [ "boolean", "null" ] }, "checked": { "type": "boolean" }, "currentFullName": { "type": [ "string", "null" ] }, "declaredRepository": { "type": [ "string", "null" ] }, "note": { "type": [ "string", "null" ] }, "ownerAvatarUrl": { "type": [ "string", "null" ] }, "ownerLogin": { "type": [ "string", "null" ] }, "reachable": { "type": [ "boolean", "null" ] }, "transferred": { "type": [ "boolean", "null" ] } }, "required": [ "checked", "declaredRepository", "currentFullName", "transferred", "archived", "reachable", "ownerLogin", "ownerAvatarUrl", "note" ], "type": "object" }, "riskTier": { "enum": [ "none", "low", "moderate", "high", "critical" ], "type": "string" }, "totalScore": { "type": "number" } }, "required": [ "name", "npmscanUrl", "lookbackDays", "currentMaintainers", "history", "repository", "findings", "totalScore", "riskTier" ], "type": "object" } }, { "description": "Checks whether a package version was published with npm's own Sigstore-backed publish provenance (`npm publish --provenance`), and cross-checks that provenance against reality rather than just reporting its presence. Three checks: (1) parses the SLSA build attestation (declared source repo, commit, builder identity, GitHub Actions run URL) and flags a builder that isn't GitHub-hosted, or an attested source repo that doesn't match package.json's own `repository` field; (2) when this version LACKS provenance, checks whether most peer packages (same npm scope, or same maintainer for an unscoped name) DO have it — a package that's the odd one out in an org that otherwise always publishes from CI is a real anomaly, not proof of malice; (3) fetches package.json from the source repository at the exact attested commit (or a best-effort matching git tag when no provenance/commit is available) and diffs its install-lifecycle scripts (preinstall/install/postinstall/prepare) and dependency names against what's actually in the published tarball — this is the single highest-signal check here, since a script or dependency that exists on npm but was never committed is exactly the pattern of a stolen-npm-token publish that bypasses CI (the event-stream/ua-parser-js incident shape). This is a heuristic, structural check: it does NOT cryptographically re-verify the Sigstore bundle (Fulcio cert chain, Rekor inclusion proof) — it trusts that npm's registry already refused to accept a publish that failed that verification, and checks the CONTENT of what the registry reports instead. Most packages don't use --provenance yet, so its bare absence is never scored on its own — only an org-norm anomaly or an actual source mismatch is. Use get_package/get_package_version first for basic package info; use this specifically to assess publish-integrity risk.", "inputSchema": { "$schema": "http://json-schema.org/draft-07/schema#", "additionalProperties": false, "properties": { "name": { "description": "Exact npm package name, e.g. \"lodash\" or \"@scope/name\"", "maxLength": 214, "minLength": 1, "type": "string" }, "version": { "description": "Exact version to check; omit to use the latest published version", "maxLength": 128, "minLength": 1, "type": "string" } }, "required": [ "name" ], "type": "object" }, "name": "check_package_provenance", "outputSchema": { "$schema": "http://json-schema.org/draft-07/schema#", "additionalProperties": false, "properties": { "findings": { "items": { "additionalProperties": false, "properties": { "locations": { "items": { "additionalProperties": false, "properties": { "file": { "type": "string" }, "snippet": { "type": "string" } }, "required": [ "file", "snippet" ], "type": "object" }, "type": "array" }, "note": { "type": "string" }, "points": { "type": "number" }, "rule": { "type": "string" }, "text": { "type": "string" } }, "required": [ "rule", "text", "points", "note", "locations" ], "type": "object" }, "type": "array" }, "name": { "type": "string" }, "npmscanUrl": { "type": "string" }, "peers": { "additionalProperties": false, "properties": { "note": { "type": [ "string", "null" ] }, "orgIdentifier": { "type": [ "string", "null" ] }, "orgKind": { "anyOf": [ { "enum": [ "scope", "maintainer" ], "type": "string" }, { "type": "null" } ] }, "peerProvenanceRate": { "type": [ "number", "null" ] }, "peersChecked": { "type": "number" }, "peersWithProvenance": { "type": "number" } }, "required": [ "orgKind", "orgIdentifier", "peersChecked", "peersWithProvenance", "peerProvenanceRate", "note" ], "type": "object" }, "provenance": { "additionalProperties": false, "properties": { "buildRunUrl": { "type": [ "string", "null" ] }, "builderId": { "type": [ "string", "null" ] }, "declaredRepository": { "type": [ "string", "null" ] }, "hasProvenance": { "type": "boolean" }, "note": { "type": [ "string", "null" ] }, "predicateType": { "type": [ "string", "null" ] }, "repositoryMatchesBuild": { "type": [ "boolean", "null" ] }, "sourceCommit": { "type": [ "string", "null" ] }, "sourceRepository": { "type": [ "string", "null" ] }, "workflowPath": { "type": [ "string", "null" ] } }, "required": [ "hasProvenance", "predicateType", "sourceRepository", "workflowPath", "builderId", "sourceCommit", "buildRunUrl", "declaredRepository", "repositoryMatchesBuild", "note" ], "type": "object" }, "riskTier": { "enum": [ "none", "low", "moderate", "high", "critical" ], "type": "string" }, "sourceDiff": { "additionalProperties": false, "properties": { "addedDependencies": { "items": { "type": "string" }, "type": "array" }, "addedInstallScripts": { "items": { "type": "string" }, "type": "array" }, "checked": { "type": "boolean" }, "gitRef": { "type": [ "string", "null" ] }, "note": { "type": [ "string", "null" ] }, "refSource": { "anyOf": [ { "enum": [ "provenance-commit", "guessed-tag" ], "type": "string" }, { "type": "null" } ] } }, "required": [ "checked", "gitRef", "refSource", "addedInstallScripts", "addedDependencies", "note" ], "type": "object" }, "totalScore": { "type": "number" }, "version": { "type": "string" } }, "required": [ "name", "version", "npmscanUrl", "provenance", "peers", "sourceDiff", "findings", "totalScore", "riskTier" ], "type": "object" } }, { "description": "Given 2-5 candidate packages for the same job (e.g. \"axios vs got vs node-fetch\"), fetches the same registry/popularity/maintenance/vulnerability enrichment get_package computes for each one in parallel and returns a structured side-by-side plus a deterministic, reasoned pick. Each candidate gets downloads + trend, popularityTier/maintenanceTier, GitHub stars, TypeScript support, license, deprecated status, latest-version vulnerability status, a lightweight installScriptRisk signal (scans lifecycle script command strings for known red flags — does NOT fetch the tarball; call analyze_install_script on a specific candidate for that deeper scan), and installSize (the candidate's own dist.unpackedSize plus a transitive rollup — summed dist.unpackedSize across its resolved dependency tree, walked up to depth 2 / 60 nodes per candidate; `installSize.transitive.truncated`/`sizeUnknownCount` flag when that sum is partial rather than pretending it's exact — call analyze_transitive_dependencies on a specific candidate for the full graph). `differentiators` names which candidates stand out on each dimension (most downloads, only ones with TS types, which are deprecated/vulnerable/flagged as a typosquat/install-script risk, smallest/largest install size). `recommendation.pick` is chosen deterministically from a weighted score (popularity, maintenance, deprecation, vulnerabilities, typosquat flag, install-script risk, TS support, GitHub stars — install size is reported but not scored) — never a deprecated or typosquat-flagged candidate — with `rationale` explaining why and `confidence` reflecting how close the top two scored. If a candidate's OSV.dev vulnerability check itself failed (network/timeout/upstream outage), `isLatestVersionVulnerable` comes back `false` only because the field has to be a boolean — `vulnerabilityCheckFailed:true` is the real signal there, and means that candidate's safe/not-safe answer is unknown, not confirmed clean. A name that can't be resolved (typo, unpublished, malformed) still appears in `candidates` with `found:false` and `resolutionError` set rather than failing the whole call; duplicate names in the input are rejected. More than 5 names is rejected with an error, never truncated: to compare more, split them into separate calls (or shortlist first) rather than dropping names to fit.", "inputSchema": { "$schema": "http://json-schema.org/draft-07/schema#", "additionalProperties": false, "properties": { "packages": { "description": "2-5 exact npm package names to compare, e.g. [\"axios\", \"got\", \"node-fetch\"]. More than 5 is rejected with an error, not truncated.", "items": { "maxLength": 214, "minLength": 1, "type": "string" }, "maxItems": 5, "minItems": 2, "type": "array" } }, "required": [ "packages" ], "type": "object" }, "name": "compare_packages", "outputSchema": { "$schema": "http://json-schema.org/draft-07/schema#", "additionalProperties": false, "properties": { "candidates": { "items": { "additionalProperties": false, "properties": { "daysSinceLastPublish": { "type": [ "number", "null" ] }, "deprecated": { "type": [ "string", "null" ] }, "description": { "type": [ "string", "null" ] }, "downloadTrend": { "additionalProperties": false, "properties": { "changePercent": { "type": [ "number", "null" ] }, "direction": { "enum": [ "growing", "stable", "declining", "unknown" ], "type": "string" } }, "required": [ "direction", "changePercent" ], "type": "object" }, "found": { "type": "boolean" }, "githubStars": { "type": [ "number", "null" ] }, "hasBuiltInTypes": { "type": "boolean" }, "highestSeverity": { "type": [ "string", "null" ] }, "installScriptRisk": { "anyOf": [ { "additionalProperties": false, "properties": { "hasLifecycleScripts": { "type": "boolean" }, "riskTier": { "enum": [ "none", "low", "moderate", "high", "critical" ], "type": "string" }, "scanScope": { "const": "lifecycle-scripts-only", "type": "string" }, "totalScore": { "type": "number" } }, "required": [ "hasLifecycleScripts", "riskTier", "totalScore", "scanScope" ], "type": "object" }, { "type": "null" } ] }, "installSize": { "anyOf": [ { "additionalProperties": false, "properties": { "transitive": { "additionalProperties": false, "properties": { "sizeUnknownCount": { "type": "number" }, "transitiveDependencyCount": { "type": "number" }, "transitiveUnpackedSize": { "type": [ "number", "null" ] }, "truncated": { "type": "boolean" } }, "required": [ "transitiveUnpackedSize", "transitiveDependencyCount", "sizeUnknownCount", "truncated" ], "type": "object" }, "unpackedSize": { "type": [ "number", "null" ] } }, "required": [ "unpackedSize", "transitive" ], "type": "object" }, { "type": "null" } ] }, "isLatestVersionVulnerable": { "type": "boolean" }, "latestVersion": { "type": [ "string", "null" ] }, "license": { "type": [ "string", "null" ] }, "maintenanceSummary": { "type": "string" }, "maintenanceTier": { "enum": [ "active", "aging", "stale", "unknown" ], "type": "string" }, "name": { "type": "string" }, "npmscanUrl": { "type": "string" }, "popularityTier": { "enum": [ "very-high", "high", "moderate", "low", "very-low", "unknown" ], "type": "string" }, "possibleTyposquatOf": { "anyOf": [ { "additionalProperties": false, "properties": { "name": { "type": "string" }, "rank": { "type": "number" } }, "required": [ "name", "rank" ], "type": "object" }, { "type": "null" } ] }, "resolutionError": { "type": [ "string", "null" ] }, "score": { "type": [ "number", "null" ] }, "vulnerabilityCheckFailed": { "type": "boolean" }, "vulnerabilityCount": { "type": "number" }, "weeklyDownloads": { "type": [ "number", "null" ] } }, "required": [ "name", "found", "resolutionError", "npmscanUrl", "description", "license", "latestVersion", "deprecated", "weeklyDownloads", "downloadTrend", "githubStars", "hasBuiltInTypes", "daysSinceLastPublish", "popularityTier", "maintenanceTier", "maintenanceSummary", "possibleTyposquatOf", "isLatestVersionVulnerable", "vulnerabilityCheckFailed", "highestSeverity", "vulnerabilityCount", "installScriptRisk", "installSize", "score" ], "type": "object" }, "type": "array" }, "differentiators": { "additionalProperties": false, "properties": { "deprecated": { "items": { "type": "string" }, "type": "array" }, "hasKnownVulnerabilities": { "items": { "type": "string" }, "type": "array" }, "hasTypeScriptSupport": { "items": { "type": "string" }, "type": "array" }, "installScriptRiskFlagged": { "items": { "type": "string" }, "type": "array" }, "largestInstallSize": { "type": [ "string", "null" ] }, "mostDownloads": { "type": [ "string", "null" ] }, "mostGithubStars": { "type": [ "string", "null" ] }, "possibleTyposquat": { "items": { "type": "string" }, "type": "array" }, "smallestInstallSize": { "type": [ "string", "null" ] } }, "required": [ "mostDownloads", "mostGithubStars", "hasTypeScriptSupport", "hasKnownVulnerabilities", "deprecated", "possibleTyposquat", "installScriptRiskFlagged", "smallestInstallSize", "largestInstallSize" ], "type": "object" }, "recommendation": { "additionalProperties": false, "properties": { "confidence": { "enum": [ "high", "medium", "low" ], "type": "string" }, "pick": { "type": [ "string", "null" ] }, "rationale": { "type": "string" }, "runnerUp": { "type": [ "string", "null" ] } }, "required": [ "pick", "runnerUp", "rationale", "confidence" ], "type": "object" } }, "required": [ "candidates", "differentiators", "recommendation" ], "type": "object" } }, { "description": "Compares two raw snapshots of a package.json, package-lock.json (npm v1-v3), yarn.lock (classic v1 or Berry), or pnpm-lock.yaml — e.g. before/after a PR — and reports which packages were added, removed, or version-bumped. An npm alias (e.g. `\"totally-safe\": \"npm:[email protected]\"`) is followed to its real target in every format — `actualName` names the real package that vulnerability/install-script data attaches to (`name` stays the declared/alias key); this is NOT silently skipped, since doing so would let a vulnerable package hide behind whatever name a project calls it. For every added or bumped package (up to 100 per call), also checks whether its resolved version carries a preinstall/install/postinstall/prepare lifecycle script that the before-version did NOT have (`installScriptIntroduced`, a headline signal — a routine-looking patch bump quietly adding a postinstall is exactly the shape of a compromised-maintainer supply-chain attack) and batch-checks it against OSV.dev, reporting `vulnerabilityDelta` (introduced/fixed/still-vulnerable/still-clean) rather than just a bare isVulnerable flag. `installScriptIntroduced` is a boolean across all four lifecycle keys, so it treats a bare `\"prepare\": \"husky\"` bump the same as a newly-added network-capable `postinstall` — read `installScriptKeysIntroduced` (null when only npm-lock's boolean hint was available, not the real scripts object; otherwise the actual key(s) added) to tell those apart before treating a flag as high-severity. `sourceIntegrityChanged` catches a DIFFERENT attack shape than a version bump: a lockfile entry whose resolved tarball URL or integrity hash changed while the version string stayed IDENTICAL — e.g. a compromised registry mirror or a hand-edited lockfile pointing a legitimate-looking \"[email protected]\" at a different, unverified artifact — which a version-only diff would report as \"no change\" (`resolvedUrl`/`integrity` are null when a format doesn't record either, package.json has neither). Scope notes: package.json is diffed as its own declared dependency list only (a manifest has no transitive data at all, and this includes `peerDependencies`, unlike batch_query_vulnerabilities/generate_sbom which exclude them by default — a diff should catch a peerDependency change just like any other); every lockfile format (package-lock.json, pnpm-lock.yaml, yarn.lock) reports its FULL resolved graph — direct and transitive alike — so a transitive-only change (e.g. a nested `qs` bumped while the direct `express` version is untouched) is caught, not just direct dependency changes; check `comparisonNote` when the two snapshots are different formats/scopes. The install-script check is presence-only (read from the registry packument or lockfile metadata, not a tarball content scan) — use analyze_install_script for a deep-dive on anything flagged here. `projectLifecycleChanges` diffs the SCANNED PROJECT's own root preinstall/install/postinstall/prepare scripts (package.json only — null when neither snapshot is one) — independent of the dependency list above, since a PR that only adds a root postinstall (`\"postinstall\": \"curl ... | sh\"`) changes nothing about added/removed/changed and would otherwise be invisible to this tool entirely; `introduced`/`changed` on a preinstall/install/postinstall key is counted in `flaggedCount`. `overridesChanges` similarly diffs package.json's `overrides` (npm), `resolutions` (yarn), or `pnpm.overrides` — these force a specific version onto a transitive dependency (often to pin past a known vulnerability), so a PR that quietly removes, downgrades, or introduces one is exactly the kind of change a dependency diff should catch, and previously nothing here read this field at all; ANY change here (introduced/removed/changed) is counted in `flaggedCount`, since an override can be a security control being weakened just as easily as an attack forcing a compromised version onto an otherwise-untouched dependency. Ideal for a CI gate reviewing a dependency-changing PR.", "inputSchema": { "$schema": "http://json-schema.org/draft-07/schema#", "additionalProperties": false, "properties": { "after": { "description": "Raw file content of the \"after\" snapshot — a package.json, package-lock.json (npm v1-v3), yarn.lock (classic v1 or Berry), or pnpm-lock.yaml. Format is auto-detected; before/after may be different formats.", "maxLength": 8388608, "minLength": 1, "type": "string" }, "before": { "description": "Raw file content of the \"before\" snapshot — a package.json, package-lock.json (npm v1-v3), yarn.lock (classic v1 or Berry), or pnpm-lock.yaml. Format is auto-detected; before/after may be different formats.", "maxLength": 8388608, "minLength": 1, "type": "string" } }, "required": [ "before", "after" ], "type": "object" }, "name": "diff_dependencies", "outputSchema": { "$schema": "http://json-schema.org/draft-07/schema#", "additionalProperties": false, "properties": { "added": { "items": { "additionalProperties": false, "properties": { "actualName": { "type": [ "string", "null" ] }, "afterVersion": { "type": [ "string", "null" ] }, "beforeVersion": { "type": [ "string", "null" ] }, "changeType": { "anyOf": [ { "enum": [ "upgrade", "downgrade", "unresolved" ], "type": "string" }, { "type": "null" } ] }, "coexistingVersions": { "anyOf": [ { "items": { "type": "string" }, "type": "array" }, { "type": "null" } ] }, "hasInstallScript": { "type": [ "boolean", "null" ] }, "highestSeverity": { "type": [ "string", "null" ] }, "installScriptIntroduced": { "type": [ "boolean", "null" ] }, "installScriptKeys": { "anyOf": [ { "items": { "enum": [ "preinstall", "install", "postinstall", "prepare" ], "type": "string" }, "type": "array" }, { "type": "null" } ] }, "installScriptKeysIntroduced": { "anyOf": [ { "items": { "enum": [ "preinstall", "install", "postinstall", "prepare" ], "type": "string" }, "type": "array" }, { "type": "null" } ] }, "integrity": { "type": [ "string", "null" ] }, "isVulnerable": { "type": [ "boolean", "null" ] }, "name": { "type": "string" }, "npmscanUrl": { "type": "string" }, "resolutionNote": { "type": [ "string", "null" ] }, "resolvedUrl": { "type": [ "string", "null" ] }, "sourceIntegrityChanged": { "type": [ "boolean", "null" ] }, "vulnerabilities": { "items": { "additionalProperties": false, "properties": { "aliases": { "items": { "type": "string" }, "type": "array" }, "fixedVersion": { "type": [ "string", "null" ] }, "id": { "type": "string" }, "npmscanUrl": { "type": "string" }, "publishedAt": { "type": [ "string", "null" ] }, "severity": { "type": [ "string", "null" ] }, "summary": { "type": [ "string", "null" ] } }, "required": [ "id", "summary", "severity", "aliases", "publishedAt", "fixedVersion", "npmscanUrl" ], "type": "object" }, "type": "array" }, "vulnerabilityDelta": { "anyOf": [ { "enum": [ "introduced", "fixed", "still-vulnerable", "still-clean", "unknown" ], "type": "string" }, { "type": "null" } ] } }, "required": [ "name", "actualName", "npmscanUrl", "beforeVersion", "afterVersion", "coexistingVersions", "changeType", "hasInstallScript", "installScriptIntroduced", "installScriptKeys", "installScriptKeysIntroduced", "sourceIntegrityChanged", "resolvedUrl", "integrity", "isVulnerable", "highestSeverity", "vulnerabilities", "vulnerabilityDelta", "resolutionNote" ], "type": "object" }, "type": "array" }, "afterFormat": { "enum": [ "package.json", "npm-lock", "yarn-lock", "pnpm-lock" ], "type": "string" }, "beforeFormat": { "enum": [ "package.json", "npm-lock", "yarn-lock", "pnpm-lock" ], "type": "string" }, "changed": { "items": { "$ref": "#/properties/added/items" }, "type": "array" }, "comparisonNote": { "type": [ "string", "null" ] }, "enrichmentNote": { "type": [ "string", "null" ] }, "flaggedCount": { "type": "number" }, "overridesChanges": { "anyOf": [ { "additionalProperties": false, "properties": { "changed": { "additionalProperties": { "additionalProperties": false, "properties": { "after": { "type": "string" }, "before": { "type": "string" } }, "required": [ "before", "after" ], "type": "object" }, "type": "object" }, "introduced": { "additionalProperties": { "type": "string" }, "type": "object" }, "removed": { "additionalProperties": { "type": "string" }, "type": "object" } }, "required": [ "introduced", "removed", "changed" ], "type": "object" }, { "type": "null" } ] }, "projectLifecycleChanges": { "anyOf": [ { "additionalProperties": false, "properties": { "changed": { "additionalProperties": { "additionalProperties": false, "properties": { "after": { "type": "string" }, "before": { "type": "string" } }, "required": [ "before", "after" ], "type": "object" }, "type": "object" }, "introduced": { "additionalProperties": { "type": "string" }, "type": "object" }, "removed": { "additionalProperties": { "type": "string" }, "type": "object" } }, "required": [ "introduced", "removed", "changed" ], "type": "object" }, { "type": "null" } ] }, "removed": { "items": { "additionalProperties": false, "properties": { "actualName": { "type": [ "string", "null" ] }, "name": { "type": "string" }, "npmscanUrl": { "type": "string" }, "version": { "type": [ "string", "null" ] } }, "required": [ "name", "actualName", "version", "npmscanUrl" ], "type": "object" }, "type": "array" }, "summary": { "type": "string" }, "totalAdded": { "type": "number" }, "totalChanged": { "type": "number" }, "totalRemoved": { "type": "number" }, "truncated": { "type": "boolean" }, "truncationNote": { "type": [ "string", "null" ] } }, "required": [ "summary", "beforeFormat", "afterFormat", "comparisonNote", "added", "removed", "changed", "totalAdded", "totalRemoved", "totalChanged", "flaggedCount", "truncated", "truncationNote", "enrichmentNote", "projectLifecycleChanges", "overridesChanges" ], "type": "object" } }, { "description": "Given the raw output of `npm audit --json` (npm 7+'s `{vulnerabilities: {...}}` format, or legacy npm 6's `{advisories: {...}}`), parses it directly — no need to re-paste package.json/lockfile content — and runs it through the same remove-now/patch-now/patch-soon/scheduled/monitor ranking prioritize_remediation exposes for hand-built finding lists (a MAL-* advisoryId in the audit report is auto-detected as malware and forces remove-now). npm audit's JSON almost never includes a CVE id (only a GHSA advisory URL), so this resolves each GHSA to its CVE alias via OSV.dev when one exists (ghsaResolvedToCveCount reports how many) before doing the same CISA KEV + FIRST.org EPSS + severity scoring — skipping this step would silently degrade most findings to severity-only ranking despite prioritize_remediation being built around CVE-keyed KEV/EPSS data. Also carries through npm-audit-specific context prioritize_remediation itself has no field for: isDirect (direct vs. transitive dependency) and fixAvailable/fixTarget (npm's own computed fix — note fixTarget can name a different package than the vulnerable one, e.g. bumping a parent to pull in a patched transitive dependency). A package with more than one distinct advisory in the source report only has its first advisory used for ranking; a warning names the package so query_vulnerabilities can be called on it directly for the rest. `yarn audit --json` and `pnpm audit --json` use different report shapes and are not supported — use batch_query_vulnerabilities with the project's manifest/lockfile for those instead.", "inputSchema": { "$schema": "http://json-schema.org/draft-07/schema#", "additionalProperties": false, "properties": { "content": { "description": "Raw stdout of `npm audit --json` — either npm 7+ format ({\"auditReportVersion\": 2, \"vulnerabilities\": {...}}) or legacy npm 6 format ({\"advisories\": {...}}).", "minLength": 1, "type": "string" } }, "required": [ "content" ], "type": "object" }, "name": "enrich_npm_audit", "outputSchema": { "$schema": "http://json-schema.org/draft-07/schema#", "additionalProperties": false, "properties": { "ghsaResolvedToCveCount": { "type": "number" }, "inputFormat": { "enum": [ "npm-audit-v2", "npm-audit-legacy" ], "type": "string" }, "ranked": { "items": { "additionalProperties": false, "properties": { "advisoryId": { "type": [ "string", "null" ] }, "advisoryTitle": { "type": [ "string", "null" ] }, "currentVersion": { "type": [ "string", "null" ] }, "cveId": { "type": [ "string", "null" ] }, "cveNpmscanUrl": { "type": [ "string", "null" ] }, "epss": { "anyOf": [ { "additionalProperties": false, "properties": { "date": { "type": "string" }, "percentile": { "type": "number" }, "score": { "type": "number" } }, "required": [ "score", "percentile", "date" ], "type": "object" }, { "type": "null" } ] }, "findingType": { "enum": [ "malware", "vulnerability", "supply-chain", "install-script" ], "type": "string" }, "fixAvailable": { "type": [ "boolean", "null" ] }, "fixTarget": { "anyOf": [ { "additionalProperties": false, "properties": { "isSemVerMajor": { "type": "boolean" }, "name": { "type": "string" }, "version": { "type": "string" } }, "required": [ "name", "version", "isSemVerMajor" ], "type": "object" }, { "type": "null" } ] }, "fixedVersion": { "type": [ "string", "null" ] }, "isDirect": { "type": [ "boolean", "null" ] }, "kev": { "anyOf": [ { "additionalProperties": false, "properties": { "dateAdded": { "type": "string" }, "dueDate": { "type": "string" }, "knownRansomwareCampaignUse": { "type": "string" }, "requiredAction": { "type": "string" } }, "required": [ "dateAdded", "dueDate", "knownRansomwareCampaignUse", "requiredAction" ], "type": "object" }, { "type": "null" } ] }, "npmscanUrl": { "type": "string" }, "packageName": { "type": "string" }, "rank": { "type": "number" }, "reason": { "type": "string" }, "score": { "type": "number" }, "severity": { "type": [ "string", "null" ] }, "tier": { "enum": [ "remove-now", "patch-now", "patch-soon", "scheduled", "monitor" ], "type": "string" } }, "required": [ "rank", "packageName", "cveId", "advisoryId", "currentVersion", "fixedVersion", "severity", "kev", "epss", "score", "tier", "findingType", "reason", "npmscanUrl", "cveNpmscanUrl", "advisoryTitle", "isDirect", "fixAvailable", "fixTarget" ], "type": "object" }, "type": "array" }, "skippedCount": { "type": "number" }, "summary": { "additionalProperties": false, "properties": { "kevListedCount": { "type": "number" }, "monitor": { "type": "number" }, "patchNow": { "type": "number" }, "patchSoon": { "type": "number" }, "removeNow": { "type": "number" }, "scheduled": { "type": "number" } }, "required": [ "removeNow", "patchNow", "patchSoon", "scheduled", "monitor", "kevListedCount" ], "type": "object" }, "totalFindings": { "type": "number" }, "uniqueCveCount": { "type": "number" }, "warnings": { "items": { "type": "string" }, "type": "array" } }, "required": [ "inputFormat", "totalFindings", "uniqueCveCount", "ghsaResolvedToCveCount", "summary", "ranked", "warnings", "skippedCount" ], "type": "object" } }, { "description": "Given the same inputs batch_query_vulnerabilities accepts — either a flat {packages:[...]} list, or raw package.json / lockfile / CycloneDX JSON / SPDX JSON content via `content` — emits a spec-valid CycloneDX 1.6 or SPDX 2.3 JSON document (pick with `format`, default 'cyclonedx') with npmscan's own OSV.dev vulnerability findings and registry license data embedded in each spec's native fields: CycloneDX gets a top-level `vulnerabilities[]` array (VEX `analysis.state: 'in_triage'` — an unreviewed automated finding, not a claim of exploitability) and per-component `licenses[]`; SPDX (which has no vulnerabilities array in 2.3) gets one `externalRefs` SECURITY/advisory entry per finding and `licenseDeclared`/`licenseConcluded`. Only a flat package inventory is known here, so the CycloneDX `dependencies[]` transitive graph and any SPDX package hierarchy are intentionally omitted rather than fabricated. Set `includeVulnerabilities`/`includeLicenses` to false to skip either enrichment pass (faster, no registry/OSV calls for that pass); pass `policy` (same shape as check_license_compliance) to also get per-package compliance context; `componentName`/`componentVersion` name the SBOM's own root component/document if known. When `content` is a package.json, `peerDependencies` are excluded by default (a peer is often intentionally left unresolved by the consumer) — pass `includePeerDependencies: true` to include them as SBOM components too, since an SBOM meant to be complete shouldn't silently omit a whole dependency category.", "inputSchema": { "$schema": "http://json-schema.org/draft-07/schema#", "additionalProperties": false, "properties": { "componentName": { "description": "Name of the SBOM's own root component/document, if known.", "maxLength": 214, "minLength": 1, "type": "string" }, "componentVersion": { "maxLength": 128, "minLength": 1, "type": "string" }, "content": { "description": "Raw dependency inventory content: package.json, package-lock.json, yarn.lock, pnpm-lock.yaml, CycloneDX JSON, or SPDX JSON. Use this OR `packages`, not both.", "minLength": 1, "type": "string" }, "format": { "description": "SBOM format to emit. Default 'cyclonedx'.", "enum": [ "cyclonedx", "spdx" ], "type": "string" }, "includeDevDependencies": { "description": "Ignored when using `packages`; only applies when `content` is a manifest/lockfile format that distinguishes dev dependencies.", "type": "boolean" }, "includeLicenses": { "description": "Resolve registry license data and embed it natively. Default true.", "type": "boolean" }, "includePeerDependencies": { "description": "Ignored when using `packages`; only applies when `content` is a package.json. peerDependencies are excluded by default — set this to also include them as SBOM components.", "type": "boolean" }, "includeVulnerabilities": { "description": "Query OSV.dev and embed findings natively. Default true.", "type": "boolean" }, "packages": { "description": "Explicit package list (1-1000 items, capped to 100 when includeLicenses is on). Use this OR `content`, not both.", "items": { "additionalProperties": false, "properties": { "name": { "maxLength": 214, "minLength": 1, "type": "string" }, "version": { "maxLength": 128, "type": "string" } }, "required": [ "name" ], "type": "object" }, "maxItems": 1000, "minItems": 1, "type": "array" }, "policy": { "additionalProperties": false, "description": "License allow/deny policy, same shape as check_license_compliance. Omit for the default policy.", "properties": { "allow": { "description": "SPDX ids, family prefixes (e.g. \"GPL\"), or category names. Anything not matching is a violation.", "items": { "maxLength": 100, "minLength": 1, "type": "string" }, "maxItems": 50, "type": "array" }, "deny": { "description": "SPDX ids, family prefixes, or category names. Always takes precedence over allow.", "items": { "maxLength": 100, "minLength": 1, "type": "string" }, "maxItems": 50, "type": "array" } }, "type": "object" } }, "type": "object" }, "name": "generate_sbom", "outputSchema": { "$schema": "http://json-schema.org/draft-07/schema#", "additionalProperties": false, "properties": { "enrichmentNote": { "type": "string" }, "format": { "enum": [ "cyclonedx", "spdx" ], "type": "string" }, "ignoredCount": { "type": "number" }, "inputFormat": { "type": "string" }, "licenseViolationCount": { "type": "number" }, "packagesWithVulnerabilities": { "type": "number" }, "parsedPackageCount": { "type": "number" }, "policy": { "additionalProperties": false, "properties": { "allow": { "items": { "type": "string" }, "type": "array" }, "deny": { "items": { "type": "string" }, "type": "array" }, "mode": { "enum": [ "default", "allow", "deny", "allow+deny" ], "type": "string" } }, "required": [ "mode", "allow", "deny" ], "type": "object" }, "sbom": { "additionalProperties": {}, "type": "object" }, "totalVulnerabilities": { "type": "number" }, "warnings": { "items": { "type": "string" }, "type": "array" } }, "required": [ "format", "sbom", "parsedPackageCount", "totalVulnerabilities", "packagesWithVulnerabilities" ], "type": "object" } }, { "description": "Look up authoritative NIST NVD data for one exact CVE ID (e.g. \"CVE-2026-2950\"), or browse/search NVD by keyword, CVSS severity, CWE, or a publication-date range. Every result is enriched with CISA KEV status (`kev`, non-null only if this CVE is a confirmed, actively-exploited-in-the-wild vulnerability — treat that as an urgent-patch signal regardless of CVSS score) and FIRST.org EPSS (`epss`, the probability of exploitation in the next 30 days — a better prioritization signal than CVSS severity alone, which measures impact, not likelihood). If the KEV or EPSS lookup itself fails (network/timeout/upstream outage), `kev`/`epss` come back `null` only because those fields have to be nullable — `kevCheckFailed`/`epssCheckFailed` (true in that case) is the real signal, and means \"unknown\", not \"confirmed absent/unscored\". For a search, a failed EPSS batch call sets `epssCheckFailed` on every result in that response, since one call scores every id together; `kevCheckFailed` is tracked per-CVE since each is looked up independently. For a single cveId lookup, if NVD has no record yet or hasn't scored it, this falls back to the raw MITRE CVE record automatically (`source: \"mitre\"` on the result) rather than returning nothing. NVD is NOT npm-scoped — unlike query_vulnerabilities/get_latest_advisories, search results can include CVEs for any ecosystem, so pass keywordSearch (e.g. the package name) to narrow it. Prefer this for the authoritative CVSS score/vector/KEV/EPSS data on a CVE already found via another tool, or when a user pastes a CVE ID/link directly; prefer get_latest_advisories for npm-specific browsing. NVD enforces a strict shared rate limit, so this tool may occasionally ask you to retry in a few seconds — do so rather than assuming failure.", "inputSchema": { "$schema": "http://json-schema.org/draft-07/schema#", "additionalProperties": false, "properties": { "cveId": { "description": "Exact CVE ID for a single lookup, e.g. \"CVE-2026-2950\". When given, search filters below are ignored and should be omitted.", "pattern": "^CVE-\\d{4}-\\d{4,}$", "type": "string" }, "cweId": { "description": "Filter by weakness type, e.g. \"CWE-79\"", "pattern": "^CWE-\\d+$", "type": "string" }, "keywordSearch": { "description": "Free-text search, e.g. a package or product name", "maxLength": 200, "minLength": 1, "type": "string" }, "publishedSince": { "description": "Publication date range start (YYYY-MM-DD). Must be given together with publishedUntil.", "pattern": "^\\d{4}-\\d{2}-\\d{2}$", "type": "string" }, "publishedUntil": { "$ref": "#/properties/publishedSince", "description": "Publication date range end (YYYY-MM-DD). Must be given together with publishedSince; range is capped at 120 days." }, "resultsPerPage": { "description": "Max results for a search (default 10, capped at 50)", "maximum": 50, "minimum": 1, "type": "integer" }, "severity": { "description": "Filter by CVSS v3 base severity", "enum": [ "CRITICAL", "HIGH", "MEDIUM", "LOW" ], "type": "string" }, "startIndex": { "description": "Pagination offset for a search", "minimum": 0, "type": "integer" } }, "type": "object" }, "name": "get_cve", "outputSchema": { "$schema": "http://json-schema.org/draft-07/schema#", "additionalProperties": false, "properties": { "cveId": { "type": "string" }, "cves": { "items": { "additionalProperties": false, "properties": { "cvss": { "$ref": "#/properties/cvss" }, "cwes": { "$ref": "#/properties/cwes" }, "description": { "$ref": "#/properties/description" }, "epss": { "$ref": "#/properties/epss" }, "epssCheckFailed": { "$ref": "#/properties/epssCheckFailed" }, "id": { "$ref": "#/properties/id" }, "kev": { "$ref": "#/properties/kev" }, "kevCheckFailed": { "$ref": "#/properties/kevCheckFailed" }, "lastModified": { "$ref": "#/properties/lastModified" }, "npmscanUrl": { "$ref": "#/properties/npmscanUrl" }, "published": { "$ref": "#/properties/published" }, "references": { "$ref": "#/properties/references" }, "source": { "$ref": "#/properties/source" }, "vulnStatus": { "$ref": "#/properties/vulnStatus" } }, "required": [ "id", "npmscanUrl", "vulnStatus", "description", "published", "lastModified", "cvss", "cwes", "references", "source", "kev", "epss", "kevCheckFailed", "epssCheckFailed" ], "type": "object" }, "type": "array" }, "cvss": { "anyOf": [ { "additionalProperties": false, "properties": { "baseScore": { "type": "number" }, "baseSeverity": { "type": [ "string", "null" ] }, "vectorString": { "type": "string" }, "version": { "enum": [ "3.1", "3.0", "2.0" ], "type": "string" } }, "required": [ "version", "baseScore", "baseSeverity", "vectorString" ], "type": "object" }, { "type": "null" } ] }, "cwes": { "items": { "type": "string" }, "type": "array" }, "dateRangeClamped": { "type": "boolean" }, "description": { "type": [ "string", "null" ] }, "epss": { "anyOf": [ { "additionalProperties": false, "properties": { "date": { "type": "string" }, "percentile": { "type": "number" }, "score": { "type": "number" } }, "required": [ "score", "percentile", "date" ], "type": "object" }, { "type": "null" } ] }, "epssCheckFailed": { "type": "boolean" }, "found": { "type": "boolean" }, "id": { "type": "string" }, "kev": { "anyOf": [ { "additionalProperties": false, "properties": { "dateAdded": { "type": "string" }, "dueDate": { "type": "string" }, "knownRansomwareCampaignUse": { "type": "string" }, "requiredAction": { "type": "string" } }, "required": [ "dateAdded", "dueDate", "knownRansomwareCampaignUse", "requiredAction" ], "type": "object" }, { "type": "null" } ] }, "kevCheckFailed": { "type": "boolean" }, "lastModified": { "type": [ "string", "null" ] }, "note": { "type": "string" }, "npmscanUrl": { "type": "string" }, "published": { "type": [ "string", "null" ] }, "references": { "items": { "additionalProperties": false, "properties": { "source": { "type": [ "string", "null" ] }, "tags": { "items": { "type": "string" }, "type": "array" }, "url": { "type": "string" } }, "required": [ "url", "source", "tags" ], "type": "object" }, "type": "array" }, "resultsPerPage": { "type": "number" }, "source": { "enum": [ "nvd", "mitre" ], "type": "string" }, "startIndex": { "type": "number" }, "totalResults": { "type": "number" }, "vulnStatus": { "type": [ "string", "null" ] } }, "type": "object" } }, { "description": "Browse recently published npm security advisories and known-malicious-package findings. Three disjoint sources, selected via type: \"reviewed\" (default) is GitHub's curated, mostly CVE-backed advisories; \"malware\" is GitHub's own known-malicious-package advisories; \"osv\" is OSV.dev's OpenSSF malicious-packages feed, a separate dataset whose entries use MAL-/OSV ids rather than GHSA ids. None of \"malware\"/\"osv\" carry a CVE or meaningful CWE beyond \"embedded malicious code\". Filter by severity, vulnerability category (XSS, SQL/NoSQL Injection, SSRF, Access Control, Code Injection, etc. — reviewed only), an affected package name, or (reviewed/malware only) look up one exact advisory by GHSA or CVE ID. Advisories GitHub has withdrawn (most often \"Duplicate Advisory: ...\" records merged into a canonical GHSA) are excluded from browse results, so a page can hold fewer than 30 entries; an exact ghsaId/cveId lookup still returns a withdrawn advisory, with withdrawnAt set — treat it as retracted, not as a live finding. Paginated with an opaque cursor: pass a previous response's nextCursor back in as cursor to fetch the next page.", "inputSchema": { "$schema": "http://json-schema.org/draft-07/schema#", "additionalProperties": false, "properties": { "affects": { "description": "Filter to advisories affecting this npm package name", "maxLength": 214, "type": "string" }, "category": { "description": "Filter by vulnerability category (reviewed only). One of: access-control, dos, xss, ssrf, auth, code-injection, info-exposure, path-traversal, input-validation, prototype-pollution, command-injection, sqli, crypto, race-condition, open-redirect, csrf, crlf-injection, xml-injection, malicious-code, deserialization", "enum": [ "access-control", "dos", "xss", "ssrf", "auth", "code-injection", "info-exposure", "path-traversal", "input-validation", "prototype-pollution", "command-injection", "sqli", "crypto", "race-condition", "open-redirect", "csrf", "crlf-injection", "xml-injection", "malicious-code", "deserialization" ], "type": "string" }, "cursor": { "description": "Opaque pagination cursor from a previous response's nextCursor, to fetch the next page", "type": "string" }, "cveId": { "description": "Look up one exact advisory by its CVE ID (e.g. \"CVE-2024-12345\") — reviewed/malware only", "type": "string" }, "direction": { "description": "Sort by published date, newest or oldest first (default desc)", "enum": [ "asc", "desc" ], "type": "string" }, "ghsaId": { "description": "Look up one exact advisory by its GHSA ID (e.g. \"GHSA-xxxx-xxxx-xxxx\") — reviewed/malware only", "type": "string" }, "severity": { "description": "Filter by severity (default all; not applicable to \"malware\"/\"osv\")", "enum": [ "critical", "high", "medium", "low", "all" ], "type": "string" }, "type": { "description": "Advisory source: \"reviewed\" (curated CVE-style, default), \"malware\" (GitHub-curated known-malicious packages), or \"osv\" (OSV.dev/OpenSSF malicious-packages feed)", "enum": [ "reviewed", "malware", "osv" ], "type": "string" } }, "type": "object" }, "name": "get_latest_advisories", "outputSchema": { "$schema": "http://json-schema.org/draft-07/schema#", "additionalProperties": false, "properties": { "advisories": { "items": { "additionalProperties": false, "properties": { "categories": { "items": { "type": "string" }, "type": "array" }, "cve": { "type": [ "string", "null" ] }, "cwes": { "items": { "additionalProperties": false, "properties": { "id": { "type": "string" }, "name": { "type": "string" } }, "required": [ "id", "name" ], "type": "object" }, "type": "array" }, "ghsaUrl": { "type": "string" }, "id": { "type": "string" }, "npmscanUrl": { "type": "string" }, "packages": { "items": { "additionalProperties": false, "properties": { "affectedRange": { "type": [ "string", "null" ] }, "name": { "type": "string" }, "patchedVersion": { "type": [ "string", "null" ] } }, "required": [ "name", "affectedRange", "patchedVersion" ], "type": "object" }, "type": "array" }, "publishedAt": { "type": "string" }, "severity": { "type": "string" }, "summary": { "type": "string" }, "withdrawnAt": { "type": [ "string", "null" ] } }, "required": [ "id", "cve", "summary", "severity", "publishedAt", "withdrawnAt", "ghsaUrl", "npmscanUrl", "cwes", "categories", "packages" ], "type": "object" }, "type": "array" }, "category": { "enum": [ "all", "access-control", "dos", "xss", "ssrf", "auth", "code-injection", "info-exposure", "path-traversal", "input-validation", "prototype-pollution", "command-injection", "sqli", "crypto", "race-condition", "open-redirect", "csrf", "crlf-injection", "xml-injection", "malicious-code", "deserialization" ], "type": "string" }, "direction": { "enum": [ "asc", "desc" ], "type": "string" }, "nextCursor": { "type": [ "string", "null" ] }, "severity": { "enum": [ "critical", "high", "medium", "low", "all" ], "type": "string" }, "type": { "enum": [ "reviewed", "malware", "osv" ], "type": "string" } }, "required": [ "type", "severity", "category", "direction", "nextCursor", "advisories" ], "type": "object" } }, { "description": "Given an npm username, returns every package npm's own maintainer:<username> search index currently returns for that account (registry.npmjs.org's /-/v1/search — the public registry API has no dedicated 'list packages by maintainer' endpoint otherwise), plus precomputed aggregates: currentlyMaintainsCount (still listed as maintainer right now vs. already-revoked), totalWeeklyDownloads and totalDependents summed across every returned package, and avatarUrl — a proxied Gravatar image (null if no email is on record). This is a plain info lookup — it does NOT run the publish-cluster / compromised-account detection that check_maintainer_blast_radius does; use that tool instead when the goal is a security read on whether this account's recent activity looks like a takeover, not just a profile summary. Natural pairing with check_maintainer_changes: once that tool names a maintainer on a package, call this with that maintainer's username to see the rest of what they touch. npmscanUrl is this account's profile page on npmscan itself; npmProfileUrl is the account's actual page on npmjs.com, included for verification since that's the authoritative record of the account.", "inputSchema": { "$schema": "http://json-schema.org/draft-07/schema#", "additionalProperties": false, "properties": { "maintainerUsername": { "description": "Exact npm username, e.g. \"sindresorhus\" — as shown at npmjs.com/~username. Not an email address, not a package name or scope.", "maxLength": 100, "minLength": 1, "type": "string" } }, "required": [ "maintainerUsername" ], "type": "object" }, "name": "get_maintainer_profile", "outputSchema": { "$schema": "http://json-schema.org/draft-07/schema#", "additionalProperties": false, "properties": { "avatarUrl": { "type": [ "string", "null" ] }, "currentlyMaintainsCount": { "type": "number" }, "maintainerUsername": { "type": "string" }, "note": { "type": [ "string", "null" ] }, "npmProfileUrl": { "type": "string" }, "npmscanUrl": { "type": "string" }, "packages": { "items": { "additionalProperties": false, "properties": { "dependentsCount": { "type": [ "number", "null" ] }, "isCurrentMaintainer": { "type": "boolean" }, "lastPublished": { "type": [ "string", "null" ] }, "name": { "type": "string" }, "npmscanUrl": { "type": "string" }, "version": { "type": "string" }, "weeklyDownloads": { "type": [ "number", "null" ] } }, "required": [ "name", "version", "lastPublished", "weeklyDownloads", "dependentsCount", "isCurrentMaintainer", "npmscanUrl" ], "type": "object" }, "type": "array" }, "packagesReturned": { "type": "number" }, "resultsTruncated": { "type": "boolean" }, "totalDependents": { "type": "number" }, "totalPackagesFound": { "type": "number" }, "totalWeeklyDownloads": { "type": "number" } }, "required": [ "maintainerUsername", "npmscanUrl", "npmProfileUrl", "avatarUrl", "totalPackagesFound", "packagesReturned", "resultsTruncated", "currentlyMaintainsCount", "totalWeeklyDownloads", "totalDependents", "packages", "note" ], "type": "object" } }, { "description": "Fetch npm registry metadata for a package: latest version, install scripts (preinstall/postinstall are a key risk signal), maintainers, license, recent version history, weekly downloads, GitHub stars, TypeScript support, days since last publish, a topPackagesRank (position among npm's ~100k most-downloaded packages, from npmscan's own periodically-refreshed snapshot — not live), and a downloadTrend (growing/stable/declining vs. ~3 months ago). Also checks the LATEST version against OSV.dev for known vulnerabilities — isLatestVersionVulnerable/highestSeverity give a direct safe/not-safe answer, and each finding includes severity, a summary, and the fixedVersion to upgrade to (use get_package_version or query_vulnerabilities to check a specific older version instead). If the OSV.dev query itself fails (network/timeout/upstream outage), isLatestVersionVulnerable comes back `false` only because the field has to be a boolean — vulnerabilityCheckFailed:true is the real signal there, and means the safe/not-safe answer is unknown, not confirmed clean. Also returns popularityTier/maintenanceTier (deterministic rule-based labels, not model-generated) and a plain-language maintenanceSummary, plus a possibleTyposquatOf flag if the name is one typo away from a top-5,000 package while itself being obscure — read `deprecated` and maintenanceSummary before recommending a package, since a long gap since the last release can mean either a stable/finished package or a slowing one. Includes a link to the full npmscan.com analysis page.", "inputSchema": { "$schema": "http://json-schema.org/draft-07/schema#", "additionalProperties": false, "properties": { "name": { "description": "Exact npm package name, e.g. \"lodash\" or \"@scope/name\"", "maxLength": 214, "minLength": 1, "type": "string" } }, "required": [ "name" ], "type": "object" }, "name": "get_package", "outputSchema": { "$schema": "http://json-schema.org/draft-07/schema#", "additionalProperties": false, "properties": { "createdAt": { "type": [ "string", "null" ] }, "daysSinceLastPublish": { "type": [ "number", "null" ] }, "description": { "type": [ "string", "null" ] }, "distTags": { "additionalProperties": { "type": "string" }, "type": "object" }, "downloadTrend": { "additionalProperties": false, "properties": { "changePercent": { "type": [ "number", "null" ] }, "direction": { "enum": [ "growing", "stable", "declining", "unknown" ], "type": "string" } }, "required": [ "direction", "changePercent" ], "type": "object" }, "githubStars": { "type": [ "number", "null" ] }, "hasBuiltInTypes": { "type": "boolean" }, "highestSeverity": { "type": [ "string", "null" ] }, "homepage": { "type": [ "string", "null" ] }, "isLatestVersionVulnerable": { "type": "boolean" }, "keywords": { "items": { "type": "string" }, "type": "array" }, "latestVersion": { "type": [ "string", "null" ] }, "latestVersionInfo": { "anyOf": [ { "additionalProperties": false, "properties": { "dependencies": { "additionalProperties": { "type": "string" }, "type": "object" }, "deprecated": { "type": [ "string", "null" ] }, "scripts": { "additionalProperties": { "type": "string" }, "type": "object" }, "tarball": { "type": [ "string", "null" ] }, "version": { "type": "string" } }, "required": [ "version", "dependencies", "scripts", "deprecated", "tarball" ], "type": "object" }, { "type": "null" } ] }, "license": { "type": [ "string", "null" ] }, "maintainers": { "items": { "additionalProperties": false, "properties": { "email": { "type": "string" }, "name": { "type": "string" } }, "required": [ "name" ], "type": "object" }, "type": "array" }, "maintenanceSummary": { "type": "string" }, "maintenanceTier": { "enum": [ "active", "aging", "stale", "unknown" ], "type": "string" }, "modifiedAt": { "type": [ "string", "null" ] }, "name": { "type": "string" }, "npmscanUrl": { "type": "string" }, "popularityTier": { "enum": [ "very-high", "high", "moderate", "low", "very-low", "unknown" ], "type": "string" }, "possibleTyposquatOf": { "anyOf": [ { "additionalProperties": false, "properties": { "name": { "type": "string" }, "rank": { "type": "number" } }, "required": [ "name", "rank" ], "type": "object" }, { "type": "null" } ] }, "recentVersions": { "items": { "additionalProperties": false, "properties": { "publishedAt": { "type": [ "string", "null" ] }, "version": { "type": "string" } }, "required": [ "version", "publishedAt" ], "type": "object" }, "type": "array" }, "repository": { "type": [ "string", "null" ] }, "topPackagesRank": { "type": [ "number", "null" ] }, "vulnerabilities": { "items": { "additionalProperties": false, "properties": { "aliases": { "items": { "type": "string" }, "type": "array" }, "fixedVersion": { "type": [ "string", "null" ] }, "id": { "type": "string" }, "npmscanUrl": { "type": "string" }, "publishedAt": { "type": [ "string", "null" ] }, "severity": { "type": [ "string", "null" ] }, "summary": { "type": [ "string", "null" ] } }, "required": [ "id", "summary", "severity", "aliases", "publishedAt", "fixedVersion", "npmscanUrl" ], "type": "object" }, "type": "array" }, "vulnerabilityCheckFailed": { "type": "boolean" }, "weeklyDownloads": { "type": [ "number", "null" ] } }, "required": [ "name", "description", "license", "homepage", "repository", "keywords", "maintainers", "distTags", "latestVersion", "latestVersionInfo", "recentVersions", "createdAt", "modifiedAt", "npmscanUrl", "weeklyDownloads", "githubStars", "hasBuiltInTypes", "daysSinceLastPublish", "popularityTier", "maintenanceTier", "maintenanceSummary", "topPackagesRank", "downloadTrend", "possibleTyposquatOf", "isLatestVersionVulnerable", "vulnerabilityCheckFailed", "highestSeverity", "vulnerabilities" ], "type": "object" } }, { "description": "Fetch registry metadata for one exact version of a package (dependencies, install scripts, tarball) AND check that exact version against OSV.dev for known vulnerabilities — isVulnerable/highestSeverity give a direct answer, and each finding includes severity, a summary, and the fixedVersion to upgrade to. Use this to check a version pinned in a lockfile rather than the latest release. If the OSV.dev query itself fails (network/timeout/upstream outage), isVulnerable comes back `false` only because the field has to be a boolean — vulnerabilityCheckFailed:true is the real signal there, and means the answer is unknown, not confirmed clean.", "inputSchema": { "$schema": "http://json-schema.org/draft-07/schema#", "additionalProperties": false, "properties": { "name": { "description": "Exact npm package name", "maxLength": 214, "minLength": 1, "type": "string" }, "version": { "description": "Exact version string, e.g. \"4.17.21\", or a dist-tag such as \"latest\" (resolved to its exact version before the vulnerability check). Semver ranges like \"^4.17.0\" are not supported.", "maxLength": 128, "minLength": 1, "type": "string" } }, "required": [ "name", "version" ], "type": "object" }, "name": "get_package_version", "outputSchema": { "$schema": "http://json-schema.org/draft-07/schema#", "additionalProperties": false, "properties": { "dependencies": { "additionalProperties": { "type": "string" }, "type": "object" }, "deprecated": { "type": [ "string", "null" ] }, "description": { "type": [ "string", "null" ] }, "highestSeverity": { "type": [ "string", "null" ] }, "isVulnerable": { "type": "boolean" }, "license": { "type": [ "string", "null" ] }, "name": { "type": "string" }, "npmscanUrl": { "type": "string" }, "scripts": { "additionalProperties": { "type": "string" }, "type": "object" }, "shasum": { "type": [ "string", "null" ] }, "tarball": { "type": [ "string", "null" ] }, "version": { "type": "string" }, "vulnerabilities": { "items": { "additionalProperties": false, "properties": { "aliases": { "items": { "type": "string" }, "type": "array" }, "fixedVersion": { "type": [ "string", "null" ] }, "id": { "type": "string" }, "npmscanUrl": { "type": "string" }, "publishedAt": { "type": [ "string", "null" ] }, "severity": { "type": [ "string", "null" ] }, "summary": { "type": [ "string", "null" ] } }, "required": [ "id", "summary", "severity", "aliases", "publishedAt", "fixedVersion", "npmscanUrl" ], "type": "object" }, "type": "array" }, "vulnerabilityCheckFailed": { "type": "boolean" } }, "required": [ "name", "version", "description", "license", "dependencies", "scripts", "deprecated", "tarball", "shasum", "npmscanUrl", "isVulnerable", "vulnerabilityCheckFailed", "highestSeverity", "vulnerabilities" ], "type": "object" } }, { "description": "Maps a finding's `rule` value from analyze_install_script, check_maintainer_changes, or check_package_provenance to the matching human-authored incident-response playbook (the same content published at /docs/playbooks) and returns its concrete, ordered steps, severity tier, real-incident references, and prevention tips — not just a link. Pass the exact `rule` string(s) a prior finding already returned (batch up to 10 in one call to cover a whole findings array; duplicates resolving to the same playbook are deduplicated) or an `id` to look up a specific playbook by slug directly. Each matched rule also gets its own short situationNote explaining specifically what that rule caught — so a batch of several different rules landing on the same playbook does not read as identical, repeated boilerplate. An unrecognized rule or id is not an error — it comes back with matched:false and a note, since a low-severity or baseline-only finding (e.g. analyze_install_script's lifecycle-present) legitimately has no dedicated playbook.", "inputSchema": { "$schema": "http://json-schema.org/draft-07/schema#", "additionalProperties": false, "properties": { "id": { "description": "A playbook slug to look up directly, e.g. \"postinstall-binary\" — see /docs/playbooks", "maxLength": 64, "minLength": 1, "type": "string" }, "rules": { "description": "1-10 exact `rule` values copied from findings already returned by analyze_install_script/check_maintainer_changes/check_package_provenance", "items": { "maxLength": 64, "minLength": 1, "type": "string" }, "maxItems": 10, "minItems": 1, "type": "array" } }, "type": "object" }, "name": "get_remediation_playbook", "outputSchema": { "$schema": "http://json-schema.org/draft-07/schema#", "additionalProperties": false, "properties": { "matches": { "items": { "additionalProperties": false, "properties": { "matched": { "type": "boolean" }, "note": { "type": "string" }, "playbookId": { "type": [ "string", "null" ] }, "requestedId": { "type": [ "string", "null" ] }, "rule": { "type": [ "string", "null" ] }, "situationNote": { "type": [ "string", "null" ] } }, "required": [ "rule", "requestedId", "matched", "playbookId", "situationNote", "note" ], "type": "object" }, "type": "array" }, "playbooks": { "items": { "additionalProperties": false, "properties": { "id": { "type": "string" }, "npmscanUrl": { "type": "string" }, "preventionTips": { "items": { "type": "string" }, "type": "array" }, "references": { "items": { "additionalProperties": false, "properties": { "kind": { "enum": [ "incident", "reading" ], "type": "string" }, "label": { "type": "string" }, "url": { "type": "string" } }, "required": [ "label", "url", "kind" ], "type": "object" }, "type": "array" }, "severity": { "enum": [ "critical", "high", "moderate", "low" ], "type": "string" }, "steps": { "items": { "additionalProperties": false, "properties": { "text": { "type": "string" }, "why": { "type": [ "string", "null" ] } }, "required": [ "text", "why" ], "type": "object" }, "type": "array" }, "title": { "type": "string" } }, "required": [ "id", "title", "severity", "steps", "references", "preventionTips", "npmscanUrl" ], "type": "object" }, "type": "array" } }, "required": [ "matches", "playbooks" ], "type": "object" } }, { "description": "Given a batch of vulnerability findings already flagged elsewhere (e.g. from batch_query_vulnerabilities, analyze_transitive_dependencies, or query_vulnerabilities across a whole package.json/lockfile audit), ranks them by what to actually fix first. Combines CISA KEV status (confirmed active exploitation in the wild — an automatic top-priority override), FIRST.org EPSS (probability of exploitation in the next 30 days — the primary ranking signal, since it measures likelihood rather than just impact), and severity (a secondary/fallback signal, most useful for a GHSA finding with no CVE alias) into one composite score and a remove-now/patch-now/patch-soon/scheduled/monitor tier per finding. A finding with `findingType: \"malware\"` (or a MAL-* advisoryId, auto-detected even when findingType is omitted) always lands in `remove-now` — the tier above patch-now — regardless of score: a confirmed-malicious package needs removal/replacement, not an \"urgent patch\" (there often isn't a fixed version to patch TO), and EPSS/severity don't meaningfully apply to \"how malicious\" the way they do to a genuine vulnerability. When EPSS data isn't available at all (no CVE id, or a real CVE that just isn't in FIRST.org's database) severity becomes the sole usable signal and is scored on its own scale instead of being diluted to a ~10% sliver of the composite — a bare CRITICAL/HIGH GHSA finding with no CVE alias lands in patch-soon/scheduled, not monitor, the way it would if severity kept its normal secondary weight with nothing else to combine it with. This does NOT re-query OSV/NVD itself — pass in the severity/CVE id findings other tools already returned; it only adds KEV/EPSS enrichment (the same data get_cve returns per-CVE) and ranks the batch. A CVE id shared by multiple findings in the same call is only looked up once. The tier is a fix-ORDER ranking across a backlog, not a severity verdict or a merge/admission gate: a CRITICAL CVE with low EPSS and no KEV listing can legitimately land in `monitor` (minimist's CVE-2021-44906 has ranked there). Do not report a `monitor`/`scheduled` finding as \"low severity\", and when deciding whether a change that INTRODUCES a vulnerability is acceptable, judge it on severity, not on this tier.", "inputSchema": { "$schema": "http://json-schema.org/draft-07/schema#", "additionalProperties": false, "properties": { "findings": { "description": "1-200 previously-flagged vulnerability findings to rank", "items": { "additionalProperties": false, "properties": { "advisoryId": { "description": "GHSA/OSV advisory id, passed through unchanged for reference — a MAL-* id is auto-detected as malware even without findingType set", "maxLength": 64, "type": "string" }, "currentVersion": { "description": "Currently installed version, passed through unchanged", "maxLength": 128, "type": "string" }, "cveId": { "description": "Exact CVE ID, e.g. \"CVE-2024-12345\" — enables CISA KEV + FIRST.org EPSS enrichment. Omit for a GHSA advisory with no CVE alias; the finding is still ranked by severity alone.", "pattern": "^CVE-\\d{4}-\\d{4,}$", "type": "string" }, "findingType": { "description": "\"malware\" forces the remove-now tier regardless of score/CVE/severity — set this (or pass a MAL-* advisoryId) for a confirmed-malicious package. Omit for an ordinary vulnerability finding.", "enum": [ "malware", "vulnerability", "supply-chain", "install-script" ], "type": "string" }, "fixedVersion": { "description": "Version that fixes this finding, passed through unchanged", "maxLength": 128, "type": "string" }, "packageName": { "description": "npm package name this finding was flagged against", "maxLength": 214, "minLength": 1, "type": "string" }, "severity": { "description": "Severity from the source finding (OSV/GHSA: CRITICAL/HIGH/MODERATE/LOW, or NVD: CRITICAL/HIGH/MEDIUM/LOW) — used as a fallback/secondary signal", "maxLength": 32, "type": "string" } }, "required": [ "packageName" ], "type": "object" }, "maxItems": 200, "minItems": 1, "type": "array" } }, "required": [ "findings" ], "type": "object" }, "name": "prioritize_remediation", "outputSchema": { "$schema": "http://json-schema.org/draft-07/schema#", "additionalProperties": false, "properties": { "ranked": { "items": { "additionalProperties": false, "properties": { "advisoryId": { "type": [ "string", "null" ] }, "currentVersion": { "type": [ "string", "null" ] }, "cveId": { "type": [ "string", "null" ] }, "cveNpmscanUrl": { "type": [ "string", "null" ] }, "epss": { "anyOf": [ { "additionalProperties": false, "properties": { "date": { "type": "string" }, "percentile": { "type": "number" }, "score": { "type": "number" } }, "required": [ "score", "percentile", "date" ], "type": "object" }, { "type": "null" } ] }, "findingType": { "enum": [ "malware", "vulnerability", "supply-chain", "install-script" ], "type": "string" }, "fixedVersion": { "type": [ "string", "null" ] }, "kev": { "anyOf": [ { "additionalProperties": false, "properties": { "dateAdded": { "type": "string" }, "dueDate": { "type": "string" }, "knownRansomwareCampaignUse": { "type": "string" }, "requiredAction": { "type": "string" } }, "required": [ "dateAdded", "dueDate", "knownRansomwareCampaignUse", "requiredAction" ], "type": "object" }, { "type": "null" } ] }, "npmscanUrl": { "type": "string" }, "packageName": { "type": "string" }, "rank": { "type": "number" }, "reason": { "type": "string" }, "score": { "type": "number" }, "severity": { "type": [ "string", "null" ] }, "tier": { "enum": [ "remove-now", "patch-now", "patch-soon", "scheduled", "monitor" ], "type": "string" } }, "required": [ "rank", "packageName", "cveId", "advisoryId", "currentVersion", "fixedVersion", "severity", "kev", "epss", "score", "tier", "findingType", "reason", "npmscanUrl", "cveNpmscanUrl" ], "type": "object" }, "type": "array" }, "summary": { "additionalProperties": false, "properties": { "kevListedCount": { "type": "number" }, "monitor": { "type": "number" }, "patchNow": { "type": "number" }, "patchSoon": { "type": "number" }, "removeNow": { "type": "number" }, "scheduled": { "type": "number" } }, "required": [ "removeNow", "patchNow", "patchSoon", "scheduled", "monitor", "kevListedCount" ], "type": "object" }, "totalFindings": { "type": "number" }, "uniqueCveCount": { "type": "number" } }, "required": [ "totalFindings", "uniqueCveCount", "summary", "ranked" ], "type": "object" } }, { "description": "Query OSV.dev for known vulnerabilities affecting an npm package, optionally scoped to one exact version (e.g. to check whether a version pinned in a lockfile is safe). Returns isVulnerable and highestSeverity as a direct answer, plus each finding's severity, a plain-language summary, CVE aliases, and the fixedVersion to upgrade to — not a raw advisory dump. Also cross-checks the name/version against the npm registry: isVulnerable:false on a package that does not actually exist there (typo, wrong ecosystem) would otherwise look identical to a genuinely clean result — see packageExists/existenceCheckNote. A name or version not found on the registry does NOT discard already-fetched OSV data or short-circuit into an error: OSV/GHSA advisory data is independent of the package's current registry listing, and a package/version pulled from npm for being malicious (unpublished/yanked) is exactly the case where real vulnerability data must still be reported, not hidden behind a 404. Use before recommending, installing, or upgrading a package.", "inputSchema": { "$schema": "http://json-schema.org/draft-07/schema#", "additionalProperties": false, "properties": { "ecosystem": { "description": "OSV ecosystem, default \"npm\"", "maxLength": 32, "type": "string" }, "name": { "description": "npm package name", "maxLength": 214, "minLength": 1, "type": "string" }, "version": { "description": "Optional exact version to narrow results, e.g. to check one version pinned in a lockfile. For the npm ecosystem a dist-tag such as \"latest\" is also accepted and resolved to its exact version first; semver ranges like \"^4.17.0\" are rejected.", "maxLength": 128, "type": "string" } }, "required": [ "name" ], "type": "object" }, "name": "query_vulnerabilities", "outputSchema": { "$schema": "http://json-schema.org/draft-07/schema#", "additionalProperties": false, "properties": { "existenceCheckNote": { "type": [ "string", "null" ] }, "highestSeverity": { "type": [ "string", "null" ] }, "isVulnerable": { "type": "boolean" }, "npmscanUrl": { "type": "string" }, "package": { "type": "string" }, "packageExists": { "type": [ "boolean", "null" ] }, "version": { "type": [ "string", "null" ] }, "vulnerabilities": { "items": { "additionalProperties": false, "properties": { "aliases": { "items": { "type": "string" }, "type": "array" }, "fixedVersion": { "type": [ "string", "null" ] }, "id": { "type": "string" }, "npmscanUrl": { "type": "string" }, "publishedAt": { "type": [ "string", "null" ] }, "severity": { "type": [ "string", "null" ] }, "summary": { "type": [ "string", "null" ] } }, "required": [ "id", "summary", "severity", "aliases", "publishedAt", "fixedVersion", "npmscanUrl" ], "type": "object" }, "type": "array" } }, "required": [ "package", "version", "npmscanUrl", "packageExists", "existenceCheckNote", "isVulnerable", "highestSeverity", "vulnerabilities" ], "type": "object" } }, { "description": "Search the npm registry by name or keywords. Each result includes its current weekly/monthly download counts, dependentsCount (how many other npm packages depend on it), topPackagesRank (position among npmscan's own top-100k-by-downloads snapshot — not live, but a second independent popularity signal), and deterministic (not model-generated) popularityTier/maintenanceTier labels — a package matching the query with a 'very-low' popularityTier, zero dependents, or a 'stale' maintenanceTier is very likely an abandoned, copy-paste, or squatted package, not a real contender, regardless of how relevant its name/description look. A result may also carry possibleTyposquatOf — set when its name is one typo away (e.g. 'raect' vs 'react') from a top-5,000 package while itself having very low popularity; treat that as a red flag to call out explicitly, not silently filter. Use these (not name recognition or the package's own README) to judge which candidates are actually established, and call get_package on your shortlist for install-script risk, TypeScript support, and GitHub stars before recommending one. Includes a link to each package's full npmscan.com risk/analysis page.", "inputSchema": { "$schema": "http://json-schema.org/draft-07/schema#", "additionalProperties": false, "properties": { "limit": { "description": "Max results to return (default 20, max 50)", "maximum": 50, "minimum": 1, "type": "integer" }, "query": { "description": "Search text, e.g. a package name or keywords", "maxLength": 64, "minLength": 2, "type": "string" } }, "required": [ "query" ], "type": "object" }, "name": "search_packages", "outputSchema": { "$schema": "http://json-schema.org/draft-07/schema#", "additionalProperties": false, "properties": { "query": { "type": "string" }, "results": { "items": { "additionalProperties": false, "properties": { "dependentsCount": { "type": [ "number", "null" ] }, "description": { "type": [ "string", "null" ] }, "keywords": { "items": { "type": "string" }, "type": "array" }, "lastPublished": { "type": [ "string", "null" ] }, "links": { "additionalProperties": false, "properties": { "homepage": { "type": "string" }, "npm": { "type": "string" }, "repository": { "type": "string" } }, "type": "object" }, "maintenanceTier": { "enum": [ "active", "aging", "stale", "unknown" ], "type": "string" }, "monthlyDownloads": { "type": [ "number", "null" ] }, "name": { "type": "string" }, "npmscanUrl": { "type": "string" }, "popularityTier": { "enum": [ "very-high", "high", "moderate", "low", "very-low", "unknown" ], "type": "string" }, "possibleTyposquatOf": { "anyOf": [ { "additionalProperties": false, "properties": { "name": { "type": "string" }, "rank": { "type": "number" } }, "required": [ "name", "rank" ], "type": "object" }, { "type": "null" } ] }, "publisher": { "type": [ "string", "null" ] }, "topPackagesRank": { "type": [ "number", "null" ] }, "version": { "type": "string" }, "weeklyDownloads": { "type": [ "number", "null" ] } }, "required": [ "name", "version", "description", "keywords", "publisher", "lastPublished", "links", "npmscanUrl", "weeklyDownloads", "monthlyDownloads", "dependentsCount", "topPackagesRank", "popularityTier", "maintenanceTier", "possibleTyposquatOf" ], "type": "object" }, "type": "array" }, "total": { "type": "number" } }, "required": [ "query", "total", "results" ], "type": "object" } }, { "description": "Given a package and a current/target version, tells you whether that specific upgrade is a safe patch/minor bump or a likely-breaking major bump, before you actually run npm install. Natural follow-up to prioritize_remediation: pass its `packageName` + `currentVersion` + `fixedVersion` straight in to check whether the suggested fix is a drop-in patch or something that needs a review pass. Classifies the jump by semver (major/minor/patch/prerelease), treats a minor bump between two pre-1.0 (0.x) versions as breaking-risk per semver's own \"the API isn't stable yet\" convention, and flags skipping over multiple major versions in one jump (e.g. 2.x -> 5.x) as needing a per-major changelog review rather than just a diff against the final target. Beyond semver, it also checks the registry for real signals the version number alone won't tell you: whether the target version is marked deprecated, whether it introduces a preinstall/install/postinstall/prepare lifecycle script the current version didn't have, whether it tightens its engines.node requirement, and whether it is itself a prerelease. Finally it batch-checks both versions against OSV.dev and reports vulnerabilityDelta (introduced/fixed/still-vulnerable/still-clean) — catching the case where a suggested \"fix\" version doesn't actually clear every open CVE. Combines all of this into one riskTier (safe/low-risk/review-recommended/breaking-change-likely/unknown) with a reasons list explaining exactly which signals drove it. This does NOT read the package's changelog/release notes or scan the target tarball's source diff for actual breaking API usage — it's a fast, deterministic pre-check, not a substitute for reading the release notes on a flagged major bump. For simulating more than one upgrade at once — e.g. every \"patch-now\" finding prioritize_remediation just ranked — pass `packages: [{packageName, currentVersion, targetVersion?}, ...]` (1-100 items) instead of `packageName`/`currentVersion`/`targetVersion`, not both. Registry fetches are deduped/parallelized and all OSV checks for the whole batch run as one call, so this is not the same cost as N single-item calls. A package that can't be resolved at all (typo, unpublished, registry error) shows up as its own `results` entry with `fetchError` set instead of failing the whole batch.", "inputSchema": { "$schema": "http://json-schema.org/draft-07/schema#", "additionalProperties": false, "properties": { "currentVersion": { "description": "Currently installed version — an exact version (e.g. \"4.17.20\"), a semver range (e.g. \"^4.17.0\"), or a dist-tag. Required when `packageName` is used.", "maxLength": 128, "minLength": 1, "type": "string" }, "packageName": { "description": "Exact npm package name, e.g. \"lodash\" or \"@scope/name\". Use this (with currentVersion) OR `packages`, not both.", "maxLength": 214, "minLength": 1, "type": "string" }, "packages": { "description": "Batch of upgrades to simulate (1-100 items), each mirroring the single-item packageName/currentVersion/targetVersion fields. Use this OR packageName/currentVersion, not both. Natural pairing with prioritize_remediation: pass its ranked findings straight in as one call instead of one simulate_dependency_upgrade call per finding.", "items": { "additionalProperties": false, "properties": { "currentVersion": { "description": "Currently installed version — an exact version, a semver range, or a dist-tag", "maxLength": 128, "minLength": 1, "type": "string" }, "packageName": { "description": "Exact npm package name, e.g. \"lodash\" or \"@scope/name\"", "maxLength": 214, "minLength": 1, "type": "string" }, "targetVersion": { "description": "Version to simulate upgrading to — exact version, range, or dist-tag. Omit to use the registry's \"latest\" dist-tag.", "maxLength": 128, "minLength": 1, "type": "string" } }, "required": [ "packageName", "currentVersion" ], "type": "object" }, "maxItems": 100, "minItems": 1, "type": "array" }, "targetVersion": { "description": "Version to simulate upgrading to — exact version, range, or dist-tag (e.g. the fixedVersion a prioritize_remediation finding named). Omit to use the registry's \"latest\" dist-tag. Only applies to the single-item `packageName` form.", "maxLength": 128, "minLength": 1, "type": "string" } }, "type": "object" }, "name": "simulate_dependency_upgrade", "outputSchema": { "$schema": "http://json-schema.org/draft-07/schema#", "additionalProperties": false, "properties": { "batchSummary": { "additionalProperties": false, "properties": { "fetchFailedCount": { "type": "number" }, "riskTierCounts": { "additionalProperties": false, "properties": { "breakingChangeLikely": { "type": "number" }, "lowRisk": { "type": "number" }, "reviewRecommended": { "type": "number" }, "safe": { "type": "number" }, "unknown": { "type": "number" } }, "required": [ "safe", "lowRisk", "reviewRecommended", "breakingChangeLikely", "unknown" ], "type": "object" }, "totalRequested": { "type": "number" }, "vulnQueryFailedCount": { "type": "number" } }, "required": [ "totalRequested", "fetchFailedCount", "riskTierCounts", "vulnQueryFailedCount" ], "type": "object" }, "currentIsVulnerable": { "type": [ "boolean", "null" ] }, "currentVersionNote": { "type": [ "string", "null" ] }, "direction": { "enum": [ "upgrade", "downgrade", "same", "unresolved" ], "type": "string" }, "engineChange": { "anyOf": [ { "additionalProperties": false, "properties": { "after": { "type": [ "string", "null" ] }, "before": { "type": [ "string", "null" ] }, "tightened": { "type": "boolean" } }, "required": [ "before", "after", "tightened" ], "type": "object" }, { "type": "null" } ] }, "installScriptIntroduced": { "type": [ "boolean", "null" ] }, "isBreakingBySemver": { "type": [ "boolean", "null" ] }, "majorVersionsSkipped": { "type": [ "number", "null" ] }, "npmscanUrl": { "type": "string" }, "packageName": { "type": "string" }, "reasons": { "items": { "type": "string" }, "type": "array" }, "requestedCurrentVersion": { "type": "string" }, "requestedTargetVersion": { "type": "string" }, "resolvedCurrentVersion": { "type": [ "string", "null" ] }, "resolvedTargetVersion": { "type": [ "string", "null" ] }, "results": { "items": { "additionalProperties": false, "properties": { "currentIsVulnerable": { "type": [ "boolean", "null" ] }, "currentVersionNote": { "type": [ "string", "null" ] }, "direction": { "enum": [ "upgrade", "downgrade", "same", "unresolved" ], "type": "string" }, "engineChange": { "anyOf": [ { "additionalProperties": false, "properties": { "after": { "type": [ "string", "null" ] }, "before": { "type": [ "string", "null" ] }, "tightened": { "type": "boolean" } }, "required": [ "before", "after", "tightened" ], "type": "object" }, { "type": "null" } ] }, "fetchError": { "type": [ "string", "null" ] }, "installScriptIntroduced": { "type": [ "boolean", "null" ] }, "isBreakingBySemver": { "type": [ "boolean", "null" ] }, "majorVersionsSkipped": { "type": [ "number", "null" ] }, "npmscanUrl": { "type": "string" }, "packageName": { "type": "string" }, "reasons": { "items": { "type": "string" }, "type": "array" }, "requestedCurrentVersion": { "type": "string" }, "requestedTargetVersion": { "type": "string" }, "resolvedCurrentVersion": { "type": [ "string", "null" ] }, "resolvedTargetVersion": { "type": [ "string", "null" ] }, "riskTier": { "enum": [ "safe", "low-risk", "review-recommended", "breaking-change-likely", "unknown" ], "type": "string" }, "semverBump": { "anyOf": [ { "enum": [ "major", "premajor", "minor", "preminor", "patch", "prepatch", "prerelease" ], "type": "string" }, { "type": "null" } ] }, "targetDeprecated": { "type": [ "string", "null" ] }, "targetIsPrerelease": { "type": [ "boolean", "null" ] }, "targetIsVulnerable": { "type": [ "boolean", "null" ] }, "targetVersionNote": { "type": [ "string", "null" ] }, "targetVulnerabilities": { "items": { "$ref": "#/properties/targetVulnerabilities/items" }, "type": "array" }, "verdict": { "type": "string" }, "vulnerabilityDelta": { "anyOf": [ { "enum": [ "introduced", "fixed", "still-vulnerable", "still-clean", "unknown" ], "type": "string" }, { "type": "null" } ] }, "zeroMajorNote": { "type": [ "string", "null" ] } }, "required": [ "packageName", "npmscanUrl", "requestedCurrentVersion", "requestedTargetVersion", "resolvedCurrentVersion", "resolvedTargetVersion", "currentVersionNote", "targetVersionNote", "direction", "semverBump", "isBreakingBySemver", "majorVersionsSkipped", "zeroMajorNote", "targetIsPrerelease", "targetDeprecated", "installScriptIntroduced", "engineChange", "currentIsVulnerable", "targetIsVulnerable", "vulnerabilityDelta", "targetVulnerabilities", "riskTier", "reasons", "verdict", "fetchError" ], "type": "object" }, "type": "array" }, "riskTier": { "enum": [ "safe", "low-risk", "review-recommended", "breaking-change-likely", "unknown" ], "type": "string" }, "semverBump": { "anyOf": [ { "enum": [ "major", "premajor", "minor", "preminor", "patch", "prepatch", "prerelease" ], "type": "string" }, { "type": "null" } ] }, "targetDeprecated": { "type": [ "string", "null" ] }, "targetIsPrerelease": { "type": [ "boolean", "null" ] }, "targetIsVulnerable": { "type": [ "boolean", "null" ] }, "targetVersionNote": { "type": [ "string", "null" ] }, "targetVulnerabilities": { "items": { "additionalProperties": false, "properties": { "aliases": { "items": { "type": "string" }, "type": "array" }, "fixedVersion": { "type": [ "string", "null" ] }, "id": { "type": "string" }, "npmscanUrl": { "type": "string" }, "publishedAt": { "type": [ "string", "null" ] }, "severity": { "type": [ "string", "null" ] }, "summary": { "type": [ "string", "null" ] } }, "required": [ "id", "summary", "severity", "aliases", "publishedAt", "fixedVersion", "npmscanUrl" ], "type": "object" }, "type": "array" }, "verdict": { "type": "string" }, "vulnerabilityDelta": { "anyOf": [ { "enum": [ "introduced", "fixed", "still-vulnerable", "still-clean", "unknown" ], "type": "string" }, { "type": "null" } ] }, "zeroMajorNote": { "type": [ "string", "null" ] } }, "type": "object" } }, { "description": "Given a package that looks deprecated, vulnerable, abandoned, or suspicious, suggest better-maintained alternatives in the same category. This tool first checks the source package's own latest-version health (deprecation, latest-version OSV verdict, popularity/maintenance tiers, typosquat flag), then combines maintainer-provided deprecation hints with deterministic npm search-based category matching. It ranks candidates using category overlap plus search_packages-style popularity/maintenance signals, filters out typosquats and weak/stale contenders, and returns a short list with plain-language whySuggested notes. A candidate is also never suggested if it's deprecated, has a confirmed HIGH/CRITICAL OSV vulnerability, or its own OSV check itself failed (network/timeout/upstream outage) — an unverifiable candidate is excluded the same as a confirmed-bad one, not defaulted to 'looks fine', since this tool's entire purpose is not recommending something dangerous. Best for turning a 'don't use this package' warning into an actionable replacement shortlist. If the OSV.dev vulnerability check fails for the SOURCE package (as opposed to a candidate, which gets excluded per above), source.isLatestVersionVulnerable comes back `false` only because the field has to be a boolean — source.vulnerabilityCheckFailed:true is the real signal there, and means that safe/not-safe answer is unknown, not confirmed clean.", "inputSchema": { "$schema": "http://json-schema.org/draft-07/schema#", "additionalProperties": false, "properties": { "limit": { "description": "Max suggestions to return (default 5, max 10)", "maximum": 10, "minimum": 1, "type": "integer" }, "name": { "description": "Exact npm package name, e.g. \"request\" or \"node-sass\"", "maxLength": 214, "minLength": 1, "type": "string" }, "reason": { "description": "Optional reason to bias filtering/ranking", "enum": [ "deprecated", "vulnerable", "abandoned", "typosquat", "general" ], "type": "string" } }, "required": [ "name" ], "type": "object" }, "name": "suggest_alternative", "outputSchema": { "$schema": "http://json-schema.org/draft-07/schema#", "additionalProperties": false, "properties": { "categoryTokens": { "items": { "type": "string" }, "type": "array" }, "confidence": { "enum": [ "high", "medium", "low" ], "type": "string" }, "nonPackageAlternatives": { "items": { "type": "string" }, "type": "array" }, "reason": { "enum": [ "deprecated", "vulnerable", "abandoned", "typosquat", "general" ], "type": "string" }, "searchedQueries": { "items": { "type": "string" }, "type": "array" }, "source": { "additionalProperties": false, "properties": { "deprecated": { "type": [ "string", "null" ] }, "highestSeverity": { "type": [ "string", "null" ] }, "isLatestVersionVulnerable": { "type": "boolean" }, "latestVersion": { "type": [ "string", "null" ] }, "maintenanceTier": { "enum": [ "active", "aging", "stale", "unknown" ], "type": "string" }, "name": { "type": "string" }, "npmscanUrl": { "type": "string" }, "popularityTier": { "enum": [ "very-high", "high", "moderate", "low", "very-low", "unknown" ], "type": "string" }, "possibleTyposquatOf": { "anyOf": [ { "additionalProperties": false, "properties": { "name": { "type": "string" }, "rank": { "type": "number" } }, "required": [ "name", "rank" ], "type": "object" }, { "type": "null" } ] }, "vulnerabilityCheckFailed": { "type": "boolean" } }, "required": [ "name", "latestVersion", "deprecated", "isLatestVersionVulnerable", "vulnerabilityCheckFailed", "highestSeverity", "popularityTier", "maintenanceTier", "possibleTyposquatOf", "npmscanUrl" ], "type": "object" }, "suggestions": { "items": { "additionalProperties": false, "properties": { "categoryOverlap": { "items": { "type": "string" }, "type": "array" }, "dependentsCount": { "type": [ "number", "null" ] }, "deprecated": { "type": [ "string", "null" ] }, "description": { "type": [ "string", "null" ] }, "githubStars": { "type": [ "number", "null" ] }, "hasBuiltInTypes": { "type": "boolean" }, "highestSeverity": { "type": [ "string", "null" ] }, "isLatestVersionVulnerable": { "type": "boolean" }, "maintenanceTier": { "enum": [ "active", "aging", "stale", "unknown" ], "type": "string" }, "matchedQueries": { "items": { "type": "string" }, "type": "array" }, "name": { "type": "string" }, "npmscanUrl": { "type": "string" }, "popularityTier": { "enum": [ "very-high", "high", "moderate", "low", "very-low", "unknown" ], "type": "string" }, "topPackagesRank": { "type": [ "number", "null" ] }, "version": { "type": [ "string", "null" ] }, "vulnerabilityCheckFailed": { "type": "boolean" }, "weeklyDownloads": { "type": [ "number", "null" ] }, "whySuggested": { "type": "string" } }, "required": [ "name", "version", "description", "npmscanUrl", "weeklyDownloads", "dependentsCount", "githubStars", "hasBuiltInTypes", "deprecated", "isLatestVersionVulnerable", "vulnerabilityCheckFailed", "highestSeverity", "popularityTier", "maintenanceTier", "topPackagesRank", "categoryOverlap", "matchedQueries", "whySuggested" ], "type": "object" }, "type": "array" } }, "required": [ "source", "reason", "confidence", "categoryTokens", "searchedQueries", "nonPackageAlternatives", "suggestions" ], "type": "object" } } ] }
Verify it yourselfcurl -s https://api.teppi.xyz/v1/evidence/sha256:5b4b70d16f42271e860a353a2852d230c1270482d92ddd1aaf64d64b76e0b9fc | sha256sum