Tutorial Lengkap Model Context Protocol (MCP) 2026: Bangun MCP Server TypeScript yang Production-Ready
Panduan komprehensif berbahasa Indonesia untuk memahami dan mengimplementasikan Model Context Protocol (MCP) dari nol hingga siap produksi. Kamu akan belajar arsitektur MCP, membuat server TypeScript yang runnable, menerapkan best practices keamanan, dan menghindari kesalahan umum.
Tutorial Lengkap Model Context Protocol (MCP) 2026: Bangun MCP Server TypeScript yang Production-Ready
1) Introduction — What & Why
Kalau kamu mengikuti tren developer di GitHub Trending dan komunitas AI engineering belakangan ini, kamu pasti sering lihat istilah MCP (Model Context Protocol) muncul di mana-mana. Kenapa? Karena setelah era “LLM bisa jawab apa saja”, sekarang fokusnya bergeser ke: “gimana caranya AI bisa pakai tools dan data real secara aman, standar, dan reusable?”
Di dunia nyata, model AI tanpa akses context itu seperti intern pintar yang tidak punya akses ke dokumen kantor, database, atau API internal. Dia bisa jelasin teori, tapi sulit mengeksekusi pekerjaan end-to-end.
Di sinilah MCP jadi game changer.
Secara sederhana, MCP adalah standar terbuka untuk menghubungkan aplikasi AI dengan sumber data dan tools eksternal. Analogi paling gampang: kalau USB-C menstandarkan cara perangkat elektronik terhubung, MCP menstandarkan cara aplikasi AI terhubung ke tools/resources/prompts.
Kenapa penting di 2026?
- Ekosistem agentic app makin ramai (coding agent, ops assistant, enterprise copilots)
- Tim engineering butuh integrasi lintas host/client tanpa bikin adapter custom berkali-kali
- Kebutuhan governance dan security meningkat (audit trail, permission, sandboxing)
- Perusahaan ingin “build once, integrate everywhere”
Di tutorial ini, kamu akan bikin MCP Server dengan TypeScript yang benar-benar runnable, plus best practices yang relevan untuk production.
2) Prerequisites
Sebelum mulai, pastikan kamu sudah siap hal berikut:
- Node.js 20+ (disarankan Node 22)
- npm atau pnpm
- Pemahaman dasar TypeScript (function, async/await, type)
- Familiar dengan konsep API dan JSON
- Opsional: pernah pakai AI host/client yang support MCP
Install awal
mkdir mcp-weather-server && cd mcp-weather-server npm init -y npm install @modelcontextprotocol/server zod npm install -D typescript tsx @types/node npx tsc --init
Update package.json agar mudah dijalankan:
{ "name": "mcp-weather-server", "version": "1.0.0", "type": "module", "scripts": { "dev": "tsx src/server.ts", "build": "tsc -p tsconfig.json", "start": "node dist/server.js" } }
3) Core Concepts (dengan analogi)
Sebelum coding, pahami fondasinya dulu.
A. Host, Client, Server
- MCP Host: aplikasi AI utama (misalnya IDE assistant)
- MCP Client: komponen penghubung dari host ke server tertentu
- MCP Server: layanan yang expose tools/resources/prompts
Analogi restoran:
- Host = restoran
- Client = pelayan
- Server = dapur spesialis
Restoran bisa punya banyak pelayan yang masing-masing komunikasi ke dapur berbeda.
B. 3 Primitive utama di MCP Server
- Tools → fungsi yang bisa dieksekusi (contoh: hitung pajak, query API)
- Resources → data yang bisa dibaca (contoh: file config, dokumentasi internal)
- Prompts → template interaksi reusable
C. Lifecycle & Capability Negotiation
Saat koneksi mulai, client dan server saling “kenalan” kemampuan.
Kalau server tidak expose tools, client tidak akan bisa memanggil tools/call.
D. Transport Layer
- STDIO: local process communication (cepat, simpel untuk local dev)
- Streamable HTTP: cocok untuk remote server / multi-client
Untuk tutorial awal, kita pakai STDIO agar fokus ke konsep.
4) Architecture / Diagram
Arsitektur yang akan kita buat:
+---------------------------+ | AI Host (Editor/Agent UI) | | - MCP Client | +-------------+-------------+ | | JSON-RPC (MCP) v +---------------------------+ | MCP Weather Server | | - Tool: weather.current | | - Tool: weather.planTrip | | - Resource: weather:// | +-------------+-------------+ | | fetch v +---------------------------+ | Open-Meteo API | +---------------------------+
Flow ringkas:
- Host connect ke server
- Host list tools/resources
- User tanya cuaca / rencana trip
- Host panggil tool
- Server fetch API eksternal + validasi
- Hasil dikembalikan ke host
5) Step-by-Step Implementation (Complete Runnable Code)
Di bagian ini kita bikin server dengan:
- validasi input pakai zod
- error handling rapi
- timeout request
- output konsisten
Buat file: src/server.ts
import { McpServer } from "@modelcontextprotocol/server"; import { StdioServerTransport } from "@modelcontextprotocol/server/stdio"; import { z } from "zod"; // ---------- Helper types ---------- type GeoResult = { latitude: number; longitude: number; name: string; country?: string; }; type CurrentWeatherResult = { temperature?: number; windspeed?: number; weathercode?: number; time?: string; }; // ---------- Safe fetch with timeout ---------- async function safeFetchJson<T>(url: string, timeoutMs = 8000): Promise<T> { const controller = new AbortController(); const timeout = setTimeout(() => controller.abort(), timeoutMs); try { const res = await fetch(url, { signal: controller.signal }); if (!res.ok) { throw new Error(`HTTP ${res.status} - ${res.statusText}`); } return (await res.json()) as T; } catch (err) { if (err instanceof Error && err.name === "AbortError") { throw new Error("Request timeout: layanan cuaca terlalu lama merespons"); } throw err; } finally { clearTimeout(timeout); } } // ---------- External API wrappers ---------- async function geocodeCity(city: string): Promise<GeoResult> { const encoded = encodeURIComponent(city); const url = `https://geocoding-api.open-meteo.com/v1/search?name=${encoded}&count=1&language=en&format=json`; const data = await safeFetchJson<{ results?: GeoResult[] }>(url); if (!data.results || data.results.length === 0) { throw new Error(`Kota tidak ditemukan: ${city}`); } return data.results[0]; } async function getCurrentWeather(lat: number, lon: number): Promise<CurrentWeatherResult> { const url = `https://api.open-meteo.com/v1/forecast?latitude=${lat}&longitude=${lon}¤t_weather=true`; const data = await safeFetchJson<{ current_weather?: CurrentWeatherResult }>(url); if (!data.current_weather) { throw new Error("Data current_weather tidak tersedia dari provider"); } return data.current_weather; } function weatherCodeToText(code?: number): string { if (code == null) return "Unknown"; if (code === 0) return "Cerah"; if ([1, 2, 3].includes(code)) return "Berawan"; if ([45, 48].includes(code)) return "Berkabut"; if ([51, 53, 55, 61, 63, 65].includes(code)) return "Hujan"; if ([71, 73, 75].includes(code)) return "Salju"; if ([95, 96, 99].includes(code)) return "Badai/Petir"; return `Kode cuaca ${code}`; } // ---------- MCP Server ---------- const server = new McpServer({ name: "weather-planner-mcp", version: "1.0.0", }); // Tool #1: weather.current server.tool( "weather.current", "Ambil cuaca terkini berdasarkan nama kota", { city: z.string().min(2, "Nama kota minimal 2 karakter"), }, async ({ city }) => { try { const geo = await geocodeCity(city); const current = await getCurrentWeather(geo.latitude, geo.longitude); const text = [ `Cuaca saat ini di ${geo.name}${geo.country ? `, ${geo.country}` : ""}:`, `- Suhu: ${current.temperature ?? "N/A"}°C`, `- Angin: ${current.windspeed ?? "N/A"} km/h`, `- Kondisi: ${weatherCodeToText(current.weathercode)}`, `- Waktu data: ${current.time ?? "N/A"}`, ].join(" "); return { content: [{ type: "text", text }], }; } catch (error) { const message = error instanceof Error ? error.message : "Unknown error"; return { content: [ { type: "text", text: `Gagal mengambil cuaca: ${message}`, }, ], isError: true, }; } } ); // Tool #2: weather.planTrip server.tool( "weather.planTrip", "Memberikan saran sederhana apakah cuaca cocok untuk aktivitas outdoor", { city: z.string().min(2), activity: z.enum(["running", "cycling", "hiking", "picnic"]), }, async ({ city, activity }) => { try { const geo = await geocodeCity(city); const current = await getCurrentWeather(geo.latitude, geo.longitude); const temp = current.temperature ?? 0; const wind = current.windspeed ?? 0; const isRainy = [51, 53, 55, 61, 63, 65, 95, 96, 99].includes( current.weathercode ?? -1 ); let score = 100; if (temp < 18 || temp > 33) score -= 25; if (wind > 28) score -= 30; if (isRainy) score -= 40; const recommendation = score >= 75 ? "Sangat direkomendasikan ✅" : score >= 45 ? "Masih memungkinkan, tapi siapkan plan B ⚠️" : "Kurang disarankan untuk outdoor ❌"; const text = [ `Trip planner untuk ${activity} di ${geo.name}:`, `- Suhu: ${temp}°C`, `- Angin: ${wind} km/h`, `- Kondisi: ${weatherCodeToText(current.weathercode)}`, `- Skor kelayakan: ${Math.max(0, score)}/100`, `- Rekomendasi: ${recommendation}`, ].join(" "); return { content: [{ type: "text", text }] }; } catch (error) { const message = error instanceof Error ? error.message : "Unknown error"; return { content: [{ type: "text", text: `Gagal membuat rencana trip: ${message}` }], isError: true, }; } } ); // Resource example server.resource( "weather://supported-activities", "Daftar aktivitas yang didukung oleh weather.planTrip", async () => { return { contents: [ { uri: "weather://supported-activities", mimeType: "application/json", text: JSON.stringify( { activities: ["running", "cycling", "hiking", "picnic"], notes: "Gunakan tool weather.planTrip dengan salah satu aktivitas di atas", }, null, 2 ), }, ], }; } ); // Boot transport stdio async function main() { const transport = new StdioServerTransport(); await server.connect(transport); console.error("MCP Weather Server running via stdio..."); } main().catch((err) => { console.error("Fatal startup error:", err); process.exit(1); });
Menjalankan server
npm run dev
Kalau sukses, proses akan menunggu koneksi dari host MCP.
Kenapa code di atas “layak produksi dasar”?
- Input tervalidasi (
zod) - Timeout network (hindari hanging)
- Error dikembalikan jelas (
isError: true) - Output stabil dan mudah dibaca model/host
- Fungsi dipisah per concern (maintainable)
6) Best Practices (tips ala industri)
1. Treat tool seperti public API contract
Jangan sering ubah nama tool/shape input-output tanpa versioning. Kalau perlu perubahan breaking, buat weather.current.v2 dulu.
2. Principle of least privilege
Kalau tool menyentuh file system, batasi scope folder. Kalau akses API, gunakan token minimum scope.
3. Deterministic output > output kreatif
Untuk tools, prioritaskan format yang konsisten agar host/agent mudah chaining.
4. Observability wajib
Log minimal: timestamp, tool name, latency, status, error class. Ini penting saat debugging workflow agentic.
5. Graceful degradation
Saat provider eksternal down, balas error yang actionable, bukan stack trace mentah.
6. Pisahkan domain logic dan MCP adapter
Business logic jangan tercampur total dengan wrapper MCP. Ini memudahkan unit test.
7) Common Mistakes (dan cara menghindarinya)
Mistake #1: Tool terlalu “saklek” atau terlalu “bebas”
- Terlalu saklek: input minim, agent jadi sulit menyelesaikan task
- Terlalu bebas: input longgar, error edge case meledak
Solusi: gunakan schema validation + default yang masuk akal.
Mistake #2: Tidak ada timeout/retry
Akibatnya proses ngegantung kalau upstream lambat.
Solusi: pakai AbortController, tentukan timeout, dan (opsional) retry eksponensial.
Mistake #3: Mencampur data sensitif dalam output tool
Contoh: API key, internal path, raw SQL credentials ikut ter-print.
Solusi: sanitize output, redaksi data rahasia sebelum return.
Mistake #4: Tidak handle “kota tidak ditemukan”
Banyak developer asumsi geocoding selalu berhasil.
Solusi: cek results null/empty, return error yang manusiawi.
Mistake #5: Tidak memikirkan evolusi protokol
SDK/protocol MCP berkembang cepat.
Solusi: pin versi dependency, baca changelog rutin, dan siapkan migration checklist.
8) Advanced Tips
Kalau kamu ingin naik level, ini jalurnya:
A. Tambahkan caching
Untuk query lokasi berulang, simpan geocoding result di memory cache (TTL 30 menit) agar latency turun.
B. Tambahkan circuit breaker
Jika API provider sering gagal, gunakan circuit breaker untuk mencegah cascading failure.
C. Migrasi ke Streamable HTTP
Saat perlu multi-tenant / remote deployment, pindah ke HTTP transport dengan auth yang jelas (bearer/OAuth).
D. Buat “composite tools”
Alih-alih banyak tool kecil tanpa pola, buat tool orkestrasi yang memanggil sub-tool secara internal untuk hasil yang lebih siap pakai user.
E. Tambahkan contract tests
Test penting:
tools/listmenampilkan semua tool expected- invalid input return
isError - success path menghasilkan format output stabil
Contoh pseudo test case:
Given city=Surabaya When call weather.current Then response contains suhu, angin, kondisi And isError is false
9) Summary & Next Steps
Kita sudah bahas dari nol sampai praktik:
- Kenapa MCP menjadi fondasi integrasi AI modern
- Konsep host/client/server + tools/resources/prompts
- Arsitektur komunikasi MCP
- Implementasi MCP server TypeScript runnable dengan error handling
- Best practices, anti-pattern, dan langkah lanjut ke production
Next steps yang saya sarankan
- Tambahkan forecast 7 hari sebagai tool baru
- Implement rate limit sederhana per user/session
- Tambahkan structured logging (misalnya pino)
- Deploy versi HTTP transport di environment staging
- Dokumentasikan contract tool di README internal tim
Kalau kamu menguasai pattern ini, kamu bisa bikin MCP server untuk banyak domain lain: finance, legal docs, customer support, internal engineering ops, sampai product analytics.
10) References
- MCP Introduction: https://modelcontextprotocol.io/introduction
- MCP Architecture: https://modelcontextprotocol.io/docs/learn/architecture
- MCP TypeScript SDK: https://github.com/modelcontextprotocol/typescript-sdk
- MCP Reference Servers: https://github.com/modelcontextprotocol/servers
- Open-Meteo API Docs: https://open-meteo.com/en/docs
- GitHub Trending (sinyal topik): https://github.com/trending
- Dev Community: https://dev.to
- Medium Web Development Tag: https://medium.com/tag/web-development
Catatan riset singkat
Dalam riset harian konten, sinyal tren yang terlihat kuat adalah: agentic workflow, MCP ecosystem, dan integrasi AI ke tooling developer. Karena itu topik MCP dipilih agar relevan dengan kebutuhan praktis developer 2026: bukan hanya “AI bisa jawab”, tapi “AI bisa kerja beneran dengan tools dan data yang terstandar”.