skills/mcp-creator/SKILL.md
Expert MCP (Model Context Protocol) server developer creating safe, performant, production-ready servers with proper security, error handling, and developer experience. Activate on 'create MCP', 'MCP server', 'build MCP', 'custom tool server', 'MCP development', 'Model Context Protocol'. NOT for using existing MCPs (just invoke them), general API development (use backend-architect), or skills/agents without external state (use skill-coach/agent-creator).
npx skillsauth add curiositech/windags-skills mcp-creatorInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Expert in building production-ready Model Context Protocol servers with security boundaries, robust error handling, and excellent developer experience.
Tool complexity assessment:
├── Multiple API endpoints needed?
├── Yes → Design separate tools for each endpoint
│ └── Example: get_user, create_user, update_user
└── No → Single tool with action parameter
└── Example: manage_user(action: "get"|"create"|"update")
Tool execution pattern:
├── Operation takes >5 seconds?
├── Yes → Design as async with polling tool
│ └── start_analysis() → check_status() → get_results()
└── No → Direct synchronous tool
└── analyze_data() returns results immediately
External service interaction:
├── Requires authentication?
├── Yes → Bundle related operations in one MCP
│ └── Share auth config across tools
└── No → Consider standalone tools or scripts
Data access pattern:
├── Read-only structured data? → Use Resources
│ └── Templates, configs, documentation
├── Actions that modify state? → Use Tools
│ └── API calls, database writes, file creation
└── Interactive operations? → Use Tools with prompts
└── Guided workflows, form filling
Deployment context:
├── Local CLI integration?
└── Use StdioTransport (simplest, most secure)
├── Multiple client support needed?
└── Use SSE Transport (HTTP-based)
├── Custom protocol requirements?
└── Implement custom Transport class
└── Production server deployment?
└── SSE with proper auth middleware
Symptom: Tools accept any type or overly permissive schemas
Detection: If schema validation catches <90% of invalid inputs
Fix: Implement strict Zod schemas with constraints
// ❌ Detection rule: Schema too permissive
{ type: "object" }
// ✅ Fix: Strict validation
const schema = z.object({
id: z.string().uuid(),
count: z.number().min(1).max(100)
})
Symptom: Server becomes unresponsive after extended use Detection: If connection pools show >90% utilization or memory usage grows continuously Fix: Implement proper resource cleanup with try/finally blocks
// ❌ Detection: No cleanup
const client = await pool.connect();
const result = await client.query(sql);
// ✅ Fix: Guaranteed cleanup
const client = await pool.connect();
try {
return await client.query(sql);
} finally {
client.release();
}
Symptom: API keys visible in logs, error messages, or responses Detection: If grep finds credentials in logs or error responses Fix: Sanitize all outputs and use secure environment variable loading
// ❌ Detection rule: Secrets in error messages
throw new Error(`API call failed with key ${apiKey}`);
// ✅ Fix: Sanitized errors
throw new Error(`API call failed: ${error.message.replace(apiKey, '[REDACTED]')}`);
Symptom: External API returns 429 errors, causing tool failures Detection: If >10% of external API calls return rate limit errors Fix: Implement exponential backoff and circuit breaker pattern
// ❌ Detection: No rate limiting
await fetch(url, { headers: { 'Authorization': `Bearer ${token}` } });
// ✅ Fix: Rate limiting with backoff
if (!rateLimiter.canProceed(url, 100, 60000)) {
await exponentialBackoff(() => fetch(url, options));
}
Symptom: Tools succeed but produce incorrect or incomplete results Detection: If tool success rate is >95% but user reports failures Fix: Implement structured error handling with proper propagation
// ❌ Detection rule: Silent failures
try {
await riskyOperation();
} catch (e) {
// Silent failure
}
// ✅ Fix: Proper error handling
try {
return await riskyOperation();
} catch (error) {
throw new McpError(ErrorCode.InternalError, `Operation failed: ${error.message}`);
}
Scenario: Create an MCP tool for querying a PostgreSQL database with user data.
Step 1 - Tool Design Decision Looking at requirements: multiple query types (get user, list users, search users). Following the decision tree:
Decision: Create database-mcp with tools: get_user, list_users, search_users
Step 2 - Security Schema Design
const getUserSchema = z.object({
userId: z.string().uuid(), // Prevent SQL injection
includeDeleted: z.boolean().default(false)
});
Novice mistake: Using z.string() without validation → allows SQL injection
Expert addition: UUID validation prevents malicious input
Step 3 - Connection Management
const pool = new Pool({
connectionString: process.env.DATABASE_URL,
max: 10, // Connection limit
idleTimeoutMillis: 30000
});
Novice mistake: Creating new connection per request → resource exhaustion Expert pattern: Connection pooling with limits
Step 4 - Error Handling Strategy
async function getUser(args: unknown) {
const { userId, includeDeleted } = getUserSchema.parse(args);
const client = await pool.connect();
try {
const query = includeDeleted
? 'SELECT * FROM users WHERE id = $1'
: 'SELECT * FROM users WHERE id = $1 AND deleted_at IS NULL';
const result = await client.query(query, [userId]);
if (result.rows.length === 0) {
return { content: [{ type: "text", text: JSON.stringify({ found: false }) }] };
}
return { content: [{ type: "text", text: JSON.stringify({
found: true,
user: result.rows[0]
}) }] };
} catch (error) {
throw new McpError(ErrorCode.InternalError, `Database query failed`);
} finally {
client.release(); // Always cleanup
}
}
Novice mistake: No connection cleanup → connection leaks Expert pattern: try/finally ensures cleanup even on error
Do NOT use MCP Creator for:
skill-coach insteadagent-creator insteadscript-writer insteadbackend-architect insteadDelegate to other skills when:
security-auditorsite-reliability-engineeragent-creator for integrationdata-ai
license: Apache-2.0 NOT for unrelated tasks outside this domain.
development
Use when designing caching strategies (cache-aside, write-through, write-behind), implementing distributed locks, building rate limiters, leaderboards, real-time streams (XADD/consumer groups), pub/sub, or tuning eviction policies. Triggers: thundering-herd on cache miss, dogpile on key expiry, Redlock vs SET-NX-PX choice, sliding-window rate limiter, hot-key on a single cluster slot, big-key blowup, MULTI/EXEC across slots, KEYS in production. NOT for Redis Cluster operations/admin (different domain), embedded KV (SQLite, leveldb), in-process LRU caches, or Memcached.
tools
Drawing the `'use client'` boundary correctly in React Server Components apps (Next.js App Router, RSC frameworks) — leaf-pushing, slot composition, serialization rules, and environment poisoning prevention. Grounded in react.dev and Next.js 16 docs.
development
Use when designing rate limiting for an API, choosing between token bucket / sliding window / leaky bucket / fixed window, implementing it in Redis, deciding edge (Cloudflare/Upstash) vs origin enforcement, sizing per-user vs per-IP vs per-endpoint quotas, returning the right 429 response with Retry-After, or fixing the boundary-burst bug in fixed-window limiters. Triggers: 429 too many requests, INCR + EXPIRE, ZADD + ZREMRANGEBYSCORE + ZCARD, X-RateLimit-Remaining header, Cloudflare WAF rate limiting rules, Upstash @upstash/ratelimit, leaky bucket shaping vs policing, distributed rate limiter consistency. NOT for DDoS mitigation specifically (different scale), CAPTCHA / bot management, full WAF design, or per-user quota billing.