get_findings
Retrieve structured vulnerability findings from penetration tests with severity, CVSS scores, descriptions, and remediation guidance. Filter results by severity level to focus on critical issues.
Instructions
Get structured vulnerability findings for a pentest. Each finding includes severity, CVSS, CWE, description, PoC, remediation, and retest command. Use the severity filter to narrow results.
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| pentest_id | Yes | The pentest ID (UUID) | |
| severity | No | Filter findings by severity level |
Implementation Reference
- src/tools/get-findings.ts:42-88 (handler)The async function handling the 'get_findings' tool request, which fetches pentest data and formats the findings.
async ({ pentest_id, severity }) => { try { const scan = await client.getPentest(pentest_id); let findings = scan.findings ?? []; if (severity) { findings = findings.filter((f) => f.severity === severity); } if (findings.length === 0) { return { content: [ { type: "text" as const, text: severity ? `No ${severity} findings for pentest ${pentest_id}.` : `No findings for pentest ${pentest_id}.`, }, ], }; } const MAX_DISPLAY = 20; const displayed = findings.slice(0, MAX_DISPLAY); const lines = [ `Findings for pentest ${pentest_id}${severity ? ` (${severity} only)` : ""}:`, `Total: ${findings.length}`, "", ...displayed.map((f, i) => formatFinding(f, i)), ]; if (findings.length > MAX_DISPLAY) { lines.push( "", `... showing ${MAX_DISPLAY} of ${findings.length} findings. Use severity filter to narrow results.`, ); } return { content: [{ type: "text" as const, text: lines.join("\n") }] }; } catch (error) { const message = error instanceof Error ? error.message : String(error); return { content: [{ type: "text" as const, text: `Failed to get findings: ${message}` }], isError: true, }; } }, - src/tools/get-findings.ts:34-40 (schema)Input schema definition for the 'get_findings' tool using Zod.
inputSchema: z.object({ pentest_id: z.string().uuid().describe("The pentest ID (UUID)"), severity: z .enum(["critical", "high", "medium", "low", "info"]) .optional() .describe("Filter findings by severity level"), }), - src/tools/get-findings.ts:25-90 (registration)The registration function that defines the 'get_findings' tool within the MCP server.
export function registerGetFindings(server: McpServer, client: TurboPentestClient): void { server.registerTool( "get_findings", { title: "Get Findings", description: "Get structured vulnerability findings for a pentest. " + "Each finding includes severity, CVSS, CWE, description, PoC, remediation, and retest command. " + "Use the severity filter to narrow results.", inputSchema: z.object({ pentest_id: z.string().uuid().describe("The pentest ID (UUID)"), severity: z .enum(["critical", "high", "medium", "low", "info"]) .optional() .describe("Filter findings by severity level"), }), }, async ({ pentest_id, severity }) => { try { const scan = await client.getPentest(pentest_id); let findings = scan.findings ?? []; if (severity) { findings = findings.filter((f) => f.severity === severity); } if (findings.length === 0) { return { content: [ { type: "text" as const, text: severity ? `No ${severity} findings for pentest ${pentest_id}.` : `No findings for pentest ${pentest_id}.`, }, ], }; } const MAX_DISPLAY = 20; const displayed = findings.slice(0, MAX_DISPLAY); const lines = [ `Findings for pentest ${pentest_id}${severity ? ` (${severity} only)` : ""}:`, `Total: ${findings.length}`, "", ...displayed.map((f, i) => formatFinding(f, i)), ]; if (findings.length > MAX_DISPLAY) { lines.push( "", `... showing ${MAX_DISPLAY} of ${findings.length} findings. Use severity filter to narrow results.`, ); } return { content: [{ type: "text" as const, text: lines.join("\n") }] }; } catch (error) { const message = error instanceof Error ? error.message : String(error); return { content: [{ type: "text" as const, text: `Failed to get findings: ${message}` }], isError: true, }; } }, ); } - src/tools/get-findings.ts:6-22 (helper)Helper function to format a single finding into a readable string.
function formatFinding(f: Finding, index: number): string { const lines = [ `[${index + 1}] ${f.severity.toUpperCase()}: ${f.title}`, ` Tool: ${f.sourceTool}`, ]; if (f.cvss !== null) lines.push(` CVSS: ${f.cvss}${f.cvssVector ? ` (${f.cvssVector})` : ""}`); if (f.cweId) lines.push(` CWE: ${f.cweId}`); if (f.owaspCategory) lines.push(` OWASP: ${f.owaspCategory}`); if (f.affectedUrl) lines.push(` URL: ${f.affectedUrl}`); if ((f.cveIds ?? []).length > 0) lines.push(` CVEs: ${f.cveIds.join(", ")}`); if (f.description) lines.push(` Description: ${f.description}`); if (f.proofOfExploit) lines.push(` PoC: ${f.proofOfExploit}`); if (f.remediation) lines.push(` Remediation: ${f.remediation}`); if (f.retestCommand) lines.push(` Retest: ${f.retestCommand}`); return lines.join("\n");