submit_audit
Submit a third-party skill URL for a behavioral security audit before installing. Returns an audit ID to track progress and avoids duplicate scans.
Instructions
Submit a third-party skill for a behavioral security audit before installing it. Accepts any GitHub or ClawHub URL. Returns an audit_id to track progress. Rate limited: one submission per 60 seconds per IP. Returns existing audit_id if URL was already scanned (deduplicated: true). Use check_audit_status to poll for results.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| skill_url | Yes | GitHub or ClawHub URL of the skill/repo to audit | |
| notification_email | No | Optional email to notify when audit completes | |
| force_rescan | No | Bypass deduplication and force a fresh audit |
Implementation Reference
- src/tools/submit-audit.ts:31-70 (handler)The async handler that executes the submit_audit tool logic: sends a POST request to /api/submit with the skill_url (and optional notification_email/force_rescan), returns the response as JSON, and handles rate-limiting (429) and other API errors.
async ({ skill_url, notification_email, force_rescan }) => { try { const body: Record<string, unknown> = { skill_url }; if (notification_email) { body.notification_email = notification_email; } if (force_rescan) { body.force_rescan = true; } const res = await apiFetch('/api/submit', { method: 'POST', body: JSON.stringify(body), }); const data = (await res.json()) as SubmitResponse; return { content: [{ type: 'text' as const, text: JSON.stringify(data, null, 2) }], }; } catch (err) { if (err instanceof ApiError) { if (err.status === 429) { return { content: [ { type: 'text' as const, text: 'Rate limited — wait 60 seconds before resubmitting.', }, ], isError: true, }; } return { content: [{ type: 'text' as const, text: err.message }], isError: true, }; } throw err; } }, - src/tools/submit-audit.ts:16-29 (schema)Input schema for submit_audit: skill_url (required string), notification_email (optional email string), and force_rescan (optional boolean).
inputSchema: { skill_url: z .string() .describe('GitHub or ClawHub URL of the skill/repo to audit'), notification_email: z .string() .email() .optional() .describe('Optional email to notify when audit completes'), force_rescan: z .boolean() .optional() .describe('Bypass deduplication and force a fresh audit'), }, - src/tools/submit-audit.ts:6-72 (registration)The registerSubmitAudit function that registers the tool with the MCP server using server.registerTool('submit_audit', ...).
export function registerSubmitAudit(server: McpServer): void { server.registerTool( 'submit_audit', { description: 'Submit a third-party skill for a behavioral security audit before installing it. ' + 'Accepts any GitHub or ClawHub URL. Returns an audit_id to track progress. ' + 'Rate limited: one submission per 60 seconds per IP. ' + 'Returns existing audit_id if URL was already scanned (deduplicated: true). ' + 'Use check_audit_status to poll for results.', inputSchema: { skill_url: z .string() .describe('GitHub or ClawHub URL of the skill/repo to audit'), notification_email: z .string() .email() .optional() .describe('Optional email to notify when audit completes'), force_rescan: z .boolean() .optional() .describe('Bypass deduplication and force a fresh audit'), }, }, async ({ skill_url, notification_email, force_rescan }) => { try { const body: Record<string, unknown> = { skill_url }; if (notification_email) { body.notification_email = notification_email; } if (force_rescan) { body.force_rescan = true; } const res = await apiFetch('/api/submit', { method: 'POST', body: JSON.stringify(body), }); const data = (await res.json()) as SubmitResponse; return { content: [{ type: 'text' as const, text: JSON.stringify(data, null, 2) }], }; } catch (err) { if (err instanceof ApiError) { if (err.status === 429) { return { content: [ { type: 'text' as const, text: 'Rate limited — wait 60 seconds before resubmitting.', }, ], isError: true, }; } return { content: [{ type: 'text' as const, text: err.message }], isError: true, }; } throw err; } }, ); } - src/index.ts:19-23 (registration)Calls registerSubmitAudit(server) to wire up the tool at server startup.
registerSubmitAudit(server); registerCheckStatus(server); registerGetReport(server); registerGetSummary(server); registerSearchAudits(server); - src/lib/types.ts:4-9 (helper)SubmitResponse type used by the handler — defines the shape of the API response (audit_id, queue_position, notification_email, deduplicated).
export interface SubmitResponse { audit_id: string; queue_position?: number; notification_email?: string; deduplicated?: boolean; }