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

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