Claude
Skills
Sign in
Back

mcp-server-builder

Included with Lifetime
$97 forever

Builds Model Context Protocol (MCP) servers for Claude with tools, resources, and prompts. Use when users request "create MCP server", "build Claude tool", "MCP integration", or "custom Claude tools".

AI Agents

What this skill does


# MCP Server Builder

Create Model Context Protocol servers to extend Claude's capabilities with custom tools and resources.

## Core Workflow

1. **Define purpose**: Identify what capabilities to add
2. **Choose transport**: stdio (local) or HTTP/SSE (remote)
3. **Design tools**: Define tool schemas and handlers
4. **Add resources**: Optional file/data access
5. **Create prompts**: Optional reusable prompts
6. **Test locally**: Verify with MCP inspector
7. **Deploy**: Configure for Claude Desktop or API

## MCP Architecture Overview

```
┌─────────────┐     MCP Protocol      ┌─────────────┐
│   Claude    │◄────────────────────►│ MCP Server  │
│   (Host)    │  JSON-RPC over stdio  │  (Your App) │
└─────────────┘                       └─────────────┘
                                            │
                                            ▼
                                      ┌───────────┐
                                      │  Tools    │
                                      │ Resources │
                                      │  Prompts  │
                                      └───────────┘
```

## Project Setup

### TypeScript MCP Server

```bash
# Create project
mkdir my-mcp-server && cd my-mcp-server
npm init -y

# Install dependencies
npm install @modelcontextprotocol/sdk zod

# Dev dependencies
npm install -D typescript @types/node tsx
```

```json
// package.json
{
  "name": "my-mcp-server",
  "version": "1.0.0",
  "type": "module",
  "main": "dist/index.js",
  "bin": {
    "my-mcp-server": "./dist/index.js"
  },
  "scripts": {
    "build": "tsc",
    "dev": "tsx watch src/index.ts",
    "start": "node dist/index.js"
  }
}
```

```json
// tsconfig.json
{
  "compilerOptions": {
    "target": "ES2022",
    "module": "NodeNext",
    "moduleResolution": "NodeNext",
    "outDir": "./dist",
    "rootDir": "./src",
    "strict": true,
    "esModuleInterop": true,
    "skipLibCheck": true,
    "declaration": true
  },
  "include": ["src/**/*"]
}
```

## Basic Server Structure

```typescript
// src/index.ts
#!/usr/bin/env node

import { Server } from "@modelcontextprotocol/sdk/server/index.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import {
  CallToolRequestSchema,
  ListToolsRequestSchema,
  ListResourcesRequestSchema,
  ReadResourceRequestSchema,
  ListPromptsRequestSchema,
  GetPromptRequestSchema,
} from "@modelcontextprotocol/sdk/types.js";

// Create server instance
const server = new Server(
  {
    name: "my-mcp-server",
    version: "1.0.0",
  },
  {
    capabilities: {
      tools: {},
      resources: {},
      prompts: {},
    },
  }
);

// Define tools
const TOOLS = [
  {
    name: "get_weather",
    description: "Get current weather for a location",
    inputSchema: {
      type: "object" as const,
      properties: {
        location: {
          type: "string",
          description: "City name or coordinates",
        },
        units: {
          type: "string",
          enum: ["celsius", "fahrenheit"],
          default: "celsius",
        },
      },
      required: ["location"],
    },
  },
  {
    name: "search_database",
    description: "Search the internal database",
    inputSchema: {
      type: "object" as const,
      properties: {
        query: {
          type: "string",
          description: "Search query",
        },
        limit: {
          type: "number",
          default: 10,
        },
      },
      required: ["query"],
    },
  },
];

// List tools handler
server.setRequestHandler(ListToolsRequestSchema, async () => {
  return { tools: TOOLS };
});

// Call tool handler
server.setRequestHandler(CallToolRequestSchema, async (request) => {
  const { name, arguments: args } = request.params;

  switch (name) {
    case "get_weather": {
      const { location, units = "celsius" } = args as {
        location: string;
        units?: string;
      };

      // Implement your logic here
      const weather = await fetchWeather(location, units);

      return {
        content: [
          {
            type: "text",
            text: JSON.stringify(weather, null, 2),
          },
        ],
      };
    }

    case "search_database": {
      const { query, limit = 10 } = args as { query: string; limit?: number };

      const results = await searchDatabase(query, limit);

      return {
        content: [
          {
            type: "text",
            text: JSON.stringify(results, null, 2),
          },
        ],
      };
    }

    default:
      throw new Error(`Unknown tool: ${name}`);
  }
});

// Start server
async function main() {
  const transport = new StdioServerTransport();
  await server.connect(transport);
  console.error("MCP Server running on stdio");
}

main().catch(console.error);

// Helper functions (implement your logic)
async function fetchWeather(location: string, units: string) {
  // Your implementation
  return { location, temperature: 22, units, condition: "sunny" };
}

async function searchDatabase(query: string, limit: number) {
  // Your implementation
  return { query, results: [], total: 0 };
}
```

