lookup_ave
Retrieve a complete AVE record for a vulnerability ID, including CVSS-AI score, indicators of compromise, and remediation steps.
Instructions
Get the full AVE record for a specific vulnerability ID.
Returns the complete record including title, description, CVSS-AI score, behavioral fingerprint, indicators of compromise, OWASP MCP mapping, NIST AI RMF mapping, and remediation steps.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| ave_id | Yes | AVE ID in the format AVE-2026-NNNNN (e.g. AVE-2026-00001) |
Output Schema
| Name | Required | Description | Default |
|---|---|---|---|
| result | Yes |
Implementation Reference
- bawbel_mcp/server.py:340-399 (handler)The tool handler function decorated with @mcp.tool(). Validates AVE ID format, calls _piranha_get to fetch the record from the PiranhaDB API, then formats the response into a human-readable string with title, severity, attack class, description, behavioral fingerprint, OWASP mappings, remediation, and indicators of compromise.
@mcp.tool() def lookup_ave(ave_id: str) -> str: """ Get the full AVE record for a specific vulnerability ID. Returns the complete record including title, description, CVSS-AI score, behavioral fingerprint, indicators of compromise, OWASP MCP mapping, NIST AI RMF mapping, and remediation steps. Args: ave_id: AVE ID in the format AVE-2026-NNNNN (e.g. AVE-2026-00001) """ ave_id = ave_id.strip().upper() if not ave_id.startswith("AVE-"): return "Error: AVE ID must be in the format AVE-2026-NNNNN" data = _piranha_get(f"/records/{ave_id}") if data.get("error"): return f"Error: {data['error']}" lines = [ f"{data.get('ave_id', '')} {data.get('title', '')}", f"Severity: {data.get('severity', '')} (CVSS-AI {data.get('cvss_ai_score', '')})", f"Attack class: {data.get('attack_class', '')}", f"Component: {data.get('component_type', '')}", f"Status: {data.get('status', '')}", "", f"Description:", f" {data.get('description', '')}", "", f"Behavioral fingerprint:", f" {data.get('behavioral_fingerprint', '')}", "", ] owasp = data.get("owasp_mapping", []) owasp_mcp = data.get("owasp_mcp", []) if owasp: lines.append(f"OWASP ASI: {', '.join(owasp)}") if owasp_mcp: lines.append(f"OWASP MCP: {', '.join(owasp_mcp)}") remediation = data.get("remediation", "") if remediation: lines.append("") lines.append("Remediation:") lines.append(f" {remediation}") iocs = data.get("indicators_of_compromise", []) if iocs: lines.append("") lines.append("Indicators of compromise:") for ioc in iocs: lines.append(f" - {ioc}") lines.append("") lines.append(f"Full record: {PIRANHA_API}/records/{ave_id}") return "\n".join(lines) - bawbel_mcp/server.py:341-351 (schema)Input schema: takes a single string parameter 'ave_id' in format AVE-2026-NNNNN. Returns a formatted string.
def lookup_ave(ave_id: str) -> str: """ Get the full AVE record for a specific vulnerability ID. Returns the complete record including title, description, CVSS-AI score, behavioral fingerprint, indicators of compromise, OWASP MCP mapping, NIST AI RMF mapping, and remediation steps. Args: ave_id: AVE ID in the format AVE-2026-NNNNN (e.g. AVE-2026-00001) """ - bawbel_mcp/server.py:340-340 (registration)Registration via the @mcp.tool() decorator from FastMCP, registering lookup_ave as an MCP tool.
@mcp.tool() - bawbel_mcp/server.py:122-131 (helper)Helper function that makes HTTP GET requests to the PiranhaDB API (https://api.piranha.bawbel.io) and returns parsed JSON. Used by lookup_ave to fetch the AVE record.
def _piranha_get(path: str) -> dict: """GET from PiranhaDB API. Returns parsed JSON or error dict.""" url = f"{PIRANHA_API}{path}" content, err = _fetch_url(url) if err: return {"error": f"PiranhaDB unavailable: {err}"} try: return json.loads(content) except json.JSONDecodeError: return {"error": "Invalid response from PiranhaDB"} - bawbel_mcp/server.py:105-119 (helper)Low-level URL fetching helper using urllib. Used by _piranha_get to make the actual HTTP request.
def _fetch_url(url: str) -> tuple[Optional[str], Optional[str]]: """Fetch content from a URL. Returns (content, error).""" try: req = urllib.request.Request( url, headers={"User-Agent": "bawbel-mcp/1.0 (https://bawbel.io)"}, ) with urllib.request.urlopen(req, timeout=10) as r: # nosec B310 # noqa: S310 return r.read(MAX_CONTENT_BYTES).decode("utf-8", errors="replace"), None except urllib.error.HTTPError as e: return None, f"HTTP {e.code}: {e.reason}" except urllib.error.URLError as e: return None, f"URL error: {e.reason}" except Exception as e: # noqa: BLE001 return None, str(e)