How to Build an MCP Server with TypeScript and Python - Nayaka Yoga Pradipta
ID | EN

How to Build an MCP Server with TypeScript and Python

Monday, Dec 23, 2024

Model Context Protocol (MCP) has become the new standard for connecting AI models with external tools and data sources. If you’re a developer looking to build an MCP server, you might be wondering: should I use TypeScript or Python?

In this tutorial, we’ll build an MCP server that is functionally identical using both languages. This way, you can compare them directly and choose the stack that best fits your needs.

What Is an MCP Server?

MCP (Model Context Protocol) is an open-source protocol developed by Anthropic to allow AI assistants like Claude to communicate with external systems in a standardized way. An MCP server is an application that provides tools, resources, and prompts that can be accessed by AI.

Think of MCP like USB for AI — a universal protocol that allows various AI models to connect to various tools without requiring custom integration for each combination.

Main Components of an MCP Server

Before we start coding, understand these three main components:

  1. Tools — Functions that AI can call to perform actions (like calculations, fetching data, etc.)
  2. Resources — Static or dynamic data that AI can read
  3. Prompts — Reusable prompt templates

In this tutorial, we’ll focus on Tools as they are the most commonly used.

TypeScript vs Python for MCP: A Comparison

Before diving into code, let’s compare both ecosystems:

AspectTypeScriptPython
SDK@modelcontextprotocol/sdkmcp (fastmcp)
Type SafetyNative, very strongOptional via type hints
EcosystemNPM, many async librariesPyPI, rich data science libs
Learning CurveMedium (need to understand JS + types)Lower (simpler syntax)
PerformanceFaster for I/O intensive tasksSlower, but sufficient for MCP
DeploymentNode.js requiredPython runtime required

Both languages are fully supported by MCP and can interoperate — meaning a TypeScript server can be consumed by a Python client, and vice versa.

Part 1: MCP Server with TypeScript

Let’s start with TypeScript. We’ll create a simple MCP server with two tools:

  • calculator — Tool for basic math operations
  • get_weather — Tool to get weather info (mock data)

Step 1: Project Setup

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

Step 2: Configure TypeScript

Update your tsconfig.json:

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

Step 3: Create the MCP Server

Create src/index.ts:

import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import { z } from "zod";

// Create MCP server
const server = new McpServer({
  name: "demo-server",
  version: "1.0.0",
});

// Calculator tool
server.tool(
  "calculator",
  "Perform basic math operations",
  {
    operation: z.enum(["add", "subtract", "multiply", "divide"]),
    a: z.number(),
    b: z.number(),
  },
  async ({ operation, a, b }) => {
    let result: number;
    
    switch (operation) {
      case "add":
        result = a + b;
        break;
      case "subtract":
        result = a - b;
        break;
      case "multiply":
        result = a * b;
        break;
      case "divide":
        if (b === 0) {
          return {
            content: [{ type: "text", text: "Error: Division by zero" }],
          };
        }
        result = a / b;
        break;
    }
    
    return {
      content: [{ type: "text", text: `Result: ${result}` }],
    };
  }
);

// Weather tool (mock)
server.tool(
  "get_weather",
  "Get current weather for a city",
  {
    city: z.string(),
  },
  async ({ city }) => {
    // Mock weather data
    const weather = {
      city,
      temperature: Math.floor(Math.random() * 30) + 10,
      condition: ["Sunny", "Cloudy", "Rainy"][Math.floor(Math.random() * 3)],
    };
    
    return {
      content: [
        {
          type: "text",
          text: `Weather in ${weather.city}: ${weather.temperature}°C, ${weather.condition}`,
        },
      ],
    };
  }
);

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

main().catch(console.error);

Step 4: Build and Run

Add scripts to package.json:

{
  "scripts": {
    "build": "tsc",
    "start": "node dist/index.js"
  }
}

Build and run:

npm run build
npm start

Part 2: MCP Server with Python

Now let’s build the same server with Python using FastMCP.

Step 1: Project Setup

mkdir mcp-server-py
cd mcp-server-py
python -m venv venv
source venv/bin/activate  # On Windows: venv\Scripts\activate
pip install fastmcp

Step 2: Create the MCP Server

Create server.py:

from fastmcp import FastMCP
import random

# Create MCP server
mcp = FastMCP("demo-server")

@mcp.tool()
def calculator(operation: str, a: float, b: float) -> str:
    """Perform basic math operations.
    
    Args:
        operation: One of 'add', 'subtract', 'multiply', 'divide'
        a: First number
        b: Second number
    """
    if operation == "add":
        result = a + b
    elif operation == "subtract":
        result = a - b
    elif operation == "multiply":
        result = a * b
    elif operation == "divide":
        if b == 0:
            return "Error: Division by zero"
        result = a / b
    else:
        return f"Error: Unknown operation {operation}"
    
    return f"Result: {result}"

@mcp.tool()
def get_weather(city: str) -> str:
    """Get current weather for a city.
    
    Args:
        city: Name of the city
    """
    # Mock weather data
    temperature = random.randint(10, 40)
    conditions = ["Sunny", "Cloudy", "Rainy"]
    condition = random.choice(conditions)
    
    return f"Weather in {city}: {temperature}°C, {condition}"

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

Step 3: Run the Server

python server.py

Comparison: TypeScript vs Python

AspectTypeScriptPython
Lines of Code~70~45
Type SafetyExplicit with Zod schemasImplicit from type hints
Decorator PatternNot used@mcp.tool()
Error HandlingExplicit return objectsSimple string returns

Which Should You Choose?

Choose TypeScript if:

  • You’re building a complex server with many tools
  • Type safety is critical for your project
  • You’re already in a Node.js ecosystem
  • You need strong IDE support

Choose Python if:

  • You want rapid prototyping
  • Your tools interact with data science libraries
  • You prefer simpler, more readable code
  • You’re integrating with ML/AI pipelines

Conclusion

Both TypeScript and Python are excellent choices for building MCP servers. The “right” choice depends on your existing stack, team expertise, and project requirements.

The MCP protocol itself is language-agnostic, so you can always switch later or even run multiple servers in different languages!


Want to learn more about MCP? Check out the official documentation.