NVD/NIST MCP server
Summary: This server exposes NIST NVD's public APIs (CVE records, CVE history, the Official CPE Dictionary, and CPE Match Criteria) as 10 read-only MCP tools over stdio, backed by a local SQLite + JSON disk cache to avoid the rate-limited upstream API.
Get one full CVE record (
nvd_get_cve): description, all CVSS metrics (v2/v3.0/v3.1/v4.0), CWEs, configurations, references, CISA KEV status — optionally omitting configurations/references or the raw payload.Get one compact CVE view (
nvd_get_cve_summary): timestamps, status, English summary, primary CVSS, CWEs (capped at 50 affected products, with truncation warnings).Batch-fetch summaries for up to 100 CVEs (
nvd_get_cves): uppercased/de-duplicated, only missing or stale IDs fetched, reportingfoundIds/missingIds.Search CVEs (
nvd_search_cves): by keyword (with exact-match option), CVE IDs, CPE name or virtual match string, CWE, source identifier, vuln statuses, published/last-modified windows, KEV window, CVSS metrics, and CERT flags.List newly published CVEs (
nvd_get_recent_cves): newest first, default last 7 days or explicit window (max 120 days), plus CPE/keyword/severity/KEV filters.List recently modified CVEs (
nvd_get_modified_cves): newest-modified first, with the same window and filter options.Read a CVE's change history (
nvd_get_cve_history): events like "New CVE Received" / "CVE Modified" with field-level old/new values, filterable byeventNameor a change date window.Search the CPE Dictionary (
nvd_search_cpes): by keyword, match string, match-criteria UUID, or last-modified window; deprecated entries excluded unlessincludeDeprecated(local filter, reported viameta.filteredOut).Look up one CPE entry (
nvd_get_cpe): by exactcpeNameId(preferred) orcpeName, with titles, refs and deprecation links.Search CPE Match Criteria (
nvd_search_cpe_matches): the CVE ↔ CPE version-range links, by CVE, match-criteria UUID, complete match string, or last-modified window.Paginate any list tool with the opaque HMAC-signed
nextCursor(reused with identical filters/pageSize; fails withINVALID_CURSORif tampered, mismatched or expired after 30 min); page sizes default to 20, max 50 (CVEs/history) or 100 (CPEs/matches).Use
metaOnly: trueto get pagination counts andmeta.ordering/meta.windowwithout pulling any items.Shape responses with
fieldsto trim large payloads (e.g. ~5.7 kB → ~570 B), with unknown keys rejected and applied keys echoed inmeta.fieldsApplied.Rely on caching/rate limiting: tiered SQLite + JSON disk cache with per-resource TTLs, cache hits never calling NVD, single-flight collapsing of identical concurrent requests, serialized upstream calls (
NVD_MIN_INTERVAL_MS), exponential-backoff retries, and stale-fallback serving during outages.Read results metadata:
data/itemsplusmeta(source, cacheStatus, freshness, warnings, ordering, window, filteredOut) andpagination(page, pageCount, pageSize, returned, totalResults, hasMore, nextCursor).Run it flexibly: as a stdio JSON-RPC server locally or in Docker, configured via optional env vars (
NVD_API_KEY,NVD_BASE_URL, TTLs,CURSOR_SECRET,LOG_LEVEL, etc.), noting all tools are read-only, idempotent and non-destructive.
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., "@NVD/NIST MCP servershow me the full details for CVE-2021-44228, including CVSS and KEV status"
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.
NIST NVD MCP server
MCP server exposing the NVD APIs - CVE search, CVE history, the Official CPE Dictionary and CPE Match Criteria - over stdio, with a local SQLite + JSON disk cache so repeated lookups do not hit the (heavily rate-limited) upstream API.
Requirements
Node.js >= 22.5 (uses the built-in
node:sqlitemodule - no native compilation)Optional but recommended: a free NVD API key
Related MCP server: vuln-nist-mcp-server
Register with an MCP client
npm install && npm run build{
"mcpServers": {
"nist-nvd": {
"command": "node",
"args": ["/absolute/path/to/nist-nvd-mcp-server/dist/main.js"],
"env": { "NVD_API_KEY": "your-key" }
}
}
}The server speaks JSON-RPC on stdin/stdout: stdout carries protocol frames only, every log line goes to stderr. It is not an HTTP server and opens no ports.
The API key is sent only in the apiKey request header - never in a URL, never logged, never written
to SQLite or the disk cache. Without it the public API allows roughly 5 requests / 30 s, so one full
sweep of the 10 tools takes 60-90 s.
Tools
Tool | Purpose |
| Full record for one CVE: description, all CVSS metrics, CWEs, configurations, references, CISA KEV status |
| Compact view of one CVE: timestamps, status, English summary, primary CVSS, CWEs, affected products, KEV |
| Summaries for up to 100 CVE IDs in one batch (only missing/stale IDs are fetched) |
| Filter CVEs by keyword, IDs, CPE, CWE, CVSS, |
| CVEs ordered by publication date, newest first |
| CVEs ordered by last-modified date, newest first |
| Change history of one CVE (paged; |
| Search the CPE Dictionary by keyword, CPE match string, match-criteria UUID, or last-modified window |
| One CPE Dictionary entry, by |
| Search CPE Match Criteria (the CVE ↔ CPE version-range links) |
Response shape
{
"data": { /* tool-specific */ },
"meta": {
"source": "cache", // "cache" | "nvd"
"cacheStatus": "hit", // "hit" | "miss" | "refresh" | "stale_fallback"
"fetchedAt": "...", "expiresAt": "...", "ageSeconds": 3, "stale": false,
"warnings": [], // stale fallback, local filtering, truncation, ...
"window": { "start": "...", "end": "..." }, // the window actually queried, when time bounded
"fieldsApplied": ["id"] // only when the caller passed `fields`
},
"pagination": { // list tools only
"page": 1, "pageCount": 16, "pageSize": 20, "returned": 20, "totalResults": 312, "hasMore": true,
"nextCursor": "eyJ2ZXJzaW9uIjoxLC..."
}
}Pagination
Read pagination.nextCursor (top level, not inside meta) and pass it back as cursor with
identical filters and pageSize until hasMore is false. pagination.page is the 1-based ordinal
of the current page in that walk and pagination.pageCount is the number of pages the current upstream
total divides into. page is carried inside the signed cursor rather than derived from the offset,
because the descending feeds read their first page from the end of the window; pageCount is an
estimate, since NVD recomputes the total on every call.
The cursor is an opaque HMAC-signed token that stands in for NVD's internal startIndex. It cannot be
forged or edited - a tampered token, a cursor reused with different filters, or one older than
CURSOR_TTL_SECONDS (default 30 min) returns INVALID_CURSOR, which carries details.reason so the
cases are distinguishable: signature means the ~350-character token was altered in transit (the
message also reports the received length when it is short, which points at truncation),
filter_mismatch means the token is intact but the filters or pageSize changed, and expired means
it is older than the TTL. The server keeps no cursor state, so a valid token is always accepted.
Relative date windows (days: 7) are frozen into the cursor so every page sees the same range.
pageSize defaults to 20 everywhere; the maxima differ per resource:
Resource | Tools | Default | Maximum |
|
| 20 | 50 |
|
| 20 | 50 |
|
| 20 | 100 |
|
| 20 | 100 |
pagination.totalResults is the upstream NVD count before local filtering, so it can exceed the
number of returned items. It stays the same on every page of a walk - it is a total, not a remaining
count - and reordering a feed window server side does not change it. Because pagination walks NVD's
startIndex offsets, a walk is a snapshot of one ordering at request time rather than a stable view:
if NVD inserts or removes a record between two page requests, an item can appear twice or be skipped.
meta.ordering is always one of published_desc, last_modified_desc, change_created_asc or
nvd_default (NVD ordering kept as-is), and each tool emits exactly one marker on every page:
nvd_get_recent_cves always published_desc, nvd_get_modified_cves always last_modified_desc,
nvd_get_cve_history always change_created_asc, and the three search/CPE tools nvd_default because
NVD returns their results unsorted.
meta.window echoes the absolute bounds that were queried, which is the only way to confirm that a
relative days: 7 resolved to the range you meant. It is absent when the query was not time bounded
and when both date filters are combined, since the field holds a single range.
Metadata-only responses
Every list tool accepts metaOnly: true, which returns an empty items array and
pagination.returned: 0 while keeping the rest of the pagination block and meta intact. It is a
presentational switch: the upstream request and the cache read still happen, so it saves response
bytes, not a call. Use it to confirm meta.ordering/meta.window or to count pages
(pagination.totalResults, pagination.pageCount) without pulling items, and keep passing the
returned nextCursor to walk on. Note the cursor still points past the suppressed page, so a pure
metadata check can ignore it, while following it continues the walk without the skipped page's items.
Response shaping with fields
CVE configuration trees, change-history details, the expanded matches list of CPE Match Criteria
and the titles/refs of a CPE dictionary entry dominate the payload, so fields returns only the
item keys you need:
// ~5.7 kB -> ~570 B for the same record
{ "cveId": "CVE-2021-44228", "fields": ["id", "primaryCvss", "isKnownExploited", "kevDateAdded"] }Omitting
fieldsreturns every field. Because a projection can omit any key, the published output schema does not mark item keys as required; thefieldsdescription lists what the default returns.An unknown name is rejected with
INVALID_INPUTand the supported set, instead of being dropped.Fields the record does not carry are omitted rather than returned as
null, and the applied list is echoed inmeta.fieldsApplied(absent when no projection was requested).It is purely presentational: the upstream query, the cache key, the TTL and the cursor are unchanged, so a page fetched with one projection can be continued with another. It prunes top-level keys only, so it cannot reach inside a
configurationstree - to inspect one product of a CVE with hundreds of criteria, setincludeConfigurations: falseand usenvd_search_cpe_matcheswithmatchStringSearchinstead.
nvd_get_cve also has includeConfigurations / includeReferences (both default true, so they only
matter when set to false), and nvd_get_cve_summary / nvd_get_cves / nvd_search_cves cap
affectedProducts at 50 entries and report the truncation in meta.warnings.
Caching and rate limiting
Two tiers: a JSON disk cache with per-resource TTLs, backed by SQLite for entity lookups (
nvd_get_cve,nvd_get_cve_summary,nvd_get_cve_history,nvd_get_cpe).A cache hit never calls NVD. Expired entries are refreshed; if NVD is unreachable the stale copy is served with
cacheStatus: "stale_fallback"and ameta.warningsentry.Concurrent identical requests are collapsed (single-flight), so a burst of 25 identical calls produces exactly one upstream request.
Upstream calls are serialized with a minimum interval (
NVD_MIN_INTERVAL_MS, default 6000) and retried with exponential backoff on 429/5xx/timeouts.Default files live under
./data(nvd.sqlite+cache/). Schema migrations are applied at startup frommigrations/.
Configuration
Every variable is optional - copy .env.example to .env and set what you need. Real environment
variables take precedence over .env.
Variable | Default | Purpose |
| - | API key, sent as the |
|
| Upstream base URL (HTTPS, or HTTP for localhost) |
|
| Minimum gap between upstream requests |
|
| Per-request timeout |
|
| Retries on 429/5xx/network errors |
|
| Database file |
|
| JSON disk cache directory |
| 300-604800 | Freshness window per resource |
| random per process | HMAC key for cursors; set it (>= 16 chars) to keep cursors valid across restarts |
|
| Cursor lifetime |
|
|
|
See .env.example for the full list with defaults and explanations.
Docker
docker build -t nist-nvd-mcp-server .
docker run -i --rm -e NVD_API_KEY=your-key -v nvd-data:/data nist-nvd-mcp-serverUse -i (not -t) so stdin stays open. The container runs as a non-root user with /data writable;
docker stop shuts it down cleanly in a few milliseconds.
Development
npm run typecheck # tsc --noEmit
npm run lint # eslint (no-console is an error: stdout must stay protocol-only)
npm test # vitest run (unit + integration + MCP contract); runs build first
npm run build # emit dist/
npm run dev # tsx src/main.ts, no build stepTests never touch the real NVD API - they run against an in-process mock server, a temp SQLite database and a temp cache directory.
Evaluation
scripts/evaluation.py scores the ten tools the way a real client uses them: it hands each question
from evaluations/nist-nvd-mcp-server.xml to an LLM together with this server's tool list, lets the
model pick the tools itself, then compares the final answer with the expected value.
python -m venv .venv && . .venv/bin/activate # Windows: .venv\Scripts\activate
pip install -r scripts/requirements.txt
OPENAI_API_KEY=... python scripts/evaluation.py \
-t stdio -c node -a "$PWD/dist/main.js" \
-e PATH="$PATH" NVD_MIN_INTERVAL_MS=6500 \
--base-url http://127.0.0.1:20128/v1 -m <model-id> \
-o evaluations/report-<model>.md evaluations/nist-nvd-mcp-server.xmlThe LLM is reached through the OpenAI-compatible chat-completions API, so any gateway serving
/v1/chat/completions with tool calling works. Set NVD_MIN_INTERVAL_MS above 6000 to stay inside the
anonymous rate limit, and point SQLITE_PATH/CACHE_DIRECTORY at a scratch directory if another
instance already has the defaults open.
The question set asks for capabilities, never tool names, and every expected answer is a stable fact
(KEV dates, CVSS scores, immutable cpeNameId / matchCriteriaId, counts over wide windows) verified
against the live API. Reports are git-ignored; the question set is committed. When reading a report,
judge the server by the per-task **Feedback** blocks and the recorded nvd_* call arguments rather
than by the score: grading is an exact string comparison, so a model that states the right value and
then adds a sentence is marked wrong, and a gateway model's scoring is not deterministic at
temperature=0.
Troubleshooting
Symptom | Cause | Fix |
| Another process holds the database file (two instances sharing | Give each instance its own |
| A variable failed validation (e.g. | Fix the value named in the stderr JSON, or unset it - every variable is optional |
| NVD throttled or unreachable | Set |
|
| Drop |
| NVD returned a payload that failed schema validation | Raise |
No output when running by hand | The server is waiting for JSON-RPC on stdin | It is a stdio server; drive it from an MCP client, or pipe a |
License
MIT - this project is not affiliated with or endorsed by NIST/NVD. It is a client for the public NVD API, whose data is provided by NIST in the public domain.
Available Tools
10 toolsnvd_get_cpeGet a CPE nameARead-onlyIdempotent
Return one entry of the NVD Official CPE Dictionary. Provide exactly one of cpeNameId (preferred, exact) or cpeName. cpeName is resolved by upstream pattern search over at most 3 pages; if the exact name is not in that window the tool returns CPE_NOT_FOUND with the scanned/total counts and suggests nvd_search_cpes. That search ignores the deprecation filter, so deprecated entries resolve too. Entries are cached for 7 days.
| Name | Required | Description | Default |
|---|---|---|---|
| cpeName | No | Exact CPE name to resolve | |
| cpeNameId | No | CPE name UUID (preferred lookup key) |
Output Schema
| Name | Required | Description |
|---|---|---|
| data | Yes | |
| meta | Yes | Cache/freshness metadata; warnings carries stale-fallback and truncation notices |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already cover the safety profile (readOnly, idempotent, non-destructive, openWorld), yet the description adds substantial behavior that structured fields do not: a 3-page pattern-search bound, a CPE_NOT_FOUND error shape with scanned/total counts, the fact that the upstream search ignores the deprecation filter, and a 7-day cache. These are exactly the operational traits an agent needs to reason about failure and staleness.
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?
Four compact sentences, front-loaded with what is returned, then the key-selection rule, then failure behavior, then caching. Every sentence carries distinct operational information with no repetition of the schema or annotations.
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?
An output schema exists, so return structure need not be explained, and the description instead covers the one output case that matters (CPE_NOT_FOUND). For a two-parameter, read-only lookup with a documented fallback path, nothing needed to invoke it correctly is missing.
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 both properties carry descriptions, so the baseline is 3. The description adds real value beyond the schema by declaring cpeNameId 'preferred, exact' versus cpeName, which is only 'resolved by upstream pattern search' — a semantic distinction the schema does not convey.
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 first sentence states a specific verb and resource ('Return one entry of the NVD Official CPE Dictionary'), immediately scoping it to a single-entry lookup. The mention of nvd_search_cpes on failure distinguishes it from the sibling search tools without the agent needing to open either schema.
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 states the selection rule explicitly: 'Provide exactly one of cpeNameId (preferred, exact) or cpeName', and names the alternative (nvd_search_cpes) for the failure case. It also explains what happens when the exact name is outside the scanned window, so the agent knows the escape hatch.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
nvd_get_cveGet CVE detailsARead-onlyIdempotent
Return the full NVD record for one CVE: description, all CVSS metrics, CWEs, configurations, references and CISA KEV status. Use nvd_get_cve_summary for the essentials, nvd_get_cves for a batch. Cached for 24 hours; on an NVD outage the stale copy is returned with a warning in meta.warnings.
| Name | Required | Description | Default |
|---|---|---|---|
| cveId | Yes | CVE identifier such as CVE-2024-3094 (case insensitive) | |
| includeRaw | No | Include the raw NVD payload when it is available in the local cache (default false) | |
| includeReferences | No | Include the reference list (default true) | |
| includeConfigurations | No | Include the CPE configuration tree (default true) |
Output Schema
| Name | Required | Description |
|---|---|---|
| data | Yes | |
| meta | Yes | Cache/freshness metadata; warnings carries stale-fallback and truncation notices |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations establish read-only, idempotent, non-destructive and open-world, but the description adds behavior they cannot express: a 24-hour cache and a documented degradation path where a stale copy is returned during an NVD outage with a warning surfaced in meta.warnings. That is real operational context about freshness and failure modes.
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?
Three dense sentences with no waste: the payload comes first, the sibling routing second, the caching/outage caveat last. Nothing is repeated and every clause carries new 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?
With an output schema present, return values need not be described, and the description still covers the caching horizon and outage fallback. For a single-record fetch tool with 100% schema coverage and annotations, nothing an agent needs is missing.
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 three optional toggles (includeRaw, includeReferences, includeConfigurations) and the cveId pattern are already fully documented in the schema. The description implies the default shape of the record but adds no syntax or default-override guidance beyond it, 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 (Return) and resource (the full NVD record for one CVE) and enumerates the payload contents: description, CVSS metrics, CWEs, configurations, references and CISA KEV status. It also explicitly distinguishes itself from nvd_get_cve_summary and nvd_get_cves, so an agent can pick it without opening any schema.
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?
Names two concrete alternatives with the condition that selects each: nvd_get_cve_summary for the essentials and nvd_get_cves for a batch. The full/summary/batch trichotomy is exactly the routing decision an agent needs.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
nvd_get_cve_historyGet CVE change historyARead-onlyIdempotent
Return the change history of one CVE: "New CVE Received", "Initial Analysis", "CVE Modified", "Rejected" and similar events, with their field-level changes and timestamps. Filter by eventName or changeBetween (maximum 120 days). Cached for 1 hour; paginate with the opaque cursor.
| Name | Required | Description | Default |
|---|---|---|---|
| cveId | Yes | CVE identifier such as CVE-2024-3094 (case insensitive) | |
| cursor | No | Opaque signed cursor from the previous page: pass the response's pagination.nextCursor. Never build it by hand; it expires after 30 minutes and is bound to the filters, pageSize and date window. | |
| pageSize | No | Page size (default 20, maximum 50) | |
| eventName | No | Exact event name, for example "CVE Modified" or "Initial Analysis" | |
| changeBetween | No | Filter on the change creation date (max 120 days) |
Output Schema
| Name | Required | Description |
|---|---|---|
| meta | Yes | Cache/freshness metadata; warnings carries stale-fallback and truncation notices |
| items | Yes | |
| pagination | Yes | Pagination block; nextCursor is null on the last page |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint, idempotentHint and openWorldHint, so the safety profile is covered. The description adds non-structured behavior: a 1-hour cache and the 120-day maximum window, plus the opaque-cursor pagination model. It does not mention rate limits or auth, so it stops short of a 5.
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 dense sentences, front-loaded with what is returned, followed by filtering, caching, and pagination constraints. No filler and every clause carries operational 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?
An output schema exists, so return values need not be described. For a single-CVE read with nested filter objects, the description covers scope, filters, cache TTL, window limit, and pagination, leaving nothing an agent needs before calling it.
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 cveId, cursor, pageSize, eventName and changeBetween are already fully documented at the schema level. The description restates eventName and changeBetween and the 120-day cap but adds no syntax, default, 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?
States a specific verb and resource ('Return the change history of one CVE') and enumerates the concrete event types returned, so an agent can distinguish it from nvd_get_cve, nvd_get_cve_summary, and nvd_get_modified_cves (which is multi-CVE) without opening any schema.
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 implied through the description of filters ('Filter by eventName or changeBetween') and pagination, but there is no explicit when-to-use guidance, no prerequisites, and no named alternative such as nvd_get_modified_cves for bulk change tracking. Adequate but leaves routing to inference.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
nvd_get_cvesGet multiple CVE summariesARead-onlyIdempotent
Return summaries for up to 100 CVE identifiers in one call. Identifiers are uppercased and de-duplicated; only missing or stale ones are fetched, in one batch. Reports foundIds, missingIds and meta.requested/found/missing; use nvd_get_cve for a full record.
| Name | Required | Description | Default |
|---|---|---|---|
| cveIds | Yes | 1-100 CVE identifiers; duplicates are removed and identifiers normalized to uppercase |
Output Schema
| Name | Required | Description |
|---|---|---|
| meta | Yes | |
| items | Yes | |
| foundIds | Yes | |
| missingIds | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnly/idempotent/openWorld, so safety is covered; the description adds non-obvious behavior: identifiers are uppercased, de-duplicated, and only missing/stale entries are fetched (a cache-aware batch read). That is real value beyond the annotations, though it overlaps the output schema by naming the response fields.
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?
Three dense, front-loaded sentences with no filler; the batch limit and routing to nvd_get_cve come early. Minor redundancy in enumerating response fields (foundIds, missingIds, meta.*) that the output schema already exposes.
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 a complete input schema, an output schema, and rich read-only annotations, the description supplies the remaining essentials: batch cap, normalization/dedup semantics, cache behavior, and sibling routing. Nothing needed to invoke it correctly is missing.
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 param already documents the 1-100 range, case-insensitivity, and de-duplication. The description restates the same normalization/limit facts rather than adding format or syntax detail beyond the schema, 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?
States a specific verb and resource with scope ('summaries for up to 100 CVE identifiers in one call') and explicitly routes the single-record case to nvd_get_cve, which lets an agent separate it from siblings without opening schemas.
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?
Names the alternative (nvd_get_cve for a full record) with the condition that selects it, giving clear batch-vs-single guidance. It stops short of addressing the other siblings (nvd_get_cve_summary, nvd_search_cves, nvd_search_cves), so no explicit exclusions beyond the one alternative.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
nvd_get_cve_summaryGet CVE summaryARead-onlyIdempotent
Return a compact view of one CVE: id, timestamps, status, English summary, primary CVSS score, CWEs, affected products, KEV flag and reference count. Configurations, references and the raw payload are omitted - use nvd_get_cve for those. Derived from the cached record, so it shares the same 24 hour freshness window.
| Name | Required | Description | Default |
|---|---|---|---|
| cveId | Yes | CVE identifier such as CVE-2024-3094 (case insensitive) |
Output Schema
| Name | Required | Description |
|---|---|---|
| data | Yes | |
| meta | Yes | Cache/freshness metadata; warnings carries stale-fallback and truncation notices |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnly, idempotent, openWorld and non-destructive, so the safety profile is covered. The description adds genuinely new behavioral context: the result is derived from a cached record sharing a 24 hour freshness window, which tells the agent results may be stale. It does not mention rate limits or auth, but the caching disclosure is the meaningful extra.
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?
Three tight sentences: field inventory first, exclusions and the alternative second, freshness caveat last. Every sentence carries information and nothing is repeated from the schema or annotations.
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 an output schema present, return values need no prose, yet the field list usefully frames the compactness tradeoff. Combined with the named alternative and the cache-freshness disclosure, an agent has everything needed to select and call this correctly.
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 there is only one parameter (cveId) with a regex pattern and example already in the schema. The description adds no format or case-handling 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?
States a specific verb (return) and resource (compact view of one CVE) and enumerates exactly what the view contains (id, timestamps, status, summary, CVSS, CWEs, products, KEV flag, reference count). It also names the sibling it differs from (nvd_get_cve), so an agent can separate the two without opening either schema.
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 routes the agent explicitly: configurations, references and raw payload are omitted, so 'use nvd_get_cve for those'. That gives a clear condition for choosing this tool versus its sibling. It stops short of stating broader when-not-to-use conditions (e.g., bulk retrieval, history), but the core routing decision is unambiguous.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
nvd_get_modified_cvesGet recently modified CVEsARead-onlyIdempotent
Return CVEs ordered by last-modified date, newest first (ordering "last_modified_desc"). Defaults to the last 7 days: use days or an explicit start+end window (mutually exclusive, maximum 120 days). All filters are sent to NVD, so totalResults is the exact upstream total. Cached for 5 minutes; paginate by passing pagination.nextCursor back as cursor with the same filters and pageSize - the resolved window travels inside the cursor, so a relative days window stays stable across pages.
| Name | Required | Description | Default |
|---|---|---|---|
| end | No | ISO-8601 window end (use with `start`) | |
| cvss | No | CVSS metric filter; requires at least one of severity or metrics | |
| days | No | Relative window in days counted back from now (default 7) | |
| start | No | ISO-8601 window start (use with `end`) | |
| cursor | No | Opaque signed cursor from the previous page: pass the response's pagination.nextCursor. Never build it by hand; it expires after 30 minutes and is bound to the filters, pageSize and date window. | |
| cpeName | No | Optional CPE name filter | |
| kevOnly | No | Only CISA KEV entries | |
| keyword | No | Optional keyword filter | |
| pageSize | No | Page size (default 20, maximum 50) | |
| noRejected | No | Exclude rejected CVEs | |
| vulnStatuses | No | Vulnerability statuses (Received, Awaiting Analysis, Undergoing Analysis, Analyzed, Modified, Deferred, Rejected). Spaced and camel-case spellings are both canonicalized, and the filter is applied by NVD. |
Output Schema
| Name | Required | Description |
|---|---|---|
| meta | Yes | Cache/freshness metadata; warnings carries stale-fallback and truncation notices |
| items | Yes | |
| pagination | Yes | Pagination block; nextCursor is null on the last page |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Goes well beyond annotations: notes the 5-minute cache, that filters are pushed upstream so totalResults is exact, that the resolved window is embedded in the cursor so a relative `days` window stays stable across pages, and the 30-minute cursor TTL. This is exactly the kind of pagination/caching contract an agent needs for a read 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?
Front-loaded with return semantics and ordering, then window rules, then caching and pagination. Four dense sentences, no filler, every clause earns its place.
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 an output schema present, it needn't describe return values, and it covers the operational hazards (caching, cursor lifetime/binding, window exclusivity, upstream filtering) that an agent would otherwise guess wrong. Complete for an 11-param read tool.
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 schema already documents most params with enums and constraints. The description still adds non-obvious semantics: cursor binding to filters/pageSize/window and cursor stability with relative days, which the schema only partly conveys.
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 precisely what the tool returns (CVEs ordered by last-modified date, newest first) and separates it from siblings like nvd_search_cves or nvd_get_cve by its ordering and windowing behavior. An agent can immediately tell this is the 'recently modified' feed.
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 explains the default window (last 7 days), the exclusive `days` vs `start`+`end` choice, and the 120-day cap. It doesn't explicitly say when to prefer a sibling (e.g. search_cves for keyword-driven queries), so it's clear but not fully routing.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
nvd_get_recent_cvesGet recently published CVEsARead-onlyIdempotent
Return CVEs ordered by publication date, newest first (ordering "published_desc"). Defaults to the last 7 days: use days or an explicit start+end window (mutually exclusive, maximum 120 days). Cached for 5 minutes; paginate by passing pagination.nextCursor back as cursor with the same filters and pageSize - the resolved window travels inside the cursor, so a relative days window stays stable across pages.
| Name | Required | Description | Default |
|---|---|---|---|
| end | No | ISO-8601 window end (use with `start`) | |
| cvss | No | CVSS metric filter; requires at least one of severity or metrics | |
| days | No | Relative window in days counted back from now (default 7) | |
| start | No | ISO-8601 window start (use with `end`) | |
| cursor | No | Opaque signed cursor from the previous page: pass the response's pagination.nextCursor. Never build it by hand; it expires after 30 minutes and is bound to the filters, pageSize and date window. | |
| cpeName | No | Optional CPE name filter | |
| kevOnly | No | Only CISA KEV entries | |
| keyword | No | Optional keyword filter | |
| pageSize | No | Page size (default 20, maximum 50) | |
| noRejected | No | Exclude rejected CVEs |
Output Schema
| Name | Required | Description |
|---|---|---|
| meta | Yes | Cache/freshness metadata; warnings carries stale-fallback and truncation notices |
| items | Yes | |
| pagination | Yes | Pagination block; nextCursor is null on the last page |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Beyond the readOnly/idempotent annotations, it discloses two non-obvious behaviors: results are cached for 5 minutes (a freshness caveat), and the resolved date window is embedded in the cursor so a relative `days` window stays stable across pages while filters and pageSize are bound. Neither fact is derivable from the annotations or top-level schema.
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 dense sentences, front-loaded with the ordering and default window before pagination mechanics. The parenthetical `("published_desc")` and nested asides add some visual noise but every clause carries operational 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?
With 10 optional parameters, a nested CVSS object, and an output schema present, the description covers the things structured fields cannot: default window, window-size cap, mutual exclusivity, cache TTL, and the exact cursor round-trip protocol. An agent has everything needed to call and paginate correctly.
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 parameter baseline is 3. The description exceeds that by stating the cross-parameter constraint (days vs start/end mutual exclusivity, 120-day max) and the default lookback, none of which appear in the per-parameter schema text.
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 ("Return CVEs") plus the ordering dimension ("ordered by publication date, newest first"), which separates it from date-based siblings like nvd_get_modified_cves. It does not explicitly name or contrast any sibling tool (nvd_get_cves, nvd_search_cves), so differentiation is implied by scope rather than stated.
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 concrete usage rules: default 7-day lookback, and that `days` and `start`+`end` are mutually exclusive alternatives capped at 120 days. What it lacks is guidance on when to prefer this over nvd_get_cves or nvd_search_cves — no tool-level alternatives are named.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
nvd_search_cpe_matchesSearch CPE Match CriteriaARead-onlyIdempotent
Search CPE Match Criteria, which link CVEs to CPE names and version ranges. At least one filter is required: cveId, matchCriteriaId, matchStringSearch or lastModified (maximum 120 days). matchStringSearch must be a complete CPE match string such as cpe:2.3:a:vendor:product::::::::; upstream rejects partial keywords and version ranges. Cached for 24 hours; paginate with the opaque cursor.
| Name | Required | Description | Default |
|---|---|---|---|
| cveId | No | Return the match criteria referenced by this CVE | |
| cursor | No | Opaque signed cursor from the previous page: pass the response's pagination.nextCursor. Never build it by hand; it expires after 30 minutes and is bound to the filters, pageSize and date window. | |
| pageSize | No | Page size (default 20, maximum 100) | |
| lastModified | No | Filter on the match criteria last-modified date (max 120 days) | |
| matchCriteriaId | No | Match criteria UUID | |
| matchStringSearch | No | Complete CPE match string (wildcards allowed, no version ranges) |
Output Schema
| Name | Required | Description |
|---|---|---|
| meta | Yes | Cache/freshness metadata; warnings carries stale-fallback and truncation notices |
| items | Yes | |
| pagination | Yes | Pagination block; nextCursor is null on the last page |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already cover the safety profile (readOnly, idempotent, non-destructive, openWorld), so the description's job is to add operational context — and it does: 24-hour caching, cursor-based pagination, and the upstream rejection of partial keywords and version ranges in matchStringSearch. These are non-obvious behaviors an agent cannot infer from the annotations or schema.
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?
Three densely packed sentences with the resource definition front-loaded, then the filter requirement, then the two gotchas (matchString syntax, caching/pagination). No filler, nothing repeated from the schema verbatim.
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 six-parameter, nested-object search with an output schema present, the description covers what the tool returns conceptually, the filter precondition, the pagination mechanics, the cache window, and the input-format trap. An agent can call it correctly without opening anything else.
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 baseline is 3, but the description adds real meaning on top: matchStringSearch must be a complete CPE match string with the cpe:2.3:a:vendor:product:*... form, and the lastModified window is capped at 120 days. It does not add anything further about cursor freshness or pageSize, which the schema already handles.
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 (Search) and resource (CPE Match Criteria) and explains what the resource is: the join that links CVEs to CPE names and version ranges. That implicitly separates it from nvd_search_cpes / nvd_get_cpe, but no sibling is named explicitly and no exclusion is stated.
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?
Gives a hard precondition ('At least one filter is required') and enumerates the four admissible filters plus the 120-day ceiling on lastModified, so an agent knows how to form a valid call. It does not, however, say when to reach for this tool over nvd_search_cpes or how it complements nvd_get_cve.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
nvd_search_cpesSearch CPE namesARead-onlyIdempotent
Search the NVD Official CPE Dictionary by keyword, match string, criteria UUID, or last-modified window. At least one filter is required; date windows are limited to 120 days. Deprecated CPEs are filtered locally unless includeDeprecated is true. totalResults is the upstream NVD count before local filtering, so it may be greater than returned items or even > 0 with an empty items array when matching entries are filtered out. Results are cached for 24 hours and use opaque cursor pagination; reuse nextCursor with the same filters and pageSize.
| Name | Required | Description | Default |
|---|---|---|---|
| cursor | No | Opaque signed cursor from the previous page: pass the response's pagination.nextCursor. Never build it by hand; it expires after 30 minutes and is bound to the filters, pageSize and date window. | |
| keyword | No | Keyword matched against CPE titles | |
| pageSize | No | Page size (default 20, maximum 100) | |
| lastModified | No | Filter on the CPE last-modified date (max 120 days) | |
| cpeMatchString | No | CPE match string to look up | |
| matchCriteriaId | No | CPE Match Criteria UUID whose CPE names should be returned | |
| includeDeprecated | No | Include deprecated CPE names (default false). This filter runs locally; see meta.filteredOut. | |
| keywordExactMatch | No | Require the exact keyword phrase (requires keyword) |
Output Schema
| Name | Required | Description |
|---|---|---|
| meta | Yes | Cache/freshness metadata; warnings carries stale-fallback and truncation notices |
| items | Yes | |
| pagination | Yes | Pagination block; nextCursor is null on the last page |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With annotations already covering read-only/idempotent/non-destructive/open-world, the description still adds substantial non-obvious behavior: deprecated CPEs filtered locally unless includeDeprecated, totalResults being the upstream count that can exceed returned items or be positive with an empty items array, and 24-hour caching. This is exactly the operational context annotations cannot express.
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?
Four dense sentences, all load-bearing, with the core scope stated first and constraints/edge cases after. The totalResults explanation is the longest clause but justifies its length because it prevents a misinterpretation of an empty result set.
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 an 8-parameter, nested-object tool with an output schema, the description covers the prerequisites, the local-vs-upstream filtering split, cache lifetime, and cursor lifetime/binding — everything an agent needs to call it correctly and interpret pagination. Return-value shape is rightly left to the output schema.
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 baseline is 3, but the description adds genuine cross-parameter semantics: cursors must be reused with the same filters and pageSize, the 120-day cap on the date window, and that includeDeprecated is a local filter reflected in meta.filteredOut. keywordExactMatch and cpeMatchString get no extra narrative, but the schema already documents them.
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 ("Search the NVD Official CPE Dictionary") and enumerates the four filter modes (keyword, match string, criteria UUID, last-modified window), so the agent knows exactly what the tool operates on. It is clear it deals with the CPE Dictionary rather than CPE matches, but it never names the nearest sibling (nvd_search_cpe_matches or nvd_get_cpe) to harden the boundary.
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?
"At least one filter is required; date windows are limited to 120 days" gives a firm precondition the agent must satisfy before calling. It stops short of routing guidance — no statement of when to prefer nvd_get_cpe or nvd_search_cpe_matches instead — so the alternative-selection layer is missing.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
nvd_search_cvesSearch CVEsARead-onlyIdempotent
Search CVE records with the NVD 2.0 filters: keyword, CVE IDs, CPE name or match string, CWE, source identifier, vuln statuses, published/last-modified windows, KEV window, CVSS metrics and CERT flags. Rules: keywordExactMatch requires keyword; isVulnerable requires cpeName; cpeName and virtualMatchString are mutually exclusive; date windows are limited to 120 days. NVD evaluates every filter, so totalResults is the exact upstream total. Cached for 15 minutes; paginate by passing pagination.nextCursor back as cursor with the same filters and pageSize.
| Name | Required | Description | Default |
|---|---|---|---|
| kev | No | ||
| cvss | No | CVSS metric filter; requires at least one of severity or metrics | |
| cweId | No | CWE identifier such as CWE-79 | |
| cursor | No | Opaque signed cursor from the previous page: pass the response's pagination.nextCursor. Never build it by hand; it expires after 30 minutes and is bound to the filters, pageSize and date window. | |
| cveIds | No | Restrict the search to these CVE identifiers | |
| cpeName | No | CPE name filter; translates to the upstream cpeName parameter | |
| hasOval | No | Only CVEs with OVAL definitions | |
| keyword | No | Keyword matched against CVE descriptions | |
| pageSize | No | Page size (default 20, maximum 50) | |
| published | No | Filter on the published date (max 120 days) | |
| noRejected | No | Exclude rejected CVEs (upstream noRejected) | |
| hasCertNotes | No | Only CVEs with CERT notes | |
| isVulnerable | No | Only CVEs where cpeName is marked vulnerable; requires cpeName, incompatible with virtualMatchString | |
| lastModified | No | Filter on the last-modified date (max 120 days) | |
| vulnStatuses | No | Vulnerability statuses (Received, Awaiting Analysis, Undergoing Analysis, Analyzed, Modified, Deferred, Rejected). Spaced and camel-case spellings are both canonicalized, and the filter is applied by NVD. | |
| hasCertAlerts | No | Only CVEs with CERT alerts | |
| sourceIdentifier | No | CNA or NVD source identifier, for example secalert@redhat.com | |
| keywordExactMatch | No | Require the exact keyword phrase (requires keyword) | |
| virtualMatchString | No | CPE match string (supports wildcards and version ranges); mutually exclusive with cpeName |
Output Schema
| Name | Required | Description |
|---|---|---|
| meta | Yes | Cache/freshness metadata; warnings carries stale-fallback and truncation notices |
| items | Yes | |
| pagination | Yes | Pagination block; nextCursor is null on the last page |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare read-only, idempotent, open-world behavior, so the description need not restate safety. It adds genuinely non-obvious traits: results are cached for 15 minutes, and NVD evaluates every filter so totalResults is the exact upstream total, plus how to paginate via nextCursor. Missing details like rate limits or cache-staleness implications keep it below 5.
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?
Three sentences, front-loaded with purpose then rules then caching/pagination, with no filler. The opening filter enumeration slightly overlaps with what the schema already lists, so it is not maximally economical, but every clause carries usable 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?
For a 19-parameter, nested-object tool with an output schema present, the description covers the essential non-schema gaps: constraint interactions, window caps, caching, exactness of totals, and pagination mechanics. An agent can call it correctly without opening the schema, though sibling routing is the one untouched area.
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 95%, so the baseline is 3, but the description adds cross-parameter semantics the schema only partially encodes: the keyword/keywordExactMatch and cpeName/isVulnerable dependencies, the exclusivity pair, and the shared 120-day window limit. It also clarifies that statuses and filters are applied upstream by NVD, which is meaning beyond the field-level text.
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+resource ('Search CVE records') and enumerates the exact NVD 2.0 filter dimensions the tool accepts, so the agent knows precisely what surface it covers. It is clearly distinct from get-style siblings in name and behavior, but never explicitly names those siblings or contrasts itself with them, keeping it short of a 5.
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 'Rules' sentence gives real operational constraints (keywordExactMatch requires keyword; isVulnerable requires cpeName; cpeName/virtualMatchString mutually exclusive; 120-day windows) and explains pagination. However, there is no guidance on when to choose this over sibling tools like nvd_get_cves or nvd_get_recent_cves, which is the main 'when-to-use' question for a search tool.
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.
10 tool updates
v0.1.0- First observed
nvd_get_cpe - First observed
nvd_get_cve - First observed
nvd_get_cve_history - First observed
nvd_get_cve_summary - First observed
nvd_get_cves - First observed
nvd_get_modified_cves - First observed
nvd_get_recent_cves - First observed
nvd_search_cpe_matches - First observed
nvd_search_cpes - First observed
nvd_search_cves
TDQS
Scored across 10 tools
Tool names and descriptions clearly delineate resource+action, but nvd_get_recent_cves and nvd_get_modified_cves are nearly identical except for ordering, and nvd_get_cve, nvd_get_cve_summary, and nvd_get_cves all target CVE records with overlapping semantics. The descriptions do distinguish scope and detail level, but an agent could easily misselect between the full, summary, and batch variants without careful reading.
Every tool follows a consistent nvd_ verb_noun pattern (get, search, and entity names like cve, cves, cpe). Variants like nvd_get_cve_summary and nvd_get_cve_history extend the base name predictably. No mixed conventions or inconsistent casing.
Ten tools is well within the sweet spot for a domain-specific API wrapper. Each tool maps to a distinct NVD endpoint or use case (single record, batch, search, history, CPE dictionary, CPE matches), so the surface feels scoped rather than padded.
The surface covers CVE retrieval (single, batch, summary, search, history, recent, modified) and CPE lookup (search, get, matches), which is core NVD functionality. Missing operations like CVE creation or modification don't apply since NVD is read-only, but there is no tool for bulk CPE dictionary listing or NVD API status, which could be minor gaps for some workflows.
Maintenance
Related MCP Connectors
NVD MCP — wraps the NIST National Vulnerability Database API.
ZEN SecDB MCP server for CVE intelligence, CVSS/EPSS scoring, advisories, SSVC, and package audits.
Search and audit NIST NVD CVEs by keyword, severity, CWE, CISA KEV status, and CPE.
Related MCP Servers
- AlicenseBqualityDmaintenanceA Model Context Protocol (MCP) server for querying the CVE-Search API. This server provides comprehensive access to CVE-Search, browse vendor and product、get CVE per CVE-ID、get the last updated CVEs.6107MIT
- AlicenseNot gradedqualityDmaintenanceA Model Context Protocol (MCP) server for querying the NIST National Vulnerability Database (NVD) API, enabling search and retrieval of CVE details, temporal context, and KEV catalog entries.14MIT
- AlicenseAqualityCmaintenanceMCP server that provides tools to search, filter, and retrieve CVE data from the NVD API, including by ID, keyword, severity, and recency.4MIT
- FlicenseAqualityBmaintenanceEnables querying and analyzing a legacy, file-based vulnerability registry via MCP tools for CVE lookup, search, vendor navigation, and aggregate statistics.5-