io.github.cyanheads/nist-nvd-mcp-server icon

nist-nvd-mcp-server

by Cyanheads

io.github.cyanheads/nist-nvd-mcp-server

Search and audit NIST NVD CVEs by keyword, severity, CWE, CISA KEV status, and CPE.

Version 0.2.0 · latest
Security
Local
View source

nist-nvd-mcp-server · v0.2.0 (latest)

by Cyanheads

75

@cyanheads/nist-nvd-mcp-server

Search and audit CVEs by keyword, severity, CWE, CISA KEV status, and CPE via the NIST National Vulnerability Database. STDIO or Streamable HTTP.

5 Tools • 1 Resource

Install in Cursor

Public Hosted Server: https://nist-nvd.caseyjhand.com/mcp


Tools

Five tools for vulnerability research, CPE auditing, and change tracking against the NIST NVD API 2.0:

Tool Description
nvd_search_cves Search CVEs by keyword, severity, CWE, date range, or CISA KEV status.
nvd_get_cve Fetch one or more CVEs by ID — full CVSS scores, CWE, CPE configs, KEV fields, and references.
nvd_search_cpes Search the NVD CPE dictionary by product keyword or partial match string.
nvd_audit_cpe Find all CVEs affecting a specific product version by CPE name or virtual match string.
nvd_get_cve_history Retrieve the change history for a CVE — score revisions, status transitions, and reference additions.

nvd_search_cves

The primary discovery tool for vulnerability surveillance and triage workflows.

  • Full-text keyword search across CVE descriptions (AND-semantics across words), or exactPhrase: true to match the keyword as a phrase
  • Severity filter by CVSS v2/v3/v4 label (LOW, MEDIUM, HIGH, CRITICAL)
  • CWE weakness filter (e.g., CWE-79, NVD-CWE-Other)
  • CISA KEV filter — limit results to known-exploited vulnerabilities
  • Convenience date shorthands: pubDays and lastModDays for "last N days" queries
  • Explicit ISO 8601 date range parameters (pubStartDate/pubEndDate, etc.) with 120-day max span
  • Auto-clamps convenience date params that exceed 120 days and reports clamped values in the response enrichment
  • Pagination via limit (up to 2000) and offset
  • Every row carries a truncated description alongside the ID, so results are distinguishable without a follow-up fetch
  • Results are always brief; call nvd_get_cve for full detail

nvd_get_cve

Fetch one or more CVEs by ID with full detail or brief summaries.

  • Batch up to 100 CVE IDs per call
  • Full mode: all CVSS scores across v2.0, v3.0, v3.1, and v4.0; CWE weaknesses; CPE configurations; CISA KEV fields; references
  • Brief mode (brief: true): ID, status, top severity, KEV name, truncated description — recommended for batches larger than 10
  • includeReferences: false to strip the references array and reduce response size
  • Per-ID parity check: the missingIds enrichment field lists any requested IDs NVD didn't return
  • Rendered text carries the affected-product criteria and references the record holds, capped with a … N more trailer; allLanguages: true renders every localized description, not just English

nvd_search_cpes

Look up product identifiers before auditing.

  • Keyword search (e.g., "apache http server", "openssl") or partial CPEv2.3 pattern
  • Returns full CPE name, human-readable title, deprecation status, and superseding CPEs
  • Pagination via limit (up to 10,000 per page) and offset — a vendor-level keyword can match tens of thousands of entries, so page with offset rather than trying to narrow further
  • Use this before nvd_audit_cpe — CPE names are arcane strings; guessing audits the wrong product

nvd_audit_cpe

Full CVE audit for a specific product version.

  • Two modes: exact cpeName (NVD auto-applies isVulnerable) or virtualMatchString with optional version range bounds
  • Version range via versionStart/versionEnd with inclusive/exclusive type control
  • Client-side severity filter (severityMin) to strip low-signal entries
  • Returns full CVE records (ID, CVSS scores, CWE, CPE configurations, KEV fields, references)
  • Pagination via limit (up to 2000) and offset — page at a modest limit instead of raising it, since each result is a full record
  • Echoes the CPE identifier used in the response enrichment so callers can verify the correct product was queried

