OSV Dependency Vulnerability Check MCP Server
Checks pinned dependency versions or pasted manifests against the OSV.dev vulnerability database, and looks up advisory details — via two MCP tools.
check_dependency_vulnerabilities(paid, needsAPIFY_TOKEN) — runs the Fairquery Apify Actor on Apify's cloud.Audit exact
{ecosystem, name, version}packages, or a pasted manifest:package.json,package-lock.json(v1–v3),requirements.txt(==pins) orgo.mod; the two inputs can be combined and merged/deduped.Covers all OSV ecosystems (npm, PyPI, Go, Maven, crates.io, RubyGems, NuGet, Packagist, Pub, Hex), case-insensitive with aliases like
pip/cargo.Filter with
minSeverity(ALL→CRITICAL, CVSS v3 base score or advisory label),includeUnknownSeverity,includeDevDependencies, and collapse duplicate GHSA/PYSEC/GO records withdedupeAliases.Cap spend/scope with
maxPackages(default 1000; extras yield a freeMAX_PACKAGES_EXCEEDEDrow).Returns one
type="package"row per unique package (vulnerable flag, vuln counts, max severity/CVSS,recommended_version) and onetype="vulnerability"row per advisory (CVE aliases, CVSS vector/score, CWE, affected/fixed ranges, references), plus machine-readable free error/warning rows.Answers questions like "is lodash@4.17.20 vulnerable and what should I upgrade to?" or "show only HIGH/CRITICAL issues for a CI gate".
Does not do reachability analysis, license checks, container/OS scans, or unpinned ranges (those produce
VERSION_NOT_PINNED/RANGE_APPROXIMATEDwarnings).
get_vulnerability_details(free, no token) — fetches full OSV records for 1–25 known advisory IDs (GHSA, PYSEC, GO, RUSTSEC, CVE) in parallel, one row per ID or aVULN_NOT_FOUND/OSV_FETCH_FAILEDerror row.
Accepts 'composer' as an ecosystem alias to check PHP Composer package dependencies for known vulnerabilities, returning CVE mappings and fixed versions.
Checks npm package dependencies for known vulnerabilities, parsing package.json and package-lock.json, filtering by severity, and recommending fixed versions.
Checks NuGet package dependencies for known vulnerabilities against the OSV.dev database.
Checks Packagist/PHP package dependencies for known vulnerabilities against the OSV.dev database.
Checks PyPI/Python package dependencies for known vulnerabilities, parsing requirements.txt, filtering by severity, and recommending fixed versions.
Checks RubyGems package dependencies for known vulnerabilities against the OSV.dev database.
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@OSV Dependency Vulnerability Check MCP Serveris lodash 4.17.20 vulnerable and what should I upgrade to?"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
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.0vulnerable, 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 |
|
Vulnerability detail |
|
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 |
|
|
| Exact package versions to check |
|
| — | Raw package.json / package-lock.json (v1–v3) / requirements.txt / go.mod |
| enum |
| Force the manifest format |
|
|
| Minimum severity of emitted vulnerability rows |
|
|
| Keep vulns with no severity data when filtering |
|
|
| Include dev deps from npm manifests |
|
|
| Collapse GHSA/PYSEC/GO records describing the same issue into one row (GHSA preferred) |
|
|
| 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 |
| $0.0005 | Each package row (vulnerable or clean) |
| $0.0015 | Each emitted vulnerability row (after the severity filter and alias de-duplication) |
| $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:
Connect an MCP client to
https://mcp.apify.comwith your Apify token.Run actor
fairquery/osv-dependency-vulnerability-check.Read the default dataset (filter
type == "vulnerability") and theRUN_SUMMARYrecord.
{
"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 callClaude 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 | Neither |
|
|
| requirements.txt lines without |
| Set |
| OSV.dev was unavailable after retries ( |
Severity | Some advisories (often Go) publish no CVSS or label. Keep |
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:
Email Validator for Agents (MX, Disposable, Typo): syntax, MX, disposable, role and typo checks without sending mail; $0.79 per 1,000 emails
Website Contact & Company Enricher: domain in, public business emails, phones, socials and company details out; $3 per 1,000 domains
Website Tech, SEO & llms.txt Check for Agents: tech stack, SEO score, AI-crawler rules and llms.txt per site; $1.50 per 1,000 sites
Sanctions & Watchlist Screener (OFAC, EU, UK, UN): fuzzy name screening against official sanctions lists; $3 per 1,000 names + $0.007 per run
LLM Data Guard: PII & Secret Redactor: redact PII and secrets before text reaches an LLM; $1.50 per 1,000 documents + $0.20 per 1,000 findings
EDGAR Company Facts & Filings for Agents: SEC filings and XBRL facts by ticker, CIK or name; from $1.50 per 1,000 companies
Company Jobs Feed: Greenhouse, Lever & Ashby: live jobs from employers' own ATS boards with age and repost signals; $0.99 per 1,000 jobs + $0.0005 per board
Competitor Change Tracker: Pricing, Terms, Careers & Changelog: watch competitors' public pricing, terms, careers and changelog pages for real changes with plain-English summaries and webhook alerts; $0.00049 per page checked + $0.0049 per change
AI Exposure Scanner: Public Secrets, Files & AI-Crawler Policy: passive, scored scan of your own domains and public GitHub repos for leaked secrets (masked), exposed files, AI-crawler policy, security headers and SPF/DMARC; $0.039 per domain + $0.0039 per repo + $0.0019 per finding
MCP server
@fairquery/agent-trust-mcp: one MCP server for Claude Desktop, Cursor and VS Code (npx -y @fairquery/agent-trust-mcp). It has 8 free tools that need no token, plus paid tools that call the PII, email, sanctions and OSV Actors with your own Apify token.
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):
AI Agent Data Toolkit Quick-Start (PDF): MCP setup for Claude Desktop and Cursor, API calls, recipes, cost estimates.
n8n + Zapier Workflow Template Pack: 10 importable n8n workflows for the four Fairquery Actors, plus Zapier setup guides.
Agent Prompt Pack for Research & Lead Ops: 69 prompts for company research, lead cleaning, SEO and security reviews.
Agent Starter Kit: 10 copy-paste MCP + n8n recipes ($5): 10 copy-paste MCP + n8n recipes, with ready-made Claude/Cursor configs and 3 starter workflows.
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.
Links
Apify Store: https://apify.com/fairquery/osv-dependency-vulnerability-check
GitHub: https://github.com/fairquery/osv-dependency-vulnerability-check
Contact: fairquery@proton.me
License: MIT
Development
Local development, tests and deployment notes are in DEVELOPMENT.md. The Apify Store README is .actor/README.md.
Available Tools
3 toolscheck_dependency_vulnerabilitiesCheck dependencies for known vulnerabilities (OSV.dev)ARead-onlyIdempotentInspect
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.
| Name | Required | Description | Default |
|---|---|---|---|
| packages | No | 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"}] | |
| maxPackages | No | 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 | |
| minSeverity | No | 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" | |
| manifestText | No | 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" | |
| manifestType | No | 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" | |
| dedupeAliases | No | 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 | |
| includeDevDependencies | No | Optional boolean, default true. false skips devDependencies (package.json) and dev packages (package-lock.json); no effect on requirements.txt / go.mod / packages | |
| includeUnknownSeverity | No | Optional boolean, default true. With minSeverity above ALL, true still emits vulnerabilities that have no severity data; false drops them |
Output Schema
| Name | Required | Description |
|---|---|---|
| count | Yes | Number of rows returned |
| items | Yes | Result rows; each has a "type" field (data rows or machine-readable "error" rows) |
TDQS
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.
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.
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.
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.
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.
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)ARead-onlyIdempotentInspect
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).
| Name | Required | Description | Default |
|---|---|---|---|
| ids | Yes | 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"] |
Output Schema
| Name | Required | Description |
|---|---|---|
| count | Yes | Number of rows returned |
| items | Yes | Result rows; each has a "type" field (data rows or machine-readable "error" rows) |
TDQS
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.
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.
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.
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.
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.
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)ARead-onlyIdempotentInspect
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.
| Name | Required | Description | Default |
|---|---|---|---|
| name | Yes | Required. 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" | |
| limit | No | Optional page size, integer 1-500, default 100. Example: 50 | |
| offset | No | Optional, integer >= 0, default 0; use nextOffset from the previous page. Example: 100 | |
| ecosystem | Yes | Required. 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
| Name | Required | Description |
|---|---|---|
| count | Yes | Rows in this page |
| items | Yes | type="vulnerability" rows or one type="error" row |
| total | Yes | Advisories found for the package |
| offset | Yes | |
| hasMore | Yes | |
| nextOffset | Yes |
TDQS
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.
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.
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.
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.
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.
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 tool update
v1.2.0- Added
list_package_vulnerabilities
2 tool updates
v1.1.4- Changed
check_dependency_vulnerabilities11 fields changed- changed
Input schema / properties / dedupeAliases / descriptionPrevious 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" - changed
Input schema / properties / includeDevDependencies / descriptionPrevious 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" - changed
Input schema / properties / includeUnknownSeverity / descriptionPrevious 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" - changed
Input schema / properties / manifestText / descriptionPrevious 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\"" - changed
Input schema / properties / manifestType / descriptionPrevious 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\"" - changed
Input schema / properties / maxPackages / descriptionPrevious 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" - changed
Input schema / properties / minSeverity / descriptionPrevious 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\"" - changed
Input schema / properties / packages / descriptionPrevious 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\"}]" - changed
Input schema / properties / packages / items / properties / ecosystem / descriptionPrevious 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\"" - changed
Input schema / properties / packages / items / properties / name / descriptionPrevious 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\"" - changed
Input schema / properties / packages / items / properties / version / descriptionPrevious 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\""
- Changed
get_vulnerability_details1 field changed- changed
Input schema / properties / ids / descriptionPrevious 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\"]"
2 tool updates
v1.1.1- Changed
check_dependency_vulnerabilities14 fields changed- added
Input schema / properties / dedupeAliases / descriptionAdded value: +"Emit one row per real vulnerability when OSV lists it under several IDs, preferring the GHSA record (default true)" - added
Input schema / properties / includeDevDependencies / descriptionAdded value: +"Include devDependencies from package.json / dev packages from package-lock.json (default true)" - added
Input schema / properties / includeUnknownSeverity / descriptionAdded value: +"With minSeverity set, still emit vulnerabilities whose severity is unknown (default true)" - changed
Input schema / properties / manifestText / descriptionPrevious 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`." - added
Input schema / properties / manifestText / maxLengthAdded value: +2000000 - added
Input schema / properties / manifestType / descriptionAdded value: +"Format of manifestText (default \"auto\" = detect from content)" - added
Input schema / properties / maxPackages / descriptionAdded value: +"Safety cap on unique packages checked per run (1-10000, default 1000); extra packages produce a MAX_PACKAGES_EXCEEDED error row" - changed
Input schema / properties / minSeverity / descriptionPrevious 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." - changed
Input schema / properties / packages / descriptionPrevious 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\"}]" - changed
Input schema / properties / packages / items / properties / ecosystem / descriptionPrevious 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)" - added
Input schema / properties / packages / items / properties / name / descriptionAdded value: +"Package name as published, e.g. \"lodash\", \"django\", \"github.com/gin-gonic/gin\", \"org.apache.logging.log4j:log4j-core\"" - added
Input schema / properties / packages / items / properties / version / descriptionAdded value: +"Exact version, e.g. \"4.17.20\" (no ranges like ^4.0.0)" - added
Input schema / properties / packages / maxItemsAdded value: +1000 - changed
Output 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" +}
- Added
get_vulnerability_details
1 tool update
v0.1.0- First observed
check_dependency_vulnerabilities
TDQS
Scored across 3 tools
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.
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.
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.
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
Related MCP Connectors
CVE lookups (NVD) and dependency-manifest audits (OSV) for AI agents. No API keys.
CVE lookups (NVD) and dependency-manifest audits (OSV) for AI agents. No API keys.
Queries live Google OSV.dev vulnerability intelligence for any PyPI, npm, Go, or Rust crate and re
Queries live Google OSV.dev vulnerability intelligence for any PyPI, npm, Go, or Rust crate and r.
Related MCP Servers
- AlicenseAqualityDmaintenanceAutomatically 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.17 npm1MIT
- AlicenseAqualityDmaintenanceAI-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.3Apache 2.0
- FlicenseNot gradedqualityCmaintenanceScans Python, Node.js, Java/Spring, and PHP dependency manifests for known vulnerabilities using OSV and GitHub Advisory APIs.-
- AlicenseAqualityBmaintenanceVulnerability intelligence for AI agents that enables CVE lookup, package vulnerability checks, and dependency auditing without API keys.5MIT