Skip to content
Private Beta ·invite-only access. Reach out to get in.
Back to blog
Product8 min read·

CVE MCP Server: Give Your AI Agent Live Vulnerability Data

An AI agent that can only search the web about CVEs is a liability. One that reads your matched feed and writes back a triage status is useful. Here is how the MCP server works.

Ask a general-purpose model about a CVE from last week and you get one of three things: a confident summary of a different vulnerability, a refusal, or a web search that lands on a content farm.

None of those is triage. The problem is not the model, it is the interface. An agent with no access to your data is guessing, and an agent that is guessing about vulnerabilities is worse than no agent at all, because it produces output shaped like an answer.

What MCP Is, in One Paragraph

The Model Context Protocol is an open protocol for exposing tools and data to LLM clients in a standard way, documented at modelcontextprotocol.io. A server declares a set of tools with typed inputs, and any MCP-capable client, Claude Desktop, Claude Code, Cursor and a growing list of others, can call them. The value is that the integration is written once rather than once per client.

Transports: Remote Streamable HTTP (and why not Stdio)

Both are live and both are documented in the API and MCP reference.

Stdio would run the server as a local process managed by your client. A stdio build lives in the repo, but it is not published to npm, so this is not a route you can take today — configure the HTTP transport above instead.

Remote skips the install entirely. Your client posts to the hosted /api/mcp endpoint with a bearer token. It is stateless per request and supports both JSON and SSE response content types through content negotiation, which matters for clients that stream.

Pick stdio if your client only supports local servers, remote if it supports HTTP transports and you would rather not manage an install.

Authentication, Key Handling and the Tier Gate

Authentication is identical to the REST API: a token of the form vai_<prefix>_<secret>, minted from the API access panel in dashboard settings.

The handling is worth stating because it constrains what you can do afterwards. The full token is displayed once at creation. Only the SHA-256 hash is stored, the 8-character prefix is kept in plaintext for lookup, and the 32-character secret is compared in constant time. You can hold up to 10 active keys per account, revoke any of them from the same panel, and revoked keys are retained for audit rather than deleted.

Being straightforward about the commercial gate rather than burying it: MCP and REST access are Max-tier features, and keys stop authenticating if a subscription downgrades. The tiers are on the pricing page.

The Nine Tools and What Each Is For

ToolPurpose
search_cvesFilter by date, technology, workflow status, and the caller's tracked stack
get_cveFull analysis for one CVE: severity, KEV and EPSS, impact, recommendation, affected systems, executive summary, technical analysis, plus your own status and notes
get_similar_cvesRanked by shared affected systems, category, CVSS distance, a KEV bonus and recency
get_cve_statusRead the current workflow state for one CVE
set_cve_statusWrite the workflow state, from a fixed enum, with optional notes
get_meProfile, tier, tracked stack with versions, focus area, current key metadata
get_statsAggregate counts across the stack: KEV, major, patches available, by severity, by status

Read Tools Should Be Stack-Scoped by Default

This is the first of two design opinions worth defending.

An agent that can see your forty relevant CVEs gives better answers than one that can see all sixteen thousand. That is not a performance argument, it is a correctness argument: retrieval is where these workflows actually fail. Given a broad corpus, a model retrieves something plausible and adjacent rather than the right record, and the failure is invisible because the output looks fine.

So search_cves and get_stats scope to your declared technologies unless you explicitly pass a flag to widen them. The narrow default is the feature. It is the same argument we made about human attention in why most CVE alerts are noise, applied to a machine reader.

Start Every Session With get_me

Have the agent call get_me first, every time.

It returns the tracked stack with versions, the tier, and the focus area, which means every subsequent answer is grounded in what you actually run rather than in what the model assumes a company like yours runs. It also fails fast and legibly if the key is wrong or the tier has lapsed, which is a much better failure than a confidently empty result set.

A Real Triage Session, Start to Finish

A Monday morning session looks like this:

  1. get_me returns the stack: PostgreSQL 15, nginx, a Node 20 runtime, Redis, a handful of libraries.
  2. search_cves with since set to last Monday returns eleven matched CVEs, not the roughly nine hundred published globally that week.
  3. The agent sorts them using KEV membership and EPSS, and reports that two matter. Because it has the records in context, it quotes them rather than recalling them.
  4. get_cve on each of the two pulls the full analysis: impact, affected systems, whether a patch exists, the recommendation.
  5. get_similar_cves on the more serious one surfaces three related historical issues in the same component, which is the context that tells you whether this is a pattern or a one-off.
  6. set_cve_status marks one IN_PROGRESS with a note naming the owner and the ticket, and the other RISK_ACCEPTED with a note recording why and a review date.

Step 6 is the part that makes this more than a reading exercise. The status transitions and notes are dated records, which is exactly the per-item evidence an auditor asks for, and they were produced as a by-product of the triage rather than as a separate chore.

Designing Write Tools an Agent Cannot Wreck

