Skip to main content
Glama
fairquery

OSV Dependency Vulnerability Check MCP Server

Dependency Vulnerability Check for Agents

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 (pay per event)

Event

Price

When

apify-actor-start

$0.00005

Once per run (Apify default start event)

package-checked

$0.0009

Each package row (vulnerable or clean)

vulnerability-found

$0.0028

Each emitted vulnerability row (after severity filter & alias de-dup)

Error and warning rows are never charged. Example: lodash + django (2 packages, 41 vulnerabilities) ≈ $0.117. Set a max charge per run in run options to cap spend; the Actor stops cleanly at the limit.

Memory / runtime

Default 256 MB, timeout 600 s. HTTP only (no browser). A 2-package run finishes in ~5–10 s.

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 check_dependency_vulnerabilities (runs this Actor through the Apify API) and the free get_vulnerability_details (direct OSV.dev lookup by advisory ID). 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.

Local development

npm install
# put input in storage/key_value_stores/default/INPUT.json
npx apify run
npm test

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.

Available Tools

2 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). Does not scan source code, containers or unpinned ranges (ranges produce VERSION_NOT_PINNED warnings). BEHAVIOR: read-only; 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.0009 per package row + $0.0028 per emitted vulnerability row; error/warning rows are free. Use minSeverity (e.g. "HIGH") and dedupeAliases=true to reduce rows and cost. Example: lodash + django (2 packages, 41 vulns) ~ $0.12. RETURNS: {count, items}. Every row has schema_version, type (package | vulnerability | error), source_url, checked_at. package rows: ecosystem, name, version, purl, vulnerable, vuln_count, vuln_ids, max_severity, max_cvss_score, fixed_versions, recommended_version (smallest version fixing all emitted vulns, or null). vulnerability rows: id, package_name, package_version, aliases, cve_ids, summary, details, severity, cvss_score, cvss_vector, cwe_ids, affected_ranges, fixed_versions, published, references, osv_url. error rows: code (INPUT_EMPTY, INVALID_PACKAGE, MANIFEST_UNDETECTED, MANIFEST_PARSE_FAILED, MAX_PACKAGES_EXCEEDED, OSV_QUERYBATCH_FAILED, OSV_VULN_FETCH_FAILED, or warnings VERSION_NOT_PINNED/VERSION_NOT_PINNABLE/RANGE_APPROXIMATED), message, retryable. EXAMPLE: {"packages":[{"ecosystem":"npm","name":"lodash","version":"4.17.20"}],"minSeverity":"HIGH"} -> 1 package row (vulnerable, recommended_version) + HIGH/CRITICAL vulnerability rows. Provide packages and/or manifestText (at least one).

