Skip to main content
Glama
firetix

MCP Vulnerability Checker Server

by firetix

get_vulnerability_timeline

Retrieve vulnerability timeline and patch status information for a CVE ID to understand disclosure history, patch availability, and remediation guidance for effective security management.

Instructions

Get vulnerability timeline and patch status information

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
cve_idYesGet comprehensive timeline and patch status information for a vulnerability including publication dates, disclosure timeline, patch availability, vendor advisories, and remediation guidance. Provide a CVE ID in the format CVE-YYYY-NNNN (e.g., CVE-2021-44228). Essential for understanding vulnerability lifecycle and planning patch management strategies.

Implementation Reference

  • Core handler function that implements the tool's logic: validates input, fetches vulnerability data from NVD and MITRE, analyzes timeline and patch status, computes risk metrics, and returns a comprehensive formatted report.
    async def get_vulnerability_timeline(
        cve_id: str,
    ) -> List[types.TextContent | types.ImageContent | types.EmbeddedResource]:
        """
        Get vulnerability timeline including patch status and remediation information.
    
        Args:
            cve_id: CVE identifier in format CVE-YYYY-NNNN
    
        Returns:
            List of content containing timeline information or error messages
        """
        # Clean up CVE ID format
        cve_id = cve_id.upper().strip()
        if not cve_id.startswith("CVE-"):
            cve_id = f"CVE-{cve_id}"
    
        # Validate CVE ID format (CVE-YYYY-NNNN)
        if not re.match(r"^CVE-\d{4}-\d{4,}$", cve_id):
            return [
                types.TextContent(
                    type="text",
                    text=f"Error: Invalid CVE ID format. Expected format: CVE-YYYY-NNNN (e.g., CVE-2021-44228). Got: {cve_id}",
                )
            ]
    
        headers = {
            "User-Agent": "MCP Vulnerability Timeline Tool v1.0",
            "Accept": "application/json",
        }
    
        timeline_data = {}
    
        try:
            timeout = httpx.Timeout(20.0, connect=10.0)
            async with httpx.AsyncClient(
                follow_redirects=True, headers=headers, timeout=timeout
            ) as client:
                # Get comprehensive CVE data from NVD
                nvd_url = f"https://services.nvd.nist.gov/rest/json/cves/2.0?cveId={cve_id}"
                try:
                    nvd_response = await client.get(nvd_url)
                    if nvd_response.status_code == 200:
                        nvd_data = nvd_response.json()
                        if nvd_data.get("totalResults", 0) > 0:
                            cve_item = nvd_data["vulnerabilities"][0]["cve"]
    
                            # Extract key timeline dates
                            published_date = parse_date(cve_item.get("published", ""))
                            modified_date = parse_date(cve_item.get("lastModified", ""))
    
                            timeline_data["nvd_info"] = {
                                "published": published_date,
                                "last_modified": modified_date,
                                "descriptions": cve_item.get("descriptions", []),
                                "references": cve_item.get("references", []),
                                "cvss_scores": cve_item.get("metrics", {}),
                            }
    
                            # Analyze references for patch and vendor information
                            patch_refs = []
                            vendor_refs = []
                            advisory_refs = []
    
                            for ref in cve_item.get("references", []):
                                url = ref.get("url", "").lower()
                                tags = [tag.lower() for tag in ref.get("tags", [])]
    
                                # Categorize references
                                if any(tag in ["patch", "vendor advisory"] for tag in tags):
                                    if "patch" in tags:
                                        patch_refs.append(ref)
                                    if "vendor advisory" in tags:
                                        vendor_refs.append(ref)
                                elif any(
                                    keyword in url
                                    for keyword in [
                                        "security",
                                        "advisory",
                                        "bulletin",
                                        "patch",
                                        "update",
                                    ]
                                ):
                                    advisory_refs.append(ref)
    
                            timeline_data["patches"] = patch_refs
                            timeline_data["vendor_advisories"] = vendor_refs
                            timeline_data["security_advisories"] = advisory_refs
    
                except Exception as e:
                    timeline_data["nvd_error"] = str(e)
    
                # Try to get additional timeline info from MITRE
                try:
                    mitre_url = f"https://cve.mitre.org/cgi-bin/cvename.cgi?name={cve_id}"
                    mitre_response = await client.get(mitre_url)
                    if mitre_response.status_code == 200:
                        content = mitre_response.text
    
                        # Look for timeline indicators in MITRE page
                        timeline_indicators = []
                        if "reserved" in content.lower():
                            timeline_indicators.append("CVE ID was reserved")
                        if "disputed" in content.lower():
                            timeline_indicators.append("Vulnerability is disputed")
                        if "rejected" in content.lower():
                            timeline_indicators.append("CVE was rejected")
    
                        timeline_data["mitre_indicators"] = timeline_indicators
    
                except Exception as e:
                    timeline_data["mitre_error"] = str(e)
    
        except Exception as e:
            return [
                types.TextContent(
                    type="text",
                    text=f"Error: Failed to fetch vulnerability timeline: {str(e)}",
                )
            ]
    
        # Generate timeline report
        if not timeline_data.get("nvd_info"):
            return [
                types.TextContent(
                    type="text",
                    text=f"No timeline information found for {cve_id}. The CVE might not exist or be publicly available yet.",
                )
            ]
    
        nvd_info = timeline_data["nvd_info"]
        published_date = nvd_info["published"]
        modified_date = nvd_info["last_modified"]
    
        # Calculate timeline metrics
        current_date = datetime.now()
        age_days = 0
        update_days = 0
    
        if published_date:
            age_days = (current_date - published_date).days
        if modified_date and published_date:
            update_days = (modified_date - published_date).days
    
        # Format the response
        result = f"ā° **Vulnerability Timeline Report: {cve_id}**\n\n"
    
        # Timeline Overview
        result += "šŸ“Š **Timeline Overview:**\n"
        if published_date:
            result += f"   • **Published:** {published_date.strftime('%Y-%m-%d')} ({age_days} days ago)\n"
        if modified_date:
            result += f"   • **Last Modified:** {modified_date.strftime('%Y-%m-%d')} ({update_days} days after publication)\n"
        result += f"   • **Age:** {age_days} days\n"
    
        # Age-based risk assessment
        if age_days > 365:
            age_risk = "🟢 STABLE"
            age_desc = "Well-established vulnerability with likely available patches"
        elif age_days > 90:
            age_risk = "🟔 MATURING"
            age_desc = "Patches likely available, check vendor advisories"
        elif age_days > 30:
            age_risk = "🟠 RECENT"
            age_desc = "Recent vulnerability, patches may be in development"
        else:
            age_risk = "šŸ”“ NEW"
            age_desc = "Very recent vulnerability, patches may not be available yet"
    
        result += f"   • **Maturity:** {age_risk} - {age_desc}\n\n"
    
        # Patch Information
        patches = timeline_data.get("patches", [])
        if patches:
            result += (
                f"šŸ”§ **Patch Information:** āœ… {len(patches)} patch reference(s) found\n"
            )
            for i, patch in enumerate(patches[:3], 1):  # Show first 3
                result += f"   {i}. {patch.get('url', 'N/A')}\n"
                if patch.get("source"):
                    result += f"      Source: {patch.get('source')}\n"
            if len(patches) > 3:
                result += f"   ... and {len(patches) - 3} more patch references\n"
        else:
            result += (
                "šŸ”§ **Patch Information:** āš ļø No explicit patch references found in NVD\n"
            )
        result += "\n"
    
        # Vendor Advisories
        vendor_advisories = timeline_data.get("vendor_advisories", [])
        if vendor_advisories:
            result += f"šŸ­ **Vendor Advisories:** āœ… {len(vendor_advisories)} advisory(ies) found\n"
            for i, advisory in enumerate(vendor_advisories[:3], 1):
                result += f"   {i}. {advisory.get('url', 'N/A')}\n"
                if advisory.get("source"):
                    result += f"      Source: {advisory.get('source')}\n"
        else:
            result += (
                "šŸ­ **Vendor Advisories:** ⚪ No vendor advisories in NVD references\n"
            )
        result += "\n"
    
        # Security Advisories
        security_advisories = timeline_data.get("security_advisories", [])
        if security_advisories:
            result += f"šŸ“¢ **Security Advisories:** āœ… {len(security_advisories)} security-related reference(s)\n"
            for i, advisory in enumerate(security_advisories[:3], 1):
                result += f"   {i}. {advisory.get('url', 'N/A')}\n"
        else:
            result += "šŸ“¢ **Security Advisories:** ⚪ No security advisories detected\n"
        result += "\n"
    
        # MITRE Status Indicators
        mitre_indicators = timeline_data.get("mitre_indicators", [])
        if mitre_indicators:
            result += "šŸ›ļø **MITRE Status:** āš ļø Special status detected\n"
            for indicator in mitre_indicators:
                result += f"   • {indicator}\n"
        else:
            result += "šŸ›ļø **MITRE Status:** āœ… Standard active CVE\n"
        result += "\n"
    
        # Remediation Timeline Estimate
        result += "šŸ› ļø **Remediation Timeline Guidance:**\n"
    
        if patches:
            result += "   • **Patch Status:** āœ… Patches appear to be available\n"
            result += "   • **Action:** Verify and apply vendor patches immediately\n"
            result += "   • **Timeline:** Patch within 24-72 hours for critical systems\n"
        elif vendor_advisories:
            result += "   • **Patch Status:** 🟔 Vendor acknowledgment found\n"
            result += "   • **Action:** Monitor vendor channels for patch release\n"
            result += "   • **Timeline:** Patches typically released within 30-90 days\n"
        elif age_days > 90:
            result += "   • **Patch Status:** āš ļø Patches may be available from vendors\n"
            result += "   • **Action:** Check vendor security pages directly\n"
            result += "   • **Timeline:** Manual verification required\n"
        else:
            result += "   • **Patch Status:** šŸ”“ Patches likely not available yet\n"
            result += "   • **Action:** Implement workarounds and monitor for updates\n"
            result += "   • **Timeline:** Monitor for next 30-60 days\n"
    
        result += "\nšŸ“‹ **Next Steps:**\n"
        result += "   1. šŸ” **Verify Impact:** Check if your systems are affected\n"
        result += "   2. šŸ›”ļø **Implement Workarounds:** If patches unavailable\n"
        result += "   3. šŸ“Š **Monitor Updates:** Set up alerts for patch releases\n"
        result += "   4. šŸŽÆ **Apply Patches:** Test and deploy when available\n"
        result += "   5. šŸ”’ **Validate Fix:** Confirm vulnerability is resolved\n\n"
    
        result += "šŸ”— **Useful Resources:**\n"
        result += f"   • NVD CVE Page: https://nvd.nist.gov/vuln/detail/{cve_id}\n"
        result += f"   • MITRE CVE Page: https://cve.mitre.org/cgi-bin/cvename.cgi?name={cve_id}\n"
        result += "   • Vendor Security Pages: Check affected product vendors\n\n"
    
        result += f"šŸ“Š **Report Generated:** {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}"
    
        return [types.TextContent(type="text", text=result)]
  • Registers the tool with the MCP server in list_tools(), defining name, description, and input schema requiring 'cve_id'.
    types.Tool(
        name="get_vulnerability_timeline",
        description="Get vulnerability timeline and patch status information",
        inputSchema={
            "type": "object",
            "required": ["cve_id"],
            "properties": {
                "cve_id": {
                    "type": "string",
                    "description": timeline_description,
                }
            },
        },
    ),
  • Defines the input schema for the tool: object with required 'cve_id' string parameter.
    inputSchema={
        "type": "object",
        "required": ["cve_id"],
        "properties": {
            "cve_id": {
                "type": "string",
                "description": timeline_description,
            }
        },
    },
  • Dispatch handler in @app.call_tool() that validates arguments and calls the tool implementation.
    elif name == "get_vulnerability_timeline":
        if "cve_id" not in arguments:
            return [
                types.TextContent(
                    type="text", text="Error: Missing required argument 'cve_id'"
                )
            ]
        return await get_vulnerability_timeline(arguments["cve_id"])
  • Helper function to parse various date formats from vulnerability data sources.
    def parse_date(date_str: str) -> Optional[datetime]:
        """Parse various date formats commonly found in vulnerability data."""
        if not date_str:
            return None
    
        # Remove timezone info for simplicity
        date_str = date_str.replace("Z", "").replace("+00:00", "")
    
        try:
            # Try ISO format first
            if "T" in date_str:
                return datetime.fromisoformat(date_str.split("T")[0])
            else:
                return datetime.fromisoformat(date_str)
        except (ValueError, TypeError):
            # Try other common formats
            for fmt in ["%Y-%m-%d", "%Y/%m/%d", "%m/%d/%Y", "%d/%m/%Y"]:
                try:
                    return datetime.strptime(date_str, fmt)
                except (ValueError, TypeError):
                    continue
        return None
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 mentions what information is retrieved but doesn't cover critical aspects like whether this is a read-only operation, potential rate limits, authentication requirements, or the format of the returned data. This leaves significant gaps for an agent to understand how to interact with the tool effectively.

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

