Skip to main content
Glama
OSV Dependency Vulnerability Check MCP Server

OSV Dependency Vulnerability Check MCP Server

Dependency Vulnerability Check for Agents

Checks npm, PyPI, Go, Maven and other dependencies (or a lockfile) against OSV.dev, for $0.50 per 1,000 packages plus $1.50 per 1,000 vulnerability rows. Error and warning rows are free. Example: a 300-package lockfile with 12 vulnerability rows costs 300 × $0.0005 + 12 × $0.0015 = $0.17, plus Apify's $0.00005 Actor-start fee.

Fairquery Apify Actor that checks open-source dependencies against the free OSV.dev vulnerability database and returns agent-ready rows: one per package (vulnerable or not) and one per vulnerability (CVE, CVSS, severity, affected/fixed versions, references).

When to use this Actor (LLM / tool selection)

Use it when an agent needs to:

  • Answer "is lodash@4.17.20 / django==3.2.0 vulnerable, and to what version should I upgrade?"

  • Audit a pasted package.json, package-lock.json, requirements.txt, or go.mod

  • Filter to HIGH/CRITICAL issues only for a CI gate or PR comment

  • Map OSV / GHSA / PYSEC / GO IDs to CVE IDs and CVSS scores

Supported ecosystems: everything OSV supports (npm, PyPI, Go, Maven, crates.io, RubyGems, NuGet, Packagist, Pub, Hex, …). Aliases like pip, golang, cargo, composer are accepted.

Do not use it for: reachability analysis, license checks, container/OS image scanning, or unpinned version ranges (it checks exact versions).

Related MCP server: DepsGuard MCP

Data sources

Resource

URL

Batch query

POST https://api.osv.dev/v1/querybatch

Vulnerability detail

GET https://api.osv.dev/v1/vulns/{id}

Free, no API key. Retries on 429/5xx with exponential backoff; detail fetches are cached and run 8 in parallel.

Input

Field

Type

Default

Description

packages

{ecosystem,name,version}[]

[]

Exact package versions to check

manifestText

string

—

Raw package.json / package-lock.json (v1–v3) / requirements.txt / go.mod

manifestType

enum

auto

Force the manifest format

minSeverity

ALL|LOW|MEDIUM|HIGH|CRITICAL

ALL

Minimum severity of emitted vulnerability rows

includeUnknownSeverity

bool

true

Keep vulns with no severity data when filtering

includeDevDependencies

bool

true

Include dev deps from npm manifests

dedupeAliases

bool

true

Collapse GHSA/PYSEC/GO records describing the same issue into one row (GHSA preferred)

maxPackages

int

1000

Safety cap on unique packages

Manifest notes: package.json ranges are approximated to their lower bound (^4.17.20 → 4.17.20) and a RANGE_APPROXIMATED warning row is emitted — prefer the lockfile. requirements.txt lines without == pins are skipped with a VERSION_NOT_PINNED warning (use pip freeze).

Example input

{
  "packages": [
    { "ecosystem": "npm", "name": "lodash", "version": "4.17.20" },
    { "ecosystem": "PyPI", "name": "django", "version": "3.2.0" }
  ],
  "minSeverity": "HIGH"
}

Output

Every row has schema_version (1.0.0), type (package | vulnerability | error), source_url (OSV API URL), and checked_at.

Package row

{
  "type": "package", "ecosystem": "npm", "name": "lodash", "version": "4.17.20",
  "purl": "pkg:npm/lodash@4.17.20", "vulnerable": true, "vuln_count": 3, "vuln_count_total": 5,
  "vuln_ids": ["GHSA-r5fr-rjxr-66jc", "GHSA-35jh-r3h4-6jhm", "GHSA-29mw-wpgm-hmr9"],
  "max_severity": "HIGH", "max_cvss_score": 8.1,
  "fixed_versions": ["4.18.0", "4.17.21"], "recommended_version": "4.18.0"
}

vuln_count is after the severity filter and alias de-duplication; vuln_count_total is the raw OSV count. recommended_version is the smallest version that fixes every emitted vuln (best-effort, null if some vuln has no fix).

Vulnerability row

Fields: id, package_name, package_version, aliases, cve_ids, summary, details (≤2000 chars), severity, cvss_score (computed CVSS v3 base score), cvss_vector, cvss_version, severity_source (cvss | database_specific | alias | none), severity_alias_id, cwe_ids, affected_ranges[] (introduced/fixed/last_affected), affected_versions_sample, fixed_versions, published, modified, references[], osv_url.

Severity: CVSS v3 base score → NONE/LOW/MEDIUM/HIGH/CRITICAL; otherwise the advisory's label (GHSA MODERATE → MEDIUM); otherwise borrowed from a GHSA alias; otherwise UNKNOWN (common for some Go advisories).

