Metadata-Version: 2.5
Name: exploitwatch-mcp
Version: 0.1.0
Summary: MCP server for CVE triage: NVD details, CISA KEV exploitation status, EPSS scores, trusted news, and a rule-based patch urgency.
Project-URL: Homepage, https://github.com/charlesdata1/exploitwatch-mcp
Project-URL: Repository, https://github.com/charlesdata1/exploitwatch-mcp
Project-URL: Issues, https://github.com/charlesdata1/exploitwatch-mcp/issues
Author: Charles Bryant
License-Expression: MIT
License-File: LICENSE
Keywords: cve,epss,kev,mcp,nvd,security,vulnerability
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Information Technology
Classifier: Programming Language :: Python :: 3
Classifier: Topic :: Security
Requires-Python: >=3.11
Requires-Dist: mcp<2,>=1.30
Requires-Dist: pydantic>=2
Requires-Dist: python-dotenv>=1
Requires-Dist: requests>=2.31
Requires-Dist: tavily-python>=0.8.5
Description-Content-Type: text/markdown

# exploitwatch-mcp

<!-- mcp-name: io.github.charlesdata1/exploitwatch-mcp -->

An [MCP](https://modelcontextprotocol.io) server for CVE triage. Give your AI assistant a CVE ID and it can
look up what the vulnerability is, whether attackers are exploiting it right now, how likely exploitation
is, and how urgently to patch.

It is the vulnerability-intelligence half of [ExploitWatch](#about), packaged so any MCP client can use it.

## Who it's for, and who it isn't

Everything it returns comes from free public sources (NVD, CISA KEV, FIRST EPSS, trusted news sites). What it
adds is a consistent, versioned triage method; a score that always says who gave it and under which CVSS
version; and access from inside the AI assistant your team already uses.

**Good fit**

- **Analysts with one CVE in front of them**, from a scanner finding, an advisory or a ticket, who want a sourced
  first answer in seconds instead of checking NVD, KEV and EPSS by hand.
- **Explaining a CVE to leadership.** The `triage_cve` prompt's `exec` format writes a short summary: the risk,
  the urgency and why, and the decision needed.
- **Teams that want one method across different assistants.** Everyone gets the same urgency rules and score
  order whether they use Claude, Cursor or another MCP client, and `methodology_version` records which rules
  applied.
- **Builders of security agents**, as a tested tool layer that keeps the urgency decision in code rather than
  in the model.

**Not a fit**

- **Not a scanner or asset inventory.** It doesn't know what you run or how exposed it is. Use it alongside the
  tool that does.
- **Not a backlog prioritiser.** It handles one CVE per call. For thousands of findings, use the KEV and EPSS
  feeds directly or your vulnerability management platform.
- **Little new data if you already have a vulnerability management platform.** If yours already shows KEV and
  EPSS, this adds conversational access and a shared method, not new intelligence.
- **Not a compliance decision.** The urgency bands are a sensible default, not your organisation's patch SLAs.

## What it provides

| Kind | Name | What it does |
|---|---|---|
| Tool | `lookup_cve` | Description, one CVSS score with its version and source, NVD's analysis status, publish date and references from the NIST National Vulnerability Database, plus a patch urgency rating |
| Tool | `check_kev` | Whether CISA's Known Exploited Vulnerabilities catalog lists the CVE, with the date added, required action, federal due date and ransomware use |
| Tool | `get_epss` | FIRST's EPSS probability that the CVE is exploited in the next 30 days, and its percentile |
| Tool | `search_cve_news` | Recent articles about the CVE from an allowlist of trusted security news sites and vendor advisories |
| Resource | `exploitwatch://methodology` | How urgency is calculated and which data sources are used |
| Prompt | `triage_cve` | A full triage of one CVE, written for an `engineer` or an `exec` |

## Patch urgency is decided by rules, not the model

The same data always gets the same urgency, so results are consistent and auditable and can't be
changed by prompt wording or web content. The first matching rule wins:

1. Actively exploited (in CISA KEV, checked live as well as NVD's copy, which can lag by days): **patch now**
2. No CVSS score yet: **needs review**. Nobody has rated it, which is not the same as low risk.
3. CVSS 9.0 or higher: **patch now**
4. CVSS 7.0 to 8.9: **patch this week**
5. CVSS 4.0 to 6.9: **patch this month**
6. Below 4.0: **monitor**

Rejected (withdrawn) CVEs get no urgency; `lookup_cve` says the CVE was rejected. EPSS is reported
as context and does not change the urgency.

### Which CVSS score

Most CVEs have several scores, and NVD no longer analyses most new ones, so the score is usually
the one from the CNA (the organisation that assigned the CVE). The order is: NVD's own score, then
the CNA's or CISA's; within each, CVSS 3.1, then 4.0, then 3.0; CVSS 2.0 only when nothing newer
exists. 3.1 comes first because the thresholds are the CVSS 3 bands. In a sample of 2,000 October
2026 CVEs, a CVE's 4.0 and 3.1 scores fell in different bands 41% of the time.

Every result shows its working:

```json
{
  "id": "CVE-2021-44228",
  "cvss_score": 10.0,
  "severity": "CRITICAL",
  "cvss_version": "3.1",
  "cvss_source": "NVD",
  "nvd_status": "Analyzed",
  "actively_exploited": true,
  "kev_checked": true,
  "kev_catalog_version": "2026.10.30",
  "urgency": "patch now",
  "urgency_reason": "actively exploited; exploitation outranks the CVSS score",
  "methodology_version": "1"
}
```

`kev_checked: false` means CISA's catalog could not be reached, so exploitation status rests on
NVD's copy alone; `kev_catalog_version` is the date of the catalog used. The full rules are in the `exploitwatch://methodology` resource.

## Does it have a UI?

No. An MCP server has no interface of its own: your MCP client (Claude Desktop, Claude Code, Cursor and
others) is the interface. You ask in plain language, for example "Triage CVE-2024-3094", and the client
calls these tools.

To try the tools by hand, the MCP Inspector opens a browser page where you can call each one:

```bash
npx @modelcontextprotocol/inspector uvx exploitwatch-mcp
```

## Install

You need [uv](https://docs.astral.sh/uv/). There is nothing else to install: `uvx` fetches and runs the server.

**Claude Code**

```bash
claude mcp add exploitwatch -- uvx exploitwatch-mcp
# with API keys: claude mcp add exploitwatch -e TAVILY_API_KEY=your-key -e NVD_API_KEY=your-key -- uvx exploitwatch-mcp
```

**Claude Desktop** (`claude_desktop_config.json`)

```json
{
  "mcpServers": {
    "exploitwatch": {
      "command": "uvx",
      "args": ["exploitwatch-mcp"],
      "env": {
        "TAVILY_API_KEY": "your-key",
        "NVD_API_KEY": "optional"
      }
    }
  }
}
```

**From a clone**: replace `uvx exploitwatch-mcp` with `uv run --directory /path/to/exploitwatch-mcp exploitwatch-mcp`.

## Configuration

| Variable | Needed for | |
|---|---|---|
| `TAVILY_API_KEY` | `search_cve_news` | Optional. Without a key, news search uses Tavily's keyless mode, which is rate-limited and may be refused. Set a key from [tavily.com](https://tavily.com) for dependable results. The other tools never need it. |
| `NVD_API_KEY` | `lookup_cve` | Optional. Raises NVD's rate limit. [Request one from NIST](https://nvd.nist.gov/developers/request-an-api-key). |

Set them in your MCP client's `env` block, as above. When running from a clone, a `.env` file in the directory you start the server from also works (see `.env.example`).

## Data sources

| Source | Used for | Notes |
|---|---|---|
| [NIST NVD](https://nvd.nist.gov/developers) | CVE details and CVSS | This product uses the NVD API but is not endorsed or certified by the NVD. |
| [CISA KEV](https://www.cisa.gov/known-exploited-vulnerabilities-catalog) | Confirmed exploitation | The catalog is downloaded once and cached for 6 hours. If it can't be reached, urgency falls back to NVD's exploitation flag. |
| [FIRST EPSS](https://www.first.org/epss/) | Exploitation probability | Updated daily by FIRST. |
| [Tavily](https://tavily.com) | News search | Limited to an allowlist of security news and vendor sites, checked by the server on every result, not just requested from Tavily. Only articles that mention the exact CVE ID are returned. |

## Validation

Before release, 10 base and edge cases were run end to end: Claude answered each one using this server's
tools, code checked the raw tool output, and a separate LLM judge (gpt-5-mini) scored every answer on a
7-point rubric, with 3 runs per case. The server's output was correct in all 60 runs. Round 1 found two
defects in the guidance the server gives assistants, both fixed before round 2; round 3 confirmed the
urgency reason ("patch now" because it is actively exploited) on Heartbleed.

- Report (2 pages): [evals/results/2026-11-04-mvp-validation.pdf](https://github.com/charlesdata1/exploitwatch-mcp/blob/main/evals/results/2026-11-04-mvp-validation.pdf)
- Every case, run, tool output, answer and judge verdict: [evals/results/2026-11-04-mvp-validation.csv](https://github.com/charlesdata1/exploitwatch-mcp/blob/main/evals/results/2026-11-04-mvp-validation.csv)
- Cases: [evals/mvp_cases.yaml](https://github.com/charlesdata1/exploitwatch-mcp/blob/main/evals/mvp_cases.yaml); rerun: `uv run --group eval python evals/run_mvp_validation.py --out new.csv`

A second validation tested executive summaries and the news domain allowlist (10 cases, 3 runs each).
Exec summaries met the sentence limit in 12 of 15 runs, up from 1 of 3, and no answer claimed to have read
a site outside the allowlist. Two exec wording gaps it found were fixed and re-tested (6 of 6 runs). After the
human review, exec summaries may again name an affected or fixed software version where the data states it,
because the version to upgrade to is part of the decision.

- Report (2 pages): [evals/results/2026-11-04-exec-domain-validation.pdf](https://github.com/charlesdata1/exploitwatch-mcp/blob/main/evals/results/2026-11-04-exec-domain-validation.pdf)
- Every case, run and verdict: [evals/results/2026-11-04-exec-domain-validation.csv](https://github.com/charlesdata1/exploitwatch-mcp/blob/main/evals/results/2026-11-04-exec-domain-validation.csv)
- Cases: [evals/exec_domain_cases.yaml](https://github.com/charlesdata1/exploitwatch-mcp/blob/main/evals/exec_domain_cases.yaml); rerun: `uv run --group eval python evals/run_mvp_validation.py --spec evals/exec_domain_cases.yaml --out new.csv`

A human review checked the evaluation by hand: 10 of the judge's verdicts across both validations, and 3
expected values against NVD's and CISA's own pages (all 3 matched). The reviewer agreed with 6 of 9 judge
verdicts. All 3 disagreements were the judge or a test criterion being too strict, and none was a wrong
answer the judge had passed. Record and evidence: [evals/human_review/](https://github.com/charlesdata1/exploitwatch-mcp/blob/main/evals/human_review/).

## Limits

- It knows about CVEs, not about you: it can't tell whether you run the affected software or how exposed it is.
- One CVE per call, and no search by product.
- CVSS is a severity score, not a risk score. Treat the urgency as a first answer, not a compliance decision.
- Without an `NVD_API_KEY`, NVD allows about 5 requests per 30 seconds.
- The urgency is enforced in code, but the wording of an answer is the client model's. In validation the
  server's own output was correct in every run, but some answers added background from the model's own
  knowledge, and exec summaries sometimes ran a sentence long.
- The domain allowlist governs `search_cve_news` only. If your client also has its own web search or browsing,
  the model can use that, and no MCP server can prevent it.

## Safety

- **News is untrusted.** Search results are third-party web content. The tool description tells the model to
  treat them as information, never as instructions, and they never change the urgency rating.
- **Clean errors.** Requests retry timeouts, rate limits and server errors. When a source is still
  unavailable, the tool returns a short message telling the model to report the data as missing rather
  than guess. Full errors go to the server log on stderr.
- **Strict input.** Every tool accepts exactly one CVE ID (`CVE-YYYY-NNNN`, any case) and rejects anything else before a request is sent.
- **Read only.** The server only reads public data. It changes nothing on your systems.

## Roadmap

- **Several CVEs per request**, for triaging a list from a scanner or an advisory.
- **Organisation context**: pair this data with your own asset lists and policies (ExploitWatch's RAG layer).
- **Source traceability**: anything an answer takes from outside these tools is labelled as such, with its source.
- **Configurable allowlist**: an organisation can approve additional news and advisory domains.
- **Optional decision inputs**: SSVC decision points, and EPSS as an optional urgency input.
- **Readability and upkeep**: CNA names instead of IDs, and a scheduled live check against the real APIs.

## Development

```bash
uv sync
uv run pytest                        # offline, uses saved NVD records
uv run python scripts/live_check.py  # live end to end against NVD, KEV, EPSS and Tavily (about 1.5 minutes)
uv run exploitwatch-mcp
```

## About

ExploitWatch is a multi-agent CVE triage system, in development, that pairs this public intelligence with an
organisation's own documents, to answer both how dangerous a vulnerability is and what the organisation must
do about it.

## License

[MIT](https://github.com/charlesdata1/exploitwatch-mcp/blob/main/LICENSE)