The second design opinion: write tools should expose a small closed enum plus free text, and nothing else.

The full write surface is one status field, constrained to OPEN, IN_PROGRESS, DEFERRED, RISK_ACCEPTED, CLOSED, and a notes field of up to 2000 characters. That is all.

Nothing in the tool surface can change alerting configuration, billing or account state. Two tools do write: set_cve_status moves a CVE through the triage states, and set_technologies replaces the tracked stack — replaces, not merges, so an agent passing an empty list clears it and narrows what stack-scoped filtering will show you. Those are the two things a confused, buggy or manipulated agent can actually do, and both are visible and reversible from the dashboard. Compare that to an agent with a general-purpose settings write tool, where the worst outcome is unbounded.

If you take one thing from this article into your own MCP server design, take that: bound the blast radius at the schema, not in the prompt.

Prompt Injection: CVE Text Is Attacker-Influenced Input

This deserves more than a disclaimer, because it is a real and specific risk in this exact workflow.

CVE descriptions, advisory text and reference titles are written by third parties. A vulnerability researcher, a vendor PSIRT, or in some cases someone with an interest in what you do next. That text is attacker-influenceable, and an agent that reads it while also holding write scope is a textbook confused-deputy setup.

Three mitigations, in order of importance:

  1. Constrain the write surface, as above. This is structural and it is why the enum exists.
  2. Treat retrieved record text as data, not instructions. A good client already does this; verify yours does.
  3. Keep a human on state changes that matter. An agent proposing RISK_ACCEPTED is a draft. A human confirming it is the decision.

No prompt can fully solve this. A schema can bound it.

Rate Limits and Agent Loops

Limits are per key at 60 requests per minute, with X-RateLimit-Limit, X-RateLimit-Remaining and X-RateLimit-Reset returned on every response, including 429s.

This matters more for agents than for scripts. A script makes the calls you wrote. An agent loop can burn a minute of budget in seconds by calling get_cve once per item over a long list.

The fix is a prompting habit rather than a code change: instruct the agent to call with wide filters and few calls. One search_cves returning eleven records beats eleven get_cve calls, and it is also better context.

One Definition of Relevance

The strongest technical claim here, and it is verifiable in the docs: the MCP server, the REST API and the dashboard all use the same matching predicate.

An agent, a scheduled script and a human looking at the web dashboard never see three different answers to the same question. That sounds like an implementation detail until the first time someone in a meeting says "the API says nine, the dashboard says fourteen", and the next hour goes to reconciling tools instead of fixing anything. The same principle drives stack-matched alerting: one definition of what affects you, applied everywhere.

REST or MCP: Which One You Actually Want

They are two interfaces over the same data, one key type, one rate limit.

  • MCP when a human is in a conversation with an agent, and the questions are exploratory.
  • REST when a scheduled job needs deterministic, paginated output that will be identical tomorrow.

Most teams end up with both: MCP for Monday triage, REST for the nightly export into whatever else has to know.

The Honest Limitation

Retrieval into context reduces fabrication substantially. It does not eliminate it.

A model with the record in front of it can still misread a version range, conflate two affected products, or overstate a recommendation. Prioritisation judgement, in particular, is still yours: even a perfectly grounded agent is reasoning about severity and likelihood, which as we argued in CVSS vs EPSS are different questions with different sources.

Treat agent output as a draft triage that a human confirms. Use get_cve so the model quotes the record rather than recalling it. That combination, grounded retrieval plus a bounded write surface plus a human on the decisions that matter, is what makes this useful rather than merely impressive.

Setup instructions for both transports, the full tool schemas and the REST contract are in the documentation.

Frequently asked questions

What is an MCP server for CVEs?

It is a Model Context Protocol server that exposes vulnerability data as tools an AI client can call directly, so the model reads your actual matched CVE records instead of recalling vulnerabilities from training data or searching the web. Clients such as Claude Desktop, Claude Code and Cursor can connect over stdio or over a remote HTTP transport.

Which MCP clients does it work with?

Any MCP client that speaks the Streamable HTTP transport — you point it at the hosted endpoint with a bearer token and install nothing. Claude Code, Claude Desktop and Cursor are all set up this way, and Settings has a per-client walkthrough. There is no npm package to install: a stdio build exists in the repo but has not been published.

Can the AI agent change things in my account?

Only a per-CVE workflow status, chosen from a fixed set of five values, plus a short free-text note. The tool surface deliberately does not expose alerting configuration, billing or account settings, so the worst outcome of a confused or manipulated agent is a mislabelled CVE rather than a changed system.

Do I need the API as well as MCP?

They are two interfaces over the same data and the same matching logic, sharing one key type and one rate limit. Use MCP when a human is in a conversation with an agent, and the REST API when a scheduled job needs deterministic, paginated output.

Stay ahead of threats

Get AI-filtered CVE alerts for your specific tech stack. Free to start.

Start for free