Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

2 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

CVEasy AI — MCP Server

A Model Context Protocol server that exposes a live CVEasy AI install — scans, findings, CVEs, assets, threat intel, metrics — to MCP clients like Claude Desktop and Claude Code.

Its purpose is to refine report-making. Today CVEasy fills report narrative sections with the bundled local model using only aggregate numbers, which keeps prose thin and occasionally wrong. This server flips that: it lets a far more capable model (Claude) pull the real, structured data behind any report and draft or critique the prose grounded in actual figures — then render the final HTML/PDF through the same backend.

┌────────────────────┐   stdio (JSON-RPC)   ┌──────────────────┐   HTTP :3001   ┌─────────────────────┐
│ Claude Desktop /    │ ───────────────────▶ │    cveasy-mcp     │ ─────────────▶ │ CVEasy AI backend   │
│ Claude Code (LLM)   │ ◀─────────────────── │  (this package)   │ ◀───────────── │ (Hono, SQLite, AI)  │
└────────────────────┘   tools/prompts/res   └──────────────────┘   /api/*        └─────────────────────┘

The server is a thin client over the CVEasy REST API — it never touches the database directly. That avoids lock contention with the running desktop app, reuses the backend's scoring/dedup logic, and survives schema changes.


Quick start

git clone https://github.com/CVEasy/cveasy-mcp && cd cveasy-mcp
bun install
bun run smoke      # spins up the server and exercises it against your live backend

bun run smoke should print SMOKE TEST PASSED if the CVEasy AI app is running (backend on :3001).

Then wire it into a client (below) and ask: "Use CVEasy to draft an executive risk summary for Acme Corp."

Requires the CVEasy AI desktop app (or bun run backend/src/index.ts) running so the backend answers on :3001. The server starts fine without it and every tool simply returns a clear "backend not reachable" error until it's up.


Configuration

All configuration is via environment variables; defaults match a stock local install.

Variable Default Purpose
CVEASY_BASE_URL http://127.0.0.1:3001 Backend base URL.
CVEASY_TIMEOUT_MS 120000 Per-request timeout (report/AI calls can be slow).
CVEASY_REPORT_DIR $HOME/Downloads Where report_generate saves files by default.
CVEASY_ALLOW_WRITES 1 When 0, all mutating tools (triage, risk, enrich, scans) are hidden.
CVEASY_ALLOW_SCANS 1 When 0, only the BAS scan-launching tools are hidden.
CVEASY_SESSION_TOKEN Operator session token, only needed if RBAC is enabled on the backend (sent as x-session-token).
CVEASY_ACCESS_TOKEN Access token, only needed if the backend runs in production/deployment mode (sent as x-access-token).

On a normal local CVEasy install RBAC is off (/api/auth/statusauthEnabled:false), so no tokens are required even for writes.


Wiring into a client

Claude Desktop

Edit ~/Library/Application Support/Claude/claude_desktop_config.json (macOS):

{
  "mcpServers": {
    "cveasy": {
      "command": "/Users/<you>/.bun/bin/bun",
      "args": ["run", "/absolute/path/to/cveasy-mcp/src/index.ts"],
      "env": { "CVEASY_BASE_URL": "http://127.0.0.1:3001" }
    }
  }
}

Use the absolute path to bun (which bun) — Claude Desktop doesn't inherit your shell PATH. Restart Claude Desktop; "cveasy" appears in the tools menu.

Claude Code

# from anywhere
claude mcp add cveasy -- /Users/<you>/.bun/bin/bun run /absolute/path/to/cveasy-mcp/src/index.ts

Or commit a project-scoped .mcp.json so the team shares it:

{
  "mcpServers": {
    "cveasy": {
      "command": "bun",
      "args": ["run", "cveasy-mcp/src/index.ts"],
      "env": { "CVEASY_BASE_URL": "http://127.0.0.1:3001" }
    }
  }
}

Standalone binary (no bun on PATH)

bun run compile          # → dist/cveasy-mcp (self-contained)
# then point the client's "command" at the absolute path of dist/cveasy-mcp with no args

The report-refinement workflow

This is the core use case. The pattern is always pull data → write/refine → (optionally) render.

  1. Pull the ground truth. report_context { type: "executive" } returns one JSON bundle with metrics, top risks, priority bands, patch compliance, threat feed, and the org profile. Every sub-source is fetched independently; any that fail land in warnings instead of failing the whole call.
  2. Draft or refine. Use a prompt — e.g. refine_executive_summary — which instructs the model to ground every number in that context and follow house style. Or just ask in natural language. (report_template_guide returns the recommended section skeleton per type.)
  3. Render the deliverable. report_render { type, kpis, sections } lays Claude's authored prose + tables into a polished, branded, print-ready HTML document using the built-in design system, and saves it. The user opens it and chooses Print → Save as PDF. This closes the loop entirely in the MCP layer — Claude controls the prose AND the layout, no backend involvement.
  4. Critique loop. critique_report { report_type: "executive", report_text: "…" } reviews an existing report against live data and lists factual errors, gaps, and rewrites.

Two ways to render

report_render (MCP-side) report_generate (backend)
Prose Claude's authored sections The local model's narrative
Templates Built into this server (src/template/) — branded, print-tuned The app's own report templates
Output Print-ready HTML (→ Save as PDF) HTML, plus PDF for executive/findings/roadmap
Backend changes None None today; a narrative-injection endpoint would let report_generate use Claude's prose too (see Roadmap)

Use report_render for the refined deliverable; use report_generate when you want the exact in-app report.

The template engine

src/template/ is a small, dependency-free, offline-safe design system:

  • design.ts — one shared stylesheet (system fonts, KPI cards, severity badges, callouts, @page/page-break print rules) + per-type accent presets.
  • markdown.ts — injection-safe Markdown→HTML (escapes first; _ is left literal so finding_fp_hash/T1110_001 survive).
  • render.tsrenderReport(model) assembles the full HTML from a ReportModel (header+logo, KPI band, sections with prose/bullets/tables/callouts, footer).

Improving a template here improves every rendered report. To port the same look into the in-app reports later, lift these into backend/src/services/report-builder.ts.


Tools (50)

Posture & metrics

Tool Purpose
posture_health Backend reachability + AI/Ollama/BASzy status. Call first if things fail.
posture_stats Global counts (CVEs, assets, scans).
posture_metrics_summary Headline risk metrics + band distribution — best source of grounded numbers.
posture_metrics_dashboard Full Command Center metric bundle.
posture_burndown Remediation burndown / velocity over time.
posture_compliance Control coverage for a named framework (pci-dss, hipaa, …).

CVEs

Tool Purpose
cve_search Search/browse + filter by severity, sort by TRIS/EPSS/CVSS/date.
cve_get Full enriched detail for one CVE.
cve_top_risk Highest-risk CVEs by TRIS.
cve_top_exploitable Most likely to be exploited (EPSS + KEV/PoC/ransomware).
cve_priority_board CVEs grouped into P0–P3 bands with SLAs.
cve_recent Most recently published/ingested CVEs.
cve_attack_chain Kill-chain steps + narrative for a CVE.
cve_remediation Generate/fetch remediation guidance (write — caches result).

Inventory & assets

Tool Purpose
inventory_list Canonical assets with criticality/OS/risk.
inventory_stats Asset counts by criticality / scan coverage.
inventory_get One asset's detail + its CVEs.
inventory_affected_by_cve Assets affected by a given CVE (blast radius).
inventory_asset_stats Scanner-side asset statistics.

Findings

Tool Purpose
triage_list The triage work queue (filter by status/CVE).
triage_stats Aggregate triage counts.
bas_findings_search Search BAS findings (severity/module/MITRE/CVE/scan; carries validation verdicts).
cve_validation_status Whether a CVE is BAS-confirmed exploitable in this environment.

BAS scans (read)

Tool Purpose
bas_scans_list List attack-simulation scans.
bas_scan_get One scan's status/progress (poll after starting).
bas_scan_findings Findings for a scan.
bas_stats Aggregate BAS stats.
bas_mitre_coverage MITRE ATT&CK coverage matrix.

Threat intel

Tool Purpose
threat_feed Board feed: top-exploitable, recent KEV, briefings, IoC stats, headlines.
threat_briefings Curated briefings (filter by category/severity).
threat_actors Known actors, sectors, CVEs, TTPs.
threat_headlines Live security-news headlines (RSS).

Reports

Tool Purpose
report_types List the report types CVEasy can produce.
org_profile Org name/industry + settings (compliance frameworks, AI provider).
report_context Assemble the structured data feeding a report type — call before writing prose.
report_render Lay author-supplied prose + tables into polished, print-ready HTML using the built-in templates. The refinement deliverable.
report_template_guide The recommended section skeleton per report type (for report_render).
report_generate Render the backend's own HTML/PDF report (local-model narrative) and save it.
system_open_file Reveal a saved file in Finder.

Mutating tools — gated by CVEASY_ALLOW_WRITES (scan tools also by CVEASY_ALLOW_SCANS)

Tool Purpose
triage_create / triage_batch_add Add CVE(s) to the triage queue.
triage_update / triage_delete Update state/owner/notes, or remove.
risk_accept / risk_approve File / approve a risk acceptance.
business_context_set Attach asset-criticality / data-classification / impact to a CVE.
enrich_cve / enrich_batch Refresh EPSS/KEV/TRIS scoring.
bas_scan_start Launch a BAS scan (target must be within an active authorization scope).
bas_validate_cve Targeted scan to confirm a CVE's exploitability.

Prompts (6)

Reusable, data-grounded report-writing workflows. Improving the prose rules here improves every report.

Prompt Args What it does
refine_executive_summary company_name?, focus? Tight 3-paragraph exec summary + recommended actions.
draft_board_narrative tone? (board/security/engineering), company_name? Board-level Situation→Complication→Resolution narrative.
write_remediation_roadmap horizon? Phased Now/Next/Later plan with owners, SLAs, expected risk reduction.
attack_sim_writeup scan_id? Narrates BAS results + MITRE coverage, CONFIRMED_EXPLOITABLE first.
patch_compliance_brief Compliance rate, worst SLA violations, top hosts, 3 actions.
critique_report report_type, report_text? Adversarially reviews a report against live data.

Each prompt tells the model to call the relevant data tool first and forbids invented figures.

Resources (5)

Read-only snapshots for clients with a resource/"attach context" UI: cveasy://reports/types, cveasy://metrics/summary, cveasy://posture/status, cveasy://org/profile, cveasy://threat/feed.


Safety & permissions

  • Writes are on by default but can be disabled wholesale (CVEASY_ALLOW_WRITES=0) for a read-only deployment. Mutating tools are annotated destructiveHint where they change/delete state, so clients can prompt before running them.
  • Scans (bas_scan_start, bas_validate_cve) actively probe systems and require the target to be inside an active BAS authorization scope on the backend (else 403). They can be disabled separately (CVEASY_ALLOW_SCANS=0).
  • RBAC: when access control is enabled on the backend, mutating actions need an operator session token (CVEASY_SESSION_TOKEN).
  • All logs go to stderr — stdout is reserved for the JSON-RPC stream.

Development

bun run typecheck   # tsc --noEmit (strict, no unused)
bun run smoke       # end-to-end stdio test against the live backend
bun run dev         # hot-reload the server
bun run build       # → dist/index.js
bun run compile     # → dist/cveasy-mcp (standalone binary)

Layout: src/config.ts (env), src/client.ts (HTTP), src/util.ts (result helpers + tool registration), src/tools/* (domain tools — incl. render.ts), src/template/* (the design system + Markdown + renderer), src/prompts.ts, src/resources.ts, src/index.ts (wiring). Adding a tool = one registerTool(...) call in the relevant module.

Roadmap / nice-to-haves

  • Port the src/template/ design system into the backend (report-builder.ts) so the in-app reports match the rendered ones, and optionally add a narrative-injection endpoint (POST /api/reports/generate { narrative }) so report_generate can use Claude's prose too. (The MCP-side loop is already closed by report_render.)
  • Native one-click PDF in report_render (currently print-to-PDF). Would need a PDF lib or headless renderer; print-ready HTML is intentionally dependency-free for now.
  • report_render_from_context — a convenience that pulls report_context and pre-fills the KPI band/tables, leaving Claude to write only the prose.
  • More section primitives (charts via inline SVG, two-column layouts, appendix tables).

About

MCP server for CVEasy AI — connect Claude Desktop & Claude Code to your live CVEasy install. Thin client over the CVEasy REST API.

Topics

Resources

Security policy

Stars

Watchers

Forks

Releases

Packages

Contributors

Languages