Building Security Analysis Workflows with VirusTotal MCP: AI Assistants Meet Threat Intelligence
Hook
What if your AI assistant could instantly query 70+ antivirus engines, analyze suspicious URLs, and correlate threat intelligence—all without you writing a single API integration?
Context
Security analysts face a common workflow bottleneck: gathering comprehensive threat intelligence requires juggling multiple tools, API calls, and context switches. You find a suspicious URL in your logs, paste it into VirusTotal’s web interface, wait for the scan, click through to see communicating files, open another tab for WHOIS data, then manually correlate everything in your incident report. Each investigation burns 10-15 minutes of repetitive clicking.
The Model Context Protocol (MCP), recently introduced by Anthropic, offers a different approach. Instead of building yet another security dashboard or CLI tool, MCP lets AI assistants like Claude directly invoke security tools as if they were functions. The virustotal-mcp project implements this pattern, wrapping VirusTotal’s API into a standardized interface that AI can query conversationally. Rather than teaching analysts to remember API endpoints and response schemas, you describe what you need: “Is this IP address associated with malware distribution?” The assistant handles the API choreography, relationship traversal, and data synthesis automatically.
Technical Insight
The virustotal-mcp server is architecturally straightforward—a Python async server that translates MCP tool invocations into VirusTotal API v3 calls. What makes it interesting isn’t complexity, but how it structures security workflows for AI consumption.
The server exposes two tiers of tools. High-level report tools (url_report, file_report, ip_report, domain_report) return aggregated views with common relationships pre-fetched. When you request a URL report, you don’t just get scan results—you automatically receive communicating files, contacted domains, and redirects in a single response. This design decision trades API quota for convenience, assuming most security investigations need this context anyway.
Here’s how the tool registration looks internally:
@server.list_tools()
async def handle_list_tools() -> list[types.Tool]:
return [
types.Tool(
name="url_report",
description="Analyze a URL with VirusTotal. Returns scan results and automatically fetches related data (communicating_files, contacted_domains, redirects).",
inputSchema={
"type": "object",
"properties": {
"url": {"type": "string", "description": "URL to analyze"}
},
"required": ["url"]
}
),
types.Tool(
name="get_url_relationships",
description="Get specific relationship data for a URL (e.g., communicating_files, contacted_domains). Supports pagination for large datasets.",
inputSchema={
"type": "object",
"properties": {
"url_id": {"type": "string"},
"relationship": {"type": "string"},
"limit": {"type": "integer", "default": 10}
},
"required": ["url_id", "relationship"]
}
)
]
The dual-tier approach is smart. For quick triage, an AI can invoke url_report and get everything. For deep investigations where you need 500 communicating files with metadata, you use get_url_relationships with pagination. The MCP protocol handles parameter validation and type safety—the AI can’t accidentally pass an integer where a string is required.
Under the hood, relationship fetching uses aiohttp for async HTTP calls to avoid blocking:
async def get_relationships(resource_type: str, resource_id: str, relationship: str, limit: int = 10):
url = f"https://www.virustotal.com/api/v3/{resource_type}/{resource_id}/{relationship}"
headers = {"x-apikey": VT_API_KEY}
params = {"limit": limit}
async with aiohttp.ClientSession() as session:
async with session.get(url, headers=headers, params=params) as response:
return await response.json()
This async pattern matters because AI assistants often make multiple tool calls in parallel when answering complex questions. If you ask “Compare the reputation of these three domains,” the assistant can fire three domain_report calls concurrently rather than waiting sequentially.
The project also exposes VirusTotal Intelligence search as an MCP tool, letting AI assistants perform threat hunting queries using VT’s advanced syntax. You can ask natural language questions like “Find Android APKs uploaded in the last week with network connections to Russian IP ranges,” and the assistant translates this into VTI query syntax: type:apk submitted:[2024-01-01+ TO 2024-01-07+] network:country:RU. This is where MCP’s value proposition becomes clear—you’re not teaching analysts query languages, you’re letting AI handle the translation layer.
The server runs as a local process, communicating with Claude Desktop or other MCP clients via stdio. Installation involves cloning the repo, setting your VirusTotal API key as an environment variable, and adding a server configuration to Claude’s config file. Once configured, VirusTotal capabilities appear as native functions in your AI assistant—no web interface, no context switching, just conversational threat intelligence queries.
Gotcha
The documentation is incomplete by the maintainer’s own admission—manual installation instructions show ‘TBD’ placeholders. You’ll need to reverse-engineer setup details from the Smithery config and source code. For a tool designed to streamline workflows, the bootstrapping experience ironically requires detective work.
More concerning is the absence of rate limit handling. VirusTotal’s free tier allows 4 requests per minute; even paid tiers have quotas. The automatic relationship fetching in report tools fires multiple API calls per invocation—a single url_report might trigger 3-4 requests under the hood. If your AI assistant gets enthusiastic and investigates a dozen URLs, you’ll hit rate limits fast. The code includes no retry logic, backoff strategies, or quota monitoring. Production use would require wrapping this server in your own rate limiting layer, which defeats the plug-and-play promise of MCP.
There’s also an architectural mismatch for batch operations. Security teams often need to check hundreds of indicators from threat feeds. The MCP model—optimized for conversational, sequential queries—isn’t ideal for bulk analysis. You’d want direct API access with request batching, not an AI assistant making 500 serial tool calls.
Verdict
Use if: You’re experimenting with AI-assisted security workflows in Claude Desktop or other MCP clients, want to prototype threat intelligence queries without building API integrations, or need quick conversational access to VirusTotal data for ad-hoc investigations. The automatic relationship aggregation genuinely speeds up reconnaissance tasks when you’re triaging alerts interactively. Skip if: You need production-grade reliability with comprehensive error handling and rate limit management, you’re processing indicators in batch (100+ IOCs), you’re not using MCP-compatible tools, or you require detailed documentation for team onboarding. In those cases, use vt-py (the official Python library) or build directly against VirusTotal’s REST API where you control retry logic, caching, and quota management explicitly.