Error / warning rows (machine-readable)

{ "type": "error", "code": "OSV_VULN_FETCH_FAILED", "message": "OSV /vulns/GHSA-… -> HTTP 503", "retryable": true, "vuln_id": "GHSA-…" }

Codes: INPUT_EMPTY, INVALID_PACKAGE, MANIFEST_UNDETECTED, MANIFEST_PARSE_FAILED, MAX_PACKAGES_EXCEEDED, OSV_QUERYBATCH_FAILED, OSV_VULN_FETCH_FAILED; warnings (with context.severity = "warning"): RANGE_APPROXIMATED, VERSION_NOT_PINNABLE, VERSION_NOT_PINNED.

Run summary

Key-value store record RUN_SUMMARY: packages checked/vulnerable, vulnerabilities emitted/filtered/deduplicated, severity counts, OSV request count, echoed input.

Pricing

Event

Price

When

package-checked

$0.0005

Each package row (vulnerable or clean)

vulnerability-found

$0.0015

Each emitted vulnerability row (after the severity filter and alias de-duplication)

apify-actor-start

$0.00005

Once per run, per GB of memory (Apify default event)

Error and warning rows are never charged.

Worked example: a 300-package lockfile with 12 vulnerability rows: 300 × $0.0005 + 12 × $0.0015 = $0.15 + $0.018 = $0.17, plus $0.00005. Set minSeverity: "HIGH" to emit (and pay for) only high and critical rows.

To cap spend, set a maximum cost per run in the run options; the Actor stops cleanly at the limit. maxPackages caps unique packages per run. Prices are from the Store pricing tab (October 2026).

Memory / runtime

Default 128 MB. HTTP only (no browser). A 2-package run finishes in about 5–10 s; time grows with the number of advisories to fetch.

MCP / Apify tools

Call from agents via Apify MCP:

  1. Connect an MCP client to https://mcp.apify.com with your Apify token.

  2. Run actor fairquery/osv-dependency-vulnerability-check.

  3. Read the default dataset (filter type == "vulnerability") and the RUN_SUMMARY record.

{
  "actor": "fairquery/osv-dependency-vulnerability-check",
  "input": { "manifestText": "django==3.2.0\nrequests==2.25.0", "minSeverity": "HIGH" }
}

Local stdio MCP server

This repo also ships a stdio MCP server (TypeScript, @modelcontextprotocol/sdk) under mcp/. It exposes three tools: check_dependency_vulnerabilities (runs this Actor through the Apify API), the free get_vulnerability_details (direct OSV.dev lookup by advisory ID) and the free list_package_vulnerabilities (all OSV.dev advisories recorded for one package across all versions, newest first, paged; it gives no per-version verdict). The two free tools call api.osv.dev directly and need no token. initialize and tools/list work without a token; check_dependency_vulnerabilities requires APIFY_TOKEN (calls are billed per the pricing above).

cd mcp && npm install && npm run build
node scripts/smoke-test.mjs          # initialize + tools/list, no token
APIFY_TOKEN=... node scripts/smoke-test.mjs --call   # real tool call

Claude Desktop / Cursor config:

{
  "mcpServers": {
    "fairquery-osv": {
      "command": "node",
      "args": ["/path/to/osv-dependency-vulnerability-check/mcp/dist/index.js"],
      "env": { "APIFY_TOKEN": "<your Apify token>" }
    }
  }
}

Docker: docker build -t fairquery-osv-mcp . (the repo-root Dockerfile builds this MCP server and is what Glama uses; the Apify Actor image is built from .actor/Dockerfile). glama.json lists fairquery as maintainer.

Troubleshooting

Symptom

Cause and fix

Run fails at once with INPUT_EMPTY

Neither packages nor manifestText was given. The sample packages in the Console form are prefill only and are not sent with API calls.

RANGE_APPROXIMATED warnings

package.json ranges were reduced to their lower bound. Paste package-lock.json instead for exact versions.

VERSION_NOT_PINNED warnings

requirements.txt lines without == are skipped. Use pip freeze output.

MANIFEST_UNDETECTED / MANIFEST_PARSE_FAILED

Set manifestType explicitly, and paste the raw file content (not a path or URL).

OSV_QUERYBATCH_FAILED / OSV_VULN_FETCH_FAILED

OSV.dev was unavailable after retries (retryable: true). These rows are free; re-run later.

Severity UNKNOWN

Some advisories (often Go) publish no CVSS or label. Keep includeUnknownSeverity on so they are not filtered out.

FAQ

Which ecosystems are supported?