nvd_get_cve_history

Track a CVE's lifecycle over time.

  • Returns change events: CVSS revisions, status transitions, reference additions, CPE configuration updates
  • order picks which end to read from — newest (default) returns the most recent events first, oldest returns NVD's native oldest-first order
  • Paginated via limit and offset, where offset counts from the end order anchors to
  • Note: the NVD history endpoint is significantly slower without an API key — set NVD_API_KEY and raise NVD_REQUEST_TIMEOUT_MS for reliable operation

Resource

Type Name Description
Resource nvd://cve/{cveId} Full CVE record by ID — same data as nvd_get_cve for a single ID, as a stable URI for injectable context.

All resource data is also reachable via tools.

Features

Built on @cyanheads/mcp-ts-core:

  • Declarative tool, resource, and prompt definitions — single file per primitive, framework handles registration and validation
  • Unified error handling — handlers throw, framework catches, classifies, and formats
  • Pluggable auth: none, jwt, oauth
  • Swappable storage backends: in-memory, filesystem, Supabase, Cloudflare KV/R2/D1
  • Structured logging with optional OpenTelemetry tracing
  • STDIO and Streamable HTTP transports

NVD-specific:

  • Request pacer enforces NVD's 5 req/30s (no key) and 50 req/30s (with key) limits with automatic queuing, at a minimum inter-request gap derived from the window and limit
  • Retry wraps the pacer rather than sitting inside it — every attempt takes its own turn in the queue, so retries count against the rate budget instead of bursting past it
  • A 403's Retry-After holds the whole queue until NVD's window resets. Keyless, a 403 fails fast and names NVD_API_KEY rather than spending a 5-request budget on retries that cannot outlast a 30-second window
  • Deterministic rejections fail fast instead of consuming retries. NVD answers both a bad parameter and a refused API key with HTTP 404, separated only by a message header — a refused key surfaces as a config fault naming NVD_API_KEY rather than as a malformed CVE ID
  • HTML-response guard catches NVD rate-limit pages served as HTML instead of 403

Agent-friendly output:

  • An enrichment block on every response, carried on both structuredContent and the rendered text — total results, returned count, page offset, the filters actually applied, and any date-clamping events, so agents can reason about what was really queried
  • missingIds in batch CVE lookups — per-ID parity check instead of a silent partial result
  • CPE echo in audit responses — cpeName or virtualMatchString reflected back so callers can verify the correct product was audited
  • Empty-result notices that name the cause — an unmatched query, a severity threshold that emptied the page, and an offset past the end of the result set are told apart rather than all reading as "nothing found"
  • An audit that finds nothing is a result, not an error — a product with no CVEs in NVD returns an empty page with totalCount: 0 on either input arm, so "no known vulnerabilities" reads as the answer it is

Getting started

Add the following to your MCP client configuration file.

{
  "mcpServers": {
    "nist-nvd-mcp-server": {
      "type": "stdio",
      "command": "bunx",
      "args": ["@cyanheads/nist-nvd-mcp-server@latest"],
      "env": {
        "MCP_TRANSPORT_TYPE": "stdio",
        "MCP_LOG_LEVEL": "info",
        "NVD_API_KEY": "your-api-key"
      }
    }
  }
}

Or with npx (no Bun required):

{
  "mcpServers": {
    "nist-nvd-mcp-server": {
      "type": "stdio",
      "command": "npx",
      "args": ["-y", "@cyanheads/nist-nvd-mcp-server@latest"],
      "env": {
        "MCP_TRANSPORT_TYPE": "stdio",
        "MCP_LOG_LEVEL": "info",
        "NVD_API_KEY": "your-api-key"
      }
    }
  }
}

Or with Docker:

