winsecure-mcp
A Windows CVE-inventory MCP server that turns installed software into a prioritized, AI-assessed to-do list — it collects and rates, you decide (no patching).
scan_inventory— refresh the installed-software inventory from Registry Uninstall keys (HKLM/HKCU/WOW6432Node),winget list, and a bounded portable.exewalk; selectable sources/roots, per-source counters, deduplicated result with source attribution.check_cves— match the inventory against local CVE sources (cvelistV5 delta index, CISA KEV, EPSS) and fill/refresh the to-do list; works offline (cve_status: "unknown").list_todos— sorted confirmed-KEV first, then confirmed findings, then severity/CVSS/EPSS; filter by status (open/assessed/dismissed/all) orkev_only.assess_todo— effort assessment on axes (a) exe-swap-only, (b) new setup needed, (c) breaking change expected, (d) affected part; uses MCP sampling when the client supports it, else returns an evidence package.save_assessment— write the verdict back (non-sampling path) with reason, confidence, and optionaldismiss.get_program— detail view of one finding: sources, paths, versions, assigned CVEs.cve_detail— single-CVE NVD API 2.0 lookup (description, CVSS, references), cached a day.reset_todos— clear the whole list or reset one entry toopen.Read-only MCP resource
winsecure://store.json— inspect inventory/to-do JSON without calling a tool.Web dashboard at
http://127.0.0.1:8788— inventory/to-do stats, severity breakdown, top risks, activity log, tool docs; its buttons run the same tool handlers.Two transports in one process — stdio (default) and MCP over Streamable HTTP at
POST /mcp;--host/--port/--no-webandWSMD_*env overrides.Honest matching — version-checked KEV matches, era-plausibility verdicts, version-merged to-dos, installer-artifact skipping, NVD enrichment; rejected matches are reported (
dropped_by_verdict,unconfirmed_cves,match_confidence), never silently hidden.Privacy-preserving — only product, version and package id leave the machine; all caches TTL-based on disk, and a scan never depends on the network.
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@winsecure-mcpscan my installed software for CVEs and create a prioritized to-do list"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
winsecure-mcp
A Windows CVE-inventory MCP server for agents (Hermes, Claude Code, Codex, …): it reads what software the machine has installed, matches it against the current CVE sources, and turns the findings into a persistent to-do list with an AI effort assessment — the chain the lookup-only CVE servers do not offer:
inventory → CVE hits → to-do list → AI assessment of the replacement effortThe server collects and rates, the human decides. There is no automatic patching in v1 and no writing intervention in the system: every write goes into the server's own JSON files, which is why this server deliberately has no approval gate.
Not in scope for v1: drivers, DLLs, kernel/OS patches (Windows Update), automatic updates.
Quick Start
You need Node.js ≥ 20 and npm. If you have never used Node before: install it with the installer from nodejs.org, then open a terminal (PowerShell) in the cloned repository and run the four commands below — they work from any folder.
git clone https://github.com/prinzalx/winsecure-mcp.git
cd winsecure-mcp
npm ci
npm run build
node dist/index.jsStarted in a terminal, the server prints an ASCII logo and announces where it lives. Under an MCP client such as Hermes it does not own a console: stdout carries the protocol and this goes to the client's log instead.
██╗ ██╗██╗███╗ ██╗███████╗███████╗ ██████╗██╗ ██╗██████╗ ███████╗ ███╗ ███╗ ██████╗██████╗
██║ ██║██║████╗ ██║██╔════╝██╔════╝██╔════╝██║ ██║██╔══██╗██╔════╝ ████╗ ████║██╔════╝██╔══██╗
██║ █╗ ██║██║██╔██╗ ██║███████╗█████╗ ██║ ██║ ██║██████╔╝█████╗ ██╔████╔██║██║ ██████╔╝
██║███╗██║██║██║╚██╗██║╚════██║██╔══╝ ██║ ██║ ██║██╔══██╗██╔══╝ ██║╚██╔╝██║██║ ██╔═══╝
╚███╔███╔╝██║██║ ╚████║███████║███████╗╚██████╗╚██████╔╝██║ ██║███████╗ ██║ ╚═╝ ██║╚██████╗██║
╚══╝╚══╝ ╚═╝╚═╝ ╚═══╝╚══════╝╚══════╝ ╚═════╝ ╚═════╝ ╚═╝ ╚═╝╚══════╝ ╚═╝ ╚═╝ ╚═════╝╚═╝
version v0.5.0
data directory C:\Users\<user>\AppData\Roaming\winsecure-mcp
store file C:\Users\<user>\AppData\Roaming\winsecure-mcp\winsecure.json
web interface http://0.0.0.0:8788
MCP transport stdio — this terminal stays attached to the agentOpen http://127.0.0.1:8788 in a browser for the web dashboard: inventory and to-do statistics,
the severity breakdown, the top risks confirmed-KEV-first, an activity log of every call this server session
answered, and the eight tools with their full docs. Its two buttons run scan_inventory and
check_cves through the same handlers an agent calls, so the page can never disagree with a tool
answer. --no-web (or WSMD_NO_WEB=1) keeps it stdio-only; --port / WSMD_PORT move it off 8788.
One process, two transports (the winadmin model)
Every start of node dist/index.js is a long-lived process that offers both transports at
once, behind one listener:
Path | Purpose |
| the default MCP transport; a client may spawn the server as its own child process |
| MCP over Streamable HTTP with real sessions; a client connects by |
| the dashboard and its JSON endpoints |
The server binds 0.0.0.0 by default so a client outside the Windows network namespace — WSL —
reaches it. --host / WSMD_HOST set the bind address explicitly, --port / WSMD_PORT the port
(default 8788, since winadmin-mcp owns 8787). --no-web turns the listener off entirely, so
then only stdio remains. Everything else on the port — including a bare curl to /mcp — belongs
to the MCP transport and answers in JSON (a bare curl gets its 406 Not Acceptable back, exactly
like winadmin); the dashboard HTML lives on /.
Why HTTP exists: a client that spawns the server per stdio runs it in its own environment. On a
WSL-hosted agent that means a Linux node looks for powershell.exe, winget.exe and the drive roots
and finds none of them, so the inventory comes back degraded with zero programs. scan_inventory
reports this honestly in its environment block (platform, node, powershell_found,
winget_found) instead of claiming a clean "0 programs". Running the server on the Windows side and
connecting by url: is the intended setup on such a host.
Related MCP server: cve-mcp
The Tools
Tool | Purpose |
| Refresh the inventory (sources selectable); returns per-source counters + the dedup result |
| Match the inventory against the CVE sources; fill/refresh the to-do list |
| Sorted confirmed-KEV first, then confirmed findings, then severity/EPSS; filterable by status |
| Effort assessment for one entry (sampling client → verdict; else evidence package) |
| Write the assessment back (the non-sampling path) |
| Detail view of one finding (sources, paths, versions, assigned CVEs) |
| NVD lookup of a single CVE |
| Clear the whole list, or reset one entry to open (the way back to an empty list) |
Every answer is wrapped the same way: a human summary line plus structuredContent, with english
status words and ISO-8601 UTC timestamps throughout, so the output is locale-independent. An empty
result is an answer, not an error.
Beyond the tools, the store file is exposed as a read-only MCP resource (winsecure://store.json),
so an agent can inspect the inventory and to-do JSON without invoking a tool. check_cves reports
cvelist.index_coverage (local CVEs vs. the estimated full corpus), which tells "no hits found" apart
from "the local index is still thin".
Inventory Sources
Registry Uninstall keys — HKLM + HKCU including WOW6432Node.
winget list— for store/winget-managed apps; the package id is carried along because it helps matching. Note: winget 1.29 has no JSON output (--format jsonerrors), so the table text is parsed by locating the separator line and splitting columns on two-or-more spaces.Portable apps — a bounded walk over the fixed drives for
.exefiles with FileVersionInfo. Excludes are mandatory and config-extensible (C:\Windows,WinSxS,node_modules,$Recycle.Bin, TEMP); the result is cut atportableMaxResultsand the visited paths are reported. Access-denied directories are skipped, not errors.
Deduplication runs over all three sources under a normalised (product, version) key; each finding carries the list of sources that reported it.
CVE Data Sources
Measured live against the running APIs (Phase 0, 10/2026):
Source | Role | Finding |
cvelistV5 (GitHub) | primary local CVE source | Full corpus is 602 MB, so the hourly delta (~5 MB) is downloaded and accumulated into a local index ( |
CISA KEV JSON feed | actively-exploited signal | Daily-cached. An exact product-name match hits only ~0.5 % of a real inventory (display name vs CVE product name), so an alias table + |
EPSS (FIRST) | prioritisation | Batch of ≤100 CVEs per call; fills |
OSV.dev batch query | not used as primary | No |
NVD API 2.0 |
| Keyless rate limit is 4 calls / 30 s; live-calls-per-program is not viable. |
Everything is cached on disk with a TTL, and a scan run never depends on the network. Without
network the server still returns the inventory with cve_status: "unknown". Privacy: only product,
version and (when present) package id leave the machine — never paths, usernames or hostnames.
The Assessment Mechanism (§5)
The server owns no LLM. At the handshake it checks whether the client declared the MCP sampling
capability:
Yes:
assess_todoasks the client directly via sampling and stores the verdict itself.No (fallback, always available):
assess_todoreturns a structured evidence package plus the fixed schema; the client assesses and writes the result back throughsave_assessment.
Both paths produce byte-for-byte the same stored shape, on exactly these axes:
Axis | Meaning |
(a) | the fix is reached by replacing the |
(b) | a new setup package from the vendor is required |
(c) | a breaking change is expected |
(d) | only a part program of a suite is affected → name it |
Configuration
Defaults work out of the box; the server writes them out on first save.
Setting | Meaning | Default |
| store, caches and config |
|
| disk-cache TTLs | 24 |
| paths never walked | see above |
| cut-off for the portable walk | 40 |
| portable walk budget | 60000 |
| per outbound request | 15000 |
Environment overrides: WSMD_CONFIG (config file), WSMD_DATA_DIR (data directory),
WSMD_OFFLINE=1 (switch the network off — the offline test), WSMD_HOST / WSMD_PORT (the
listener's bind address and port), WSMD_NO_WEB (the dashboard). CLI
--host / --config / --data-dir / --port / --no-web win.
Development
npm run typecheck # tsc --noEmit
npm run build # → dist/ (+ webui.html)
npm test # build + node --test tests/*.test.mjs
node scripts/e2e.mjs --assess # full real stdio run on this host
node scripts/sampling-test.mjs # proves both assessment paths
node scripts/http-test.mjs # drives a real MCP session on /mcp over HTTP
node scripts/banner.mjs # regenerate the console logoEnd-to-end run on a Windows 11 test host (real numbers)
scan_inventory → 357 programs after dedup (registry 205, winget 209, portable 40 cut at max)
check_cves → cvelist index 1991 CVEs / 1169 products (0.7 % coverage, cold-start phase)
list_todos → the v0.5.0 verdict rules turned this run's 6 false positives into zero to-dos
assess_todo → evidence package returned (client cannot sample); saved via save_assessment
cve_detail → CVE-2024-21412: CVSS 8.1 — Internet Shortcut Files Security Feature BypassThe live beta (v0.4.0) produced six to-dos on this host and all six were unconfirmed name
matches, none an actual exposure: two Edge versions matched the same two 2016 EdgeHTML CVEs as
two separate rows, WhatsApp 2.2639 a 2019 CVE, Git 2.55 a CVE affecting Git < 2.50.1, 7-Zip 26.02 a
CVE affecting < 24.07, and Notepad++ 7.54 came from two installer .exe files in document folders.
After the v0.5.0 verdict rules the same run reports 0 CVE hit(s) ... 8 name match(es) rejected by the version verdict, i.e. no to-do for Edge, WhatsApp, Git or 7-Zip.
Offline test (WSMD_OFFLINE=1, cold cache): inventory 357 programs, cve_status: "unknown",
source_errors: ["offline","offline"], no failures.
A second probe ran the server in a Linux (WSL) sandbox where neither powershell.exe nor
winget.exe is reachable. That is what shaped the source-health rule: a scan on a host it cannot
see now reports degraded: true, names every source that contributed nothing (missing interpreter,
no fixed drive) and adds the environment block, instead of claiming a clean "0 programs".
Matching Honesty (v0.3.0, verdict rules extended in v0.5.0)
Rules that keep the hit list trustworthy, all of them visible in the answer rather than buried:
A KEV product-name match is version-checked. The KEV feed carries no version range, so the hit is verified against the local CVE record: outside the affected range it is dropped (Chrome 120 hit
CVE-2020-16017, which NVD limits to Chrome prior to 86.0.4240.198), and when no range can be evaluated the hit is kept unconfirmed —match_confidence: "low", listed inunconfirmed_cves, and it does not liftmax_severity.check_cvescounts them separately.A name-only match must also be plausible for its era (v0.5.0). The delta index only ever accumulates recent CVEs, so an old CVE (a 2016 EdgeHTML bug, a 2019 WhatsApp bug) may never get local range data at all. When a KEV name match has no range that confirmed it and the installed version's era sits clearly above the CVE's publication year, the pair is impossible on its face and drops before it can become a to-do. Everything the verdict rejected counts up as
dropped_by_verdict, so the filtering is visible instead of silent.Several installed versions of one product are ONE to-do (v0.5.0). Edge 152 and Edge 155 are the same finding: the to-do represents the newest version and lists the members in
versions, so the list has no near-duplicate rows per version.An installer archive is not installed software (v0.5.0). A
*installer*.exe/*setup*.exethe portable walk found outside Program Files is taggedinstaller_artifact(a downloaded setup in a document folder); if no other source reported the program,check_cvesskips it (installer_artifacts_skipped).A KEV hit is never rendered
severity: "none"as if that were a fact. Whatever the local index does not score is completed from the disk-cached NVD helper before the to-do is built (nvd_enrichedin the answer), and one NVD answer is applied to every hit object of that CVE id (v0.5.0 — the live beta saw the same CVE scored on one to-do and null on another). A hit that stays unscored carriescvss_source: "nvd_unreachable"/"nvd_no_score"so hit level and to-do level cannot disagree.Ranking never puts an unverified hit above a confirmed one (v0.5.0).
list_todosand the dashboard sort verified-KEV first, then any confirmed finding, then severity/CVSS/EPSS — an entry whose only KEV signal is an unconfirmed name match cannot headline the list.
Registration in Hermes
Run the server on the Windows host and connect by url, the same way winadmin-mcp is connected:
winsecure:
url: http://172.28.176.1:8788/mcp
enabled: true172.28.176.1 is the Windows side of the vEthernet (WSL) adapter, i.e. the address a WSL Hermes
reaches. Open the port for the WSL subnet only — not for every interface:
netsh advfirewall firewall add rule name="winsecure-mcp" dir=in action=allow protocol=TCP localport=8788 remoteip=172.28.160.0/20The old stdio entry (command: node, args: [.../dist/index.js]) is what caused the empty
inventory, because it started the server inside WSL; replace it with the url: form above.
Register with manage_connections install, then — after any server restart —
manage_connections enable. Note: Hermes is not installed on this host, so the registration and
the live sampling path could not be exercised here; the tools were all proven callable over real
stdio MCP (scripts/e2e.mjs lists and calls all 8) and over HTTP (scripts/http-test.mjs), and the
sampling path is proven with a mock-capable client (scripts/sampling-test.mjs). Hermes uses the
tool-name prefix mcp__winsecure__; match on the name behind the prefix.
Project Structure
src/
index.ts MCP server, stdio + Streamable HTTP transports, sampling handshake, dashboard
dashboard.ts dashboard state + the in-memory activity ring buffer
webui.html the dashboard page (copied to dist/ by the build)
config.ts defaults + config file + CLI/env overrides
model.ts domain types (english, locale-independent, ISO-8601 UTC)
store.ts single JSON file for inventory + to-do list (atomic rename)
utils/ result wrapper, powershell, net (TTL disk cache), matching, zip
modules/inventory/ sources (registry/winget/portable) + dedupe
modules/cves/ feeds (KEV/cvelistV5/EPSS/NVD) + matching engine
modules/todos/ todo model (schema, evidence, merge) + tools
skills/windows-cve-triage/SKILL.mdOne listener serves the dashboard, /api/* and the /mcp endpoint, and its run endpoint goes
through the same tool handlers, so the "only writes to its own files" rule holds on the web path
too. --no-web closes the listener completely; stdio keeps running either way.
Available Tools
8 toolsassess_todoAssess to-doA
Effort assessment for one to-do on axes a-d. With a sampling-capable client the server asks it directly and stores the verdict; otherwise it returns an evidence package for save_assessment.
| Name | Required | Description | Default |
|---|---|---|---|
| todo_id | Yes | The id from list_todos |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full burden, and it does disclose non-obvious dual-mode behavior plus the fact that a verdict is stored (a mutation). It omits what the evidence package contains, what happens to a previously stored verdict, and what permissions or preconditions the write requires.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two tightly written sentences, with the core function front-loaded and the branching behavior second. No filler, but the undefined 'axes a-d' shorthand costs a little clarity within that compact frame.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
There is no output schema, no annotations, and the tool performs a write (stores the verdict), so the description should carry more: what the evidence package looks like, how the assessment is consumed downstream, and what 'axes a-d' means. It covers the branching model well but leaves the payload and result semantics undefined.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100% and the single `todo_id` parameter is documented as 'The id from list_todos', so the schema does the work. The description adds no format, provenance, or validity detail beyond what the schema already states; baseline 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
Names a specific verb+resource ('Effort assessment for one to-do') and hints at sibling differentiation by naming `save_assessment`. However, 'axes a-d' is unexplained jargon that an agent cannot act on without outside knowledge, so it is clear but not fully self-contained.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explains the two operating contexts: sampling-capable clients get the verdict stored directly, others receive an evidence package destined for `save_assessment`. That routing is genuinely useful, though it never states when an agent should avoid this tool or whether re-assessment is expected.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
check_cvesCheck CVEsA
Match the stored inventory against the local CVE sources (cvelistV5 delta, CISA KEV, EPSS) and fill the ToDo list. Never requires the network.
| Name | Required | Description | Default |
|---|---|---|---|
| refresh | No | Force re-download of the sources even when the cache is fresh | |
| with_epss | No | Look up EPSS scores for the matched CVEs. Defaults to true |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full burden, and it does disclose two useful behaviors: the specific local data sources (cvelistV5 delta, CISA KEV, EPSS) and the guarantee that no network access is needed. It also reveals a write side effect ('fill the ToDo list'). However, it does not say whether existing ToDo entries are overwritten or appended, what permissions are required, or how much work the match entails.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two sentences, zero filler, and the core action and its inputs are front-loaded before the network-free guarantee. Every clause carries information.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
There is no output schema, and the description never says what the call returns or how the ToDo list is affected beyond 'fill it'. For a tool that mutates ToDo state with no annotations to cover safety or idempotency, more disclosure would be warranted.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so both booleans (refresh, with_epss) are already fully documented in the schema, including the default for with_epss. The description adds no additional meaning about them, which is the expected baseline when the schema does the work.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
It names a concrete verb (match) plus the two operands (stored inventory vs. local CVE sources) and the resulting side effect (filling the ToDo list). That is far more specific than the sibling names alone, though it never explicitly contrasts itself with scan_inventory, which an agent could plausibly confuse it with.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description implies the situation (post-inventory matching against local CVE data) but never states when to call this versus scan_inventory, assess_todo or cve_detail, nor any prerequisite or ordering. Usage is inferable from context rather than stated.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
cve_detailCVE detailA
Look up a single CVE at NVD API 2.0: description, CVSS, references. Cached for a day.
| Name | Required | Description | Default |
|---|---|---|---|
| cve_id | Yes | A CVE id, e.g. CVE-2024-21413 |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are supplied, so the description carries the full behavioral burden. It does disclose the useful trait that results are 'cached for a day,' but it is silent on NVD rate limits, behavior for unknown/invalid CVE ids, and whether auth or a key is required.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
A single sentence that front-loads the verb, resource, source, and return fields, then appends the caching caveat. Nothing is wasted.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a one-parameter lookup with no output schema, the description tells the agent what data comes back (description, CVSS, references) and notes caching. Only edge-case behavior (invalid ids, rate limiting, auth) is left uncovered.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
With schema description coverage at 100% and only one parameter, the schema already documents cve_id, its pattern, and an example. The description adds no format or semantics beyond that, so the baseline 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
It gives a specific verb (look up), a scoped resource (a single CVE), the upstream source (NVD API 2.0), and the returned fields (description, CVSS, references). The word 'single' implicitly separates it from the bulk-checking sibling check_cves, though no sibling is named explicitly.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Usage is only implied: 'a single CVE' suggests this is for one-off lookups rather than batch checks like check_cves, but there is no explicit when-to-use/when-not-to-use statement or prerequisite detail.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_programGet programC
Detail view of one inventory entry: every source that reported it, its paths, versions and the CVEs assigned to it.
| Name | Required | Description | Default |
|---|---|---|---|
| limit | No | Maximum matches to return. Defaults to 10 | |
| program | Yes | Name substring or the exact inventory id | |
| with_cves | No | Include the CVE hits of each match. Defaults to true |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full behavioral burden. It describes the returned fields but omits whether the call is read-only, what happens when nothing matches, and how the 'one inventory entry' framing squares with the schema's multi-match 'limit' parameter (default 10, max 50) and the with_cves toggle — a real ambiguity for a lookup tool.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
A single front-loaded sentence that names the subject first and then lists the returned content. It is efficient and contains no filler, though it spends its words on return values rather than the invocation guidance an agent also needs.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
There is no output schema and no annotations, so the description is the only source of behavioral context, and it only partially covers this. The return composition is sketched, but match/multiple-match behavior, defaults, and failure modes are left to the schema or entirely unstated.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so limit, program, and with_cves are already fully documented in the schema with defaults and constraints. The description adds no parameter-level detail beyond implying CVE inclusion, so the baseline 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('Detail view of one inventory entry') and enumerates the payload (sources, paths, versions, CVEs), which is far more informative than the bare title 'Get program'. It does not name or differentiate itself from siblings like scan_inventory or cve_detail, though, so an agent must infer the boundary itself.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
There is no explicit when-to-use guidance or mention of alternatives such as scan_inventory or cve_detail. The phrase 'Detail view' weakly implies this is the drill-down counterpart to a scan, but nothing states when to prefer this tool or what input form (name substring vs exact id) is appropriate.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_todosList to-dosA
The CVE to-do list, sorted confirmed-KEV first, then confirmed findings, then severity/EPSS. Filterable by status.
| Name | Required | Description | Default |
|---|---|---|---|
| limit | No | Maximum entries. Defaults to 40 | |
| status | No | Filter by status. Defaults to all non-dismissed | |
| kev_only | No | Only entries with at least one actively exploited CVE |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are supplied, so the description carries the behavioral burden. It does disclose the non-obvious sort order (confirmed-KEV, then confirmed findings, then severity/EPSS), which is real added value, but says nothing about permissions, pagination, or the shape of the returned entries.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two short sentences with no filler; the priority ordering — the most decision-relevant fact — leads the description, and filtering is appended compactly.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With no annotations and no output schema, the description should carry more. It explains ordering and filtering but omits what a returned to-do actually contains (CVE id, status, KEV flag) and how the KEV-first sort interacts with the kev_only filter.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100% and each parameter is fully documented (limit default 40, status enum with a default, kev_only boolean). The description's 'filterable by status' merely restates one schema field and adds no syntax or semantics beyond it, so baseline 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description names the resource ('The CVE to-do list') and its ordering, which combined with the verb in the tool name makes the operation unambiguous. It distinguishes itself from siblings like assess_todo or reset_todos by being the enumeration tool, though it never explicitly contrasts them.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
'Filterable by status' plus the stated priority ordering implies this is the triage/entry-point read for a vulnerability queue, but the description gives no explicit when-to-use, when-not-to-use, or pointer to an alternative such as scan_inventory or check_cves.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
reset_todosReset to-dosA
Clear the to-do list back to empty, or reset one entry to open. The way back to a clean list without editing the JSON file.
| Name | Required | Description | Default |
|---|---|---|---|
| todo_id | No | Reset a single to-do to open. Omit (or use "*") to clear the entire list |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full burden. It does disclose the destructive outcome ('back to empty', entry 'reset to open'), which is genuinely useful context, but it omits reversibility, whether confirmation is needed, and permissions.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two tight sentences, front-loaded with the primary action, followed by a short rationale. The trailing 'without editing the JSON file' clause is mildly redundant but does justify the tool's existence.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
A simple one-optional-parameter tool with no output schema; the description covers both call modes adequately. A brief note on whether the reset is recoverable would make it fully complete.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the todo_id semantics (omit or "*" for full clear) are already fully documented in the schema. The description restates the two modes but adds no syntax or format detail beyond the schema, so the baseline 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description names a specific verb ('clear', 'reset') and resource ('to-do list'), and distinguishes its two operating modes: wiping the whole list vs. resetting one entry to open. It does not explicitly differentiate itself from siblings like list_todos or save_assessment, but the intent is unambiguous.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It gives a clear context for use: getting back to a clean list without hand-editing the JSON file. There is no explicit when-not-to-use clause and no named alternative sibling, which keeps it short of a 5.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
save_assessmentSave assessmentC
Write an effort assessment back to a to-do (the non-sampling path). Sets the status to assessed.
| Name | Required | Description | Default |
|---|---|---|---|
| reason | Yes | Short justification | |
| dismiss | No | Set the status to dismissed instead of assessed | |
| todo_id | Yes | The id from list_todos | |
| confidence | No | How sure the assessment is. Defaults to medium | |
| affected_part | No | (d) name the part program when only part of a suite is affected | |
| exe_swap_only | Yes | (a) only the .exe/file has to be replaced | |
| new_setup_needed | Yes | (b) a new setup from the vendor is needed | |
| breaking_change_expected | Yes | (c) a breaking change is expected |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full burden, and it does disclose one real side effect: it sets the status to 'assessed' (or 'dismissed' per the dismiss param). It says nothing about permissions, idempotency, whether an existing assessment is overwritten, or what a successful write returns.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two short sentences, no filler, and the action is front-loaded before the status side effect. The only dead weight is the unexplained parenthetical about the non-sampling path.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
This is a mutation tool with eight parameters (five required), no annotations, and no output schema, so the description needs to do more work. It never explains the relationship to assess_todo, the sampling distinction, or any failure/authorization behavior, leaving significant gaps for a write operation.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so the eight parameters and their meanings are already fully documented in the schema. The description adds no syntax, format, or defaulting detail beyond the schema, so the baseline 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a specific verb and resource ('Write an effort assessment back to a to-do'), which is concrete enough to act on. However, '(the non-sampling path)' is internal jargon that does not help distinguish this tool from the sibling assess_todo, leaving the core purpose only partially differentiated.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
There is no explicit when-to-use guidance and no mention of the obvious alternative assess_todo. The parenthetical '(the non-sampling path)' is an implicit hint about differing execution modes, but it is not explained, so an agent cannot reliably choose between the two.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
scan_inventoryScan inventoryA
Refresh the installed-software inventory from the registry, winget list and a portable .exe scan. Returns per-source counters and the deduplicated result.
| Name | Required | Description | Default |
|---|---|---|---|
| roots | No | Drive roots for the portable scan. Defaults to the fixed disks | |
| sources | No | Which sources to read. Defaults to all three |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description carries the full behavioral burden. It discloses the mechanics (three sources read) and the return shape (per-source counters plus deduplicated result), but says nothing about whether the stored inventory is overwritten, how long the scan takes, whether winget/portable scanning needs network or elevated permissions, or what happens on partial failure.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two tight sentences, front-loaded with the action and scope, followed by the return summary. Every clause earns its place; no filler or restatement of the tool name.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With no output schema, the description does the right thing by summarizing return values, and it covers both optional parameters' domains. The remaining gap is side-effect/permission context for a refresh operation that mutates stored inventory state, which matters more given the absence of annotations.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so both parameters are already documented in the schema and the baseline is 3. The description usefully connects the 'portable .exe scan' wording to the `roots` parameter and enumerates the three source names matching the `sources` enum, but adds no default or format detail beyond the schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
Specific verb+resource: 'Refresh the installed-software inventory', with the three data sources named concretely (registry, winget list, portable .exe scan). That is far clearer than a bare 'scan', though it never names a sibling to distinguish itself from get_program or check_cves, which also touch installed software.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
'Refresh' implies the use case (re-sync a stale inventory), but there is no explicit when-to-use statement, no exclusion of alternatives, and no note on how this differs from get_program (single lookup) or check_cves. Usage is only inferable.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
1 tool update
v0.5.0- Added
reset_todos
7 tool updates
v0.1.0- First observed
assess_todo - First observed
check_cves - First observed
cve_detail - First observed
get_program - First observed
list_todos - First observed
save_assessment - First observed
scan_inventory
TDQS
Scored across 8 tools
Most tools target clearly separate stages: inventory scanning, CVE matching, CVE detail lookup, program detail, and todo management. The main overlap is between assess_todo and save_assessment, since assess_todo can both store a verdict and return evidence for save_assessment, but the descriptions clarify the sampling vs non-sampling paths.
All names use snake_case consistently and are easy to read. Most follow a verb_noun pattern (scan_inventory, list_todos, reset_todos, assess_todo, check_cves, get_program, save_assessment), with cve_detail as a minor noun-phrase deviation.
Eight tools is well within the ideal 3-15 range for a focused security triage server. Each tool appears to serve a distinct phase of the workflow rather than bloating the surface.
The surface covers the core lifecycle: inventory refresh, local CVE matching, todo listing/resetting, CVE detail, program detail, and assessment persistence. Minor gaps remain around fully closing or dismissing a todo and listing stored inventory entries without re-scanning, but agents can largely work around these.
Maintenance
Related MCP Connectors
Read-only CVE intelligence, remediation playbooks, and agent setup guides. Not a scanner.
CVE lookups (NVD) and dependency-manifest audits (OSV) for AI agents. No API keys.
CVE lookups (NVD) and dependency-manifest audits (OSV) for AI agents. No API keys.
CVE intelligence: exploitation (KEV/EPSS), detection coverage, fixed versions, CPE configurations.
Related MCP Servers
- AlicenseNot gradedqualityCmaintenanceEnables CVE lookups and risk assessment by integrating CISA Known Exploited Vulnerabilities (KEV) data and CVSS metrics. It helps users prioritize patching efforts by ranking vulnerabilities based on exploitation status and calculated risk scores.MIT
- AlicenseAqualityCmaintenanceUnifies NVD, EPSS, CISA KEV, GitHub Advisory, and OSV into a single MCP server, enabling AI agents to query vulnerability intelligence conversationally with 23 tools for incident response, prioritization, dependency audits, and threat monitoring.41292 npm30MIT
- AlicenseNot gradedqualityDmaintenanceMCP server for querying live CISA KEV, EPSS, and enriched vulnerability feeds with full provenance. Enables natural-language access to auditable security-intelligence data from Claude Desktop and other MCP clients.MIT
- AlicenseAqualityBmaintenanceEnables AI agents to search, correlate, and monitor real-time vulnerability intelligence from NVD, CISA KEV, EPSS, and MITRE ATT&CK, including CVE details, critical CVE tracking, known exploited vulnerabilities, and exploitation probability scores.52MIT