Skip to main content
Glama
README.md
<p align="center">
  <h1 align="center">๐Ÿ›ก๏ธ VulnPilot</h1>
  <p align="center">
    <strong>Contextual Software Composition Analysis and Exploit Intelligence for AI Assistant Workflows</strong>
  </p>
  <p align="center">
    Powered by <a href="https://osv.dev">OSV.dev</a>, <a href="https://www.first.org/epss/">FIRST EPSS</a>, and <a href="https://www.cisa.gov/known-exploited-vulnerabilities-catalog">CISA KEV</a>
  </p>
  <p align="center">
    <a href="#overview">Overview</a> ยท <a href="#quickstart">Quickstart</a> ยท <a href="#mcp-client-setup">MCP Client Setup</a> ยท <a href="#how-it-works">How It Works</a> ยท <a href="#tool-reference">Tool Reference</a> ยท <a href="#dependency-evidence-guide">Dependency Evidence Guide</a> ยท <a href="#development--testing">Development</a>
  </p>
</p>

---

## Overview

### What It Is

**VulnPilot** is an open-source Model Context Protocol (MCP) server that arms AI coding assistants with deep, contextual dependency analysis. It enables AI agents to query vulnerability advisories in real time, analyze whether vulnerable code paths are actually imported in your project, enrich findings with real-world threat telemetry, and output self-contained HTML security dashboards.

### Why It Is

Modern AI coding assistants (such as Claude Desktop, Cursor, and VS Code Copilot) excel at writing code, suggesting libraries, and refactoring projects. However, AI agents operate blindly regarding security posture:
- They do not know if a recommended package version contains known security vulnerabilities.
- They cannot differentiate between a vulnerability in production code versus one isolated in test utilities.
- They lack real-world threat intelligence to determine if a CVE is actively exploited by threat actors or merely a theoretical risk.

VulnPilot bridges this gap by giving AI assistants native MCP tools to inspect package manifests, parse source code parse-trees, evaluate active exploit databases, and prioritize remediation accurately.

### How Beneficial It Is

- **Noise Reduction:** Avoid blanket package upgrades by identifying whether vulnerable code is actually reachable in your project or restricted to test suites.
- **Real-World Threat Telemetry:** Enriches raw CVE identifiers with FIRST EPSS probability scores (likelihood of exploitation in the next 30 days) and CISA KEV catalog indicators (known active cyberattacks and ransomware campaigns).
- **Direct vs. Transitive Detection:** Automatically inspects lock files (`uv.lock`, `poetry.lock`, `package-lock.json`, `yarn.lock`, etc.) and manifests to distinguish top-level dependencies from sub-dependencies.
- **Zero Friction Setup:** No external API keys, complex setup, or cloud subscriptions required. Runs locally via STDIO.
- **Polished HTML Security Dashboards:** Generates interactive, portable HTML reports complete with executive summaries, sortable vulnerability tables, and color-coded risk gauges.

### For Whom It Is

VulnPilot is built for:
- **Software Engineers:** Seeking automated security checks while writing code alongside AI assistants.
- **Security & DevOps Teams:** Requiring evidence-based vulnerability triage without false-alarm alerts.
- **AI Pair Programmers:** Developers using Claude Desktop, Cursor, VS Code Copilot, Zed, Windsurf, or custom agentic workflows who want their AI assistants to write secure, audited code by default.

---

## Core Ecosystems & Intelligence Sources

### Supported Ecosystems

| Ecosystem | Vulnerability Lookup | Static Reachability Analysis | Scope & Direct/Transitive Detection | Package Coordinate Format | Example |
| :--- | :--- | :--- | :--- | :--- | :--- |
| **PyPI** | Yes (`check_package`) | Yes (`analyze_python_reachability`) | Direct & Transitive | `package-name` | `django` |
| **npm** | Yes (`check_package`) | Yes (`analyze_javascript_reachability`) | Direct & Transitive | `package-name` | `lodash` |
| **Maven** | Yes (`check_package`) | Yes (`analyze_java_reachability`) | Direct & Transitive | `groupId:artifactId` | `org.apache.logging.log4j:log4j-core` |
| **Gradle** | Yes (`check_package`) | Yes (`analyze_java_reachability`) | Direct & Transitive | `groupId:artifactId` | `com.google.guava:guava` |

### Threat Intelligence Telemetry

