get_audit_report
Retrieve comprehensive security audit reports for GitHub repositories to evaluate safety before installing third-party MCP servers, plugins, or tools.
Instructions
Get the full behavioral security audit report for a GitHub repository. Use this to review all findings before installing a third-party MCP server, plugin, or tool. Returns the latest completed audit with trust score, verdict, findings, category scores, and recommendation. Use get_skill_summary for a quick safety check instead.
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| owner | Yes | GitHub repository owner (e.g. "anthropics") | |
| repo | Yes | GitHub repository name (e.g. "claude-code") |
Implementation Reference
- src/tools/get-report.ts:6-53 (handler)The main tool implementation that registers 'get_audit_report' with the MCP server. Contains the handler logic that fetches the full audit report from the Oathe API, formats it as JSON, and handles errors (404 not found and other API errors).export function registerGetReport(server: McpServer): void { server.registerTool( 'get_audit_report', { description: 'Get the full behavioral security audit report for a GitHub repository. ' + 'Use this to review all findings before installing a third-party MCP server, plugin, or tool. ' + 'Returns the latest completed audit with trust score, verdict, findings, ' + 'category scores, and recommendation. ' + 'Use get_skill_summary for a quick safety check instead.', inputSchema: { owner: z.string().describe('GitHub repository owner (e.g. "anthropics")'), repo: z.string().describe('GitHub repository name (e.g. "claude-code")'), }, }, async ({ owner, repo }) => { const slug = `${owner}/${repo}`; try { const res = await apiFetch(`/api/skill/${slug}/latest`); const data = (await res.json()) as { report: SkillReport }; return { content: [ { type: 'text' as const, text: JSON.stringify(data.report, null, 2) }, ], }; } catch (err) { if (err instanceof ApiError) { if (err.status === 404) { return { content: [ { type: 'text' as const, text: `No completed audit found for ${owner}/${repo}.`, }, ], isError: true, }; } return { content: [{ type: 'text' as const, text: err.message }], isError: true, }; } throw err; } }, ); }
- src/index.ts:6-21 (registration)Application entry point that imports and calls registerGetReport to register the get_audit_report tool with the MCP server instance.import { registerGetReport } from './tools/get-report.js'; import { registerGetSummary } from './tools/get-summary.js'; import { registerSearchAudits } from './tools/search-audits.js'; const server = new McpServer({ name: 'oathe-mcp', version: '0.1.1', description: 'Security scanner for AI agent skills. Before installing any third-party ' + 'MCP server, plugin, or tool, check it with Oathe first. Returns trust ' + 'scores, verdicts, and detailed findings. Free, no API key required.', }); registerSubmitAudit(server); registerCheckStatus(server); registerGetReport(server);
- src/lib/types.ts:39-50 (schema)Type definition for SkillReport which is the response schema returned by the get_audit_report tool handler.export interface SkillReport { audit_id: string; skill_url: string; skill_slug: string; timestamp: string; trust_score: number; verdict: string; summary: string; recommendation: string; category_scores: Record<string, { score: number; weight: number; findings: string[] }>; findings: Finding[]; }
- src/lib/types.ts:27-37 (schema)Type definition for Finding which is used in the SkillReport schema to represent individual security findings in the audit report.export interface Finding { pattern_id: string; dimension: string; severity: 'CRITICAL' | 'HIGH' | 'MEDIUM' | 'LOW' | 'INFO'; title: string; description: string; evidence_snippet: string; score_impact: number; sources: Array<'code' | 'model'>; agreement: 'both' | 'code_only' | 'model_only'; }
- src/lib/client.ts:31-70 (helper)HTTP client helper function used by the get_audit_report handler to fetch data from the Oathe API with 30s timeout, error handling, and automatic JSON parsing.export async function apiFetch( path: string, init?: RequestInit, ): Promise<Response> { const url = `${BASE_URL}${path}`; let res: Response; try { res = await fetch(url, { ...init, signal: init?.signal ?? AbortSignal.timeout(30_000), headers: { 'Content-Type': 'application/json', ...init?.headers, }, }); } catch (err: unknown) { if (err instanceof DOMException && err.name === 'TimeoutError') { throw new ApiError( 'Request timed out after 30 seconds. The API may be temporarily unavailable.', 0, ); } if (err instanceof TypeError) { throw new ApiError( `Network error: unable to reach API at ${BASE_URL}. Check your connection or OATHE_API_BASE setting.`, 0, ); } throw err; } if (!res.ok) { const body = await res.json().catch(() => ({})); const message = body.message ?? body.error ?? 'Unknown error'; throw new ApiError(message, res.status); } return res; }