Skip to main content
Glama
millsks

nvd-cve-mcp-server

by millsks
README.md
# NVD CVE MCP Server (Python, stdio)

A Model Context Protocol (MCP) server that exposes CVE search tools backed by the NVD API v2.0.

## Features

- `search_cve_by_id` — look up an exact CVE ID (e.g. `CVE-2024-1234`)
- `search_cve_by_keyword` — search by product name/keyword, with optional `days_back` date filter
- `get_recent_cves` — get newly published CVEs from a configurable time window (default: 7 days)
- `search_by_severity` — filter by severity: `CRITICAL`, `HIGH`, `MEDIUM`, `LOW`
- NVD API rate limiting + automatic retry with exponential backoff (handles 429, 5xx errors)
- Respects `Retry-After` response headers; up to 3 retries per request
- NVD API date range limit enforced: `days_back` is validated against the 120-day maximum
- stdio transport (recommended for Claude Desktop and most MCP clients)

## Data Source

- NVD Vulnerability API v2.0:
  - https://nvd.nist.gov/developers/vulnerabilities
  - Endpoint used: `https://services.nvd.nist.gov/rest/json/cves/2.0`

## Project Structure

```text
nvd_cve_mcp_server/
├── pixi.toml
├── pyproject.toml
├── README.md
└── src/nvd_cve_mcp_server/
    ├── __init__.py
    ├── nvd_client.py
    └── server.py
```

## Setup

### Option 1: pixi (recommended)

Supported platforms: `linux-64`, `linux-aarch64`, `osx-arm64`, `osx-64`, `win-64`

```bash
cd nvd-cve-mcp-server
pixi install
pixi run run-mcp-server
```

### Development workflow (pixi tasks)

The project uses pixi tasks for all quality and packaging workflows:

```bash
pixi run lint          # ruff lint
pixi run format        # ruff formatter
pixi run format-check  # verify formatting only
pixi run typecheck     # mypy (strict)
pixi run test          # pytest
pixi run check         # lint + format-check + typecheck + test
```

### Build and release artifacts

- PyPI artifacts (wheel + sdist) are built with Hatch:

```bash
pixi run build-pypi
```

- Conda package is built from a v1 recipe (`recipe/recipe.yaml`) aligned with conda-forge/feedstock workflows.
  The recipe source is expected to be a version tag tarball (`v<version>`) with a pinned SHA256.

```bash
pixi run build-conda
```

### Changelog generation

`git-cliff` is configured in `pyproject.toml` and generates `CHANGELOG.md` from Conventional Commit history.

```bash
pixi run changelog
```

## Conventional Commits

Use commit messages that follow: `type(scope): description`

Common types:

- `feat`: new functionality
- `fix`: bug fix
- `docs`: documentation changes
- `refactor`: internal refactors
- `test`: tests
- `build`: packaging/build tooling
- `ci`: CI/CD changes
- `chore`: maintenance

Examples:

- `feat(server): add severity filter tool`
- `fix(nvd): handle retry-after parsing`
- `build(release): add hatch pypi build task`

History rewrite note: if commit history is rewritten to conform to Conventional Commits, coordinate with collaborators and force-push carefully.

### Option 2: pip / venv

```bash
cd nvd-cve-mcp-server
python -m venv .venv
source .venv/bin/activate
pip install -e .
python -m nvd_cve_mcp_server.server
```

## Configuration

Environment variables:

- `NVD_API_KEY` (optional, recommended for higher NVD rate limits)
- `NVD_RATE_LIMIT_REQUESTS` (optional)
- `NVD_RATE_LIMIT_WINDOW_SECONDS` (optional)

Defaults used by server:

- Without API key: `5` requests / `30` seconds
- With API key: `50` requests / `30` seconds

## MCP Transport

The server uses **stdio transport**:

```python
mcp.run(transport="stdio")
```

## Example MCP Client Configuration (Claude Desktop style)

Adjust Python path/environment for your machine:

```json
{
  "mcpServers": {
    "cve": {
      "command": "python",
      "args": ["-m", "nvd_cve_mcp_server.server"],
      "cwd": "/path/to/nvd-cve-mcp-server",
      "env": {
        "NVD_API_KEY": "your_api_key_here"
      }
    }
  }
}
```

## Tool Usage Examples

### 1) `search_cve_by_id`

**Input:**
```json
{ "cve_id": "CVE-2024-3094" }
```

### 2) `search_cve_by_keyword`

Search by keyword with no date filter:

**Input:**
```json
{ "keyword": "openssl", "limit": 5 }
```

Search by keyword limited to the last 30 days (`days_back` max is 120):

**Input:**
```json
{ "keyword": "openssl", "limit": 5, "days_back": 30 }
```

### 3) `get_recent_cves`

Defaults to the last 7 days. Accepts any value from 1–120 for `days_back`:

**Input:**
```json
{ "limit": 10, "days_back": 7 }
```

### 4) `search_by_severity`

**Input:**
```json
{ "severity": "HIGH", "limit": 10 }
```

## Response Shape

Each tool returns a normalized structure like:

```json
{
  "success": true,
  "total_results": 123,
  "returned_results": 10,
  "cves": [
    {
      "id": "CVE-2024-0001",
      "published": "2024-01-01T00:00:00.000",
      "last_modified": "2024-01-02T00:00:00.000",
      "description": "...",
      "severity": "HIGH",
      "base_score": 7.5,
      "vector": "CVSS:3.1/...",
      "cwes": ["CWE-79"],
      "references": ["https://..."]
    }
  ]
}
```

Error case:

```json
{
  "success": false,
  "error": "NVD API request failed ..."
}
```

## Error Handling & Retry Behavior

The `NVDClient` automatically retries transient failures up to **3 times** using exponential backoff with jitter:

| Condition | Behavior |
| --- | --- |
| HTTP 429 / 5xx | Retry with backoff; honour `Retry-After` header if present |
| Timeout | Retry with backoff |
| Network error | Retry with backoff |
| Invalid date range (`days_back > 120`) | Immediate error — no retry |
| Invalid severity value | Immediate error — no retry |

TDQS

A3.5/5.0

Scored across 4 tools

Disambiguation5/5

Each tool has a clearly distinct purpose: recent CVEs, severity filter, ID lookup, and keyword search. No overlap or confusion.

Naming Consistency3/5

Mixed naming patterns: 'get_recent_cves' uses 'get' while others use 'search'. Also 'search_by_severity' lacks 'cve' unlike 'search_cve_by_id' and 'search_cve_by_keyword'.

Tool Count5/5

With 4 tools covering common CVE search methods, the count is well-scoped for the purpose without being excessive.

Completeness4/5

Core CVE queries (time, severity, ID, keyword) are covered. Missing explicit date range or CVSS score search but acceptable for a simple server.

Maintenance

ActivityInactive
ResponsivenessUnresponsive