Everything OSV.dev supports: npm, PyPI, Go, Maven, crates.io, RubyGems, NuGet, Packagist, Pub, Hex and more.

Does no result mean my package is safe?

No. It means OSV.dev has no matching advisory for that exact version. It is not reachability analysis or a full security review.

How much does it cost?

$0.0005 per package row plus $0.0015 per vulnerability row, and a $0.00005 start fee. Error and warning rows are free.

How do I limit spend?

Use minSeverity to skip low-severity rows, set a maximum cost per run in the run options, and/or lower maxPackages.

Can an AI agent call it?

Yes, through Apify MCP with Actor fairquery/osv-dependency-vulnerability-check, or through the Fairquery MCP server (npx -y @fairquery/agent-trust-mcp). Its free osv_query_packages and osv_get_vulnerability tools query OSV.dev directly.

Fairquery family

Other Fairquery tools on the Apify Store. Each one returns structured rows with machine-readable error codes, and error rows are never charged:

All Fairquery Actors: https://apify.com/fairquery

Kits & templates

Optional guides from Fairquery for wiring this Actor into agents and automations (the Actor works fine without them):

Disclaimer

Data comes from OSV.dev (aggregating GitHub Advisory Database, PyPA, Go Vulnerability DB and others) under their respective licenses. No warranty of completeness; absence of results does not prove a package is safe.

Development

Local development, tests and deployment notes are in DEVELOPMENT.md. The Apify Store README is .actor/README.md.

Available Tools

3 tools
check_dependency_vulnerabilitiesCheck dependencies for known vulnerabilities (OSV.dev)A
Read-onlyIdempotent
Inspect

WHAT: Check exact package versions, or a pasted manifest (package.json, package-lock.json v1-v3, requirements.txt with == pins, go.mod), against the OSV.dev vulnerability database (GHSA, PYSEC, GO, RUSTSEC, CVE aliases). WHEN TO USE: auditing a project or a list of dependencies before upgrading or shipping, or answering "is lodash 4.17.20 vulnerable and what should I upgrade to?". WHEN NOT TO USE: for the full record of an advisory ID you already have use get_vulnerability_details (free); to browse all advisories of a package without a version use list_package_vulnerabilities (free). Does not scan source code, containers or unpinned ranges (ranges produce VERSION_NOT_PINNED warnings). BEHAVIOR: runs the Fairquery Apify Actor fairquery/osv-dependency-vulnerability-check through the Apify API, which queries api.osv.dev. Requires APIFY_TOKEN. Typical run 5-60 s depending on package count. COST: paid (billed to your Apify account, pay-per-event): $0.00005 per run + $0.0005 per package row + $0.0015 per emitted vulnerability row; error/warning rows are free. Example: lodash + django (2 packages, 41 vulns) ~ $0.06. RETURNS: one type="package" row per unique package (recommended_version = smallest version fixing every emitted vuln, or null) plus one type="vulnerability" row per advisory; type="error" rows carry code (INPUT_EMPTY, INVALID_PACKAGE, MANIFEST_UNDETECTED, MANIFEST_PARSE_FAILED, MAX_PACKAGES_EXCEEDED, OSV_QUERYBATCH_FAILED, OSV_VULN_FETCH_FAILED, or the warnings VERSION_NOT_PINNED / VERSION_NOT_PINNABLE / RANGE_APPROXIMATED) and retryable. EXAMPLE: {"packages":[{"ecosystem":"npm","name":"lodash","version":"4.17.20"}],"minSeverity":"HIGH"} -> 1 package row (vulnerable, recommended_version) + HIGH/CRITICAL vulnerability rows. PARAMETERS: packages and/or manifestText: at least one is required although the schema marks both optional (neither -> INPUT_EMPTY, not billed); both may be combined and packages parsed from the manifest are merged with packages, deduped by ecosystem+name+version. Every unique package is one billed row, so maxPackages (default 1000) is also your spend cap; extras produce a free MAX_PACKAGES_EXCEEDED row. Versions must be pinned: requirements.txt needs "==" pins, package.json ranges such as "^4.17.0" are approximated (RANGE_APPROXIMATED warning) - paste package-lock.json for exact results. manifestType: leave "auto" unless detection fails (MANIFEST_UNDETECTED). minSeverity uses the CVSS v3 base score, else the advisory label; package rows are always emitted, but their vulnerable, vuln_count, max_severity and recommended_version then cover only the vulns that passed the filter (vuln_count_total keeps the unfiltered count); includeUnknownSeverity decides whether vulns without any severity pass that filter, and has no effect when minSeverity is "ALL". dedupeAliases=false emits one row per OSV ID (GHSA and PYSEC copies of the same issue), which raises cost. includeDevDependencies only affects package.json / package-lock.json.

