submit_audit
Submit third-party AI skills for behavioral security audits before installation. Accepts GitHub or ClawHub URLs to analyze trust scores and returns an audit ID for tracking progress.
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
TableJSON 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 function that executes the submit_audit tool logic. It constructs the request body with skill_url, optional notification_email and force_rescan, makes a POST request to /api/submit, handles rate limiting (429 errors), and returns the audit_id in the response.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:6-72 (registration)The registerSubmitAudit function that registers the submit_audit tool with the MCP server, including its description, input schema (Zod validation), and the handler function.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/tools/submit-audit.ts:16-29 (schema)Input schema definition for submit_audit tool using Zod. Validates skill_url (required), notification_email (optional email), and force_rescan (optional boolean) parameters.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/lib/types.ts:4-9 (schema)TypeScript interface defining the SubmitResponse structure returned by the API, containing audit_id, optional queue_position, notification_email, and deduplicated fields.export interface SubmitResponse { audit_id: string; queue_position?: number; notification_email?: string; deduplicated?: boolean; }
- src/index.ts:19-19 (registration)Registration call that invokes registerSubmitAudit to register the submit_audit tool with the MCP server instance.registerSubmitAudit(server);