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:
- Tools — Functions that AI can call to perform actions (like calculations, fetching data, etc.)
- Resources — Static or dynamic data that AI can read
- 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:
| Aspect | TypeScript | Python |
|---|---|---|
| SDK | @modelcontextprotocol/sdk | mcp (fastmcp) |
| Type Safety | Native, very strong | Optional via type hints |
| Ecosystem | NPM, many async libraries | PyPI, rich data science libs |
| Learning Curve | Medium (need to understand JS + types) | Lower (simpler syntax) |
| Performance | Faster for I/O intensive tasks | Slower, but sufficient for MCP |
| Deployment | Node.js required | Python 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
| Aspect | TypeScript | Python |
|---|---|---|
| Lines of Code | ~70 | ~45 |
| Type Safety | Explicit with Zod schemas | Implicit from type hints |
| Decorator Pattern | Not used | @mcp.tool() |
| Error Handling | Explicit return objects | Simple 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.