{
  "mcpServers": {
    "nist-nvd-mcp-server": {
      "type": "stdio",
      "command": "docker",
      "args": [
        "run", "-i", "--rm",
        "-e", "MCP_TRANSPORT_TYPE=stdio",
        "-e", "NVD_API_KEY=your-api-key",
        "ghcr.io/cyanheads/nist-nvd-mcp-server:latest"
      ]
    }
  }
}

For Streamable HTTP, set the transport and start the server:

MCP_TRANSPORT_TYPE=http MCP_HTTP_PORT=3010 NVD_API_KEY=... bun run start:http
# Server listens at http://localhost:3010/mcp

Prerequisites

  • Bun v1.3.0 or higher (or Node.js v24+).
  • Optional: NVD API key — free, raises rate limit from 5 req/30s to 50 req/30s.

Installation

  1. Clone the repository:
git clone https://github.com/cyanheads/nist-nvd-mcp-server.git
  1. Navigate into the directory:
cd nist-nvd-mcp-server
  1. Install dependencies:
bun install
  1. Configure environment:
cp .env.example .env
# edit .env and set NVD_API_KEY if you have one

Configuration

Variable Description Default
NVD_API_KEY NVD API key. Without it, rate limit is 5 req/30s; with it, 50 req/30s. Get one free at nvd.nist.gov/developers/request-an-api-key.
NVD_REQUEST_TIMEOUT_MS Per-request timeout in milliseconds. The history endpoint is slow without an API key — raise to 60000 if using nvd_get_cve_history without a key. 10000
MCP_TRANSPORT_TYPE Transport: stdio or http. stdio
MCP_HTTP_PORT Port for HTTP server. 3010
MCP_AUTH_MODE Auth mode: none, jwt, or oauth. none
MCP_LOG_LEVEL Log level (RFC 5424). info
LOGS_DIR Directory for log files (Node.js only). <project-root>/logs
OTEL_ENABLED Enable OpenTelemetry instrumentation. false

See .env.example for the full list of optional overrides.

Running the server

Local development

  • Build and run:

    # One-time build
    bun run rebuild
    
    # Run the built server
    bun run start:stdio
    # or
    bun run start:http
    
  • Run checks and tests:

    bun run devcheck   # Lint, format, typecheck, security
    bun run test       # Vitest test suite
    bun run lint:mcp   # Validate MCP definitions against spec
    

Docker

docker build -t nist-nvd-mcp-server .
docker run --rm -e NVD_API_KEY=your-key -p 3010:3010 nist-nvd-mcp-server

The Dockerfile defaults to HTTP transport, stateless session mode, and logs to /var/log/nist-nvd-mcp-server. OpenTelemetry peer dependencies are installed by default — build with --build-arg OTEL_ENABLED=false to omit them.

Project structure

Directory Purpose
src/index.ts createApp() entry point — registers tools/resources and inits services.
src/config Server-specific environment variable parsing and validation with Zod.
src/mcp-server/tools Tool definitions (*.tool.ts).
src/mcp-server/resources Resource definitions (*.resource.ts).
src/services/nvd-http NVD HTTP client with rate-limit pacing and retry.
src/services/nvd-cve CVE service — search, fetch-by-ID, CPE audit, change history, normalization.
src/services/nvd-cpe CPE service — dictionary search and normalization.
src/services/nvd-source Source service — resolves NVD contributor identifiers to their published names.
tests/ Unit and integration tests mirroring src/.

Development guide

See CLAUDE.md for development guidelines and architectural rules. The short version:

  • Handlers throw, framework catches — no try/catch in tool logic
  • Use ctx.log for request-scoped logging, ctx.state for tenant-scoped storage
  • Register new tools and resources via the barrels in src/mcp-server/*/definitions/index.ts
  • Wrap external API calls: validate raw → normalize to domain type → return output schema; never fabricate missing fields

Contributing

Issues and pull requests are welcome. Run checks and tests before submitting:

bun run devcheck
bun run test

License

Apache-2.0 — see LICENSE for details.