## Tools

### Tool Schema Definition

```typescript
// src/tools/index.ts
import { z } from "zod";

// Define input schemas with Zod for validation
export const GetWeatherSchema = z.object({
  location: z.string().describe("City name or coordinates"),
  units: z.enum(["celsius", "fahrenheit"]).default("celsius"),
});

export const SearchSchema = z.object({
  query: z.string().min(1).describe("Search query"),
  filters: z
    .object({
      category: z.string().optional(),
      dateFrom: z.string().optional(),
      dateTo: z.string().optional(),
    })
    .optional(),
  limit: z.number().min(1).max(100).default(10),
});

// Convert Zod schema to JSON Schema for MCP
export function zodToJsonSchema(schema: z.ZodObject<any>) {
  // Use zod-to-json-schema package in production
  return schema;
}
```

### Tool Handler Pattern

```typescript
// src/tools/handlers.ts
import { z } from "zod";

type ToolHandler<T extends z.ZodSchema> = (
  args: z.infer<T>
) => Promise<{ content: Array<{ type: string; text: string }> }>;

export function createToolHandler<T extends z.ZodSchema>(
  schema: T,
  handler: (args: z.infer<T>) => Promise<any>
): ToolHandler<T> {
  return async (rawArgs) => {
    // Validate input
    const args = schema.parse(rawArgs);

    // Execute handler
    const result = await handler(args);

    // Format response
    return {
      content: [
        {
          type: "text",
          text: typeof result === "string" ? result : JSON.stringify(result, null, 2),
        },
      ],
    };
  };
}

// Usage
export const handleGetWeather = createToolHandler(
  GetWeatherSchema,
  async ({ location, units }) => {
    const response = await fetch(
      `https://api.weather.com/v1/current?location=${location}&units=${units}`
    );
    return response.json();
  }
);
```

## Resources

### Static Resources

```typescript
// src/resources/index.ts
const RESOURCES = [
  {
    uri: "config://app-settings",
    name: "Application Settings",
    description: "Current application configuration",
    mimeType: "application/json",
  },
  {
    uri: "file://docs/readme",
    name: "Documentation",
    description: "Project documentation",
    mimeType: "text/markdown",
  },
];

// List resources handler
server.setRequestHandler(ListResourcesRequestSchema, async () => {
  return { resources: RESOURCES };
});

// Read resource handler
server.setRequestHandler(ReadResourceRequestSchema, async (request) => {
  const { uri } = request.params;

  switch (uri) {
    case "config://app-settings":
      return {
        contents: [
          {
            uri,
            mimeType: "application/json",
            text: JSON.stringify(getAppSettings(), null, 2),
          },
        ],
      };

    case "file://docs/readme":
      const content = await fs.readFile("./README.md", "utf-8");
      return {
        contents: [
          {
            

Related in AI Agents