Skip to main content
Build Your Own MCP Server: Step-by-Step with TypeScript
Back to Blog
AI & Automation April 3, 2026 8 min readby Matthias Meyer

Build Your Own MCP Server: Step-by-Step with TypeScript

Build an MCP server in under 30 minutes: from setup through tool definition to deployment. Using the official Anthropic SDK with practical code examples.

An MCP server is a program that exposes structured tools to AI models via the standardized Model Context Protocol. Using Anthropic's official TypeScript SDK, you can build a working MCP server in under 30 minutes. This article covers every step: from setup to deployment.

MCP (Model Context Protocol) has become the de facto standard for AI tool integration since November 2024. Over 10,000 MCP servers already exist. But most developers use pre-built servers — missing the potential of building custom tools tailored to their exact needs.

What do I need to build an MCP server?

An MCP server requires three things: Node.js (version 18+), the official @modelcontextprotocol/sdk package, and an MCP-compatible client for testing (Claude Desktop, Claude Code, or Cursor).

The basic structure is simple:

mkdir my-mcp-server && cd my-mcp-server
npm init -y
npm install @modelcontextprotocol/sdk zod
npm install -D typescript @types/node
npx tsc --init

The SDK offers two transport options: stdio (local server, reads from stdin/stdout) and HTTP with SSE (remote server, runs as a web service). For getting started, we recommend stdio — it works immediately without any network setup.

How do I define tools in the MCP schema?

Tools are the core of every MCP server. A tool has a name, a description (which the AI model reads to decide whether to use the tool), and an input schema with Zod validation.

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-server",
  version: "1.0.0",
});

server.tool(
  "get_weather",
  "Get current weather data for a city",
  { city: z.string().describe("City name") },
  async ({ city }) => {
    const res = await fetch(
      `https://wttr.in/${encodeURIComponent(city)}?format=j1`
    );
    const data = await res.json();
    const temp = data.current_condition[0].temp_C;
    return {
      content: [{ type: "text", text: `${city}: ${temp}°C` }],
    };
  }
);

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

Important: The tool description determines whether the AI calls it. Write it from the model's perspective: "Get current weather data for a city" is better than "Weather API wrapper".

How do I connect the server to Claude Desktop?

After building (npx tsc), the server must be registered in the Claude Desktop config. The file is located at:

  • macOS: ~/Library/Application Support/Claude/claude_desktop_config.json
  • Windows: %APPDATA%\Claude\claude_desktop_config.json
{
  "mcpServers": {
    "my-server": {
      "command": "node",
      "args": ["/path/to/my-mcp-server/dist/index.js"]
    }
  }
}

Restart Claude Desktop. A tool icon appears in the chat — your tool is now available. Test with: "What's the weather in Berlin?"

For Claude Code, it's even simpler:

claude mcp add my-server node /path/to/dist/index.js

What are the best practices for production MCP servers?

Going from prototype to production requires five measures:

  1. Error handling: MCP tools must never crash. Catch every error and return a readable message. The AI can work with "API unreachable", but not with a stack trace.

  2. Input validation: Zod validates automatically, but define tight schemas. z.string().max(100) instead of z.string(). AI models sometimes send unexpected inputs.

  3. Timeouts: External API calls need timeouts. AbortSignal.timeout(10_000) prevents hanging requests.

  4. Logging: Use server.sendLoggingMessage() instead of console.log. This routes logs to the MCP client, not the transport stream.

  5. Rate limiting: If your server calls external APIs, implement server-side rate limiting. AI models invoke tools more aggressively than human users.

How do I deploy an MCP server remotely?

For remote deployment, switch from stdio to HTTP+SSE transport:

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

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) => {
  await transport.handlePostMessage(req, res);
});
app.listen(3100);

Clients connect via URL instead of command. In Claude Desktop:

{
  "mcpServers": {
    "my-server": {
      "url": "https://my-server.example.com/sse"
    }
  }
}

Security: Remote MCP servers need authentication. The protocol supports OAuth 2.1 — or you can use API keys in headers. Without auth, your server is publicly accessible.

Conclusion

Building your own MCP server gives you full control over what tools your AI can use. The barrier to entry is low (one npm package, one file), the potential is high. Start with a simple tool, test it in Claude Desktop, and expand step by step.

Further reading: What is the MCP Protocol? | MCP Server Architecture | MCP Tools Installation Tutorial

Matthias Meyer

Matthias Meyer

Founder & AI Architect

Full-stack developer with 10+ years of experience in web design and AI systems. Builds AI-ready websites and AI automations for SMBs and agencies.

mcptutorialtypescriptsdkserverbuild
Build Your Own MCP Server: Step-by-Step with TypeScript