mcp-builder

Original🇺🇸 English
Translated

Use when the user needs to build MCP (Model Context Protocol) servers — tool definitions, resource management, prompt templates, transport layers, and client integration. Triggers: user says "MCP", "MCP server", "model context protocol", building tools for AI clients, creating AI integrations.

2installs
Added on

NPX Install

npx skill4agent add pixel-process-ug/superkit-agents mcp-builder

MCP Builder

Overview

Build production-quality MCP (Model Context Protocol) servers that expose tools, resources, and prompts to AI clients. This skill covers the full development lifecycle: tool definition, resource management, prompt templates, transport configuration (stdio, SSE), error handling, security hardening, testing, and client integration.

Phase 1: Design

  1. Identify capabilities to expose (tools, resources, prompts)
  2. Define tool schemas with Zod/JSON Schema
  3. Plan resource URI patterns
  4. Design error handling strategy
  5. Choose transport layer (stdio for CLI, SSE for web)
STOP — Present the capability inventory and transport choice to user for approval.

Capability Selection Decision Table

What You HaveMCP PrimitiveExample
Actions that modify stateTool
create-issue
,
send-email
,
deploy-app
Actions that read/queryTool
search-documents
,
get-status
Data the AI should readResource
config://settings
,
docs://api/endpoints
Reusable prompt patternsPrompt
code-review
,
summarize-document
Real-time data feedsResource (subscribable)
metrics://cpu/current

Transport Selection Decision Table

ContextTransportWhy
CLI tool, local client (Claude Desktop)StdioSimple, no network overhead
Web application, remote clientsSSENetwork-accessible, real-time
Both local and remoteStdio + SSESupport both use cases
High-throughput, bidirectionalWebSocket (custom)Lower latency than SSE

Phase 2: Implementation

  1. Set up MCP server project structure
  2. Implement tool handlers with input validation
  3. Implement resource providers
  4. Add prompt templates
  5. Configure transport and authentication
STOP — Run basic smoke tests before moving to hardening.

Project Structure

src/
  index.ts          # Server entry point
  tools/
    search.ts       # Tool implementations
    create.ts
  resources/
    documents.ts    # Resource providers
    config.ts
  prompts/
    review.ts       # Prompt templates
  lib/
    database.ts     # Shared utilities
    validation.ts
tests/
  tools.test.ts
  resources.test.ts
package.json
tsconfig.json

Tool Definition Pattern

typescript
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
import { z } from 'zod';

const server = new McpServer({
  name: 'my-mcp-server',
  version: '1.0.0',
});

server.tool(
  'search-documents',
  'Search documents by query. Returns matching documents with relevance scores.',
  {
    query: z.string().describe('Search query string'),
    limit: z.number().min(1).max(100).default(10).describe('Maximum results to return'),
    filter: z.object({
      type: z.enum(['article', 'page', 'note']).optional(),
      dateAfter: z.string().datetime().optional(),
    }).optional().describe('Optional filters'),
  },
  async ({ query, limit, filter }) => {
    const results = await searchEngine.search(query, { limit, ...filter });
    return {
      content: [{
        type: 'text',
        text: JSON.stringify(results, null, 2),
      }],
    };
  }
);

Tool Design Principles

PrincipleRule
Clear namingverb-noun format:
search-documents
,
create-issue
Descriptive descriptionsExplain what, when, and return value
Validated inputsZod schemas with
.describe()
on every field
Structured outputsWell-formatted text or JSON
Idempotent when possibleSame input produces same result
Actionable errorsSpecific error messages with
isError: true

Tool Response Patterns

typescript
// Text response
return { content: [{ type: 'text', text: 'Operation completed successfully' }] };

// Structured data response
return { content: [{ type: 'text', text: JSON.stringify(data, null, 2) }] };

// Multi-part response
return {
  content: [
    { type: 'text', text: `Found ${results.length} results:` },
    { type: 'text', text: results.map(r => `- ${r.title}: ${r.summary}`).join('\n') },
  ],
};

// Image response
return { content: [{ type: 'image', data: base64Data, mimeType: 'image/png' }] };

// Error response
return {
  content: [{ type: 'text', text: `Error: ${error.message}` }],
  isError: true,
};

Resource Management

Resource Definition

typescript
// Static resource
server.resource(
  'config',
  'config://app/settings',
  { mimeType: 'application/json' },
  async () => ({
    contents: [{
      uri: 'config://app/settings',
      mimeType: 'application/json',
      text: JSON.stringify(appConfig),
    }],
  })
);

// Dynamic resource with URI template
server.resource(
  'document',
  new ResourceTemplate('docs://{category}/{id}', { list: undefined }),
  { mimeType: 'text/markdown' },
  async (uri, { category, id }) => ({
    contents: [{
      uri: uri.href,
      mimeType: 'text/markdown',
      text: await getDocument(category, id),
    }],
  })
);

Resource URI Conventions

file:///path/to/file          — Local files
https://api.example.com/data  — Remote HTTP resources
db://database/table/id        — Database records
config://app/settings         — Configuration
docs://category/slug          — Documentation

Prompt Templates

typescript
server.prompt(
  'code-review',
  'Generate a code review for the given file',
  {
    filePath: z.string().describe('Path to the file to review'),
    severity: z.enum(['strict', 'normal', 'lenient']).default('normal'),
  },
  async ({ filePath, severity }) => {
    const code = await readFile(filePath, 'utf-8');
    return {
      messages: [{
        role: 'user',
        content: {
          type: 'text',
          text: `Review this code with ${severity} standards:\n\n\`\`\`\n${code}\n\`\`\``,
        },
      }],
    };
  }
);

