add-tool — independently scanned and version-tracked by SaferSkills.
SaferSkills independently audited add-tool (Agent Skill) and scored it 100/100 (green). The audit ran 55 deterministic rules across Security, Supply Chain, Maintenance, Transparency, and Community; it found 0 high-severity and 0 lower-severity findings. The full rule-by-rule trace and per-finding evidence are below. Free, methodology-open.
Findings & checks · 0 flagged
Every scanned point with the score it earned and what moved between them.
First recorded scan — no prior version to compare against.
The primary manifest — the file an agent reads to learn what this artifact does.
Tools use the tool() builder from @cyanheads/mcp-ts-core. Each tool lives in src/mcp-server/tools/definitions/ with a .tool.ts suffix and is registered in the barrel index.ts.
For the full tool() API, Context interface, and error codes, read:
node_modules/@cyanheads/mcp-ts-core/CLAUDE.md
multi-step async work, it should use task: true
src/mcp-server/tools/definitions/{{tool-name}}.tool.tssrc/mcp-server/tools/definitions/index.tsbun run dev:stdio or dev:http/**
* @fileoverview {{TOOL_DESCRIPTION}}
* @module mcp-server/tools/definitions/{{TOOL_NAME}}
*/
import { tool, z } from '@cyanheads/mcp-ts-core';
export const {{TOOL_EXPORT}} = tool('{{tool_name}}', {
title: '{{TOOL_TITLE}}',
description: '{{TOOL_DESCRIPTION}}',
annotations: { readOnlyHint: true },
input: z.object({
// All fields need .describe(). Only JSON-Schema-serializable Zod types allowed.
}),
output: z.object({
// All fields need .describe(). Only JSON-Schema-serializable Zod types allowed.
}),
// auth: ['tool:{{tool_name}}:read'],
async handler(input, ctx) {
ctx.log.info('Processing', { /* relevant input fields */ });
// Pure logic — throw on failure, no try/catch
return { /* output */ };
},
format: (result) => [{ type: 'text', text: JSON.stringify(result, null, 2) }],
});Add task: true and use ctx.progress for long-running operations:
export const {{TOOL_EXPORT}} = tool('{{tool_name}}', {
description: '{{TOOL_DESCRIPTION}}',
task: true,
input: z.object({ /* ... */ }),
output: z.object({ /* ... */ }),
async handler(input, ctx) {
await ctx.progress!.setTotal(totalSteps);
for (const step of steps) {
if (ctx.signal.aborted) break;
await ctx.progress!.update(`Processing: ${step}`);
// ... do work ...
await ctx.progress!.increment();
}
return { /* output */ };
},
});// src/mcp-server/tools/definitions/index.ts
import { existingTool } from './existing-tool.tool.js';
import { {{TOOL_EXPORT}} } from './{{tool-name}}.tool.js';
export const allToolDefinitions = [
existingTool,
{{TOOL_EXPORT}},
];src/mcp-server/tools/definitions/{{tool-name}}.tool.ts.describe() annotationsz.custom(), z.date(), z.transform(), z.bigint(), z.symbol(), z.void(), z.map(), z.set())@fileoverview and @module header presenthandler(input, ctx) is pure — throws on failure, no try/catchauth scopes declared if the tool needs authorizationtask: true added if the tool is long-runningdefinitions/index.ts barrel and allToolDefinitionsbun run devcheck passesbun run dev:stdio or dev:http~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.