- **OSV.dev API:** Real-time vulnerability advisories from PyPI, npm, Maven, and OSV databases.
- **FIRST EPSS (Exploit Prediction Scoring System):** Probability metrics detailing the likelihood of a vulnerability being exploited in the wild within 30 days.
- **CISA KEV (Known Exploited Vulnerabilities):** Catalog flagging vulnerabilities actively exploited in real-world cyberattacks or ransomware campaigns.

---

## Quickstart

### Prerequisites

| Requirement | Minimum Version | Recommended Tool |
| :--- | :--- | :--- |
| **Python** | $\ge$ 3.10 | Installed system Python |
| **uv** | Latest | [Astral uv package manager](https://docs.astral.sh/uv/) |

### Installation

```bash
# Clone the repository
git clone https://github.com/arojit/vulnpilot-mcp.git
cd vulnpilot-mcp

# Sync environment and install dependencies
uv sync
```

### Verify Installation

Optionally, run this to confirm the server starts correctly before configuring your MCP client:

```bash
uv run vulnpilot-mcp
```

> **Note:** You do **not** need to run this manually during normal use. Your MCP client (Claude Desktop, Cursor, VS Code, etc.) launches the server process automatically via the configuration below. Simply configure the client and restart it.


---

## MCP Client Setup

Configure VulnPilot in your preferred AI environment:

<details>
<summary><strong>Claude Desktop</strong></summary>

Add the server configuration to `claude_desktop_config.json`:

```json
{
  "mcpServers": {
    "vulnpilot": {
      "command": "/absolute/path/to/uv",
      "args": [
        "--directory", "/absolute/path/to/vulnpilot-mcp",
        "run", "vulnpilot-mcp"
      ]
    }
  }
}
```

</details>

<details>
<summary><strong>Cursor</strong></summary>

Add the server configuration to `.cursor/mcp.json`:

```json
{
  "mcpServers": {
    "vulnpilot": {
      "command": "/absolute/path/to/uv",
      "args": [
        "--directory", "/absolute/path/to/vulnpilot-mcp",
        "run", "vulnpilot-mcp"
      ]
    }
  }
}
```

</details>

<details>
<summary><strong>VS Code / GitHub Copilot</strong></summary>

Add the server configuration to `.vscode/mcp.json`:

```json
{
  "servers": {
    "vulnpilot": {
      "command": "/absolute/path/to/uv",
      "args": [
        "--directory", "/absolute/path/to/vulnpilot-mcp",
        "run", "vulnpilot-mcp"
      ]
    }
  }
}
```

</details>

> **Path Configuration Note:** Replace `/absolute/path/to/uv` with your system path to `uv` (obtain via `which uv`) and replace `/absolute/path/to/vulnpilot-mcp` with the exact directory location where you cloned the repository.
>
> **Corporate Network & SSL Custom Root CAs:** If your system uses corporate SSL proxies or custom root certificates, include the `--system-certs` argument:
> ```json
> "args": [
>   "--directory", "/absolute/path/to/vulnpilot-mcp",
>   "run", "--system-certs", "vulnpilot-mcp"
> ]
> ```
>
> **Recommended Audit Prompt:**
> Use this prompt with your connected AI client to invoke all VulnPilot tools (`check_package`, `analyze_reachability`, `generate_report`) in a single automated workflow:
> ```
> Run a full VulnPilot security audit on this project: check package vulnerabilities, analyze code reachability, and generate the HTML security report.
> ```

---

## How It Works

<p align="center">
  <img src="assets/how-it-works.png" alt="How VulnPilot Works diagram" width="450" />
</p>

VulnPilot follows a structured five-stage workflow to deliver contextual security intelligence to your AI assistant:

```
[ 1. Package Vulnerability Check ] โ”€โ”€> [ 2. Direct vs. Transitive Inspection ]
                                                      โ”‚
[ 5. HTML Report Generation ] <โ”€โ”€ [ 4. Priority Triage Engine ] <โ”€โ”€ [ 3. Reachability Analysis ]
```

### Stage 1: Package Vulnerability Lookup (`check_package`)
1. The AI assistant invokes `check_package` with a package coordinate and version number.
2. VulnPilot fetches advisories from OSV.dev and normalizes vulnerability records.
3. Extracted CVE identifiers are cross-referenced with FIRST EPSS and CISA KEV databases.

### Stage 2: Direct vs. Transitive Dependency Classification
1. VulnPilot inspects project manifests (`pyproject.toml`, `package.json`, `pom.xml`, `build.gradle`) and lock files (`uv.lock`, `poetry.lock`, `package-lock.json`, `yarn.lock`, etc.).
2. The dependency is categorized as `direct` (declared explicitly) or `transitive` (pulled in indirectly by sub-dependencies).

### Stage 3: Static Code Reachability Analysis (`analyze_*_reachability`)
1. VulnPilot scans source code files using Abstract Syntax Tree (AST) parsing for Python, or structured token scanning for JavaScript, TypeScript, and Java.
2. It detects import statements and determines whether usage exists in production source code or is restricted to test directories.

### Stage 4: Triage Priority Engine
VulnPilot calculates a remediation priority score based on deterministic risk criteria:

| Priority Level | Condition | Rationale |
| :--- | :--- | :--- |
| **IMMEDIATE** | Listed in CISA KEV catalog (`known_exploited = true`) | Actively exploited in cyberattacks or ransomware campaigns in the wild. |
| **URGENT** | Reachable in production (`is_reachable = true`) AND EPSS probability $\ge 0.5$ | High probability of imminent exploit on an active code path. |
| **HIGH** | Production dependency (`dependency_scope = "production"`) AND severity is `CRITICAL` | Critical vulnerability exposed directly in production code. |
| **NORMAL** | Default fallback for all other vulnerabilities | Lower overall risk, theoretical issue, or restricted to test/development files. |

### Stage 5: Interactive HTML Report Generation (`generate_report`)
1. Results from vulnerability checks and reachability analyses are aggregated.
2. VulnPilot renders a self-contained HTML report featuring executive statistics, interactive tables, color-coded badges, and remediation recommendations.
3. The generated report file is saved to `.vulnpilot/vulnpilot-report-{timestamp}.html`.

> **Sample Report:** View an interactive sample report generated by VulnPilot: https://arojit.github.io/vulnpilot-mcp/

---

## Tool Reference

VulnPilot exposes native MCP **Tools**, **Prompts**, and **Resources**.

---

### `check_package`

Queries vulnerability databases for a given package version and enriches results with EPSS probability and CISA KEV indicators.

#### Arguments

| Argument | Type | Default | Description |
| :--- | :--- | :--- | :--- |
| `package_name` | `string` | *Required* | Package coordinate (e.g. `django`, `lodash`, `org.apache.logging.log4j:log4j-core`) |
| `version` | `string` | *Required* | Exact version string (e.g. `2.2.0`, `2.14.1`) |
| `ecosystem` | `string` | `"PyPI"` | Ecosystem choice: `PyPI`, `npm`, `Maven`, or `Gradle` |
| `is_reachable` | `boolean` | `null` | Optional signal indicating if vulnerable code path is imported in project |
| `dependency_scope` | `string` | `"unknown"` | Usage scope: `production`, `development`, or `unknown` |

---

### Reachability Analysis Tools

Static code analysis tools verify whether a package is imported in project source files and classify code locations as production vs. test.

- **`analyze_python_reachability`:** Scans Python projects using `ast` parse-trees. Inspects `pyproject.toml`, `setup.cfg`, `requirements.txt`, and lock files (`uv.lock`, `poetry.lock`, `pdm.lock`, `pylock.toml`).
- **`analyze_javascript_reachability`:** Scans JavaScript and TypeScript projects (`.js`, `.ts`, `.jsx`, `.tsx`, `.mjs`, `.cjs`). Inspects `package.json` and lock files (`package-lock.json`, `yarn.lock`, `pnpm-lock.yaml`).
- **`analyze_java_reachability`:** Scans Java projects. Detects Maven (`pom.xml`) and Gradle (`build.gradle`, `build.gradle.kts`) dependencies.

#### Common Arguments

| Argument | Type | Default | Description |
| :--- | :--- | :--- | :--- |
| `project_path` | `string` | *Required* | Absolute path to the root directory of the project being audited |
| `package_name` | `string` | *Required* | Package name (use `groupId:artifactId` for Maven and Gradle) |
| `import_names` | `string[]` | *Auto-derived* | Custom import module overrides (e.g. `["bs4"]` for `beautifulsoup4`) |

---

### `generate_report`

Compiles scan results into a self-contained, interactive HTML security dashboard.

#### Arguments

| Argument | Type | Default | Description |
| :--- | :--- | :--- | :--- |
| `results` | `PackageReport[]` | *Required* | Aggregated list of package report objects from `check_package` and reachability tools |
| `project_name` | `string` | `"Project"` | Display title for report header |
| `ecosystem` | `string` | `"PyPI"` | Primary ecosystem (`PyPI`, `npm`, `Maven`, `Gradle`) |
| `output_dir` | `string` | `".vulnpilot"` | Target directory for saving HTML report |

The generated file is saved to `.vulnpilot/vulnpilot-report-{timestamp}.html`.

> **Sample HTML Report Output:** Inspect a live sample report output: https://arojit.github.io/vulnpilot-mcp/

---

#### Example Usage

<p align="center">
  <img src="assets/vuln-pilot-demo.gif" alt="VulnPilot demo" width="800" />
</p>


---

### MCP Prompts

Prompts provide structured, multi-step instruction templates for AI clients:

- **`security_audit`:** Guides the AI assistant to audit an entire list of dependencies, evaluate reachability for vulnerable findings, and construct an executive security summary.
- **`triage_vulnerability`:** Conducts a deep-dive triage on a specific package version, checking exploit telemetry and code reachability.
- **`generate_dependency_evidence`:** Provides terminal commands needed to produce dependency tree metadata for ecosystems lacking default lock files.

---

### MCP Resources

Read-only reference documents for AI assistants:

| Resource URI | Name | Format | Purpose |
| :--- | :--- | :--- | :--- |
| `vulnpilot://supported-ecosystems` | Supported Ecosystems | `application/json` | Schema definitions, supported package formats, and example coordinates. |
| `vulnpilot://triage-rules` | Triage Priority Rules | `text/markdown` | Formal rules explaining priority assignment logic (`IMMEDIATE` to `NORMAL`). |
| `vulnpilot://dependency-evidence-guide` | Dependency Evidence Guide | `text/markdown` | Terminal instructions for exporting dependency lock files and tree reports. |

---

## Dependency Evidence Guide

VulnPilot automatically parses existing lock files and project manifests. For projects without built-in lock files, generate dependency metadata using these commands (run from your target project root):

<details>
<summary><strong>Python (pip)</strong></summary>

If using standard pip without a lockfile, export package metadata:

```bash
mkdir -p .vulnpilot
python -m pip inspect --local > .vulnpilot/pip-inspect.json
```

If the virtual environment is not activated:

```bash
mkdir -p .vulnpilot
.venv/bin/python -m pip inspect --local > .vulnpilot/pip-inspect.json
```

</details>

<details>
<summary><strong>Python (uv, Poetry, PDM)</strong></summary>

No command required when standard lock files exist:
- `uv.lock` (uv)
- `poetry.lock` (Poetry)
- `pdm.lock` (PDM)
- `pylock.toml` (PEP 751)

</details>

<details>
<summary><strong>JavaScript / TypeScript (npm, Yarn, pnpm)</strong></summary>

No command required when standard lock files exist:
- `package-lock.json` (npm)
- `yarn.lock` (Yarn)
- `pnpm-lock.yaml` (pnpm)

</details>

<details>
<summary><strong>Java (Maven)</strong></summary>

Export the dependency tree report:

```bash
mkdir -p .vulnpilot
mvn dependency:tree -DoutputFile=.vulnpilot/maven-dependency-tree.txt
```

</details>

<details>
<summary><strong>Java (Gradle)</strong></summary>

Export the runtime dependency tree:

```bash
mkdir -p .vulnpilot
./gradlew dependencies --configuration runtimeClasspath > .vulnpilot/gradle-dependencies.txt
```

For test dependencies:

```bash
mkdir -p .vulnpilot
./gradlew dependencies --configuration testRuntimeClasspath > .vulnpilot/gradle-test-dependencies.txt
```

</details>

> **Git Configuration Tip:** Add `.vulnpilot/` to your project's `.gitignore` file to avoid committing local scan reports and evidence dumps.

---

## Development & Testing

### Installation for Contributors

```bash
# Install all development tools and dependencies
uv sync --all-groups
```

### Running Test Suites

```bash
# Execute pytest suite
uv run pytest
```

### Testing with MCP Inspector

Test tools interactively in your browser using the MCP Inspector GUI:

```bash
uv run mcp dev src/vulnpilot/server.py
```

### Project File Hierarchy

```
vulnpilot-mcp/
โ”œโ”€โ”€ src/vulnpilot/
โ”‚   โ”œโ”€โ”€ __init__.py               # Package marker
โ”‚   โ”œโ”€โ”€ server.py                 # MCP server tools, prompts, and resources
โ”‚   โ”œโ”€โ”€ models.py                 # Pydantic data schemas
โ”‚   โ”œโ”€โ”€ osv_client.py             # OSV.dev API client & normalizer
โ”‚   โ”œโ”€โ”€ epss_client.py            # FIRST EPSS API client
โ”‚   โ”œโ”€โ”€ cisa_kev_client.py        # CISA KEV catalog client
โ”‚   โ”œโ”€โ”€ triage.py                 # Priority triage engine
โ”‚   โ”œโ”€โ”€ cve_utils.py              # CVE regex and utility parsers
โ”‚   โ”œโ”€โ”€ report_generator.py        # Interactive HTML report renderer
โ”‚   โ””โ”€โ”€ reachability/             # Language-specific reachability scanners
โ”‚       โ”œโ”€โ”€ __init__.py          # Module re-exports
โ”‚       โ”œโ”€โ”€ _common.py           # Shared path parsing & evidence classification
โ”‚       โ”œโ”€โ”€ python_reachability.py
โ”‚       โ”œโ”€โ”€ python_dependencies.py
โ”‚       โ”œโ”€โ”€ javascript_reachability.py
โ”‚       โ”œโ”€โ”€ javascript_dependencies.py
โ”‚       โ”œโ”€โ”€ java_reachability.py
โ”‚       โ””โ”€โ”€ java_dependencies.py
โ”œโ”€โ”€ tests/                        # Comprehensive unit & integration tests
โ”œโ”€โ”€ pyproject.toml                # Project build metadata & dependencies
โ””โ”€โ”€ README.md
```

---

## Enhancements

This section documents planned and shipped improvements that increase scanning efficiency and developer ergonomics.

### Batch Package Scanning with Concurrent API Calls

**Status:** Planned

**Problem:** The current `check_package` tool accepts a single package at a time, meaning an AI agent auditing 30 dependencies must make 30 sequential API calls - each waiting for the previous one to complete.

**Enhancement:** Accept a list of `{ package_name, version, ecosystem, is_reachable, dependency_scope }` objects in a single `check_package` invocation, then dispatch each lookup concurrently using Python's `concurrent.futures.ThreadPoolExecutor`. Results are collected and returned as an ordered list, preserving per-package attribution.

**Benefits:**
- **Speed:** Wall-clock scan time for N packages approaches the latency of a single lookup instead of N ร— latency.
- **Ergonomics:** AI agents issue one tool call per audit instead of one per dependency.
- **Unchanged interface contract:** Each individual result object retains the same schema as today.

**Example batch input (proposed):**

```json
{
  "packages": [
    { "package_name": "django",   "version": "3.2.0",  "dependency_scope": "production" },
    { "package_name": "requests", "version": "2.25.0", "dependency_scope": "production" },
    { "package_name": "pytest",   "version": "7.1.0",  "dependency_scope": "development" }
  ],
  "ecosystem": "PyPI"
}
```

---

## Technology Stack

| Component Layer | Technology |
| :--- | :--- |
| **MCP Framework** | [FastMCP](https://github.com/modelcontextprotocol/python-sdk) (`mcp[cli]`) |
| **Data Validation** | [Pydantic v2](https://docs.pydantic.dev) |
| **HTTP Client** | [httpx](https://www.python-httpx.org) |
| **Vulnerability Data** | [OSV.dev API](https://osv.dev) |
| **Exploit Telemetry** | [FIRST EPSS](https://www.first.org/epss/) & [CISA KEV Catalog](https://www.cisa.gov/known-exploited-vulnerabilities-catalog) |
| **Build Backend** | [Hatchling](https://hatch.pypa.io) |
| **Package Manager** | [uv](https://docs.astral.sh/uv/) |
| **Testing Engine** | [pytest](https://docs.pytest.org) with [pytest-asyncio](https://pytest-asyncio.readthedocs.io) |

---

## License

This project is licensed under the [Apache License 2.0](LICENSE). See the [LICENSE](LICENSE) file for details.

TDQS

A4.2/5.0

Scored across 3 tools

Disambiguation5/5

Each tool has a clear, distinct purpose: check_package queries vulnerability databases, analyze_reachability scans project imports, and generate_report compiles results into an HTML report. No overlapping functionality.

Naming Consistency5/5

All tool names follow the verb_noun pattern in snake_case (check_package, analyze_reachability, generate_report), ensuring predictability and clarity.

Tool Count5/5

Three tools cover the essential workflow of vulnerability checking, reachability analysis, and report generation. The count is well-scoped for a security scanning server.

Completeness4/5

The toolset covers the core lifecycle: check vulnerabilities, analyze reachability, and generate reports. A minor gap is the lack of a tool to directly retrieve detailed advisory information, but the report tool compensates.