@cyanheads/nist-nvd-mcp-server 0.3.0 → 0.3.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +55 -27
- package/CLAUDE.md +55 -27
- package/Dockerfile +109 -36
- package/README.md +69 -65
- package/changelog/0.3.x/0.3.1.md +34 -0
- package/changelog/0.3.x/0.3.2.md +34 -0
- package/changelog/template.md +9 -26
- package/dist/index.js +5 -0
- package/dist/index.js.map +1 -1
- package/dist/mcp-server/resources/definitions/nvd-cve.resource.d.ts +3 -2
- package/dist/mcp-server/resources/definitions/nvd-cve.resource.d.ts.map +1 -1
- package/dist/mcp-server/resources/definitions/nvd-cve.resource.js +4 -3
- package/dist/mcp-server/resources/definitions/nvd-cve.resource.js.map +1 -1
- package/dist/mcp-server/tools/definitions/nvd-audit-cpe.tool.d.ts +2 -0
- package/dist/mcp-server/tools/definitions/nvd-audit-cpe.tool.d.ts.map +1 -1
- package/dist/mcp-server/tools/definitions/nvd-audit-cpe.tool.js +9 -7
- package/dist/mcp-server/tools/definitions/nvd-audit-cpe.tool.js.map +1 -1
- package/dist/mcp-server/tools/definitions/nvd-get-cve-history.tool.d.ts +4 -0
- package/dist/mcp-server/tools/definitions/nvd-get-cve-history.tool.d.ts.map +1 -1
- package/dist/mcp-server/tools/definitions/nvd-get-cve-history.tool.js +4 -0
- package/dist/mcp-server/tools/definitions/nvd-get-cve-history.tool.js.map +1 -1
- package/dist/mcp-server/tools/definitions/nvd-get-cve.tool.d.ts +6 -0
- package/dist/mcp-server/tools/definitions/nvd-get-cve.tool.d.ts.map +1 -1
- package/dist/mcp-server/tools/definitions/nvd-get-cve.tool.js +9 -3
- package/dist/mcp-server/tools/definitions/nvd-get-cve.tool.js.map +1 -1
- package/dist/mcp-server/tools/definitions/nvd-search-cpes.tool.d.ts +2 -0
- package/dist/mcp-server/tools/definitions/nvd-search-cpes.tool.d.ts.map +1 -1
- package/dist/mcp-server/tools/definitions/nvd-search-cpes.tool.js +4 -2
- package/dist/mcp-server/tools/definitions/nvd-search-cpes.tool.js.map +1 -1
- package/dist/mcp-server/tools/definitions/nvd-search-cves.tool.d.ts +2 -0
- package/dist/mcp-server/tools/definitions/nvd-search-cves.tool.d.ts.map +1 -1
- package/dist/mcp-server/tools/definitions/nvd-search-cves.tool.js +18 -16
- package/dist/mcp-server/tools/definitions/nvd-search-cves.tool.js.map +1 -1
- package/dist/services/nvd-cpe/nvd-cpe-service.d.ts.map +1 -1
- package/dist/services/nvd-cpe/nvd-cpe-service.js +1 -5
- package/dist/services/nvd-cpe/nvd-cpe-service.js.map +1 -1
- package/dist/services/nvd-cve/nvd-cve-service.d.ts.map +1 -1
- package/dist/services/nvd-cve/nvd-cve-service.js +8 -14
- package/dist/services/nvd-cve/nvd-cve-service.js.map +1 -1
- package/dist/services/nvd-http/nvd-http-client.d.ts.map +1 -1
- package/dist/services/nvd-http/nvd-http-client.js +2 -1
- package/dist/services/nvd-http/nvd-http-client.js.map +1 -1
- package/manifest.json +13 -3
- package/package.json +14 -12
- package/server.json +16 -24
package/Dockerfile
CHANGED
|
@@ -3,8 +3,18 @@
|
|
|
3
3
|
#
|
|
4
4
|
# This stage installs all dependencies (including dev), builds the TypeScript
|
|
5
5
|
# source code into JavaScript, and prepares the production assets.
|
|
6
|
+
#
|
|
7
|
+
# Pinned to $BUILDPLATFORM rather than the target platform: `bun run build` emits
|
|
8
|
+
# JavaScript, and only `dist/` crosses into the production stage. Built for the
|
|
9
|
+
# target instead, the non-native leg of a `--platform linux/amd64,linux/arm64`
|
|
10
|
+
# build runs under QEMU, where bun >= 1.4 aborts with a JavaScriptCore allocator
|
|
11
|
+
# assertion and fails the multi-arch push.
|
|
12
|
+
#
|
|
13
|
+
# The constraint this assumes: the build stage produces platform-independent
|
|
14
|
+
# output. A stage that compiles a native addon needs the target-arch toolchain
|
|
15
|
+
# and cannot cross-compile this way — drop the flag there.
|
|
6
16
|
# ==============================================================================
|
|
7
|
-
FROM oven/bun:1.4.
|
|
17
|
+
FROM --platform=$BUILDPLATFORM oven/bun:1.4.2 AS build
|
|
8
18
|
|
|
9
19
|
WORKDIR /usr/src/app
|
|
10
20
|
|
|
@@ -24,68 +34,132 @@ RUN bun run build
|
|
|
24
34
|
|
|
25
35
|
|
|
26
36
|
# ==============================================================================
|
|
27
|
-
# Production Stage
|
|
37
|
+
# Production Dependencies Stage
|
|
28
38
|
#
|
|
29
|
-
#
|
|
30
|
-
#
|
|
31
|
-
#
|
|
39
|
+
# Installs the production dependency tree for the target platform. Every step
|
|
40
|
+
# here can run JavaScript — bunfig.toml's security scanner runs as a Bun
|
|
41
|
+
# program, and so do the OTel and musl-prune scripts — so the stage runs on
|
|
42
|
+
# $BUILDPLATFORM and cross-installs with `--os`/`--cpu`, which pick each
|
|
43
|
+
# platform-specific optional dependency (native bindings such as DuckDB's) for
|
|
44
|
+
# the target. Only `node_modules` leaves this stage.
|
|
45
|
+
#
|
|
46
|
+
# A clean image rather than `FROM build`: the build stage's node_modules holds
|
|
47
|
+
# devDependencies.
|
|
32
48
|
# ==============================================================================
|
|
33
|
-
FROM oven/bun:1.4.
|
|
49
|
+
FROM --platform=$BUILDPLATFORM oven/bun:1.4.2 AS deps
|
|
34
50
|
|
|
35
51
|
WORKDIR /usr/src/app
|
|
36
52
|
|
|
37
|
-
#
|
|
38
|
-
#
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
#
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
#
|
|
50
|
-
|
|
53
|
+
# Copy dependency manifests. `bunfig.toml` rides along so every install below
|
|
54
|
+
# passes its release-age gate and security scanner, as a local install does.
|
|
55
|
+
COPY package.json bun.lock bunfig.toml ./
|
|
56
|
+
|
|
57
|
+
# The scanner bunfig.toml names is a devDependency, and Bun installs a missing
|
|
58
|
+
# scanner through the same production-filtered install, which omits it and
|
|
59
|
+
# aborts. Seed it from the build stage's full install instead. Remove this line,
|
|
60
|
+
# and the `rm` at the end of this stage, if bunfig.toml stops naming a scanner.
|
|
61
|
+
COPY --from=build /usr/src/app/node_modules/@socketsecurity/bun-security-scanner ./node_modules/@socketsecurity/bun-security-scanner
|
|
62
|
+
|
|
63
|
+
# Docker names the target architecture `amd64`/`arm64`; Bun's `--cpu` takes
|
|
64
|
+
# `x64`/`arm64`. Mapped once here, read by both installs below. `oven/bun`
|
|
65
|
+
# publishes only these two architectures, so any other target fails here.
|
|
66
|
+
ARG TARGETOS
|
|
67
|
+
ARG TARGETARCH
|
|
68
|
+
RUN case "$TARGETARCH" in \
|
|
69
|
+
amd64) echo x64 ;; \
|
|
70
|
+
arm64) echo arm64 ;; \
|
|
71
|
+
*) echo "Unsupported TARGETARCH '$TARGETARCH': expected amd64 or arm64" >&2; exit 1 ;; \
|
|
72
|
+
esac > .bun-cpu
|
|
51
73
|
|
|
52
74
|
# Install only production dependencies, ignoring any lifecycle scripts (like 'prepare')
|
|
53
75
|
# that are not needed in the final production image.
|
|
54
76
|
# `--omit=peer` drops the framework's optional peer tiers (test runner, service
|
|
55
77
|
# SDKs, parsers) that Bun would otherwise auto-install. Anything this server
|
|
56
78
|
# actually imports belongs in its own `dependencies`, so nothing needed at
|
|
57
|
-
# runtime is lost.
|
|
58
|
-
# install re-resolves the graph and pulls every optional peer back in.
|
|
79
|
+
# runtime is lost.
|
|
59
80
|
RUN --mount=type=cache,target=/root/.bun/install/cache \
|
|
60
|
-
bun install --production --omit=peer --frozen-lockfile --ignore-scripts
|
|
81
|
+
bun install --production --omit=peer --frozen-lockfile --ignore-scripts \
|
|
82
|
+
--os="$TARGETOS" --cpu="$(cat .bun-cpu)"
|
|
61
83
|
|
|
62
84
|
# Conditionally install OpenTelemetry optional peer dependencies (Tier 3).
|
|
63
|
-
#
|
|
64
|
-
# with: docker build --build-arg OTEL_ENABLED=
|
|
85
|
+
# Installed by default. Omit them for a leaner image at build time
|
|
86
|
+
# with: docker build --build-arg OTEL_ENABLED=false
|
|
87
|
+
# The script reads the list and each range from the installed framework's
|
|
88
|
+
# `peerDependencies` and passes the target flags on to its `bun install`.
|
|
89
|
+
COPY scripts/install-otel.ts ./scripts/
|
|
65
90
|
ARG OTEL_ENABLED=true
|
|
66
91
|
RUN --mount=type=cache,target=/root/.bun/install/cache \
|
|
67
92
|
if [ "$OTEL_ENABLED" = "true" ]; then \
|
|
68
|
-
bun
|
|
69
|
-
@opentelemetry/instrumentation-http \
|
|
70
|
-
@opentelemetry/exporter-metrics-otlp-http \
|
|
71
|
-
@opentelemetry/exporter-trace-otlp-http \
|
|
72
|
-
@opentelemetry/instrumentation-pino \
|
|
73
|
-
@opentelemetry/resources \
|
|
74
|
-
@opentelemetry/sdk-metrics \
|
|
75
|
-
@opentelemetry/sdk-node \
|
|
76
|
-
@opentelemetry/sdk-trace-node \
|
|
77
|
-
@opentelemetry/semantic-conventions; \
|
|
93
|
+
bun scripts/install-otel.ts --os="$TARGETOS" --cpu="$(cat .bun-cpu)"; \
|
|
78
94
|
fi
|
|
79
95
|
|
|
96
|
+
# `--os`/`--cpu` have no libc counterpart, so a native dependency published in
|
|
97
|
+
# glibc and musl variants (DuckDB's bindings, for one) installs both. The
|
|
98
|
+
# runtime image is Debian (glibc) and never loads the musl copy; the script
|
|
99
|
+
# deletes every package whose own `libc` admits only musl. It follows every
|
|
100
|
+
# install, since a later `bun install` restores what it removes. A server on a
|
|
101
|
+
# musl (Alpine) runtime image drops these two lines.
|
|
102
|
+
COPY scripts/prune-musl-packages.ts ./scripts/
|
|
103
|
+
RUN bun scripts/prune-musl-packages.ts
|
|
104
|
+
|
|
105
|
+
# The seeded scanner served only the installs above; keep it out of the image.
|
|
106
|
+
RUN rm -rf node_modules/@socketsecurity/bun-security-scanner
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
# ==============================================================================
|
|
110
|
+
# Production Stage
|
|
111
|
+
#
|
|
112
|
+
# This stage creates a minimal, optimized, and secure image for running the
|
|
113
|
+
# application. It uses a slim base image and only includes production
|
|
114
|
+
# dependencies and build artifacts. Its only Bun invocations are HEALTHCHECK
|
|
115
|
+
# and CMD, which run on the real target at container start.
|
|
116
|
+
# ==============================================================================
|
|
117
|
+
FROM oven/bun:1.4.2-slim AS production
|
|
118
|
+
|
|
119
|
+
WORKDIR /usr/src/app
|
|
120
|
+
|
|
121
|
+
# Set the environment to production for performance.
|
|
122
|
+
ENV NODE_ENV=production
|
|
123
|
+
|
|
124
|
+
# OCI image metadata (https://github.com/opencontainers/image-spec/blob/main/annotations.md)
|
|
125
|
+
ARG APP_VERSION
|
|
126
|
+
LABEL org.opencontainers.image.title="nist-nvd-mcp-server"
|
|
127
|
+
LABEL org.opencontainers.image.description="Search and audit CVEs by keyword, severity, CWE, CISA KEV status, and CPE via the NIST National Vulnerability Database. STDIO or Streamable HTTP."
|
|
128
|
+
LABEL org.opencontainers.image.licenses="Apache-2.0"
|
|
129
|
+
LABEL org.opencontainers.image.version="${APP_VERSION}"
|
|
130
|
+
LABEL org.opencontainers.image.source="https://github.com/cyanheads/nist-nvd-mcp-server"
|
|
131
|
+
|
|
132
|
+
# The manifest comes from the build context: the deps stage's copy was rewritten
|
|
133
|
+
# by the OTel install, and the runtime reads only its name, version, and type.
|
|
134
|
+
COPY package.json ./
|
|
135
|
+
COPY --from=deps /usr/src/app/node_modules ./node_modules
|
|
136
|
+
|
|
80
137
|
# Copy the compiled application code from the build stage
|
|
81
138
|
COPY --from=build /usr/src/app/dist ./dist
|
|
82
139
|
|
|
140
|
+
# Mirror CLI (MirrorService adopters only — Tier 3, opt-in):
|
|
141
|
+
# Copy your mirror lifecycle scripts and emit a runtime tsconfig so Bun resolves
|
|
142
|
+
# the @/ path alias against ./dist/ rather than ./src/.
|
|
143
|
+
# See the api-mirror skill for the full recipe.
|
|
144
|
+
#
|
|
145
|
+
# COPY --from=build /usr/src/app/scripts/<your>-mirror-init.ts \
|
|
146
|
+
# /usr/src/app/scripts/<your>-mirror-refresh.ts \
|
|
147
|
+
# /usr/src/app/scripts/<your>-mirror-verify.ts \
|
|
148
|
+
# /usr/src/app/scripts/_mirror-context.ts \
|
|
149
|
+
# ./scripts/
|
|
150
|
+
# RUN echo '{"compilerOptions":{"baseUrl":".","paths":{"@/*":["./dist/*"]}}}' > tsconfig.json
|
|
151
|
+
|
|
83
152
|
# The 'oven/bun' image already provides a non-root user named 'bun'.
|
|
84
153
|
# We will use this existing user for enhanced security.
|
|
85
154
|
|
|
86
155
|
# Create and set permissions for the log directory, assigning ownership to the 'bun' user.
|
|
87
156
|
RUN mkdir -p /var/log/nist-nvd-mcp-server && chown -R bun:bun /var/log/nist-nvd-mcp-server
|
|
88
157
|
|
|
158
|
+
# Writable data dirs for on-disk SQLite stores (catalog index / observations
|
|
159
|
+
# mirror), owned by the runtime user. Mount a volume over either in production.
|
|
160
|
+
RUN mkdir -p /usr/src/app/.cache /usr/src/app/.mirror \
|
|
161
|
+
&& chown -R bun:bun /usr/src/app/.cache /usr/src/app/.mirror
|
|
162
|
+
|
|
89
163
|
# Switch to the non-root user
|
|
90
164
|
USER bun
|
|
91
165
|
|
|
@@ -101,7 +175,6 @@ ENV MCP_TRANSPORT_TYPE="http"
|
|
|
101
175
|
ENV MCP_SESSION_MODE="stateless"
|
|
102
176
|
ENV MCP_LOG_LEVEL="info"
|
|
103
177
|
ENV LOGS_DIR="/var/log/nist-nvd-mcp-server"
|
|
104
|
-
ENV MCP_FORCE_CONSOLE_LOGGING="true"
|
|
105
178
|
|
|
106
179
|
# Expose the port the server listens on
|
|
107
180
|
EXPOSE ${MCP_HTTP_PORT}
|
package/README.md
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
|
|
8
8
|
<div align="center">
|
|
9
9
|
|
|
10
|
-
[](./CHANGELOG.md) [](./LICENSE) [](https://github.com/users/cyanheads/packages/container/package/nist-nvd-mcp-server) [](https://modelcontextprotocol.io/) [](https://www.npmjs.com/package/@cyanheads/nist-nvd-mcp-server) [](https://www.typescriptlang.org/) [](https://bun.sh/)
|
|
11
11
|
|
|
12
12
|
</div>
|
|
13
13
|
|
|
@@ -27,9 +27,11 @@
|
|
|
27
27
|
|
|
28
28
|
---
|
|
29
29
|
|
|
30
|
-
##
|
|
30
|
+
## Overview
|
|
31
31
|
|
|
32
|
-
|
|
32
|
+
CVE and CPE data from the NIST National Vulnerability Database. Search and audit vulnerabilities by keyword, severity, CWE, or CISA KEV status, resolve products to CPE names, and track a CVE's revision history from any MCP client. Runs as a stdio process, a local Streamable HTTP server, or the public hosted endpoint above.
|
|
33
|
+
|
|
34
|
+
### Tools
|
|
33
35
|
|
|
34
36
|
| Tool | Description |
|
|
35
37
|
|:-----|:------------|
|
|
@@ -39,106 +41,108 @@ Five tools for vulnerability research, CPE auditing, and change tracking against
|
|
|
39
41
|
| `nvd_audit_cpe` | Find all CVEs affecting a specific product version by CPE name or virtual match string. |
|
|
40
42
|
| `nvd_get_cve_history` | Retrieve the change history for a CVE — score revisions, status transitions, and reference additions. |
|
|
41
43
|
|
|
42
|
-
###
|
|
44
|
+
### Resources
|
|
43
45
|
|
|
44
|
-
|
|
46
|
+
| Resource | Description |
|
|
47
|
+
|:---------|:------------|
|
|
48
|
+
| `nvd://cve/{cveId}` | Full CVE record by ID — same data as `nvd_get_cve` for a single ID, as a stable URI for injectable context. |
|
|
45
49
|
|
|
46
|
-
|
|
47
|
-
- Severity filter by CVSS v2/v3/v4 label (LOW, MEDIUM, HIGH, CRITICAL)
|
|
48
|
-
- CWE weakness filter (e.g., `CWE-79`, `NVD-CWE-Other`)
|
|
49
|
-
- CISA KEV filter — limit results to known-exploited vulnerabilities
|
|
50
|
-
- Convenience date shorthands: `pubDays` and `lastModDays` for "last N days" queries
|
|
51
|
-
- Explicit ISO 8601 date range parameters (`pubStartDate`/`pubEndDate`, etc.) with 120-day max span
|
|
52
|
-
- Auto-clamps convenience date params that exceed 120 days and reports clamped values in the response enrichment
|
|
53
|
-
- Pagination via `limit` (up to 2000) and `offset`
|
|
54
|
-
- Every row carries a truncated description alongside the ID, so results are distinguishable without a follow-up fetch
|
|
55
|
-
- Results are always brief; call `nvd_get_cve` for full detail
|
|
50
|
+
All resource data is also reachable via tools.
|
|
56
51
|
|
|
57
|
-
|
|
52
|
+
## Capability reference
|
|
58
53
|
|
|
59
|
-
### `
|
|
54
|
+
### `nvd_search_cves` <sub>tool</sub>
|
|
55
|
+
|
|
56
|
+
- Full-text keyword search (AND-semantics across words), or `exactPhrase: true` for an exact-phrase match — requires `keyword`
|
|
57
|
+
- Filters: CVSS severity band (LOW/MEDIUM/HIGH/CRITICAL — CRITICAL requires `severityVersion: "v3"` or `"v4"`), CWE ID, CISA KEV status, `noRejected` (default true)
|
|
58
|
+
- Date filters: `pubDays`/`lastModDays` convenience shorthands (auto-clamped to 120 days, clamping reported in the enrichment) or explicit ISO 8601 ranges (120-day max span, both ends required); the two forms per axis are mutually exclusive
|
|
59
|
+
- Pagination via `limit` (up to 2000, default 20) and `offset`
|
|
60
|
+
- Always returns brief summaries with a truncated description; call `nvd_get_cve` for full detail
|
|
61
|
+
|
|
62
|
+
---
|
|
60
63
|
|
|
61
|
-
|
|
64
|
+
### `nvd_get_cve` <sub>tool</sub>
|
|
62
65
|
|
|
63
66
|
- Batch up to 100 CVE IDs per call
|
|
64
|
-
- Full mode:
|
|
65
|
-
-
|
|
66
|
-
- `includeReferences: false`
|
|
67
|
-
-
|
|
68
|
-
- Rendered text
|
|
67
|
+
- Full mode (default): CVSS scores across v2.0/v3.0/v3.1/v4.0, CWE weaknesses, CPE configurations, CISA KEV fields, references
|
|
68
|
+
- `brief: true` returns trimmed rows (ID, status, top severity, KEV name, truncated description) — recommended for batches over 10
|
|
69
|
+
- `includeReferences: false` strips the references array; `allLanguages: true` renders every localized description instead of English-only
|
|
70
|
+
- `missingIds` enrichment field lists any requested IDs NVD didn't return
|
|
71
|
+
- Rendered text caps references at 15 per record, with a `… N more` trailer
|
|
69
72
|
|
|
70
73
|
---
|
|
71
74
|
|
|
72
|
-
### `nvd_search_cpes`
|
|
75
|
+
### `nvd_search_cpes` <sub>tool</sub>
|
|
73
76
|
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
- Keyword search (e.g., `"apache http server"`, `"openssl"`) or partial CPEv2.3 pattern
|
|
77
|
+
- Keyword search (e.g. `"apache http server"`) or a partial CPEv2.3 pattern via `cpeMatchString` — at least one required
|
|
77
78
|
- Returns full CPE name, human-readable title, deprecation status, and superseding CPEs
|
|
78
|
-
- Pagination via `limit` (up to 10,000
|
|
79
|
-
- Use
|
|
79
|
+
- Pagination via `limit` (up to 10,000, default 20) and `offset` — a vendor-level keyword can match tens of thousands of entries, so page rather than narrowing further
|
|
80
|
+
- Use before `nvd_audit_cpe` to resolve the exact CPE name a product needs
|
|
80
81
|
|
|
81
82
|
---
|
|
82
83
|
|
|
83
|
-
### `nvd_audit_cpe`
|
|
84
|
-
|
|
85
|
-
Full CVE audit for a specific product version.
|
|
84
|
+
### `nvd_audit_cpe` <sub>tool</sub>
|
|
86
85
|
|
|
87
|
-
- Two modes: exact `cpeName` (NVD auto-applies `isVulnerable`) or `virtualMatchString` with optional
|
|
88
|
-
-
|
|
89
|
-
-
|
|
90
|
-
-
|
|
91
|
-
-
|
|
92
|
-
- Echoes the CPE identifier used in the response enrichment so callers can verify the correct product was queried
|
|
86
|
+
- Two modes: exact `cpeName` (NVD auto-applies `isVulnerable`) or `virtualMatchString` with optional `versionStart`/`versionEnd` bounds (inclusive/exclusive)
|
|
87
|
+
- Client-side `severityMin` filter drops low-signal entries from the fetched page — it can only remove what `limit` already retrieved
|
|
88
|
+
- Returns full CVE records (CVSS scores, CWE, CPE configurations, KEV fields, references)
|
|
89
|
+
- Pagination via `limit` (up to 2000, default 20) and `offset` — page at a modest limit rather than raising it, since each result is a full record
|
|
90
|
+
- `auditTarget` enrichment field echoes the CPE identifier used, so callers can verify the correct product was queried
|
|
93
91
|
|
|
94
92
|
---
|
|
95
93
|
|
|
96
|
-
### `nvd_get_cve_history`
|
|
97
|
-
|
|
98
|
-
Track a CVE's lifecycle over time.
|
|
94
|
+
### `nvd_get_cve_history` <sub>tool</sub>
|
|
99
95
|
|
|
100
96
|
- Returns change events: CVSS revisions, status transitions, reference additions, CPE configuration updates
|
|
101
|
-
- `order` picks
|
|
102
|
-
- Paginated via `limit` and `offset`,
|
|
103
|
-
-
|
|
97
|
+
- `order` picks the anchor end — `newest` (default) reads most-recent-first, `oldest` reads NVD's native order
|
|
98
|
+
- Paginated via `limit` (up to 2000, default 20) and `offset`, counted from the end `order` anchors to
|
|
99
|
+
- The history endpoint is markedly slower without an API key — set `NVD_API_KEY` and raise `NVD_REQUEST_TIMEOUT_MS`
|
|
104
100
|
|
|
105
|
-
|
|
101
|
+
---
|
|
106
102
|
|
|
107
|
-
|
|
108
|
-
|:-----|:-----|:------------|
|
|
109
|
-
| Resource | `nvd://cve/{cveId}` | Full CVE record by ID — same data as `nvd_get_cve` for a single ID, as a stable URI for injectable context. |
|
|
103
|
+
### `nvd://cve/{cveId}` <sub>resource</sub>
|
|
110
104
|
|
|
111
|
-
|
|
105
|
+
- Full CVE record as `application/json` — same data as `nvd_get_cve` for one ID, with references and English-only descriptions
|
|
106
|
+
- `cveId` must match `CVE-YYYY-NNNNN`; a well-formed but unknown ID throws `cve_not_found`
|
|
112
107
|
|
|
113
108
|
## Features
|
|
114
109
|
|
|
115
|
-
Built on [`@cyanheads/mcp-ts-core`](https://
|
|
116
|
-
|
|
117
|
-
- Declarative tool, resource, and prompt definitions — single file per primitive, framework handles registration and validation
|
|
118
|
-
- Unified error handling — handlers throw, framework catches, classifies, and formats
|
|
119
|
-
- Pluggable auth: `none`, `jwt`, `oauth`
|
|
120
|
-
- Swappable storage backends: `in-memory`, `filesystem`, `Supabase`, `Cloudflare KV/R2/D1`
|
|
121
|
-
- Structured logging with optional OpenTelemetry tracing
|
|
122
|
-
- STDIO and Streamable HTTP transports
|
|
110
|
+
Built on [`@cyanheads/mcp-ts-core`](https://github.com/cyanheads/mcp-ts-core): stdio and Streamable HTTP transports, pluggable auth (`none` / `jwt` / `oauth`), swappable storage (`in-memory`, `filesystem`, `Supabase`, `Cloudflare KV/R2/D1`), structured logging with optional OpenTelemetry tracing.
|
|
123
111
|
|
|
124
112
|
NVD-specific:
|
|
125
113
|
|
|
126
114
|
- Request pacer enforces NVD's 5 req/30s (no key) and 50 req/30s (with key) limits with automatic queuing, at a minimum inter-request gap derived from the window and limit
|
|
127
115
|
- Retry wraps the pacer rather than sitting inside it — every attempt takes its own turn in the queue, so retries count against the rate budget instead of bursting past it
|
|
128
|
-
- A 403's `Retry-After` holds the whole queue until NVD's window resets
|
|
129
|
-
- Deterministic rejections fail fast instead of consuming retries
|
|
130
|
-
- HTML-response guard catches NVD rate-limit pages served as HTML instead of 403
|
|
116
|
+
- A 403's `Retry-After` holds the whole queue until NVD's window resets; keyless, a 403 fails fast and names `NVD_API_KEY` rather than spending the 5-request budget on retries that cannot outlast a 30-second window
|
|
117
|
+
- Deterministic rejections fail fast instead of consuming retries — NVD answers both a bad parameter and a refused API key with HTTP 404, separated only by a `message` header, so a refused key surfaces as a config fault naming `NVD_API_KEY` rather than as a malformed CVE ID
|
|
118
|
+
- HTML-response guard catches NVD rate-limit pages served as HTML instead of a 403
|
|
131
119
|
|
|
132
120
|
Agent-friendly output:
|
|
133
121
|
|
|
134
122
|
- An `enrichment` block on every response, carried on both `structuredContent` and the rendered text — total results, returned count, page offset, the filters actually applied, and any date-clamping events, so agents can reason about what was really queried
|
|
135
|
-
- `missingIds` in batch CVE lookups — per-ID parity check instead of a silent partial result
|
|
123
|
+
- `missingIds` in batch CVE lookups — a per-ID parity check instead of a silent partial result
|
|
136
124
|
- CPE echo in audit responses — `cpeName` or `virtualMatchString` reflected back so callers can verify the correct product was audited
|
|
137
|
-
- Empty-result notices that name the cause — an unmatched query, a severity threshold that emptied the page,
|
|
138
|
-
- An audit that finds nothing is a result, not an error — a product with no CVEs in NVD returns an empty page with `totalCount: 0` on either input arm, so "no known vulnerabilities" reads as the answer it is
|
|
125
|
+
- Empty-result notices that name the cause — an unmatched query, a severity threshold that emptied the page, an offset past the end of the result set, and a clean audit ("no known vulnerabilities") are told apart rather than all reading as errors or "nothing found"
|
|
139
126
|
|
|
140
127
|
## Getting started
|
|
141
128
|
|
|
129
|
+
### Public Hosted Instance
|
|
130
|
+
|
|
131
|
+
A public instance is available at `https://nist-nvd.caseyjhand.com/mcp` — no installation required. Point any MCP client at it via Streamable HTTP:
|
|
132
|
+
|
|
133
|
+
```json
|
|
134
|
+
{
|
|
135
|
+
"mcpServers": {
|
|
136
|
+
"nist-nvd-mcp-server": {
|
|
137
|
+
"type": "streamable-http",
|
|
138
|
+
"url": "https://nist-nvd.caseyjhand.com/mcp"
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
### Self-Hosted / Local
|
|
145
|
+
|
|
142
146
|
Add the following to your MCP client configuration file.
|
|
143
147
|
|
|
144
148
|
```json
|
|
@@ -205,7 +209,7 @@ MCP_TRANSPORT_TYPE=http MCP_HTTP_PORT=3010 NVD_API_KEY=... bun run start:http
|
|
|
205
209
|
|
|
206
210
|
### Prerequisites
|
|
207
211
|
|
|
208
|
-
- [Bun v1.
|
|
212
|
+
- [Bun v1.4.0](https://bun.sh/) or higher (or Node.js v24+).
|
|
209
213
|
- Optional: [NVD API key](https://nvd.nist.gov/developers/request-an-api-key) — free, raises rate limit from 5 req/30s to 50 req/30s.
|
|
210
214
|
|
|
211
215
|
### Installation
|
|
@@ -308,7 +312,7 @@ See [`CLAUDE.md`](./CLAUDE.md) for development guidelines and architectural rule
|
|
|
308
312
|
|
|
309
313
|
## Contributing
|
|
310
314
|
|
|
311
|
-
Issues
|
|
315
|
+
Issues are welcome. Run checks and tests before submitting:
|
|
312
316
|
|
|
313
317
|
```sh
|
|
314
318
|
bun run devcheck
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
---
|
|
2
|
+
summary: "Adopts mcp-ts-core ^0.13.6: argument rejections classify InvalidParams with a recovery hint, caller disconnects classify RequestCancelled, and the public hosted endpoint is now published in server.json and the README."
|
|
3
|
+
breaking: false
|
|
4
|
+
security: false
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# 0.3.1 — 2026-09-20
|
|
8
|
+
|
|
9
|
+
## Added
|
|
10
|
+
|
|
11
|
+
- **Public hosted endpoint** — `https://nist-nvd.caseyjhand.com/mcp` is published as a `streamable-http` remote in `server.json` and documented in the README.
|
|
12
|
+
|
|
13
|
+
## Changed
|
|
14
|
+
|
|
15
|
+
- **Argument rejections classify `InvalidParams` (-32602)** instead of `ValidationError`, carrying `data.reason: "invalid_arguments"` and a schema-derived recovery hint.
|
|
16
|
+
- **Tool error text closes with `(reason … · not retryable)`** whenever the thrown error carries a `data.reason` or a boolean `data.retryable`.
|
|
17
|
+
- **A caller disconnect mid-call classifies `RequestCancelled` (-32011)** instead of an internal error.
|
|
18
|
+
- **The upstream NVD request URL no longer appears on client-facing `error.data`.**
|
|
19
|
+
- **The server card publishes the resolved session mode** (`stateless`) under `_meta`.
|
|
20
|
+
- Bun engines floor raised to `>=1.4.0`.
|
|
21
|
+
- Development skills moved from `skills/` to `framework-skills/`, so a plugin install no longer pulls them in as agent-facing skills.
|
|
22
|
+
|
|
23
|
+
## Fixed
|
|
24
|
+
|
|
25
|
+
- **Multi-arch Docker publish no longer fails on an arm64 build host** — the build stage cross-compiles instead of running under QEMU.
|
|
26
|
+
|
|
27
|
+
## Dependencies
|
|
28
|
+
|
|
29
|
+
- `@cyanheads/mcp-ts-core` `^0.12.3` → `^0.13.6`
|
|
30
|
+
- `zod` `^4.4.3` → `^4.6.5`
|
|
31
|
+
- `@biomejs/biome` (dev) `^2.5.10` → `^2.5.14`
|
|
32
|
+
- `@types/node` (dev) `^26.2.0` → `^26.6.1`
|
|
33
|
+
- `ignore` (dev) `^7.0.6` → `^7.0.9`
|
|
34
|
+
- `tsc-alias` (dev) `^1.9.2` → `^1.9.5`
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
---
|
|
2
|
+
summary: "Adopts mcp-ts-core ^0.13.14: numeric and boolean strings are accepted for number and boolean arguments, tool errors carry a request ID, and the Claude Code and Codex plugins and the .mcpb bundle take an optional NVD API key instead of sending a placeholder."
|
|
3
|
+
breaking: false
|
|
4
|
+
security: false
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# 0.3.2 — 2026-10-08
|
|
8
|
+
|
|
9
|
+
## Changed
|
|
10
|
+
|
|
11
|
+
- **Numeric and boolean strings are repaired and accepted** for number and boolean arguments (`"limit": "2"`, `"brief": "true"`) instead of rejected (mcp-ts-core 0.13.14).
|
|
12
|
+
- **Argument-rejection hints lead with the field path** (`severity: Invalid option: expected one of …`) (mcp-ts-core 0.13.9).
|
|
13
|
+
- **Tool and resource error results carry `data.requestId`**, and a tool error's text ends with `request <id>` (mcp-ts-core 0.13.10). Error codes, `data.reason`, and recovery hints are otherwise unchanged.
|
|
14
|
+
- **The NVD request debug log record names the endpoint only**, no longer the full request URL with the caller's query values.
|
|
15
|
+
- **`server.json` npm entries launch the package with `npx`** with no `run start:*` arguments, and the Streamable HTTP entry sets `MCP_TRANSPORT_TYPE=http` (mcp-ts-core 0.13.11 template).
|
|
16
|
+
- **Docker image**: production dependencies install in a `deps` stage on the build platform, so the arm64 image no longer runs Bun under emulation (0.13.10); musl-only packages are pruned from the image (0.13.11); base images move to Bun 1.4.2 (0.13.7).
|
|
17
|
+
- Framework resync: `framework-skills/`, `scripts/` (adds `install-otel.ts` and `prune-musl-packages.ts`), `.gitignore`/`.dockerignore` (`.env*` and registry token files), `.mcpbignore` (`logs/`, `.cache/`, `coverage/`, `tests/`), and the CodeQL workflow (one analysis per language).
|
|
18
|
+
- Handlers no longer call `ctx.recoveryFor`; the framework fills each declared recovery hint at the tool and resource boundary.
|
|
19
|
+
- `.env.example` lists the new framework variables (`MCP_REQUEST_STATE_KEY`, `LOG_TOOL_FAILURE_PAYLOADS`, `LOG_LLM_INTERACTIONS`, OTLP per-signal endpoints); `CLAUDE.md`/`AGENTS.md` guidance and README badges updated.
|
|
20
|
+
|
|
21
|
+
## Fixed
|
|
22
|
+
|
|
23
|
+
- **Plugins and bundle** (#48): the Claude Code and Codex plugin manifests sent the literal placeholder `your-nvd-api-key` as `NVD_API_KEY`, which NVD rejects, so every call failed until the user edited the file. The key is now an optional user setting — Claude Code `userConfig` (sensitive), Codex `env_vars`, and a new `user_config` option in the `.mcpb` bundle. Left empty, the server runs keyless.
|
|
24
|
+
|
|
25
|
+
## Dependencies
|
|
26
|
+
|
|
27
|
+
- `@cyanheads/mcp-ts-core` `^0.13.6` → `^0.13.14`
|
|
28
|
+
- `pino-pretty` `^13.1.3` → `^13.2.0`
|
|
29
|
+
- `@biomejs/biome` (dev) `^2.5.14` → `^2.5.15`
|
|
30
|
+
- `@socketsecurity/bun-security-scanner` (dev) `^1.1.2` → `^1.1.3`
|
|
31
|
+
- `@types/node` (dev) `^26.6.1` → `^26.6.4`
|
|
32
|
+
- `ignore` (dev) `^7.0.9` → `^7.0.12`
|
|
33
|
+
- `tsc-alias` (dev) `^1.9.5` → `^1.9.7`
|
|
34
|
+
- `vitest` (dev) `^4.1.11` → `^5.0.3`
|
package/changelog/template.md
CHANGED
|
@@ -6,8 +6,8 @@
|
|
|
6
6
|
|
|
7
7
|
# Required. One-line GitHub Release-style headline. 350 character cap — a
|
|
8
8
|
# ceiling, not a target. Default short and scannable. Don't pad, don't stitch
|
|
9
|
-
# unrelated changes with commas/semicolons into an inventory — pick the
|
|
10
|
-
# headline
|
|
9
|
+
# unrelated changes with commas/semicolons into an inventory — pick the one
|
|
10
|
+
# headline the release is about. Quotes required: unquoted YAML treats
|
|
11
11
|
# `: ` inside the value as a key separator and fails GitHub's strict parser.
|
|
12
12
|
summary: ""
|
|
13
13
|
|
|
@@ -117,30 +117,13 @@ security: false
|
|
|
117
117
|
in that unrelated item's metadata.
|
|
118
118
|
|
|
119
119
|
TAG ANNOTATIONS — the annotated tag body renders as the GitHub Release body
|
|
120
|
-
via `gh release create --notes-from-tag`.
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
Dependency bumps: ← section header
|
|
128
|
-
← blank line
|
|
129
|
-
- `@cyanheads/mcp-ts-core` ^0.9.1 → ^0.9.6 ← bullet
|
|
130
|
-
← blank line
|
|
131
|
-
Changed: ← only sections with entries
|
|
132
|
-
← blank line
|
|
133
|
-
- `format()` output includes `query` in text mode
|
|
134
|
-
← blank line
|
|
135
|
-
Added:
|
|
136
|
-
← blank line
|
|
137
|
-
- `manifest.json` scaffolded for MCPB bundle support
|
|
138
|
-
- Install badges (Claude Desktop, Cursor, VS Code)
|
|
139
|
-
← blank line
|
|
140
|
-
<N> tests pass; `bun run devcheck` clean. ← footer
|
|
141
|
-
|
|
142
|
-
Never a flat comma-separated string. Always structured markdown with
|
|
143
|
-
sections. The tag must scan well as a rendered GitHub Release page.
|
|
120
|
+
via `gh release create --notes-from-tag`. It is a condensed digest of this
|
|
121
|
+
entry, never a copy, and its format is owned by the `release-and-publish`
|
|
122
|
+
skill (step 4, "Create the annotated tag"): a short subject line without the
|
|
123
|
+
version, flat headline bullets — no Keep-a-Changelog section headers, no
|
|
124
|
+
gates line — at most one deps line, issue backlinks, and the changelog link
|
|
125
|
+
last. In release-PR mode the `git-wrapup` skill authors those bullets as the
|
|
126
|
+
PR body's `## Changes` and the tag copies them.
|
|
144
127
|
-->
|
|
145
128
|
|
|
146
129
|
## Added
|
package/dist/index.js
CHANGED
|
@@ -15,6 +15,11 @@ import { initNvdSourceService } from './services/nvd-source/nvd-source-service.j
|
|
|
15
15
|
await createApp({
|
|
16
16
|
name: 'nist-nvd-mcp-server',
|
|
17
17
|
title: 'nist-nvd-mcp-server',
|
|
18
|
+
/**
|
|
19
|
+
* Every tool here is a read-only NVD lookup — no handler calls `ctx.requestInput`,
|
|
20
|
+
* so nothing needs a session to come back to. `MCP_SESSION_MODE` still overrides.
|
|
21
|
+
*/
|
|
22
|
+
sessionMode: 'stateless',
|
|
18
23
|
tools: [nvdGetCve, nvdSearchCves, nvdAuditCpe, nvdSearchCpes, nvdGetCveHistory],
|
|
19
24
|
resources: [nvdCveResource],
|
|
20
25
|
prompts: [],
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AACA;;;;GAIG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AACnD,OAAO,EAAE,eAAe,EAAE,MAAM,2BAA2B,CAAC;AAC5D,OAAO,EAAE,cAAc,EAAE,MAAM,6CAA6C,CAAC;AAC7E,OAAO,EACL,WAAW,EACX,SAAS,EACT,gBAAgB,EAChB,aAAa,EACb,aAAa,GACd,MAAM,yCAAyC,CAAC;AACjD,OAAO,EAAE,iBAAiB,EAAE,MAAM,uCAAuC,CAAC;AAC1E,OAAO,EAAE,iBAAiB,EAAE,MAAM,uCAAuC,CAAC;AAC1E,OAAO,EAAE,iBAAiB,EAAE,MAAM,wCAAwC,CAAC;AAC3E,OAAO,EAAE,oBAAoB,EAAE,MAAM,6CAA6C,CAAC;AAEnF,MAAM,SAAS,CAAC;IACd,IAAI,EAAE,qBAAqB;IAC3B,KAAK,EAAE,qBAAqB;IAC5B,KAAK,EAAE,CAAC,SAAS,EAAE,aAAa,EAAE,WAAW,EAAE,aAAa,EAAE,gBAAgB,CAAC;IAC/E,SAAS,EAAE,CAAC,cAAc,CAAC;IAC3B,OAAO,EAAE,EAAE;IACX,YAAY,EACV,4FAA4F;QAC5F,qGAAqG;QACrG,qFAAqF;QACrF,qFAAqF;QACrF,8EAA8E;QAC9E,6EAA6E;QAC7E,uEAAuE;IAEzE,KAAK,CAAC,IAAI;QACR,MAAM,GAAG,GAAG,eAAe,EAAE,CAAC;QAC9B,iBAAiB,CAAC,GAAG,CAAC,MAAM,EAAE,GAAG,CAAC,gBAAgB,CAAC,CAAC;QACpD,iBAAiB,CAAC,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,OAAO,CAAC,CAAC;QAC7C,iBAAiB,CAAC,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,OAAO,CAAC,CAAC;QAC7C,oBAAoB,CAAC,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,OAAO,CAAC,CAAC;IAClD,CAAC;CACF,CAAC,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AACA;;;;GAIG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AACnD,OAAO,EAAE,eAAe,EAAE,MAAM,2BAA2B,CAAC;AAC5D,OAAO,EAAE,cAAc,EAAE,MAAM,6CAA6C,CAAC;AAC7E,OAAO,EACL,WAAW,EACX,SAAS,EACT,gBAAgB,EAChB,aAAa,EACb,aAAa,GACd,MAAM,yCAAyC,CAAC;AACjD,OAAO,EAAE,iBAAiB,EAAE,MAAM,uCAAuC,CAAC;AAC1E,OAAO,EAAE,iBAAiB,EAAE,MAAM,uCAAuC,CAAC;AAC1E,OAAO,EAAE,iBAAiB,EAAE,MAAM,wCAAwC,CAAC;AAC3E,OAAO,EAAE,oBAAoB,EAAE,MAAM,6CAA6C,CAAC;AAEnF,MAAM,SAAS,CAAC;IACd,IAAI,EAAE,qBAAqB;IAC3B,KAAK,EAAE,qBAAqB;IAC5B;;;OAGG;IACH,WAAW,EAAE,WAAW;IACxB,KAAK,EAAE,CAAC,SAAS,EAAE,aAAa,EAAE,WAAW,EAAE,aAAa,EAAE,gBAAgB,CAAC;IAC/E,SAAS,EAAE,CAAC,cAAc,CAAC;IAC3B,OAAO,EAAE,EAAE;IACX,YAAY,EACV,4FAA4F;QAC5F,qGAAqG;QACrG,qFAAqF;QACrF,qFAAqF;QACrF,8EAA8E;QAC9E,6EAA6E;QAC7E,uEAAuE;IAEzE,KAAK,CAAC,IAAI;QACR,MAAM,GAAG,GAAG,eAAe,EAAE,CAAC;QAC9B,iBAAiB,CAAC,GAAG,CAAC,MAAM,EAAE,GAAG,CAAC,gBAAgB,CAAC,CAAC;QACpD,iBAAiB,CAAC,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,OAAO,CAAC,CAAC;QAC7C,iBAAiB,CAAC,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,OAAO,CAAC,CAAC;QAC7C,oBAAoB,CAAC,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,OAAO,CAAC,CAAC;IAClD,CAAC;CACF,CAAC,CAAC"}
|
|
@@ -14,11 +14,12 @@ export declare const nvdCveResource: import("@cyanheads/mcp-ts-core").ResourceDe
|
|
|
14
14
|
}, {
|
|
15
15
|
/**
|
|
16
16
|
* Thrown by the service, not this handler: a single-ID fetch that NVD answers with no
|
|
17
|
-
* records raises `cve_not_found` there. The entry stays declared here so the
|
|
18
|
-
*
|
|
17
|
+
* records raises `cve_not_found` there. The entry stays declared here so the framework
|
|
18
|
+
* fills this recovery text onto the wire when that throw reaches the resource boundary.
|
|
19
19
|
*/
|
|
20
20
|
readonly reason: "cve_not_found";
|
|
21
21
|
readonly code: JsonRpcErrorCode.NotFound;
|
|
22
|
+
readonly thrownBy: "service";
|
|
22
23
|
readonly when: "The CVE ID is well-formed but NVD holds no record for it.";
|
|
23
24
|
readonly recovery: "Verify the CVE ID is correct, or use nvd_search_cves to find it by keyword or date range.";
|
|
24
25
|
}]>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"nvd-cve.resource.d.ts","sourceRoot":"","sources":["../../../../src/mcp-server/resources/definitions/nvd-cve.resource.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAY,CAAC,EAAE,MAAM,wBAAwB,CAAC;AACrD,OAAO,EAAE,gBAAgB,EAAE,MAAM,+BAA+B,CAAC;AAKjE,eAAO,MAAM,cAAc;;;;;;;;IAuBrB;;;;OAIG
|
|
1
|
+
{"version":3,"file":"nvd-cve.resource.d.ts","sourceRoot":"","sources":["../../../../src/mcp-server/resources/definitions/nvd-cve.resource.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAY,CAAC,EAAE,MAAM,wBAAwB,CAAC;AACrD,OAAO,EAAE,gBAAgB,EAAE,MAAM,+BAA+B,CAAC;AAKjE,eAAO,MAAM,cAAc;;;;;;;;IAuBrB;;;;OAIG;;;;;;GAgCP,CAAC"}
|
|
@@ -27,11 +27,12 @@ export const nvdCveResource = resource('nvd://cve/{cveId}', {
|
|
|
27
27
|
{
|
|
28
28
|
/**
|
|
29
29
|
* Thrown by the service, not this handler: a single-ID fetch that NVD answers with no
|
|
30
|
-
* records raises `cve_not_found` there. The entry stays declared here so the
|
|
31
|
-
*
|
|
30
|
+
* records raises `cve_not_found` there. The entry stays declared here so the framework
|
|
31
|
+
* fills this recovery text onto the wire when that throw reaches the resource boundary.
|
|
32
32
|
*/
|
|
33
33
|
reason: 'cve_not_found',
|
|
34
34
|
code: JsonRpcErrorCode.NotFound,
|
|
35
|
+
thrownBy: 'service',
|
|
35
36
|
when: 'The CVE ID is well-formed but NVD holds no record for it.',
|
|
36
37
|
recovery: 'Verify the CVE ID is correct, or use nvd_search_cves to find it by keyword or date range.',
|
|
37
38
|
},
|
|
@@ -39,7 +40,7 @@ export const nvdCveResource = resource('nvd://cve/{cveId}', {
|
|
|
39
40
|
async handler(params, ctx) {
|
|
40
41
|
const { cveId } = params;
|
|
41
42
|
if (!CVE_ID_REGEX.test(cveId)) {
|
|
42
|
-
throw ctx.fail('invalid_cve_id_format', `Invalid CVE ID format: "${cveId}". Expected format: CVE-YYYY-NNNNN.`, { cveId
|
|
43
|
+
throw ctx.fail('invalid_cve_id_format', `Invalid CVE ID format: "${cveId}". Expected format: CVE-YYYY-NNNNN.`, { cveId });
|
|
43
44
|
}
|
|
44
45
|
ctx.log.debug('Fetching CVE resource', { cveId });
|
|
45
46
|
const service = getNvdCveService();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"nvd-cve.resource.js","sourceRoot":"","sources":["../../../../src/mcp-server/resources/definitions/nvd-cve.resource.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,QAAQ,EAAE,CAAC,EAAE,MAAM,wBAAwB,CAAC;AACrD,OAAO,EAAE,gBAAgB,EAAE,MAAM,+BAA+B,CAAC;AACjE,OAAO,EAAE,gBAAgB,EAAE,MAAM,uCAAuC,CAAC;AAEzE,MAAM,YAAY,GAAG,qBAAqB,CAAC;AAE3C,MAAM,CAAC,MAAM,cAAc,GAAG,QAAQ,CAAC,mBAAmB,EAAE;IAC1D,IAAI,EAAE,gBAAgB;IACtB,WAAW,EACT,sEAAsE;QACtE,0FAA0F;QAC1F,sDAAsD;IACxD,QAAQ,EAAE,kBAAkB;IAE5B,MAAM,EAAE,CAAC,CAAC,MAAM,CAAC;QACf,KAAK,EAAE,CAAC;aACL,MAAM,EAAE;aACR,QAAQ,CAAC,gFAAgF,CAAC;KAC9F,CAAC;IAEF,MAAM,EAAE;QACN;YACE,MAAM,EAAE,uBAAuB;YAC/B,IAAI,EAAE,gBAAgB,CAAC,eAAe;YACtC,IAAI,EAAE,uDAAuD;YAC7D,QAAQ,EACN,uFAAuF;SAC1F;QACD;YACE;;;;eAIG;YACH,MAAM,EAAE,eAAe;YACvB,IAAI,EAAE,gBAAgB,CAAC,QAAQ;YAC/B,IAAI,EAAE,2DAA2D;YACjE,QAAQ,EACN,2FAA2F;SAC9F;KACF;IAED,KAAK,CAAC,OAAO,CAAC,MAAM,EAAE,GAAG;QACvB,MAAM,EAAE,KAAK,EAAE,GAAG,MAAM,CAAC;QACzB,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC;YAC9B,MAAM,GAAG,CAAC,IAAI,CACZ,uBAAuB,EACvB,2BAA2B,KAAK,qCAAqC,EACrE,EAAE,KAAK,EAAE,
|
|
1
|
+
{"version":3,"file":"nvd-cve.resource.js","sourceRoot":"","sources":["../../../../src/mcp-server/resources/definitions/nvd-cve.resource.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,QAAQ,EAAE,CAAC,EAAE,MAAM,wBAAwB,CAAC;AACrD,OAAO,EAAE,gBAAgB,EAAE,MAAM,+BAA+B,CAAC;AACjE,OAAO,EAAE,gBAAgB,EAAE,MAAM,uCAAuC,CAAC;AAEzE,MAAM,YAAY,GAAG,qBAAqB,CAAC;AAE3C,MAAM,CAAC,MAAM,cAAc,GAAG,QAAQ,CAAC,mBAAmB,EAAE;IAC1D,IAAI,EAAE,gBAAgB;IACtB,WAAW,EACT,sEAAsE;QACtE,0FAA0F;QAC1F,sDAAsD;IACxD,QAAQ,EAAE,kBAAkB;IAE5B,MAAM,EAAE,CAAC,CAAC,MAAM,CAAC;QACf,KAAK,EAAE,CAAC;aACL,MAAM,EAAE;aACR,QAAQ,CAAC,gFAAgF,CAAC;KAC9F,CAAC;IAEF,MAAM,EAAE;QACN;YACE,MAAM,EAAE,uBAAuB;YAC/B,IAAI,EAAE,gBAAgB,CAAC,eAAe;YACtC,IAAI,EAAE,uDAAuD;YAC7D,QAAQ,EACN,uFAAuF;SAC1F;QACD;YACE;;;;eAIG;YACH,MAAM,EAAE,eAAe;YACvB,IAAI,EAAE,gBAAgB,CAAC,QAAQ;YAC/B,QAAQ,EAAE,SAAS;YACnB,IAAI,EAAE,2DAA2D;YACjE,QAAQ,EACN,2FAA2F;SAC9F;KACF;IAED,KAAK,CAAC,OAAO,CAAC,MAAM,EAAE,GAAG;QACvB,MAAM,EAAE,KAAK,EAAE,GAAG,MAAM,CAAC;QACzB,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC;YAC9B,MAAM,GAAG,CAAC,IAAI,CACZ,uBAAuB,EACvB,2BAA2B,KAAK,qCAAqC,EACrE,EAAE,KAAK,EAAE,CACV,CAAC;QACJ,CAAC;QAED,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,uBAAuB,EAAE,EAAE,KAAK,EAAE,CAAC,CAAC;QAClD,MAAM,OAAO,GAAG,gBAAgB,EAAE,CAAC;QAEnC,yFAAyF;QACzF,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,SAAS,CACpC,CAAC,KAAK,CAAC,WAAW,EAAE,CAAC,EACrB,EAAE,iBAAiB,EAAE,IAAI,EAAE,YAAY,EAAE,KAAK,EAAE,EAChD,GAAG,CACJ,CAAC;QAEF,OAAO,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IACxB,CAAC;CACF,CAAC,CAAC"}
|
|
@@ -102,6 +102,8 @@ export declare const nvdAuditCpe: import("@cyanheads/mcp-ts-core").ToolDefinitio
|
|
|
102
102
|
readonly code: JsonRpcErrorCode.RateLimited;
|
|
103
103
|
readonly when: "NVD returned HTTP 403 indicating the rate limit was exceeded.";
|
|
104
104
|
readonly retryable: true;
|
|
105
|
+
/** Raised by the HTTP client on NVD's 403, below this handler. */
|
|
106
|
+
readonly thrownBy: "service";
|
|
105
107
|
readonly recovery: "Wait for the NVD rate window to reset or set the NVD_API_KEY environment variable for higher limits.";
|
|
106
108
|
}], {
|
|
107
109
|
readonly totalCount: z.ZodNumber;
|