M

Mcp Builder Expert

Comprehensive skill designed for guide, creating, high, quality. Includes structured workflows, validation checks, and reusable patterns for development.

SkillClipticsdevelopmentv1.0.0MIT
0 views0 copies

MCP Server Builder Skill

A Claude Code skill for building production-quality Model Context Protocol (MCP) servers — covering tool design, resource exposure, transport configuration, authentication, error handling, and deployment.

When to Use This Skill

Choose this skill when:

  • Building a new MCP server to expose tools and data to LLMs
  • Designing tool interfaces for Claude Code integration
  • Implementing resource endpoints for data access
  • Adding authentication and authorization to MCP servers
  • Deploying MCP servers to production environments
  • Testing and debugging MCP server implementations

Consider alternatives when:

  • You need to use existing MCP tools, not build them (use MCP client)
  • You need a REST/GraphQL API without MCP (use a web framework)
  • You need to modify Claude Code's built-in tools (not possible via MCP)

Quick Start

# TypeScript MCP Server npm init -y npm install @modelcontextprotocol/sdk zod
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'; import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js'; import { z } from 'zod'; const server = new McpServer({ name: 'my-data-server', version: '1.0.0', }); // Define a tool server.tool( 'query_database', 'Execute a read-only SQL query against the analytics database', { sql: z.string().describe('SQL query to execute (SELECT only)'), limit: z.number().default(100).describe('Maximum rows to return'), }, async ({ sql, limit }) => { if (!sql.trim().toUpperCase().startsWith('SELECT')) { return { content: [{ type: 'text', text: 'Error: Only SELECT queries allowed' }] }; } const results = await db.query(sql, { limit }); return { content: [{ type: 'text', text: JSON.stringify(results, null, 2) }] }; } ); // Define a resource server.resource('schema://tables', 'Database schema information', async () => ({ contents: [{ uri: 'schema://tables', text: JSON.stringify(await db.getSchema()) }] })); // Start server const transport = new StdioServerTransport(); await server.connect(transport);

Core Concepts

MCP Components

ComponentPurposeExample
ToolsFunctions the LLM can callquery_database, send_email, create_ticket
ResourcesRead-only data endpointsschema://tables, config://app, docs://api
PromptsReusable prompt templatessummarize_data, explain_error

Tool Design Patterns

// Pattern: Tool with validation and structured response server.tool( 'create_ticket', 'Create a support ticket in the ticketing system', { title: z.string().min(5).max(200).describe('Ticket title'), description: z.string().describe('Detailed description of the issue'), priority: z.enum(['low', 'medium', 'high', 'critical']).describe('Ticket priority'), assignee: z.string().optional().describe('Team member to assign'), }, async ({ title, description, priority, assignee }) => { const ticket = await ticketService.create({ title, description, priority, assignee }); return { content: [{ type: 'text', text: `Created ticket #${ticket.id}: ${ticket.title}\nStatus: ${ticket.status}\nPriority: ${ticket.priority}` }] }; } ); // Pattern: Tool with error handling server.tool('fetch_metrics', 'Get application metrics for a time range', { metric: z.string().describe('Metric name (e.g., cpu_usage, memory, requests)'), period: z.enum(['1h', '24h', '7d', '30d']).describe('Time period'), }, async ({ metric, period }) => { try { const data = await metricsService.query(metric, period); return { content: [{ type: 'text', text: formatMetrics(data) }] }; } catch (error) { return { content: [{ type: 'text', text: `Error fetching ${metric}: ${error.message}` }], isError: true }; } });

Configuration

ParameterTypeDefaultDescription
namestringServer name (required)
versionstring"1.0.0"Server version
transportstring"stdio"Transport: stdio, sse, streamable-http
authstring"none"Authentication: none, token, oauth
max_concurrentnumber10Maximum concurrent tool calls
timeoutnumber30000Tool execution timeout (ms)
log_levelstring"info"Logging: debug, info, warn, error

Best Practices

  1. Write detailed tool descriptions — the LLM decides when and how to call tools based on descriptions; include when to use the tool, what it returns, and any important constraints.

  2. Use Zod schemas with .describe() on every parameter — parameter descriptions help the LLM provide correct inputs; without them, the LLM guesses at parameter meanings.

  3. Return structured data, not formatted text — return JSON or structured strings so the LLM can interpret and present the data appropriately for the user's question.

  4. Handle errors gracefully with isError: true — return error messages as content with the error flag instead of throwing exceptions; this gives the LLM information to respond helpfully.

  5. Make tools idempotent when possible — tools that can be safely called multiple times with the same input simplify error recovery; the LLM may retry failed tool calls.

Common Issues

LLM calls the wrong tool — Tool descriptions are too similar. Differentiate descriptions clearly and include "Use this when..." guidance. Avoid generic names like getData — be specific like get_user_profile.

Tool timeout on long operations — Increase the timeout for specific tools or use progress reporting. Consider breaking long operations into multiple smaller tools that can be called sequentially.

Server crashes on malformed input — Even with Zod validation, edge cases can cause issues. Wrap tool handlers in try-catch and return error content instead of crashing the server.

Community

Reviews

Write a review

No reviews yet. Be the first to review this template!

Similar Templates