Skip to content

Vulners Python SDK

The official Python client for the Vulners vulnerability intelligence database. Version 4 is a ground-up modernization of the library: a fully typed data model, mirrored sync and async clients, documentation shipped inside the package, first-class AI-agent support, and a built-in MCP server — while staying 100% backward compatible with existing v3 code.

Source and issues: github.com/vulnersCom/api · Package: pypi.org/project/vulners

Installation

Requires Python 3.10+. A plain install ships everything needed for fast, modern transport — HTTP/2, response compression, archive streaming — with prebuilt wheels, so there is no build step:

pip install -U vulners

Optional extras:

pip install -U "vulners[mcp]"     # + built-in Model Context Protocol server
pip install -U "vulners[otel]"    # + opt-in OpenTelemetry tracing

API key

All API calls require an API key. Sign in at vulners.com, open your personal menu, select the API KEYS tab and generate a key with the api scope — see Getting an API key for a step-by-step guide with screenshots.

The client accepts the key as an argument — Vulners(api_key="...") — or reads it from the VULNERS_API_KEY environment variable, so a plain Vulners() works too. Keep your API key confidential to prevent unauthorized access.

60-second tour

Search runs a Lucene query and returns a page of typed Bulletin models — fields are attributes, not dict keys:

from vulners import Vulners

with Vulners(api_key="YOUR_API_KEY_HERE") as v:
    # Full-text search: CVEs known to be exploited in the wild
    page = v.search.query(
        "type:cve AND enchantments.exploitation.wildExploited:true", limit=10
    )
    print(page.total, "documents match")
    for bulletin in page.data:
        print(bulletin.id, "-", bulletin.title, "-", bulletin.cvss and bulletin.cvss.score)

    # Fetch a single document by id  -> Bulletin | None
    cve = v.search.get_bulletin("CVE-2021-44228")
    if cve is not None:
        print(cve.title, cve.published)
import asyncio

from vulners import AsyncVulners

async def main() -> None:
    async with AsyncVulners(api_key="YOUR_API_KEY_HERE") as v:
        # Full-text search: CVEs known to be exploited in the wild
        page = await v.search.query(
            "type:cve AND enchantments.exploitation.wildExploited:true", limit=10
        )
        print(page.total, "documents match")
        for bulletin in page.data:
            print(bulletin.id, "-", bulletin.title, "-", bulletin.cvss and bulletin.cvss.score)

        # Fetch a single document by id  -> Bulletin | None
        cve = await v.search.get_bulletin("CVE-2021-44228")
        if cve is not None:
            print(cve.title, cve.published)

asyncio.run(main())

page.data holds the current page of results; iterating the page itself (for b in page) transparently walks further pages up to the 10,000-document search window, and v.search.iter_query(...) streams the whole window as a generator.

Validating API Key

Ensure that API key is active and valid with this quick curl request. Replace with actual API key. Remember, keep your API key confidential to prevent unauthorized access.

curl -X POST https://vulners.com/api/v4/audit/software/ \
  -H "Content-Type: application/json" \
  -H "X-Api-Key: <YOUR-API-KEY>" \
  -d '{
    "software": [{"product": "django", "version": "1.9"}], "fields": []
  }'

In Python you get the same signal for free: on an invalid key the client raises AuthenticationError — a subclass of VulnersError — with the key redacted from the error payload, so it never leaks into logs.

What's new in v4

Fully typed data model

Every search and document call returns pydantic models instead of raw dicts. The hierarchy mirrors the Vulners data model: a base Bulletin → 18 family models (cve, exploit, unix, microsoft, scanner, …) → ~238 per-collection models. The most specific model is chosen automatically from the document's type, isinstance checks hold at every level, unknown collections fall back to GenericBulletin, and fields that are not modelled yet are still preserved on the object.

from vulners import CveBulletin, Vulners

with Vulners() as v:
    cve = v.search.get_bulletin("CVE-2021-44228", fields=["*"])

    print(cve.type, cve.bulletin_family)            # snake_case attributes
    print(cve.cvss.score if cve.cvss else None)     # nested typed objects (CVSS, EPSS, ...)
    print(cve.epss[0].epss if cve.epss else None)   # EPSS probability
    print(isinstance(cve, CveBulletin))             # True

    raw = cve.model_dump()                          # plain dict when you need JSON