NameRequiredDescriptionDefault
packagesNoOptional if manifestText is given (at least one is required). 0-1000 {ecosystem, name, version} objects; one billed row per unique package. Example: [{"ecosystem":"npm","name":"lodash","version":"4.17.20"}]
maxPackagesNoOptional integer 1-10000, default 1000. Safety/spend cap on unique packages checked per run; extra packages are skipped with one free MAX_PACKAGES_EXCEEDED error row. Example: 200
minSeverityNoOptional, one of "ALL" | "LOW" | "MEDIUM" | "HIGH" | "CRITICAL", default "ALL". Only emit (and bill) vulnerability rows at or above this severity (CVSS v3 base score, else advisory label); package rows are always emitted. Example: "HIGH"
manifestTextNoOptional if packages is given. Raw file content (<= 2,000,000 chars) of package.json, package-lock.json (v1-v3), requirements.txt (== pins) or go.mod; packages found are merged into `packages`. Example: "django==3.2.0\nrequests==2.19.0"
manifestTypeNoOptional, one of "auto" | "package.json" | "package-lock.json" | "requirements.txt" | "go.mod", default "auto" (detect from content). Only used with manifestText. Example: "requirements.txt"
dedupeAliasesNoOptional boolean, default true = one row per real vulnerability when OSV lists it under several IDs (GHSA record preferred); false = one billed row per OSV ID
includeDevDependenciesNoOptional boolean, default true. false skips devDependencies (package.json) and dev packages (package-lock.json); no effect on requirements.txt / go.mod / packages
includeUnknownSeverityNoOptional boolean, default true. With minSeverity above ALL, true still emits vulnerabilities that have no severity data; false drops them

Output Schema

NameRequiredDescription
countYesNumber of rows returned
itemsYesResult rows; each has a "type" field (data rows or machine-readable "error" rows)

TDQS

A4.9/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Despite annotations already supplying readOnlyHint/idempotentHint/openWorldHint, the description adds operational context annotations cannot: APIFY_TOKEN requirement, 5-60s runtime, a full pay-per-event cost model with a worked example, the concrete error/warning codes emitted, and which rows are free vs. billable. This is exactly the beyond-annotations context the dimension rewards.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Strongly front-loaded and header-labeled (WHAT/WHEN TO USE/WHEN NOT TO USE/BEHAVIOR/COST/RETURNS/EXAMPLE/PARAMETERS), and the length is justified by the tool's cost and error complexity. It loses a point for restating some schema content (the minSeverity scoring rule and enum values) that the schema already carries.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With an output schema present the description still goes beyond it by enumerating emitted row types, recommended_version semantics, and error/warning codes. Combined with auth, cost, and param-interaction coverage, nothing an agent needs to call this correctly is missing; the required-params mismatch in the schema is even explicitly corrected.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters5/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100% (baseline 3), but the description adds meaning the schema omits: packages and manifestText are 'at least one required although the schema marks both optional' (neither -> INPUT_EMPTY, not billed), manifest-parsed packages are merged and deduped by ecosystem+name+version, maxPackages doubles as a spend cap, and minSeverity's interaction with package-row fields (vuln_count_total) and includeUnknownSeverity is spelled out.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource ('Check exact package versions, or a pasted manifest ... against the OSV.dev vulnerability database') and enumerates the ecosystems and advisory sources covered. It also explicitly names the two sibling tools it is not, so an agent can differentiate without opening the schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Has explicit WHEN TO USE ('auditing a project or a list of dependencies before upgrading or shipping') and WHEN NOT TO USE sections that route to get_vulnerability_details and list_package_vulnerabilities by condition (existing advisory ID vs. versionless browsing). Also states exclusions (source code, containers, unpinned ranges).

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

get_vulnerability_detailsGet vulnerability advisory details (free)A
Read-onlyIdempotent
Inspect

WHAT: Fetch the full OSV record for one or more known vulnerability IDs (e.g. GHSA-35jh-r3h4-6jhm, PYSEC-2021-9, GO-2022-0969, RUSTSEC-2021-0078, CVE-2021-44228) directly from the public OSV.dev API. WHEN TO USE: you already have an advisory/CVE ID (e.g. from check_dependency_vulnerabilities or a security report) and need its summary, details, affected ranges, fixed versions, severity vectors or references. WHEN NOT TO USE: to find which vulnerabilities affect given package versions or a manifest use check_dependency_vulnerabilities (paid); to list every advisory of a package without IDs use list_package_vulnerabilities (free). COST/BEHAVIOR: free; one HTTP GET per ID to api.osv.dev, no token; OSV documents no rate limit. RETURNS: one row per ID: type="vulnerability" with the raw OSV record fields plus osv_url, or type="error" (VULN_NOT_FOUND or OSV_FETCH_FAILED, see PARAMETERS). PARAMETERS: ids: each ID is trimmed and fetched separately (in parallel) and yields exactly one row in input order, so one bad ID never fails the call: unknown IDs return VULN_NOT_FOUND rows (not retryable), network/5xx problems OSV_FETCH_FAILED rows (retryable - resend just those IDs). Use the exact IDs from check_dependency_vulnerabilities (id / vuln_ids / aliases); a CVE-... ID resolves only when OSV holds it as its own record, otherwise query its GHSA alias. Duplicate IDs are fetched twice. For more than 25 IDs, split into several calls. EXAMPLE: {"ids":["GHSA-35jh-r3h4-6jhm"]} -> 1 vulnerability row (lodash command injection, fixed in 4.17.21).

