Skip to main content
Glama

VirusTotal MCP Server

url.ts3.72 kB
import { AxiosInstance } from 'axios'; import { queryVirusTotal, encodeUrlForVt } from '../utils/api.js'; import { formatUrlScanResults } from '../formatters/index.js'; import { GetUrlReportArgsSchema, GetUrlRelationshipArgsSchema } from '../schemas/index.js'; import { logToFile } from '../utils/logging.js'; import { RelationshipData } from '../types/virustotal.js'; // Default relationships to fetch const DEFAULT_RELATIONSHIPS = [ 'communicating_files', 'contacted_domains', 'contacted_ips', 'downloaded_files', 'redirects_to', 'redirecting_urls', 'related_threat_actors' ] as const; export async function handleGetUrlReport(axiosInstance: AxiosInstance, args: unknown) { const parsedArgs = GetUrlReportArgsSchema.safeParse(args); if (!parsedArgs.success) { throw new Error("Invalid URL format"); } const url = parsedArgs.data.url; const encodedUrl = encodeUrlForVt(url); // First submit URL for scanning logToFile(`Scanning URL: ${url}`); const scanResponse = await queryVirusTotal( axiosInstance, '/urls', 'post', new URLSearchParams({ url }) ); const analysisId = scanResponse.data.id; logToFile(`Analysis ID: ${analysisId}`); // Wait for analysis to complete await new Promise(resolve => setTimeout(resolve, 3000)); // Get analysis results const analysisResponse = await queryVirusTotal( axiosInstance, `/analyses/${analysisId}` ); // Then get full data for specified relationships const relationshipData: Record<string, RelationshipData> = {}; for (const relType of DEFAULT_RELATIONSHIPS) { logToFile(`Fetching ${relType}`); try { const response = await queryVirusTotal( axiosInstance, `/urls/${encodedUrl}/${relType}`, 'get' ); // Only log relationship metadata logToFile(`${relType} count: ${ Array.isArray(response.data) ? response.data.length : response.data ? '1' : '0' }`); // Format the relationship data if (Array.isArray(response.data)) { relationshipData[relType] = { data: response.data, meta: response.meta }; } else if (response.data) { relationshipData[relType] = { data: response.data, meta: response.meta }; } } catch (error) { logToFile(`Failed to fetch ${relType}`); // Continue with other relationships even if one fails } } // Combine the analysis results with relationships const combinedData = { id: analysisId, url: url, attributes: analysisResponse.data.attributes, scan_date: new Date().toISOString(), relationships: relationshipData }; return { content: [ formatUrlScanResults(combinedData) ], }; } export async function handleGetUrlRelationship(axiosInstance: AxiosInstance, args: unknown) { const parsedArgs = GetUrlRelationshipArgsSchema.safeParse(args); if (!parsedArgs.success) { throw new Error("Invalid arguments for URL relationship query"); } const { url, relationship, limit, cursor } = parsedArgs.data; const encodedUrl = encodeUrlForVt(url); const params: Record<string, string | number> = { limit }; if (cursor) params.cursor = cursor; logToFile(`Fetching ${relationship} for URL: ${url}`); const result = await queryVirusTotal( axiosInstance, `/urls/${encodedUrl}/${relationship}`, 'get' ); return { content: [ formatUrlScanResults({ url: url, attributes: result.data.attributes, relationships: { [relationship]: { data: result.data, meta: result.meta } } }) ], }; }

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/BurtTheCoder/mcp-virustotal'

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