Field-by-field reference for every family and collection lives in the SDK repository: data models.

Sync and async, mirrored

Vulners and AsyncVulners expose identical resource namespaces with identical signatures — every method has an awaitable twin, and auto-paginating iterators get an a-prefix (iter_queryaiter_query, iter_collectionaiter_collection). Any example in this documentation converts to async by adding await and async with:

from vulners import Vulners

with Vulners() as v:
    results = v.audit.software(["cpe:2.3:a:apache:log4j:2.14.1"])
import asyncio

from vulners import AsyncVulners

async def main() -> None:
    async with AsyncVulners() as v:
        results = await v.audit.software(["cpe:2.3:a:apache:log4j:2.14.1"])

asyncio.run(main())

Documentation built in

The package repository carries its entire documentation next to the code — readable offline, greppable, and indexable by your tools:

  • documentation/ — quickstart tutorial, task-focused how-to guides, full API reference, and explanations of the network, error and pagination models.
  • api.md — a generated one-file index of every method: signature, return type and HTTP route.
  • llms.txt — an llms.txt-standard index of every documentation page.

100% agent-friendly

v4 is designed to be driven by AI coding agents as comfortably as by humans. Point Claude Code, Cursor or Codex at the repository (or the installed package) and it discovers everything it needs without guessing:

  • AGENTS.md — a task-oriented guide with install, authentication, the full namespace → method map, and agent-specific notes on pagination, errors and billing.
  • .agents/skills/vulners-api/ — a ready-made skill folder that agents pick up in repository checkouts.
  • Fully typed models with docstrings — agents and IDEs read exact field names and signatures instead of reverse-engineering JSON.
  • Safe by default — the API key is held as a secret and redacted from error messages, so it does not leak into agent transcripts or logs.

Built-in MCP server

The mcp extra ships a minimal, self-hosted Model Context Protocol server, so any MCP client — Claude Code, Claude Desktop, Cursor, VS Code — can call Vulners as tools:

pip install -U "vulners[mcp]"
export VULNERS_API_KEY=YOUR_API_KEY_HERE
vulners-mcp   # serves MCP over stdio; python -m vulners.mcp also works
Tool Purpose
search_bulletins(query, limit, offset) Lucene search across the whole database; paginated
get_bulletin(id, fields, full) fetch one bulletin — compact summary by default
search_exploits(query, limit, offset) exploits and PoCs for a CVE or product
cve_lookup(cve) CVE risk attributes: CVSS, CWE, CPE, EPSS
audit_software(software, match) vulnerabilities for CPE / software strings
audit_linux(os_name, os_version, packages) vulnerabilities for a Linux package list
smart_audit(software) free-form names → CPE/PURL + vulnerabilities (billed per string)

Responses are deliberately compact — long strings are clipped and long lists are capped — so tool output stays inside an agent's context budget. The key is always passed via the environment, never on the command line:

claude mcp add vulners -e VULNERS_API_KEY=YOUR_API_KEY_HERE -- vulners-mcp
{
  "mcpServers": {
    "vulners": {
      "command": "vulners-mcp",
      "env": { "VULNERS_API_KEY": "YOUR_API_KEY_HERE" }
    }
  }
}

Claude Desktop: Settings → Developer → Edit Config (claude_desktop_config.json). Cursor: .cursor/mcp.json (project) or ~/.cursor/mcp.json (global).

Prefer zero setup?

The official fully managed MCP endpoint is hosted at mcp.vulners.com — nothing to install and always on. See Vulners MCP for connection details, available tools and usage patterns.

Upgrading from v3

v4 is 100% backward compatible: the legacy VulnersApi / VScannerApi classes keep working unchanged, so upgrading is just pip install -U vulners. New code should use the Vulners / AsyncVulners clients — the migration guide maps every v3 method to its v4 equivalent.

Next steps

  • Quickstart — the three basic calls: search, audit, and archive.
  • API Reference — every endpoint with curl and Python examples.
  • Data model — the document schema behind the typed models.
  • Vulners MCP — the hosted MCP endpoint for AI assistants.