check_vulnerabilities
Scan project dependencies for security vulnerabilities using OSV.dev database. Choose scan modes for detailed reports, quick overviews, or critical issues only.
Instructions
Scans project dependencies (package.json, composer.json) for known security vulnerabilities using the OSV.dev database. Supports multiple scan modes: 'full' for detailed reports, 'summary' for quick overview, 'critical-high-only' for auto-scans showing only actionable issues. Use this tool when: user asks about security/vulnerabilities, after package installations (npm install, composer update), before commits/builds, or when starting work in a new project with dependency files.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| project_path | No | Path to project directory (default: current directory) | |
| file_type | No | Which file(s) to check (default: both) | |
| scan_mode | No | Output detail level: 'full' shows all vulnerabilities with details, 'summary' shows only counts, 'critical-high-only' shows detailed info for CRITICAL/HIGH only (default: full) |
Implementation Reference
- src/index.ts:443-470 (handler)Handler for the check_vulnerabilities tool call. Extracts parameters (project_path, file_type, scan_mode), invokes appropriate scanning functions for package.json and/or composer.json, and returns formatted markdown results.if (request.params.name === "check_vulnerabilities") { const projectPath = (request.params.arguments?.project_path as string) || process.cwd(); const fileType = (request.params.arguments?.file_type as string) || "both"; const scanMode = (request.params.arguments?.scan_mode as ScanMode) || "full"; let result = ""; if (fileType === "package.json" || fileType === "both") { result += await checkPackageJson(projectPath, scanMode); result += "\n\n"; } if (fileType === "composer.json" || fileType === "both") { result += await checkComposerJson(projectPath, scanMode); } return { content: [ { type: "text", text: result, }, ], }; }
- src/index.ts:414-435 (schema)JSON schema defining the input parameters for the check_vulnerabilities tool: project_path (string), file_type (enum), scan_mode (enum).inputSchema: { type: "object", properties: { project_path: { type: "string", description: "Path to project directory (default: current directory)", }, file_type: { type: "string", enum: ["package.json", "composer.json", "both"], description: "Which file(s) to check (default: both)", }, scan_mode: { type: "string", enum: ["full", "summary", "critical-high-only"], description: "Output detail level: 'full' shows all vulnerabilities with details, " + "'summary' shows only counts, 'critical-high-only' shows detailed info for CRITICAL/HIGH only (default: full)", }, }, },
- src/index.ts:407-436 (registration)Tool registration in the ListTools response, including name, description, and reference to inputSchema.{ name: "check_vulnerabilities", description: "Scans project dependencies (package.json, composer.json) for known security vulnerabilities using the OSV.dev database. " + "Supports multiple scan modes: 'full' for detailed reports, 'summary' for quick overview, 'critical-high-only' for auto-scans showing only actionable issues. " + "Use this tool when: user asks about security/vulnerabilities, after package installations (npm install, composer update), " + "before commits/builds, or when starting work in a new project with dependency files.", inputSchema: { type: "object", properties: { project_path: { type: "string", description: "Path to project directory (default: current directory)", }, file_type: { type: "string", enum: ["package.json", "composer.json", "both"], description: "Which file(s) to check (default: both)", }, scan_mode: { type: "string", enum: ["full", "summary", "critical-high-only"], description: "Output detail level: 'full' shows all vulnerabilities with details, " + "'summary' shows only counts, 'critical-high-only' shows detailed info for CRITICAL/HIGH only (default: full)", }, }, }, },
- src/index.ts:178-283 (helper)Helper function that scans package.json for dependencies, queries OSV API for vulnerabilities, counts by severity, and generates markdown report based on scan mode.async function checkPackageJson( projectPath: string, mode: ScanMode ): Promise<string> { try { const packageJsonPath = path.join(projectPath, "package.json"); const content = await fs.readFile(packageJsonPath, "utf-8"); const packageJson = JSON.parse(content); const allDeps = { ...packageJson.dependencies, ...packageJson.devDependencies, }; let results = "# Security Scan Results (package.json)\n\n"; let criticalCount = 0; let highCount = 0; let moderateCount = 0; let lowCount = 0; const allVulnerabilities: Array<{ packageName: string; version: string; vulnerabilities: Vulnerability[]; }> = []; for (const [packageName, versionRange] of Object.entries(allDeps)) { // Extract version from range (simplified - remove ^~>=< symbols) const version = (versionRange as string).replace(/[\^~>=<]/g, ""); const vulnerabilities = await checkVulnerability( packageName, version, "npm" ); if (vulnerabilities.length > 0) { allVulnerabilities.push({ packageName, version, vulnerabilities }); for (const vuln of vulnerabilities) { const severity = vuln.severity.toUpperCase(); if (severity.includes("CRITICAL")) criticalCount++; else if (severity.includes("HIGH")) highCount++; else if (severity.includes("MODERATE")) moderateCount++; else lowCount++; } } } // Summary mode: just show counts if (mode === "summary") { const total = criticalCount + highCount + moderateCount + lowCount; if (total === 0) { results += "\nā **No known security vulnerabilities found!**\n"; } else { results += `## š Summary\n`; results += `- š“ Critical: ${criticalCount}\n`; results += `- š High: ${highCount}\n`; results += `- š” Moderate: ${moderateCount}\n`; results += `- š¢ Low: ${lowCount}\n`; results += `\n**Total vulnerabilities found: ${total}**\n\n`; results += `Run with scan_mode="full" for detailed information.\n`; } return results; } // Full or critical-high-only mode: show details for (const { packageName, version, vulnerabilities } of allVulnerabilities) { results += formatVulnerabilities( vulnerabilities, packageName, version, mode ); } // Summary section const total = criticalCount + highCount + moderateCount + lowCount; if (total === 0) { results += "\nā **No known security vulnerabilities found!**\n"; } else { results += `\n## š Summary\n`; if (mode === "critical-high-only") { results += `- š“ Critical: ${criticalCount}\n`; results += `- š High: ${highCount}\n`; if (moderateCount + lowCount > 0) { results += `\n_Also found ${moderateCount + lowCount} moderate/low severity issues (hidden in this mode)._\n`; results += `_Run with scan_mode="full" to see all vulnerabilities._\n`; } } else { results += `- š“ Critical: ${criticalCount}\n`; results += `- š High: ${highCount}\n`; results += `- š” Moderate: ${moderateCount}\n`; results += `- š¢ Low: ${lowCount}\n`; results += `\n**Total vulnerabilities found: ${total}**\n`; } } return results; } catch (error) { if ((error as NodeJS.ErrnoException).code === "ENOENT") { return "ā package.json file not found in this directory."; } throw error; } }
- src/index.ts:55-116 (helper)Core helper that queries the OSV.dev API for vulnerabilities in a specific package/version/ecosystem and maps results to standardized Vulnerability interface.async function checkVulnerability( packageName: string, version: string, ecosystem: string ): Promise<Vulnerability[]> { try { const response = await fetch("https://api.osv.dev/v1/query", { method: "POST", headers: { "Content-Type": "application/json", }, body: JSON.stringify({ package: { name: packageName, ecosystem: ecosystem, }, version: version, }), }); if (!response.ok) { throw new Error(`OSV API error: ${response.statusText}`); } const data = (await response.json()) as OSVResponse; if (!data.vulns || data.vulns.length === 0) { return []; } return data.vulns.map((vuln) => { let severity = "UNKNOWN"; // Try to get severity from different sources if (vuln.database_specific?.severity) { severity = vuln.database_specific.severity; } else if (vuln.severity && vuln.severity.length > 0) { // CVSS score parsing const cvss = vuln.severity.find((s) => s.type === "CVSS_V3"); if (cvss) { const score = parseFloat(cvss.score.split("/")[0] || "0"); if (score >= 9.0) severity = "CRITICAL"; else if (score >= 7.0) severity = "HIGH"; else if (score >= 4.0) severity = "MODERATE"; else severity = "LOW"; } } return { id: vuln.id, summary: vuln.summary || "No description available", severity: severity, references: vuln.references || [], package_name: packageName, affected_versions: [version], }; }); } catch (error) { console.error(`Error checking ${packageName}:`, error); return []; } }