NameRequiredDescriptionDefault
idsYesRequired. 1-25 advisory IDs, 3-100 chars each (surrounding whitespace is trimmed): GHSA-xxxx-xxxx-xxxx, PYSEC-YYYY-N, GO-YYYY-NNNN, RUSTSEC-YYYY-NNNN or CVE-YYYY-NNNNN. Example: ["GHSA-35jh-r3h4-6jhm","PYSEC-2021-9"]

Output Schema

NameRequiredDescription
countYesNumber of rows returned
itemsYesResult rows; each has a "type" field (data rows or machine-readable "error" rows)

TDQS

A5/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare read-only, open-world, idempotent and non-destructive, and the description still adds substantial behavior: free tier, one HTTP GET per ID to api.osv.dev, no token, no documented rate limit, partial-failure semantics (one bad ID never fails the call), and retryability classification per error type. This is well beyond the annotation baseline.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Labeled sections (WHAT / WHEN TO USE / WHEN NOT TO USE / COST-BEHAVIOR / RETURNS / PARAMETERS / EXAMPLE) front-load the decision-relevant content and keep every sentence load-bearing. Long, but dense rather than padded.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Despite an output schema existing, the description's return-shape and error-code notes are actionable (VULN_NOT_FOUND vs. OSV_FETCH_FAILED retry guidance). For a single-parameter, network-backed lookup, nothing an agent needs to call and interpret it correctly is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters5/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is already 100%, yet the description adds real meaning: IDs are trimmed and fetched in parallel yielding exactly one row per ID in input order, duplicates are fetched twice, CVE IDs resolve only if OSV holds them as their own record (otherwise query the GHSA alias), and calls should be split above 25 IDs. None of this is inferable from the schema alone.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb (fetch) and resource (full OSV record for advisory IDs) with concrete example IDs spanning GHSA/PYSEC/GO/RUSTSEC/CVE, and explicitly names the two sibling tools it is not. An agent can distinguish it from check_dependency_vulnerabilities and list_package_vulnerabilities without opening any schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Uses explicit WHEN TO USE and WHEN NOT TO USE sections, naming both alternatives and the selecting condition (already have an ID vs. need to discover which advisories affect a package/version). Even notes the cost tier of each sibling.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

list_package_vulnerabilitiesList all known vulnerabilities of a package (free)A
Read-onlyIdempotent
Inspect

WHAT: List every OSV.dev advisory recorded for one package across all of its versions (no version needed), with the affected version ranges and fixed versions for that package. WHEN TO USE: "what security issues has lodash had?", choosing a safe version before adding a dependency, or browsing advisories for a package when you have no exact version or advisory ID. WHEN NOT TO USE: to check exact pinned versions or a manifest and get upgrade recommendations use check_dependency_vulnerabilities (paid); for the full record of one advisory use get_vulnerability_details (free). BEHAVIOR: POST /v1/query to api.osv.dev without a version; follows OSV pagination up to 10 pages; typically 1-3 s. An unknown package name returns 0 rows, not an error (OSV does not distinguish). COST: free; no APIFY_TOKEN, nothing sent to Fairquery or Apify; OSV documents no rate limit. RETURNS: one type="vulnerability" summary row per advisory, newest published first; Errors: INVALID_ECOSYSTEM, OSV_FETCH_FAILED (retryable). PARAMETERS: ecosystem accepts aliases (pip -> PyPI, cargo -> crates.io, gem -> RubyGems, composer -> Packagist, golang -> Go, java -> Maven) and other OSV ecosystem names verbatim (e.g. "Debian:12"). name must match the published package exactly; affected_ranges and fixed_versions only cover entries for this exact package, not sibling packages the same advisory also lists. limit/offset page the sorted rows; every call re-queries OSV, which is free. withdrawn advisories are kept and carry a withdrawn timestamp. EXAMPLE: {"ecosystem":"npm","name":"lodash","limit":2} -> total 10, newest first: {"id":"GHSA-r5fr-rjxr-66jc","severity":"HIGH","affected_ranges":[{"introduced":"4.0.0","fixed":"4.18.0"}],"fixed_versions":["4.18.0"],...}, then GHSA-f23m-r3pf-42rh.

