meta-mcp-builder — independently scanned and version-tracked by SaferSkills.
SaferSkills independently audited meta-mcp-builder (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.
Degree of freedom: MIXED. Which tools to expose [HIGH freedom]; SDK tool shape, annotations, env-based auth, and Inspector [LOW freedom — run exactly].
Create MCP servers that enable LLMs to interact with external services.
Observe: "give Claude access to Linear"; agents will search issues and file one — not walk the full GraphQL schema. Interpret: start with workflow-shaped tools, not 40 raw endpoints. Classify:linear_search_issues,linear_create_issue; zod params;createisreadOnlyHint: false. Ship: envLINEAR_API_KEY(throw if missing); Inspector on both tools; no hardcoded token.
meta-skill-creator; calling an existing MCP is not this skillMCP (Model Context Protocol) servers expose tools that AI agents can use. Quality is measured by how well they enable agents to accomplish real tasks.
Recommended: TypeScript with MCP SDK
Alternative: Python with FastMCP
my-mcp-server/
├── src/
│ ├── index.ts # Entry point
│ ├── tools/ # Tool implementations
│ │ ├── search.ts
│ │ └── create.ts
│ └── utils/ # Shared utilities
│ ├── api-client.ts
│ └── error-handler.ts
├── package.json
├── tsconfig.json
└── README.md// ✅ Good - action-oriented, prefixed
'github_create_issue'
'github_list_repos'
'slack_send_message'
// ❌ Avoid - vague
'process'
'handle'
'do_thing'Under-description is the common failure. State what the tool does, when to use it and when not to, what each parameter means, caveats, and what it does not return — three to four sentences or more. Keep behavioral steering ("always prefer this tool") and worked examples out of the description; they constrain exploration and cost tokens on every request, and belong in a skill.
{
name: 'github_search_issues',
description: 'Search GitHub issues in one repository by free-text query, state, and labels. Returns up to `limit` issues with title, number, state, and URL; does not return bodies or comments (use github_get_issue for those). For creating an issue use github_create_issue.',
}import { z } from 'zod';
const searchIssuesSchema = z.object({
query: z.string().describe('Search query string'),
state: z.enum(['open', 'closed', 'all']).default('open'),
labels: z.array(z.string()).optional().describe('Filter by labels'),
limit: z.number().min(1).max(100).default(10),
});// ❌ Bad
throw new Error('Failed');
// ✅ Good
throw new Error(
`GitHub API rate limit exceeded. ` +
`Resets at ${resetTime}. ` +
`Try again later or authenticate for higher limits.`
);import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
import { z } from 'zod';
const server = new McpServer({
name: 'my-service',
version: '1.0.0',
});
// Define tool
server.tool(
'service_action',
'Description of what this tool does and when to use it',
{
param1: z.string().describe('What this param is for'),
param2: z.number().optional().describe('Optional param'),
},
async ({ param1, param2 }) => {
// Implementation
const result = await performAction(param1, param2);
return {
content: [
{
type: 'text',
text: JSON.stringify(result, null, 2),
},
],
};
}
);server.tool(
'delete_item',
'Delete an item permanently',
{ id: z.string() },
async ({ id }) => { /* ... */ },
{
annotations: {
readOnlyHint: false, // Modifies data
destructiveHint: true, // Cannot be undone
idempotentHint: true, // Safe to retry
openWorldHint: false, // Closed set of operations
},
}
);| Approach | When to Use |
|---|---|
| full API coverage | Agent needs flexibility to compose operations |
| Workflow tools | Specific task needs multi-step automation |
Default: start with the tools that match the agent's real jobs (workflow-shaped), then add raw-coverage tools only where agents need to compose operations the workflow tools do not cover. Past a few dozen tools, rely on the client's tool search / deferred loading instead of always-loading every schema.
// Return structured data
return {
content: [{
type: 'text',
text: JSON.stringify({
success: true,
data: results,
metadata: { count: results.length },
}, null, 2),
}],
};const listItemsSchema = z.object({
limit: z.number().min(1).max(100).default(20),
cursor: z.string().optional().describe('Pagination cursor from previous response'),
});
// Return cursor in response
return {
items: results,
nextCursor: hasMore ? lastId : null,
};npm run build # Must pass without errorsnpx @modelcontextprotocol/inspectorconst apiKey = process.env.SERVICE_API_KEY;
if (!apiKey) {
throw new Error('SERVICE_API_KEY environment variable required');
}import { RateLimiter } from 'limiter';
const limiter = new RateLimiter({
tokensPerInterval: 100,
interval: 'minute',
});
async function callApi() {
await limiter.removeTokens(1);
// Make API call
}const cache = new Map<string, { data: any; expiry: number }>();
async function getCached(key: string, fetcher: () => Promise<any>) {
const cached = cache.get(key);
if (cached && cached.expiry > Date.now()) {
return cached.data;
}
const data = await fetcher();
cache.set(key, { data, expiry: Date.now() + 60000 });
return data;
}~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.