Tutorial Membuat MCP Server dengan TypeScript dan Python
Senin, 23 Des 2024
Model Context Protocol (MCP) telah menjadi standar baru dalam menghubungkan AI models dengan external tools dan data sources. Kalau kamu developer yang ingin membangun MCP server, pasti bertanya-tanya: lebih baik pakai TypeScript atau Python?
Dalam tutorial ini, kita akan membangun MCP server yang identik secara fungsional menggunakan kedua bahasa. Dengan begitu, kamu bisa membandingkan secara langsung dan memilih stack yang paling cocok untuk kebutuhanmu.
Apa Itu MCP Server?
MCP (Model Context Protocol) adalah protokol open-source yang dikembangkan oleh Anthropic untuk memungkinkan AI assistants seperti Claude berkomunikasi dengan external systems secara standardized. MCP server adalah aplikasi yang menyediakan tools, resources, dan prompts yang bisa diakses oleh AI.
Bayangkan MCP seperti USB untuk AI — satu protokol universal yang memungkinkan berbagai AI models terhubung ke berbagai tools tanpa perlu custom integration untuk setiap kombinasi.
Komponen Utama MCP Server
Sebelum kita mulai coding, pahami dulu tiga komponen utama:
- Tools — Fungsi yang bisa dipanggil AI untuk melakukan aksi (seperti menghitung, fetch data, dll)
- Resources — Data statis atau dinamis yang bisa dibaca AI
- Prompts — Template prompt yang bisa di-reuse
Dalam tutorial ini, kita fokus pada Tools karena ini yang paling sering digunakan.
Perbandingan TypeScript vs Python untuk MCP
Sebelum masuk ke code, mari kita lihat perbandingan kedua ecosystem:
| Aspek | TypeScript | Python |
|---|---|---|
| SDK | @modelcontextprotocol/sdk | mcp (fastmcp) |
| Type Safety | Native, sangat kuat | Optional via type hints |
| Ecosystem | NPM, banyak async libraries | PyPI, rich data science libs |
| Learning Curve | Medium (perlu paham JS + types) | Lower (syntax lebih simpel) |
| Performance | Lebih cepat untuk I/O intensive | Lebih lambat, tapi cukup untuk MCP |
| Deployment | Node.js required | Python runtime required |
Kedua bahasa sama-sama fully supported oleh MCP dan bisa interoperate — artinya TypeScript server bisa dikonsumsi Python client, dan sebaliknya.
Part 1: MCP Server dengan TypeScript
Mari kita mulai dengan TypeScript. Kita akan membuat MCP server sederhana dengan dua tools:
- calculator — Tool untuk operasi matematika dasar
- get_weather — Tool untuk mendapatkan info cuaca (mock data)
Step 1: Setup Project
Buat folder baru dan inisialisasi project:
mkdir mcp-server-typescript
cd mcp-server-typescript
npm init -y
Install dependencies yang diperlukan:
npm install @modelcontextprotocol/sdk zod
npm install -D typescript @types/node tsx
Penjelasan packages:
@modelcontextprotocol/sdk— Official MCP SDK untuk TypeScriptzod— Library untuk schema validation (digunakan untuk mendefinisikan input tools)typescript— TypeScript compilertsx— Runner untuk menjalankan TypeScript langsung
Step 2: Konfigurasi TypeScript
Buat file tsconfig.json:
{
"compilerOptions": {
"target": "ES2022",
"module": "NodeNext",
"moduleResolution": "NodeNext",
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true,
"outDir": "./dist",
"rootDir": "./src"
},
"include": ["src/**/*"]
}
Update package.json untuk menambahkan type module dan scripts:
{
"name": "mcp-server-typescript",
"version": "1.0.0",
"type": "module",
"scripts": {
"start": "tsx src/index.ts",
"build": "tsc"
}
}
Step 3: Membuat MCP Server
Buat folder src dan file src/index.ts:
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import { z } from "zod";
// Inisialisasi MCP Server
const server = new McpServer({
name: "demo-server",
version: "1.0.0",
});
// Tool 1: Calculator
// Mendefinisikan schema input menggunakan Zod
const CalculatorInputSchema = z.object({
operation: z.enum(["add", "subtract", "multiply", "divide"]),
a: z.number(),
b: z.number(),
});
server.tool(
"calculator",
"Melakukan operasi matematika dasar: penjumlahan, pengurangan, perkalian, pembagian",
CalculatorInputSchema.shape,
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" as const,
text: "Error: Tidak bisa membagi dengan nol",
},
],
};
}
result = a / b;
break;
}
return {
content: [
{
type: "text" as const,
text: `Hasil ${operation}(${a}, ${b}) = ${result}`,
},
],
};
}
);
// Tool 2: Get Weather (Mock)
const WeatherInputSchema = z.object({
city: z.string().describe("Nama kota untuk mendapatkan info cuaca"),
});
server.tool(
"get_weather",
"Mendapatkan informasi cuaca untuk kota tertentu",
WeatherInputSchema.shape,
async ({ city }) => {
// Mock weather data
const weatherData: Record<string, { temp: number; condition: string }> = {
jakarta: { temp: 32, condition: "Cerah berawan" },
bandung: { temp: 24, condition: "Hujan ringan" },
surabaya: { temp: 34, condition: "Cerah" },
yogyakarta: { temp: 28, condition: "Berawan" },
bali: { temp: 30, condition: "Cerah" },
};
const cityLower = city.toLowerCase();
const weather = weatherData[cityLower];
if (!weather) {
return {
content: [
{
type: "text" as const,
text: `Maaf, data cuaca untuk kota "${city}" tidak tersedia. Kota yang tersedia: Jakarta, Bandung, Surabaya, Yogyakarta, Bali`,
},
],
};
}
return {
content: [
{
type: "text" as const,
text: `Cuaca di ${city}: ${weather.temp}°C, ${weather.condition}`,
},
],
};
}
);
// Menjalankan server dengan STDIO transport
async function main() {
const transport = new StdioServerTransport();
await server.connect(transport);
console.error("MCP Server (TypeScript) berjalan...");
}
main().catch(console.error);
Step 4: Menjalankan Server TypeScript
Jalankan server:
npm start
Server akan berjalan dan menunggu koneksi via STDIO. Untuk testing dengan Claude Desktop, kamu perlu menambahkan konfigurasi di file claude_desktop_config.json.
Konfigurasi Claude Desktop (TypeScript)
Tambahkan ke claude_desktop_config.json:
{
"mcpServers": {
"demo-typescript": {
"command": "npx",
"args": ["tsx", "/path/to/mcp-server-typescript/src/index.ts"]
}
}
}
Part 2: MCP Server dengan Python
Sekarang mari kita buat server yang identik menggunakan Python. Kita akan menggunakan package mcp yang juga dikenal sebagai FastMCP.
Step 1: Setup Project
Buat folder baru dan setup virtual environment:
mkdir mcp-server-python
cd mcp-server-python
python -m venv venv
source venv/bin/activate # Linux/Mac
# atau: venv\Scripts\activate # Windows
Install dependencies:
pip install mcp
Atau jika kamu menggunakan uv (recommended untuk project baru):
uv init mcp-server-python
cd mcp-server-python
uv add mcp
Step 2: Membuat MCP Server
Buat file server.py:
from mcp.server.fastmcp import FastMCP
from typing import Literal
# Inisialisasi MCP Server
mcp = FastMCP("demo-server")
# Tool 1: Calculator
@mcp.tool()
def calculator(
operation: Literal["add", "subtract", "multiply", "divide"],
a: float,
b: float
) -> str:
"""Melakukan operasi matematika dasar: penjumlahan, pengurangan, perkalian, pembagian"""
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: Tidak bisa membagi dengan nol"
result = a / b
else:
return f"Error: Operasi '{operation}' tidak dikenal"
return f"Hasil {operation}({a}, {b}) = {result}"
# Tool 2: Get Weather (Mock)
@mcp.tool()
def get_weather(city: str) -> str:
"""Mendapatkan informasi cuaca untuk kota tertentu
Args:
city: Nama kota untuk mendapatkan info cuaca
"""
# Mock weather data
weather_data = {
"jakarta": {"temp": 32, "condition": "Cerah berawan"},
"bandung": {"temp": 24, "condition": "Hujan ringan"},
"surabaya": {"temp": 34, "condition": "Cerah"},
"yogyakarta": {"temp": 28, "condition": "Berawan"},
"bali": {"temp": 30, "condition": "Cerah"},
}
city_lower = city.lower()
weather = weather_data.get(city_lower)
if not weather:
available_cities = ", ".join([c.title() for c in weather_data.keys()])
return f'Maaf, data cuaca untuk kota "{city}" tidak tersedia. Kota yang tersedia: {available_cities}'
return f"Cuaca di {city}: {weather['temp']}°C, {weather['condition']}"
# Entry point
if __name__ == "__main__":
mcp.run()
Step 3: Menjalankan Server Python
Jalankan server:
python server.py
Atau dengan uv:
uv run server.py
Konfigurasi Claude Desktop (Python)
Tambahkan ke claude_desktop_config.json:
{
"mcpServers": {
"demo-python": {
"command": "python",
"args": ["/path/to/mcp-server-python/server.py"]
}
}
}
Atau dengan uv:
{
"mcpServers": {
"demo-python": {
"command": "uv",
"args": ["--directory", "/path/to/mcp-server-python", "run", "server.py"]
}
}
}
Perbandingan Side-by-Side
Mari kita bandingkan kedua implementasi secara langsung:
Inisialisasi Server
TypeScript:
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
const server = new McpServer({
name: "demo-server",
version: "1.0.0",
});
Python:
from mcp.server.fastmcp import FastMCP
mcp = FastMCP("demo-server")
Winner: Python — Lebih concise, satu baris sudah cukup.
Mendefinisikan Tool
TypeScript:
const CalculatorInputSchema = z.object({
operation: z.enum(["add", "subtract", "multiply", "divide"]),
a: z.number(),
b: z.number(),
});
server.tool(
"calculator",
"Deskripsi tool",
CalculatorInputSchema.shape,
async ({ operation, a, b }) => {
// logic
return {
content: [{ type: "text" as const, text: "result" }],
};
}
);
Python:
@mcp.tool()
def calculator(
operation: Literal["add", "subtract", "multiply", "divide"],
a: float,
b: float
) -> str:
"""Deskripsi tool"""
# logic
return "result"
Winner: Python — Decorator pattern jauh lebih clean. Type hints sudah cukup untuk schema, tidak perlu Zod.
Return Value
TypeScript:
return {
content: [
{
type: "text" as const,
text: `Hasil: ${result}`,
},
],
};
Python:
return f"Hasil: {result}"
Winner: Python — Langsung return string, SDK yang handle wrapping-nya.
Lines of Code Comparison
| Komponen | TypeScript | Python |
|---|---|---|
| Imports | 3 lines | 2 lines |
| Server init | 4 lines | 1 line |
| Calculator tool | 35 lines | 18 lines |
| Weather tool | 30 lines | 22 lines |
| Main/run | 6 lines | 2 lines |
| Total | ~78 lines | ~45 lines |
Python menghasilkan code yang ~40% lebih pendek untuk fungsionalitas yang sama.
Kapan Memilih TypeScript?
Pilih TypeScript jika:
1. Tim Kamu Sudah Familiar dengan JavaScript/TypeScript
Jika tim development kamu sudah bekerja dengan Node.js ecosystem, tidak perlu belajar bahasa baru.
2. Butuh Strong Type Safety
TypeScript dengan Zod memberikan runtime validation yang sangat kuat. Ini penting untuk:
- API yang menerima input kompleks
- Production systems yang butuh reliability tinggi
- Tim besar dimana type checking mencegah bugs
3. Integrasi dengan Node.js Ecosystem
Kalau MCP server kamu perlu:
- Real-time features dengan WebSocket
- Integration dengan frontend frameworks (React, Vue, dll)
- NPM packages yang tidak ada equivalent di Python
4. Performance untuk I/O Intensive Tasks
Node.js event loop sangat efisien untuk concurrent I/O operations.
Kapan Memilih Python?
Pilih Python jika:
1. Rapid Prototyping
FastMCP membuat development sangat cepat. Dari nol ke working server bisa dalam hitungan menit.
2. Data Science / ML Integration
Jika MCP server kamu perlu:
- Pandas untuk data processing
- NumPy untuk numerical computation
- Integration dengan ML models (PyTorch, TensorFlow, scikit-learn)
- Data analysis dan visualization
3. Tim yang Lebih Nyaman dengan Python
Python syntax lebih approachable, terutama untuk tim yang background-nya bukan web development.
4. Scripting dan Automation
Python unggul untuk:
- System administration tasks
- File processing
- Web scraping
- API integrations
Advanced: Menambahkan Resources
Selain tools, MCP juga mendukung Resources. Berikut contoh menambahkan resource di kedua bahasa:
TypeScript:
server.resource(
"config://app",
"Application configuration",
async () => ({
contents: [
{
uri: "config://app",
mimeType: "application/json",
text: JSON.stringify({ version: "1.0.0", env: "development" }),
},
],
})
);
Python:
@mcp.resource("config://app")
def get_config() -> str:
"""Application configuration"""
import json
return json.dumps({"version": "1.0.0", "env": "development"})
Tips Deployment
TypeScript Deployment
- Build untuk production:
npm run build
node dist/index.js
- Docker:
FROM node:20-alpine
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production
COPY dist ./dist
CMD ["node", "dist/index.js"]
Python Deployment
- Dengan requirements.txt:
pip freeze > requirements.txt
pip install -r requirements.txt
python server.py
- Docker:
FROM python:3.11-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY . .
CMD ["python", "server.py"]
Testing MCP Server
Untuk testing, kamu bisa menggunakan MCP Inspector — tool official untuk debugging:
# Install MCP Inspector
npx @modelcontextprotocol/inspector
Ini akan membuka web interface dimana kamu bisa:
- Connect ke MCP server
- List available tools
- Test memanggil tools dengan berbagai input
- Inspect responses
Error Handling Best Practices
TypeScript
server.tool(
"risky_operation",
"A tool that might fail",
schema,
async (input) => {
try {
const result = await riskyFunction(input);
return {
content: [{ type: "text" as const, text: result }],
};
} catch (error) {
return {
content: [
{
type: "text" as const,
text: `Error: ${error instanceof Error ? error.message : "Unknown error"}`,
},
],
isError: true,
};
}
}
);
Python
@mcp.tool()
def risky_operation(input: str) -> str:
"""A tool that might fail"""
try:
result = risky_function(input)
return result
except Exception as e:
raise McpError(f"Error: {str(e)}")
Kesimpulan
Kedua bahasa sama-sama capable untuk membuat MCP server. Pilihan terbaik tergantung pada:
| Kriteria | Rekomendasi |
|---|---|
| Development speed | Python |
| Type safety | TypeScript |
| Data science integration | Python |
| Web ecosystem integration | TypeScript |
| Simplicity | Python |
| Production reliability | TypeScript (marginal) |
Rekomendasi saya:
- Untuk prototyping dan personal projects: Mulai dengan Python
- Untuk production di perusahaan dengan Node.js stack: TypeScript
- Untuk data/ML-heavy applications: Python
Yang terpenting, MCP adalah protokol — jadi server TypeScript bisa berkomunikasi dengan client Python dan sebaliknya. Kamu tidak terkunci pada satu ecosystem.
Selamat mencoba! Jika ada pertanyaan, silakan tinggalkan komentar di bawah.