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