NameRequiredDescriptionDefault
nameYesRequired. Package name exactly as published: npm "lodash" or "@scope/pkg", PyPI "django", Go module path "github.com/gin-gonic/gin", Maven "groupId:artifactId". Example: "lodash"
limitNoOptional page size, integer 1-500, default 100. Example: 50
offsetNoOptional, integer >= 0, default 0; use nextOffset from the previous page. Example: 100
ecosystemYesRequired. OSV ecosystem, case-insensitive for the common ones: npm, PyPI, Go, Maven, crates.io, RubyGems, NuGet, Packagist, Pub, Hex (aliases pip/cargo/gem/composer accepted). Example: "npm"

Output Schema

NameRequiredDescription
countYesRows in this page
itemsYestype="vulnerability" rows or one type="error" row
totalYesAdvisories found for the package
offsetYes
hasMoreYes
nextOffsetYes

TDQS

A4.8/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already cover the read-only/open-world/idempotent safety profile, but the description adds substantially more: POST /v1/query with no version body, pagination capped at 10 pages, 1-3s latency, unknown package returning 0 rows instead of an error, withdrawn advisories retained, and named error codes (INVALID_ECOSYSTEM, OSV_FETCH_FAILED). This is exactly the extra behavioral context annotations cannot express.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Labeled sections (WHAT/WHEN TO USE/WHEN NOT TO USE/BEHAVIOR/COST/RETURNS/PARAMETERS/EXAMPLE) make it highly scannable, and the most decision-relevant content is front-loaded. It runs long, and the free/no-rate-limit point recurs across COST and PARAMETERS, which keeps it from a perfect score.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With an output schema present and 100% schema coverage, the description still supplies the error taxonomy, pagination model, cost/auth posture, and a concrete worked example with a sample response. An agent has everything needed to call it correctly on the first attempt.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so baseline is 3, and the description still adds real semantics: alias mapping plus verbatim OSV ecosystem names like 'Debian:12', exact-package-name matching, the caveat that affected_ranges/fixed_versions cover only this package and not sibling packages in the same advisory, and that offset/limit re-query OSV on every call. It falls short of 5 only because the ecosystem alias list partially duplicates the schema.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The WHAT line states a specific verb+resource+scope: list every OSV.dev advisory for one package across all versions, no version required. It also immediately distinguishes itself from the 'exact pinned version' case covered by the sibling check tool.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explicit WHEN TO USE (sample questions, choosing a safe version, browsing with no version/advisory ID) and WHEN NOT TO USE that names both siblings with the condition that selects them (exact pinned versions/manifest -> check_dependency_vulnerabilities; full single-advisory record -> get_vulnerability_details). Nothing is left to inference.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

  1. 1 tool updatev1.2.0
    • Addedlist_package_vulnerabilities
  2. 2 tool updatesv1.1.4
    • Changedcheck_dependency_vulnerabilities11 fields changed
      • changedInput schema / properties / dedupeAliases / description
        Previous value: -"Emit one row per real vulnerability when OSV lists it under several IDs, preferring the GHSA record (default true)"New value: +"Optional boolean, default true = one row per real vulnerability when OSV lists it under several IDs (GHSA record preferred); false = one billed row per OSV ID"
      • changedInput schema / properties / includeDevDependencies / description
        Previous value: -"Include devDependencies from package.json / dev packages from package-lock.json (default true)"New value: +"Optional boolean, default true. false skips devDependencies (package.json) and dev packages (package-lock.json); no effect on requirements.txt / go.mod / packages"
      • changedInput schema / properties / includeUnknownSeverity / description
        Previous value: -"With minSeverity set, still emit vulnerabilities whose severity is unknown (default true)"New value: +"Optional boolean, default true. With minSeverity above ALL, true still emits vulnerabilities that have no severity data; false drops them"
      • changedInput schema / properties / manifestText / description
        Previous value: -"Optional; up to 2,000,000 chars of raw file content of package.json, package-lock.json, requirements.txt or go.mod. Packages found are added to `packages`."New value: +"Optional if packages is given. Raw file content (<= 2,000,000 chars) of package.json, package-lock.json (v1-v3), requirements.txt (== pins) or go.mod; packages found are merged into `packages`. Example: \"django==3.2.0\\nrequests==2.19.0\""
      • changedInput schema / properties / manifestType / description
        Previous value: -"Format of manifestText (default \"auto\" = detect from content)"New value: +"Optional, one of \"auto\" | \"package.json\" | \"package-lock.json\" | \"requirements.txt\" | \"go.mod\", default \"auto\" (detect from content). Only used with manifestText. Example: \"requirements.txt\""
      • changedInput schema / properties / maxPackages / description
        Previous value: -"Safety cap on unique packages checked per run (1-10000, default 1000); extra packages produce a MAX_PACKAGES_EXCEEDED error row"New value: +"Optional integer 1-10000, default 1000. Safety/spend cap on unique packages checked per run; extra packages are skipped with one free MAX_PACKAGES_EXCEEDED error row. Example: 200"
      • changedInput schema / properties / minSeverity / description
        Previous value: -"Only emit vulnerabilities at or above this severity (CVSS v3 base score, else advisory label). Default ALL. Package rows are always emitted."New value: +"Optional, one of \"ALL\" | \"LOW\" | \"MEDIUM\" | \"HIGH\" | \"CRITICAL\", default \"ALL\". Only emit (and bill) vulnerability rows at or above this severity (CVSS v3 base score, else advisory label); package rows are always emitted. Example: \"HIGH\""
      • changedInput schema / properties / packages / description
        Previous value: -"Up to 1000 exact package versions to check (optional if manifestText is given). Example: [{\"ecosystem\":\"npm\",\"name\":\"lodash\",\"version\":\"4.17.20\"}]"New value: +"Optional if manifestText is given (at least one is required). 0-1000 {ecosystem, name, version} objects; one billed row per unique package. Example: [{\"ecosystem\":\"npm\",\"name\":\"lodash\",\"version\":\"4.17.20\"}]"
      • changedInput schema / properties / packages / items / properties / ecosystem / description
        Previous value: -"OSV ecosystem name: npm, PyPI, Go, Maven, crates.io, RubyGems, NuGet, Packagist, Pub, Hex (aliases like pip/cargo/gem are accepted)"New value: +"Required. OSV ecosystem, case-insensitive: npm, PyPI, Go, Maven, crates.io, RubyGems, NuGet, Packagist, Pub, Hex (aliases like pip/cargo/gem are accepted). Example: \"PyPI\""
      • changedInput schema / properties / packages / items / properties / name / description
        Previous value: -"Package name as published, e.g. \"lodash\", \"django\", \"github.com/gin-gonic/gin\", \"org.apache.logging.log4j:log4j-core\""New value: +"Required. Package name exactly as published: npm \"lodash\" or \"@scope/pkg\", PyPI \"django\", Go module path \"github.com/gin-gonic/gin\", Maven \"groupId:artifactId\" e.g. \"org.apache.logging.log4j:log4j-core\""
      • changedInput schema / properties / packages / items / properties / version / description
        Previous value: -"Exact version, e.g. \"4.17.20\" (no ranges like ^4.0.0)"New value: +"Required. One exact version, e.g. \"4.17.20\" (no ranges like ^4.0.0 or >=2); Go versions keep the \"v\" prefix, e.g. \"v1.9.0\""
    • Changedget_vulnerability_details1 field changed
      • changedInput schema / properties / ids / description
        Previous value: -"Required. 1-25 advisory IDs (3-100 chars each): GHSA-xxxx-xxxx-xxxx, PYSEC-YYYY-N, GO-YYYY-NNNN, RUSTSEC-YYYY-NNNN or CVE-YYYY-NNNNN. Example: [\"GHSA-35jh-r3h4-6jhm\"]"New value: +"Required. 1-25 advisory IDs, 3-100 chars each (surrounding whitespace is trimmed): GHSA-xxxx-xxxx-xxxx, PYSEC-YYYY-N, GO-YYYY-NNNN, RUSTSEC-YYYY-NNNN or CVE-YYYY-NNNNN. Example: [\"GHSA-35jh-r3h4-6jhm\",\"PYSEC-2021-9\"]"
  3. 2 tool updatesv1.1.1
    • Changedcheck_dependency_vulnerabilities14 fields changed
      • addedInput schema / properties / dedupeAliases / description
        Added value: +"Emit one row per real vulnerability when OSV lists it under several IDs, preferring the GHSA record (default true)"
      • addedInput schema / properties / includeDevDependencies / description
        Added value: +"Include devDependencies from package.json / dev packages from package-lock.json (default true)"
      • addedInput schema / properties / includeUnknownSeverity / description
        Added value: +"With minSeverity set, still emit vulnerabilities whose severity is unknown (default true)"
      • changedInput schema / properties / manifestText / description
        Previous value: -"Raw package.json, package-lock.json, requirements.txt (== pins) or go.mod content"New value: +"Optional; up to 2,000,000 chars of raw file content of package.json, package-lock.json, requirements.txt or go.mod. Packages found are added to `packages`."
      • addedInput schema / properties / manifestText / maxLength
        Added value: +2000000
      • addedInput schema / properties / manifestType / description
        Added value: +"Format of manifestText (default \"auto\" = detect from content)"
      • addedInput schema / properties / maxPackages / description
        Added value: +"Safety cap on unique packages checked per run (1-10000, default 1000); extra packages produce a MAX_PACKAGES_EXCEEDED error row"
      • changedInput schema / properties / minSeverity / description
        Previous value: -"Only return vulnerabilities at or above this severity (default ALL)"New value: +"Only emit vulnerabilities at or above this severity (CVSS v3 base score, else advisory label). Default ALL. Package rows are always emitted."
      • changedInput schema / properties / packages / description
        Previous value: -"Exact package versions to check"New value: +"Up to 1000 exact package versions to check (optional if manifestText is given). Example: [{\"ecosystem\":\"npm\",\"name\":\"lodash\",\"version\":\"4.17.20\"}]"
      • changedInput schema / properties / packages / items / properties / ecosystem / description
        Previous value: -"OSV ecosystem, e.g. npm, PyPI, Go, Maven"New value: +"OSV ecosystem name: npm, PyPI, Go, Maven, crates.io, RubyGems, NuGet, Packagist, Pub, Hex (aliases like pip/cargo/gem are accepted)"
      • addedInput schema / properties / packages / items / properties / name / description
        Added value: +"Package name as published, e.g. \"lodash\", \"django\", \"github.com/gin-gonic/gin\", \"org.apache.logging.log4j:log4j-core\""
      • addedInput schema / properties / packages / items / properties / version / description
        Added value: +"Exact version, e.g. \"4.17.20\" (no ranges like ^4.0.0)"
      • addedInput schema / properties / packages / maxItems
        Added value: +1000
      • changedOutput schema / (root)
        Previous value: -nullNew value: +{
        +  "$schema": "http://json-schema.org/draft-07/schema#",
        +  "additionalProperties": false,
        +  "properties": {
        +    "count": {
        +      "description": "Number of rows returned",
        +      "type": "integer"
        +    },
        +    "items": {
        +      "description": "Result rows; each has a \"type\" field (data rows or machine-readable \"error\" rows)",
        +      "items": {
        +        "additionalProperties": {},
        +        "type": "object"
        +      },
        +      "type": "array"
        +    }
        +  },
        +  "required": [
        +    "count",
        +    "items"
        +  ],
        +  "type": "object"
        +}
    • Addedget_vulnerability_details
  4. 1 tool updatev0.1.0
    • First observedcheck_dependency_vulnerabilities

