# How to Create MCP Servers Using the mcp-builder Skill: A Complete Guide

> Learn to build MCP servers with the mcp-builder skill. This guide covers Python or Node/TypeScript, input validation, annotations, and transport config for your custom servers.

- Repository: [Anthropic/skills](https://github.com/anthropics/skills)
- Tags: how-to-guide
- Published: 2026-02-16

---

**The mcp-builder skill in the anthropics/skills repository provides ready-made templates for building Model Context Protocol (MCP) servers in Python or Node/TypeScript, complete with input validation, tool annotations, and transport configuration.**

If you want to extend AI assistants with custom tools that interact with external APIs or data sources, the mcp-builder skill offers a standardized foundation. This guide walks you through creating production-ready MCP servers using the official templates, referencing specific implementation details from [`skills/mcp-builder/reference/python_mcp_server.md`](https://github.com/anthropics/skills/blob/main/skills/mcp-builder/reference/python_mcp_server.md) and [`skills/mcp-builder/reference/node_mcp_server.md`](https://github.com/anthropics/skills/blob/main/skills/mcp-builder/reference/node_mcp_server.md).

## What Is the mcp-builder Skill?

The mcp-builder skill is a scaffolding system located in the `anthropics/skills` repository under `skills/mcp-builder/`. It provides complete reference implementations for building MCP servers in two languages:

- **Python**: Uses the `FastMCP` class from the `mcp>=1.1.0` SDK with Pydantic v2 for input validation
- **Node/TypeScript**: Uses the `McpServer` class from `@modelcontextprotocol/sdk` with Zod schemas for type safety

The skill includes best-practice checklists in [`skills/mcp-builder/SKILL.md`](https://github.com/anthropics/skills/blob/main/skills/mcp-builder/SKILL.md), helper scripts for testing in `skills/mcp-builder/scripts/`, and detailed reference guides for each language.

## Prerequisites and Installation

Before creating an MCP server with the mcp-builder skill, install the appropriate SDK and dependencies for your chosen language.

### Python Setup

Install the MCP SDK and Pydantic v2:

```bash
pip install "mcp>=1.1.0" pydantic httpx

```

The [`skills/mcp-builder/scripts/requirements.txt`](https://github.com/anthropics/skills/blob/main/skills/mcp-builder/scripts/requirements.txt) file specifies `mcp>=1.1.0` as the minimum version for Python implementations.

### Node/TypeScript Setup

Initialize your project and install the required packages:

```bash
npm init -y
npm install @modelcontextprotocol/sdk zod axios
npm install --save-dev typescript @types/node

```

The Node reference guide in [`skills/mcp-builder/reference/node_mcp_server.md`](https://github.com/anthropics/skills/blob/main/skills/mcp-builder/reference/node_mcp_server.md) uses these specific packages for SDK functionality, schema validation, and HTTP requests.

## Step-by-Step Guide to Creating an MCP Server

Follow these steps to implement a complete MCP server using the mcp-builder skill templates.

### Step 1: Choose Your Service Name and Follow Naming Conventions

The mcp-builder skill enforces specific naming conventions based on your language choice:

- **Python**: Use `{service}_mcp` in snake_case (e.g., `github_mcp`, `slack_mcp`)
- **Node/TypeScript**: Use `{service}-mcp-server` in kebab-case (e.g., `github-mcp-server`, `slack-mcp-server`)

These conventions appear in [`skills/mcp-builder/reference/python_mcp_server.md`](https://github.com/anthropics/skills/blob/main/skills/mcp-builder/reference/python_mcp_server.md) and [`skills/mcp-builder/reference/node_mcp_server.md`](https://github.com/anthropics/skills/blob/main/skills/mcp-builder/reference/node_mcp_server.md) respectively.

### Step 2: Initialize the Server

Create your server instance with the appropriate class from the MCP SDK.

**Python (FastMCP):**

```python
from mcp.server.fastmcp import FastMCP

mcp = FastMCP("example_mcp")

```

**Node/TypeScript (McpServer):**

```typescript
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";

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

```

### Step 3: Define Input Validation Models

Input validation ensures type safety and provides clear error messages to AI models.

**Python with Pydantic v2:**

```python
from pydantic import BaseModel, Field, ConfigDict
from typing import Optional

class UserSearchInput(BaseModel):
    model_config = ConfigDict(str_strip_whitespace=True, validate_assignment=True, extra="forbid")
    
    query: str = Field(..., description="Search string", min_length=2, max_length=200)
    limit: Optional[int] = Field(default=20, ge=1, le=100)
    offset: Optional[int] = Field(default=0, ge=0)
    response_format: str = Field(default="markdown")

```

**Node/TypeScript with Zod:**

```typescript
import { z } from "zod";

const UserSearchInputSchema = z.object({
  query: z.string().min(2).max(200),
  limit: z.number().int().min(1).max(100).default(20),
  offset: z.number().int().min(0).default(0),
  response_format: z.enum(["markdown", "json"]).default("markdown")
}).strict();

type UserSearchInput = z.infer<typeof UserSearchInputSchema>;

```

### Step 4: Register Tools with Annotations

Tool annotations inform AI models about the behavior and safety characteristics of your tools.

**Python:**

```python
@mcp.tool(
    name="example_search_users",
    annotations={
        "readOnlyHint": True,
        "destructiveHint": False,
        "idempotentHint": True,
        "openWorldHint": True,
    }
)
async def example_search_users(params: UserSearchInput) -> str:
    """Search users – returns markdown or JSON."""
    # Implementation here

    return "results"

```

**Node/TypeScript:**

```typescript
server.registerTool(
  "example_search_users",
  {
    title: "Search Example Users",
    description: "Search users by name/email/team; returns markdown or JSON.",
    inputSchema: UserSearchInputSchema,
    annotations: {
      readOnlyHint: true,
      destructiveHint: false,
      idempotentHint: true,
      openWorldHint: true
    }
  },
  async (params: UserSearchInput) => {
    // Implementation here
    return { content: [{ type: "text", text: "results" }] };
  }
);

```

The four annotation hints are defined in the reference guides:
- **readOnlyHint**: Indicates the tool does not modify external state
- **destructiveHint**: Indicates the tool does not delete or damage data
- **idempotentHint**: Indicates re-calling the tool has no extra effect
- **openWorldHint**: Set to `true` only if the tool calls external APIs the model cannot control

### Step 5: Choose a Transport Protocol

The mcp-builder skill supports two transport methods:

**stdio (default)**: For local execution and subprocess integration
**streamable_http**: For remote HTTP services and multiple clients

**Python stdio:**

```python
if __name__ == "__main__":
    mcp.run()

```

**Python HTTP:**

```python
if __name__ == "__main__":
    mcp.run(transport="streamable_http", port=8000)

```

**Node/TypeScript stdio:**

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

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

```

**Node/TypeScript HTTP:**

```typescript
import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";

const transport = new StreamableHTTPServerTransport();
// Additional Express setup required as shown in node_mcp_server.md

```

### Step 6: Run the Server

**Python:**

```bash
python example_mcp.py

```

**Node/TypeScript:**

```bash
npm run build
node dist/index.js

```

Or for HTTP transport:

```bash
TRANSPORT=http node dist/index.js

```

## Working with Resources and Lifecycles

Beyond tools, MCP servers can expose resources and manage persistent connections through lifecycle hooks.

### Registering Static Resources

Resources provide read-only access to files or data URIs.

**Python:**

```python
@mcp.resource("file://documents/{name}")
async def get_document(name: str) -> str:
    with open(f"./docs/{name}") as f:
        return f.read()

```

**Node/TypeScript:**

```typescript
server.registerResource(
  {
    uri: "file://documents/{name}",
    name: "Document Resource",
    description: "Access documents by name",
    mimeType: "text/plain"
  },
  async (uri: string) => {
    const name = uri.split("/").pop()!;
    const content = await Deno.readTextFile(`./docs/${name}`);
    return { contents: [{ uri, mimeType: "text/plain", text: content }] };
  }
);

```

### Managing Connection Lifecycles

Use lifespan hooks for persistent connections like database pools.

**Python:**

```python
from contextlib import asynccontextmanager

@asynccontextmanager
async def app_lifespan():
    db = await asyncpg.create_pool(...)
    yield {"db": db}
    await db.close()

mcp = FastMCP("example_mcp", lifespan=app_lifespan)

```

**Node/TypeScript:**

```typescript
const lifespan = async () => {
  const db = await connectDb();
  return { db };
};

const server = new McpServer({ 
  name: "example-mcp", 
  version: "1.0.0", 
  lifespan 
});

```

## Testing and Evaluation

The mcp-builder skill includes utilities for testing your implementation.

The [`skills/mcp-builder/scripts/connections.py`](https://github.com/anthropics/skills/blob/main/skills/mcp-builder/scripts/connections.py) file provides examples for creating MCP client sessions to test your server interactively. For automated evaluation, use [`skills/mcp-builder/scripts/evaluation.py`](https://github.com/anthropics/skills/blob/main/skills/mcp-builder/scripts/evaluation.py), which offers a CLI helper for evaluating an MCP server against a task XML file.

Before shipping, consult the best-practice checklist in [`skills/mcp-builder/SKILL.md`](https://github.com/anthropics/skills/blob/main/skills/mcp-builder/SKILL.md). This comprehensive checklist covers strategic design, implementation quality, TypeScript-specific rules, advanced features, project configuration, and testing requirements.

## Summary

- The **mcp-builder skill** provides complete scaffolding for MCP servers in Python (FastMCP) and Node/TypeScript (McpServer)
- **Naming conventions** differ by language: use `{service}_mcp` for Python and `{service}-mcp-server` for Node
- **Input validation** uses Pydantic v2 models in Python and Zod schemas in TypeScript
- **Tool annotations** (`readOnlyHint`, `destructiveHint`, `idempotentHint`, `openWorldHint`) are required to inform AI models about tool behavior
- **Transport options** include `stdio` for local execution and `streamable_http` for remote services
- Reference implementations are available in [`skills/mcp-builder/reference/python_mcp_server.md`](https://github.com/anthropics/skills/blob/main/skills/mcp-builder/reference/python_mcp_server.md) and [`skills/mcp-builder/reference/node_mcp_server.md`](https://github.com/anthropics/skills/blob/main/skills/mcp-builder/reference/node_mcp_server.md)

## Frequently Asked Questions

### What is the difference between FastMCP and McpServer?

**FastMCP** is the Python SDK class (`from mcp.server.fastmcp import FastMCP`) that provides a decorator-based approach for registering tools and resources. **McpServer** is the Node/TypeScript SDK class (`from "@modelcontextprotocol/sdk/server/mcp.js"`) that uses explicit method calls like `server.registerTool()`. Both implement the same Model Context Protocol but follow language-specific idioms—Python uses Pydantic for validation while Node uses Zod.

### How do I choose between stdio and HTTP transport?

Use **stdio** transport when your MCP server runs as a local subprocess integrated with desktop AI applications like Claude Desktop. This is the default and most common configuration. Use **streamable_http** transport when deploying your server as a remote service accessible to multiple clients over the network, or when you need to integrate with existing HTTP infrastructure. The Python SDK supports `mcp.run(transport="streamable_http", port=8000)`, while Node requires instantiating `StreamableHTTPServerTransport`.

### What are the required tool annotations and what do they mean?

Every tool registered with the mcp-builder skill must include four boolean annotations defined in [`skills/mcp-builder/reference/python_mcp_server.md`](https://github.com/anthropics/skills/blob/main/skills/mcp-builder/reference/python_mcp_server.md) and [`skills/mcp-builder/reference/node_mcp_server.md`](https://github.com/anthropics/skills/blob/main/skills/mcp-builder/reference/node_mcp_server.md): **readOnlyHint** (true if the tool doesn't modify external state), **destructiveHint** (true if the tool deletes or damages data), **idempotentHint** (true if calling multiple times has the same effect as once), and **openWorldHint** (true only if the tool calls external APIs the model cannot control). These hints help AI models understand tool safety and side effects.

### Where can I find the complete reference documentation for implementing MCP servers?

The complete reference documentation is located in the `skills/mcp-builder/reference/` directory of the anthropics/skills repository. For Python implementations, see [`skills/mcp-builder/reference/python_mcp_server.md`](https://github.com/anthropics/skills/blob/main/skills/mcp-builder/reference/python_mcp_server.md), which covers FastMCP initialization, Pydantic validation, decorators, and transports. For Node/TypeScript, see [`skills/mcp-builder/reference/node_mcp_server.md`](https://github.com/anthropics/skills/blob/main/skills/mcp-builder/reference/node_mcp_server.md), which details McpServer setup, Zod schemas, and HTTP transport configuration. Both files contain production-ready code examples and implementation patterns.