Transport Layers

Stdio Transport (CLI tools, local development)

typescript
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';

const transport = new StdioServerTransport();
await server.connect(transport);

SSE Transport (Web applications, remote servers)

typescript
import express from 'express';
import { SSEServerTransport } from '@modelcontextprotocol/sdk/server/sse.js';

const app = express();

app.get('/sse', async (req, res) => {
  const transport = new SSEServerTransport('/messages', res);
  await server.connect(transport);
});

app.post('/messages', async (req, res) => {
  // Handle incoming messages
});

app.listen(3001);

Phase 3: Hardening

  1. Add comprehensive error handling
  2. Implement rate limiting and timeouts
  3. Security review (input sanitization, permission checks)
  4. Write integration tests
  5. Document tools and resources for clients
STOP — All tests must pass and security review must be complete before deployment.

Error Handling

typescript
server.tool('risky-operation', 'Performs an operation that might fail', {
  input: z.string(),
}, async ({ input }) => {
  try {
    const result = await performOperation(input);
    return { content: [{ type: 'text', text: JSON.stringify(result) }] };
  } catch (error) {
    if (error instanceof ValidationError) {
      return {
        content: [{ type: 'text', text: `Invalid input: ${error.message}` }],
        isError: true,
      };
    }
    if (error instanceof NotFoundError) {
      return {
        content: [{ type: 'text', text: `Resource not found: ${error.message}` }],
        isError: true,
      };
    }
    console.error('Unexpected error:', error);
    return {
      content: [{ type: 'text', text: 'An unexpected error occurred. Please try again.' }],
      isError: true,
    };
  }
});

Error Handling Rules

RuleWhy
Never expose stack traces to clientsSecurity risk
Return
isError: true
for all errors
Client can distinguish success/failure
Log unexpected errors server-sideDebugging and monitoring
Provide actionable error messagesClient can self-correct
Handle timeouts for external callsPrevent hanging requests
Validate all inputs before processingReject bad data early

Security Considerations

CategoryRules
Input validationZod schemas, path traversal prevention, length limits
Permission modelLeast privilege, whitelist directories, separate read/write tools
SecretsEnv vars only, never in responses, mask in logs, rotate regularly
Rate limitingLimit tool invocations per client
AuditingLog all tool calls with timestamps

Testing MCP Servers

typescript
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
import { InMemoryTransport } from '@modelcontextprotocol/sdk/inMemory.js';
import { Client } from '@modelcontextprotocol/sdk/client/index.js';

describe('MCP Server', () => {
  let server: McpServer;
  let client: Client;

  beforeEach(async () => {
    server = createServer();
    client = new Client({ name: 'test-client', version: '1.0.0' });
    const [clientTransport, serverTransport] = InMemoryTransport.createLinkedPair();
    await Promise.all([
      server.connect(serverTransport),
      client.connect(clientTransport),
    ]);
  });

  test('search-documents returns results', async () => {
    const result = await client.callTool({
      name: 'search-documents',
      arguments: { query: 'test', limit: 5 },
    });
    expect(result.content[0].type).toBe('text');
    const data = JSON.parse(result.content[0].text);
    expect(data.length).toBeLessThanOrEqual(5);
  });

  test('handles invalid input gracefully', async () => {
    const result = await client.callTool({
      name: 'search-documents',
      arguments: { query: '', limit: -1 },
    });
    expect(result.isError).toBe(true);
  });
});

Client Integration

Claude Desktop Configuration

json
{
  "mcpServers": {
    "my-server": {
      "command": "node",
      "args": ["/path/to/server/dist/index.js"],
      "env": {
        "API_KEY": "your-key-here"
      }
    }
  }
}

Anti-Patterns / Common Mistakes

Anti-PatternWhy It Is WrongWhat to Do Instead
Tools that do too many thingsHard to use, hard to testSplit into focused single-purpose tools
Missing input validationCrashes, security holesAlways use Zod schemas
Returning raw stack tracesSecurity risk, confusing for AIReturn
isError: true
with clean message
No timeout on external callsHangs indefinitelySet timeouts on all I/O
Hardcoded secrets in sourceCredential exposureUse environment variables
Tools without descriptionsClients cannot discover purposeWrite clear descriptions
Blocking event loop with sync opsServer becomes unresponsiveUse async/await for all I/O
No testsRegressions go undetectedTest with InMemoryTransport

Documentation Lookup (Context7)

Use
mcp__context7__resolve-library-id
then
mcp__context7__query-docs
for up-to-date docs. Returned docs override memorized knowledge.
  • @anthropic-ai/sdk
    — for Claude API client, tool definitions, or streaming

Integration Points

SkillIntegration
senior-devops
Containerize and deploy MCP servers
agent-development
MCP servers provide tools for agents
security-review
Security hardening of tool inputs/outputs
test-driven-development
TDD for tool implementation
deployment
CI/CD pipeline for MCP server releases
planning
MCP server design is part of the implementation plan

Skill Type

FLEXIBLE — Adapt project structure, transport choice, and tooling to the use case. Tool validation with Zod and error handling with
isError
are strongly recommended. Security review is recommended before production deployment.