TDQS

A4.9/5.0

Scored across 3 tools

Disambiguation5/5

Each tool has a clearly distinct input and purpose: check_dependency_vulnerabilities takes pinned versions/manifests, get_vulnerability_details takes advisory IDs, and list_package_vulnerabilities takes a package name with no version. The descriptions explicitly cross-reference each other with WHEN TO USE / WHEN NOT TO USE, leaving no meaningful overlap.

Naming Consistency5/5

All three names follow a consistent snake_case verb_noun pattern: check_, get_, and list_ prefixes with clear resource nouns. The verbs vary appropriately by action rather than chaotically, and there is no mixed casing or style.

Tool Count5/5

Three tools map cleanly to the three core OSV.dev query modes: version/manifest audit, advisory-by-ID lookup, and package advisory listing. The server is a focused wrapper, so each tool earns its place without redundancy or excessive surface area.

Completeness4/5

The surface covers the main workflows: checking pinned versions or manifests, retrieving full advisory records, and listing all advisories for a package. Minor gaps exist, such as querying by commit hash or browsing advisories across an entire ecosystem, but these are unlikely to block typical auditing tasks.

Maintenance

ActivityMaintained
ResponsivenessNo issues

Related MCP Connectors

Related MCP Servers

  • A
    license
    A
    quality
    D
    maintenance
    Automatically scans project dependencies (npm, Composer) for security vulnerabilities using the OSV.dev database, providing real-time alerts and detailed remediation guidance directly in your IDE.
    1
    7 npm
    1
    MIT
  • A
    license
    A
    quality
    D
    maintenance
    AI-powered dependency vulnerability and breaking change analyzer that scans dependencies, identifies vulnerabilities via OSV.dev, and uses AI to assess real impact and suggest fixes.
    3
    Apache 2.0
  • A
    license
    A
    quality
    B
    maintenance
    Vulnerability intelligence for AI agents that enables CVE lookup, package vulnerability checks, and dependency auditing without API keys.
    5
    MIT