mcp-nvd
# NVD Database MCP Server
[](https://pypi.org/project/mcp-nvd)
<a href="https://glama.ai/mcp/servers/@marcoeg/mcp-nvd">
<img width="380" height="200" src="https://glama.ai/mcp/servers/@marcoeg/mcp-nvd/badge" />
</a>
A [Model Context Protocol](https://modelcontextprotocol.io/) server implementation to query the NIST National Vulnerability Database (NVD) via its API. [https://nvd.nist.gov/](https://nvd.nist.gov/)
As a prerequisite an NVD API key is required. ([Request here](https://nvd.nist.gov/developers/request-an-api-key)).
## Status
Works with Claude Desktop app and other MCP compliant hosts and clients using both the `stdio` and `sse` transports.
## Features
- Query specific CVEs by ID with detailed vulnerability data.
- Search the NVD database by keyword with customizable result options.
- Supports Server-Sent Events (SSE) transport for real-time communication.
- Compatible with MCP-compliant clients like Claude Desktop.
### Tools
The server implements the following tools to query the NVD Database:
- **`get_cve`**:
- **Description**: Retrieves a CVE record by its ID.
- **Parameters**:
- `cve_id` (str): The CVE ID (e.g., `CVE-2019-1010218`).
- `concise` (bool, default `False`): If `True`, returns a shorter format.
- **Returns**: Detailed CVE info including scores, weaknesses, and references.
- **`search_cve`**:
- **Description**: Searches the NVD database by keyword.
- **Parameters**:
- `keyword` (str): Search term (e.g., `Red Hat`).
- `exact_match` (bool, default `False`): If `True`, requires an exact phrase match.
- `concise` (bool, default `False`): If `True`, returns shorter CVE records.
- `results` (int, default `10`): Maximum number of CVE records (1-2000).
- **Returns**: List of matching CVEs with total count.
## Configuration
1. Create or edit the Claude Desktop configuration file located at:
- On macOS: `~/Library/Application Support/Claude/claude_desktop_config.json`
- On Windows: `%APPDATA%/Claude/claude_desktop_config.json`
2. Add the following:
```json
{
"mcpServers": {
"mcp-nvd": {
"command": "/path/to/uvx",
"args": ["mcp-nvd"],
"env": {
"NVD_API_KEY": "your-api-key"
}
}
}
}
```
3. Replace `/path/to/uvx` with the absolute path to the `uvx` executable. Find the path with `which uvx` command in a terminal. This ensures that the correct version of `uvx` is used when starting the server.
4. Restart Claude Desktop to apply the changes.
## Development
### Setup
1. **Prerequisites**:
- Python 3.10 or higher.
- An NVD API key ([request here](https://nvd.nist.gov/developers/request-an-api-key)).
- `uv` package manager ([installation](https://docs.astral.sh/uv/)).
2. **Clone the Repository**:
```bash
git clone https://github.com/marcoeg/mcp-nvd
cd mcp-nvd
```
3. **Set Environment Variables**:
- Create a `.env` file in the project root:
```
NVD_API_KEY=your-api-key
```
- Replace `your-api-key` with your NVD API key.
4. **Install Dependencies**:
```bash
uv sync
uv pip install -e .
```
### Run with the MCP Inspector
```bash
cd /path/to/the/repo
source .env
npx @modelcontextprotocol/inspector uv \
--directory /path/to/repo/mcp-nvd run mcp-nvd
```
Then open the browser to the URL indicated by the MCP Inspector, typically `http://localhost:8077?proxyPort=8078`
> Switch freely between `stdio` and `sse` transport types in the inspector.
### Testing with the SSE Client
#### Run the Server:
```bash
cd /path/to/the/repo
source .env
uv run mcp-nvd --transport sse --port 9090
```
- Runs with SSE transport on port `9090` by default.
#### Run the Client:
Test `get_cve`:
```bash
uv run client.py http://localhost:9090/sse CVE-2019-1010218
```
Test `search_cve` (default 10 results):
```bash
uv run client.py http://localhost:9090/sse "search:Red Hat"
```
Test `search_cve` (exact match, 5 results):
```bash
uv run client.py http://localhost:9090/sse "search:Microsoft Windows:exact:5"
```
## Docker Setup
### Build
```bash
docker build -t mcp-nvd:latest .
```
### Run
With `.env`:
```bash
docker run -d -p 9090:9090 -v /path/to/.env:/app/.env mcp-nvd:latest
```
With env var:
```bash
docker run -d -p 9090:9090 -e NVD_API_KEY="your-key" mcp-nvd:latest
```
Custom port:
```bash
docker run -d -p 8080:8080 -v /path/to/.env:/app/.env mcp-nvd:latest uv run mcp-nvd --transport sse --port 8080 --host 0.0.0.0
```
### Verify
```bash
docker logs <container_id>
# Expect: INFO: Uvicorn running on http://0.0.0.0:9090
```
Test:
```bash
uv run client.py http://localhost:9090/sse CVE-2019-1010218
```
### Notes
- Ensure `.env` has `NVD_API_KEY=your-key` or use `-e`.
- Default port: `9090`.
---
Here’s the summary formatted as Markdown comments within a code block, suitable for inclusion in a file like `docker-compose.yaml` or `README.md`:
### Using Docker Compose for Testing
This `docker-compose.yaml`, located in the `tests/` directory, defines a service for testing the MCP-NVD server using a pre-built Docker image. It’s designed for a testing use case, similar to a standalone service like `clickhouse`, and assumes the image is built beforehand rather than rebuilt each time.
#### Assumptions
- **Pre-built Image**: The service uses a pre-built image tagged as `mcp-nvd:test`, available locally or in a registry. The image is based on the `Dockerfile` in the parent directory, which sets up the MCP-NVD server with `uv` and runs it in SSE mode on port 9090.
#### How to Build the Image
To create the `mcp-nvd:test` image:
1. Navigate to the project root:
```bash
cd ./mcp-nvd
```
2. Build the image using the Dockerfile:
```bash
docker build -t mcp-nvd:test .
```
- This builds the image with all dependencies from `pyproject.toml` and the `mcp_nvd/` module, setting the default command to run the server.
#### Running the Service
From the `tests/` directory:
```bash
cd tests
docker-compose up
```
- **Access**: The server runs at `http://localhost:9090`.
- **Stop**: `docker-compose down`.
- **Environment**: Ensure `NVD_API_KEY` is in `../.env` or use `docker-compose --env-file ../.env up`.
#### Running `test_tools.py` in the Docker Compose Scenario
To run the unit tests (`test_tools.py`) within the Docker environment:
1. **Start the Service**: Ensure the `mcp-nvd` service is running via `docker-compose up`.
2. **Exec into the Container**:
- Identify the container name (e.g., `mcp-nvd-mcp-nvd-1`) with:
```bash
docker ps
```
- Run the tests inside the container:
```bash
docker exec -it mcp-nvd-mcp-nvd-1 python /app/tests/test_tools.py
```
- **Note**: Assumes `test_tools.py` is copied into the image at `/app/tests/`. If not, modify the Dockerfile to include:
```dockerfile
COPY tests/ ./tests/
```
Then rebuild the image with `docker build -t mcp-nvd:test .` from the root.
3. **Alternative**: Run tests locally against the containerized service:
```bash
cd tests
python test_tools.py
```
- This tests against `http://localhost:9090` while the service runs.
#### Key Details
- **Port**: 9090 is exposed for SSE access.
- **Logs**: Stored in a `log-data` volume (optional).
- **Image**: Must be built once and tagged as `mcp-nvd:test` before running `docker-compose`.
---
Credits to [@sidharthrajaram](https://github.com/sidharthrajaram/) for its working pattern for SSE-based MCP clients and servers: [https://github.com/sidharthrajaram/mcp-sse](https://github.com/sidharthrajaram/mcp-sse)
TDQS
Scored across 2 tools
The two tools have clearly distinct purposes: get_cve retrieves a specific CVE by ID, while search_cve finds CVEs by keyword. There is no overlap in functionality, making it easy for an agent to choose the correct tool based on whether it needs a specific item or a broader search.
Both tools follow a consistent verb_noun pattern (get_cve and search_cve), using the same base noun 'cve' and descriptive verbs that clearly indicate their actions. This consistency enhances readability and predictability.
With only 2 tools, the server feels thin for the domain of CVE management, as it lacks essential operations like filtering by date, severity, or vendor, or updating/creating entries. While the tools cover basic retrieval and search, the scope is incomplete for typical security workflows.
The tool surface is severely incomplete for CVE management, missing critical operations such as filtering by parameters like date range or CVSS score, handling CVE updates or annotations, and providing bulk operations. This will likely cause agent failures when more complex queries or actions are needed.