Conciseness5/5

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

The description is a single, efficient sentence that directly states the tool's purpose without any unnecessary words. It's front-loaded and easy to parse, making it highly concise and well-structured for quick understanding.

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 lack of annotations and output schema, the description is insufficient for a tool that retrieves detailed vulnerability information. It doesn't explain what the output looks like (e.g., timeline format, patch status details), nor does it address behavioral traits like data freshness or error handling, leaving the agent with incomplete context for proper usage.

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

Parameters3/5

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

The input schema has 100% description coverage, with the 'cve_id' parameter well-documented in the schema itself. The description doesn't add any meaningful information beyond what's already in the schema (e.g., it doesn't clarify parameter usage or constraints), so it meets the baseline score for high schema coverage without compensating value.

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 with a specific verb ('Get') and resource ('vulnerability timeline and patch status information'), making it immediately understandable. However, it doesn't explicitly differentiate this tool from its siblings like 'cve_lookup' or 'search_vulnerabilities', which might also provide vulnerability information, so it doesn't reach the highest score.

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. With siblings like 'cve_lookup' and 'search_vulnerabilities' available, there's no indication of what makes this tool unique or when it should be preferred over others, leaving the agent to guess based on the name alone.

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/firetix/vulnerability-intelligence-mcp-server'

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