PromptsApr 6, 2026·2 min read

Build Your Own MCP Server — Step-by-Step Guide

Complete guide to building a custom MCP server from scratch. Covers the protocol, TypeScript and Python SDKs, tool definition, resource management, testing, and deployment patterns.

PR
Prompt Lab · Community
Quick Use

Use it first, then decide how deep to go

This block should tell both the user and the agent what to copy, install, and apply first.

# TypeScript (recommended)
npx @anthropic/create-mcp-server my-mcp-server
cd my-mcp-server && npm run dev
# Python
pip install mcp

Your MCP server is running. Add it to .mcp.json to test with Claude Code.


Intro

The Model Context Protocol (MCP) is how AI agents like Claude Code connect to external tools and data sources. This guide walks you through building a custom MCP server from scratch — from understanding the protocol to deploying a production server. Whether you want to connect your internal APIs, databases, or SaaS tools to Claude Code, this guide covers everything. Best for developers who want to extend their AI agent with custom integrations. Works with: Claude Code, Cursor, any MCP client.


Architecture Overview

Claude Code (MCP Client)
    ↓ JSON-RPC over stdio/SSE
Your MCP Server
    ↓ Your code
External Service (API, DB, SaaS)

Three Primitives

Primitive What It Does Example
Tools Actions the agent can take create_issue, send_email
Resources Data the agent can read file://config.json, db://users
Prompts Templates for common tasks summarize_code, review_pr

TypeScript Implementation

1. Project Setup

npx @anthropic/create-mcp-server my-server
cd my-server

2. Define Tools

import { Server } from "@modelcontextprotocol/sdk/server/index.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";

const server = new Server({ name: "my-server", version: "1.0.0" }, {
  capabilities: { tools: {} }
});

server.setRequestHandler("tools/list", async () => ({
  tools: [{
    name: "create_ticket",
    description: "Create a support ticket in our system",
    inputSchema: {
      type: "object",
      properties: {
        title: { type: "string", description: "Ticket title" },
        priority: { type: "string", enum: ["low", "medium", "high"] }
      },
      required: ["title"]
    }
  }]
}));

server.setRequestHandler("tools/call", async (request) => {
  if (request.params.name === "create_ticket") {
    const { title, priority } = request.params.arguments;
    // Call your API here
    const ticket = await createTicket(title, priority);
    return { content: [{ type: "text", text: `Created ticket #${ticket.id}` }] };
  }
});

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

3. Define Resources

server.setRequestHandler("resources/list", async () => ({
  resources: [{
    uri: "config://app-settings",
    name: "Application Settings",
    mimeType: "application/json"
  }]
}));

server.setRequestHandler("resources/read", async (request) => {
  if (request.params.uri === "config://app-settings") {
    return { contents: [{ uri: request.params.uri, text: JSON.stringify(settings) }] };
  }
});

Python Implementation

from mcp.server import Server
from mcp.types import Tool, TextContent

server = Server("my-server")

@server.list_tools()
async def list_tools():
    return [Tool(
        name="search_docs",
        description="Search internal documentation",
        inputSchema={"type": "object", "properties": {"query": {"type": "string"}}, "required": ["query"]}
    )]

@server.call_tool()
async def call_tool(name: str, arguments: dict):
    if name == "search_docs":
        results = search(arguments["query"])
        return [TextContent(type="text", text=str(results))]

if __name__ == "__main__":
    import asyncio
    from mcp.server.stdio import stdio_server
    asyncio.run(stdio_server(server))

Testing

Add to .mcp.json:

{
  "mcpServers": {
    "my-server": {
      "command": "node",
      "args": ["./dist/index.js"]
    }
  }
}

Restart Claude Code and test: "Use my-server to create a ticket titled 'Fix login bug'"

Deployment Patterns

Pattern When to Use
Local stdio Dev tools, personal workflows
Docker Team-shared servers
SSE (HTTP) Remote/cloud deployment
npm package Public distribution

FAQ

Q: What is an MCP server? A: A program that exposes tools, resources, and prompts to AI agents via the Model Context Protocol — letting agents interact with external services.

Q: Which language should I use? A: TypeScript for web APIs and npm distribution. Python for data science and ML tools.

Q: How do I publish my MCP server? A: Publish to npm (npx my-mcp-server) or PyPI (pip install my-mcp-server). Add to the MCP servers registry.


🙏

Source & Thanks

Based on the MCP Specification by Anthropic.

MCP SDK — Official SDKs for TypeScript and Python

Discussion

Sign in to join the discussion.
No comments yet. Be the first to share your thoughts.

Related Assets