ParametersJSON Schema
NameRequiredDescriptionDefault
packagesNoUp to 1000 exact package versions to check (optional if manifestText is given). Example: [{"ecosystem":"npm","name":"lodash","version":"4.17.20"}]
maxPackagesNoSafety cap on unique packages checked per run (1-10000, default 1000); extra packages produce a MAX_PACKAGES_EXCEEDED error row
minSeverityNoOnly emit vulnerabilities at or above this severity (CVSS v3 base score, else advisory label). Default ALL. Package rows are always emitted.
manifestTextNoOptional; 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`.
manifestTypeNoFormat of manifestText (default "auto" = detect from content)
dedupeAliasesNoEmit one row per real vulnerability when OSV lists it under several IDs, preferring the GHSA record (default true)
includeDevDependenciesNoInclude devDependencies from package.json / dev packages from package-lock.json (default true)
includeUnknownSeverityNoWith minSeverity set, still emit vulnerabilities whose severity is unknown (default true)

Output Schema

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

TDQS

A4.8/5.0
Behavior5/5

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

Annotations already declare readOnly/idempotent/openWorld, but the description adds substantial extra context: the backing Apify actor and upstream api.osv.dev, the required APIFY_TOKEN, typical 5-60s runtime, the pay-per-event cost model with per-row pricing, and a concrete cost example. These are behavioral facts 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?

Long but deliberately structured under WHAT/WHEN TO USE/WHEN NOT TO USE/BEHAVIOR/COST/RETURNS/EXAMPLE labels and front-loaded. The RETURNS section restates fields already carried by the output schema, which is the one mildly expendable block.

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?

For a paid, externally-dependent, 8-parameter tool this is complete: inputs, auth, runtime, pricing, error/warning codes, and an example are all present, and return-value detail is a bonus rather than a gap given an output schema exists.

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 the baseline is 3, but the description adds real decision-relevant meaning: minSeverity and dedupeAliases are framed as cost-reduction levers, versions must be pinned (ranges yield VERSION_NOT_PINNED warnings), and a worked example shows packages plus minSeverity in use.

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+resource (check exact package versions or a manifest against OSV.dev), names the advisories sources, and explicitly distinguishes itself from the sibling get_vulnerability_details by function.

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 before upgrading/shipping) and WHEN NOT TO USE sections that name the alternative tool get_vulnerability_details and the condition selecting it, plus scoping exclusions (no source/container scanning, no 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). COST/BEHAVIOR: free; read-only HTTP GET to api.osv.dev, no token, no rate limit documented by OSV (be reasonable: max 25 IDs per call). CVE IDs only resolve if OSV indexes them directly; prefer GHSA/ecosystem IDs. RETURNS: {count, items}: one row per ID with type="vulnerability" and the raw OSV schema fields (id, summary, details, aliases, severity, affected, references, published, modified, osv_url), or type="error" with code VULN_NOT_FOUND (404) or OSV_FETCH_FAILED (retryable). EXAMPLE: {"ids":["GHSA-35jh-r3h4-6jhm"]} -> 1 vulnerability row (lodash command injection, fixed in 4.17.21).

ParametersJSON Schema
NameRequiredDescriptionDefault
idsYesRequired. 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"]

Output Schema

ParametersJSON 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?

Annotations already declare read-only, idempotent, open-world, non-destructive, but the description adds real behavioral context beyond them: no token required, no documented rate limit but a 25-ID-per-call cap, the caveat that CVE IDs only resolve if OSV indexes them directly, and the error codes VULN_NOT_FOUND (404) and OSV_FETCH_FAILED (retryable).

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?

Front-loaded WHAT/WHEN/COST/RETURNS/EXAMPLE structure makes scanning trivial, and each block carries non-redundant information. Despite its length, no sentence is filler.

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?

Even though an output schema exists (so return values need not be spelled out), the description still previews the {count, items} shape and error rows. Auth, cost, limits, ID caveats, and routing are all covered for a single-parameter read tool.

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 the baseline is 3, but the description goes further by enumerating accepted ID formats (GHSA/PYSEC/GO/RUSTSEC/CVE), restating the 25-ID ceiling, and warning that CVE IDs may not resolve. That is genuine added meaning about which values will succeed, though the per-ID length bounds remain schema-only.

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) with scope (one or more known vulnerability IDs) and example ID families. It explicitly names the sibling tool it is not (check_dependency_vulnerabilities) and the distinguishing condition, so an agent can separate the two without opening either 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 (you already hold an advisory/CVE ID) and WHEN NOT TO USE (to find which vulnerabilities affect package versions or a manifest, use check_dependency_vulnerabilities). The alternative and the selecting condition are both stated.

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. 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
  2. 1 tool updatev0.1.0
    • First observedcheck_dependency_vulnerabilities

TDQS

A4.7/5.0

Scored across 2 tools

Disambiguation5/5

The two tools target clearly different inputs and directions: check_dependency_vulnerabilities maps package versions/manifests to vulnerabilities, while get_vulnerability_details fetches records for known IDs. Each description explicitly names the other in a 'WHEN NOT TO USE' section, making misselection very unlikely.

Naming Consistency5/5

Both names follow a clean snake_case verb_noun pattern (check_dependency_vulnerabilities, get_vulnerability_details) with the domain noun consistently placed at the end. No stylistic deviations or mixed conventions.

Tool Count3/5

Two tools is on the thin side for a server whose domain includes manifest parsing, severity filtering, and advisory lookup; additional capabilities are folded into parameters rather than separate tools. It is defensible as a minimal surface, but the rubric places 1-2 tools at borderline.

Completeness4/5

The core lifecycle is covered: input dependencies (explicit packages or manifests), resolve vulnerabilities, and retrieve full advisory records with fixed versions. Minor gaps remain, such as enumerating or searching advisories without having IDs or exact pinned versions (unpinned ranges only yield warnings).

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
    24 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