Skip to main content
Glama
marcoeg

mcp-nvd

get_cve

Retrieve detailed Common Vulnerabilities and Exposures (CVE) information from the NIST National Vulnerability Database using a CVE ID, providing formatted vulnerability data for security analysis.

Instructions

Get a CVE based on the ID and return a formatted string with detailed attributes.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
cve_idYes
conciseNo

Implementation Reference

  • The primary handler function for the 'get_cve' tool. Decorated with @mcp.tool() for MCP registration. Fetches specific CVE data from the NVD API and returns a formatted string response.
    @mcp.tool()
    async def get_cve(cve_id: str, concise: bool = False) -> str:
        """Get a CVE based on the ID and return a formatted string with detailed attributes."""
        url = f"{BASE_URL}?cveId={cve_id}"
        data = await make_nvd_request(url)
    
        if not data or "vulnerabilities" not in data or not data["vulnerabilities"]:
            return f"No data found for CVE ID: {cve_id}"
    
        cve = data["vulnerabilities"][0]["cve"]
        logger.info(f"Processing CVE: {cve_id}")
        return format_cve(cve, concise)
  • Key helper function used by get_cve to format the raw CVE data into a human-readable string, supporting both concise and detailed output.
    def format_cve(cve: Dict[str, Any], concise: bool = False) -> str:
        """Helper function to format a single CVE entry, shared by get_cve and search_cve."""
        try:
            cve_id = cve["id"]
            source_identifier = cve["sourceIdentifier"]
            published = cve["published"]
            last_modified = cve["lastModified"]
            vuln_status = cve["vulnStatus"]
            description = next(
                (desc["value"] for desc in cve["descriptions"] if desc["lang"] == "en"),
                "No English description available",
            )
    
            # Extract CVSS v3.1 metrics
            cvss_v31_metric = next(
                (metric for metric in cve.get("metrics", {}).get("cvssMetricV31", []) if metric["type"] == "Primary"),
                None,
            )
            cvss_v31_data = cvss_v31_metric["cvssData"] if cvss_v31_metric else None
            cvss_v31_score = cvss_v31_data.get("baseScore", "N/A") if cvss_v31_data else "N/A"
            cvss_v31_severity = cvss_v31_data.get("baseSeverity", "N/A") if cvss_v31_data else "N/A"
            cvss_v31_vector = cvss_v31_data.get("vectorString", "N/A") if cvss_v31_data else "N/A"
            cvss_v31_exploitability = cvss_v31_metric.get("exploitabilityScore", "N/A") if cvss_v31_metric else "N/A"
            cvss_v31_impact = cvss_v31_metric.get("impactScore", "N/A") if cvss_v31_metric else "N/A"
    
            # Extract CVSS v2.0 metrics
            cvss_v2 = next(
                (metric["cvssData"] for metric in cve.get("metrics", {}).get("cvssMetricV2", []) if metric["type"] == "Primary"),
                None,
            )
            cvss_v2_score = cvss_v2.get("baseScore", "N/A") if cvss_v2 else "N/A"
            cvss_v2_severity = cvss_v2.get("baseSeverity", "N/A") if cvss_v2 else "N/A"
            cvss_v2_vector = cvss_v2.get("vectorString", "N/A") if cvss_v2 else "N/A"
    
            # Extract weaknesses (CWE IDs)
            weaknesses = [
                desc["value"] for weak in cve.get("weaknesses", []) for desc in weak["description"] if desc["lang"] == "en"
            ]
            weaknesses_str = ", ".join(weaknesses) if weaknesses else "None listed"
    
            # Extract references with tags
            references = [f"{ref['url']} ({', '.join(ref.get('tags', []))})" for ref in cve.get("references", [])]
            references_str = "\n  - " + "\n  - ".join(references) if references else "None listed"
    
            # Extract configurations (CPEs)
            cpe_matches = []
            for node in cve.get("configurations", [{}])[0].get("nodes", []):
                for match in node.get("cpeMatch", []):
                    if match.get("vulnerable", False):
                        cpe_matches.append(match["criteria"])
            configurations_str = "\n  - " + "\n  - ".join(cpe_matches) if cpe_matches else "None listed"
    
            # Format output
            if concise:
                return (
                    f"CVE ID: {cve_id}\n"
                    f"Description: {description}\n"
                    f"CVSS v3.1 Score: {cvss_v31_score} ({cvss_v31_severity})"
                )
            else:
                return (
                    f"CVE ID: {cve_id}\n"
                    f"Source Identifier: {source_identifier}\n"
                    f"Published: {published}\n"
                    f"Last Modified: {last_modified}\n"
                    f"Vulnerability Status: {vuln_status}\n"
                    f"Description: {description}\n"
                    f"CVSS v3.1 Score: {cvss_v31_score} ({cvss_v31_severity})\n"
                    f"CVSS v3.1 Vector: {cvss_v31_vector}\n"
                    f"CVSS v3.1 Exploitability Score: {cvss_v31_exploitability}\n"
                    f"CVSS v3.1 Impact Score: {cvss_v31_impact}\n"
                    f"CVSS v2.0 Score: {cvss_v2_score} ({cvss_v2_severity})\n"
                    f"CVSS v2.0 Vector: {cvss_v2_vector}\n"
                    f"Weaknesses (CWE): {weaknesses_str}\n"
                    f"References:\n{references_str}\n"
                    f"Affected Configurations (CPE):\n{configurations_str}"
                )
        except Exception as e:
            logger.error(f"Error formatting CVE {cve.get('id', 'unknown')}: {str(e)}")
            return f"Error processing CVE: {str(e)}"
  • Shared helper function for making asynchronous HTTP requests to the NVD API, used by get_cve to retrieve CVE data.
    async def make_nvd_request(url: str) -> Dict[str, Any] | None:
        """Make a request to the NVD API with proper error handling."""
        async with httpx.AsyncClient() as client:
            try:
                response = await client.get(url, headers=HEADERS, timeout=30.0)
                response.raise_for_status()
                return response.json()
            except httpx.HTTPStatusError as e:
                logger.error(f"HTTP error: {e.response.status_code} - {e.response.text}")
                return None
            except httpx.RequestError as e:
                logger.error(f"Request error: {e}")
                return None
            except Exception as e:
                logger.error(f"Unexpected error: {e}")
                return None
  • Export of the get_cve function for use in the package.
    from .server import (
        get_cve,
Behavior2/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations are provided, so the description carries the full burden of behavioral disclosure. It states the tool returns a 'formatted string with detailed attributes,' which hints at read-only behavior but lacks specifics on permissions, rate limits, error handling, or data sources. For a tool with zero annotation coverage, this is insufficient to inform the agent about key operational traits like safety or performance constraints.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is a single, straightforward sentence that efficiently conveys the core action and output. It's front-loaded with the main purpose and avoids unnecessary words, making it easy to parse. However, it could be slightly more structured by separating usage notes or parameter hints, but overall, it's concise and effective for its length.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness2/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the complexity of retrieving CVE data, the lack of annotations, no output schema, and low schema description coverage, the description is incomplete. It doesn't address critical aspects like what 'detailed attributes' include, how errors are handled, or dependencies on external databases. For a tool with two parameters and no structured support, more context is needed to ensure reliable agent invocation.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters2/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The schema description coverage is 0%, meaning parameters are undocumented in the schema. The description mentions 'based on the ID' and 'concise' (implied by 'formatted string'), but it doesn't explain what 'cve_id' entails (e.g., format like 'CVE-2024-12345') or what 'concise' does (e.g., reduces output detail). With low coverage, the description adds minimal value beyond the schema, failing to compensate for the documentation gap.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the tool's purpose: 'Get a CVE based on the ID and return a formatted string with detailed attributes.' It specifies the verb ('Get'), resource ('CVE'), and output format ('formatted string with detailed attributes'), which is specific and actionable. However, it doesn't explicitly differentiate from its sibling tool 'search_cve', which likely searches for CVEs rather than retrieving a specific one by ID, leaving room for improvement in sibling distinction.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines2/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description provides no guidance on when to use this tool versus alternatives. It mentions retrieving a CVE by ID but doesn't clarify scenarios where this is appropriate compared to 'search_cve' or other potential tools. There's no mention of prerequisites, exclusions, or contextual cues for selection, leaving the agent with minimal usage direction.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Install Server

Other Tools

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/marcoeg/mcp-nvd'

If you have feedback or need assistance with the MCP directory API, please join our Discord server