dailytutorfor.you
Data Science & AI

Membangun MCP Server Production-Ready dengan TypeScript (Panduan Lengkap 2026)

Panduan lengkap berbahasa Indonesia untuk membangun MCP Server modern dengan TypeScript: mulai dari konsep dasar, arsitektur, implementasi runnable, best practices, common mistakes, hingga tips advanced untuk production.

10 menit baca

Membangun MCP Server Production-Ready dengan TypeScript (Panduan Lengkap 2026)

1) Introduction — Apa itu MCP dan Kenapa Lagi Naik Daun?

Kalau kamu sering mengikuti GitHub Trending atau diskusi developer belakangan ini, kamu pasti melihat pola yang sama: AI agent, tool calling, automation workflow, dan MCP (Model Context Protocol) muncul berulang-ulang.

Kenapa? Karena di 2026, tantangan kita bukan lagi “bisa bikin chatbot atau tidak”, tapi gimana caranya AI benar-benar bisa kerja: akses data, menjalankan aksi, dan tetap aman.

Di sinilah MCP jadi penting.

Bayangkan AI seperti karyawan baru yang sangat pintar, tapi belum punya akses ke alat kantor. Dia bisa berpikir, tapi tidak bisa buka database, baca file project, atau panggil API internal. MCP adalah standar “USB-C”-nya AI tools: satu protokol, banyak integrasi.

Real-world context

Contoh kasus nyata di tim engineering:

  • Tim support ingin AI bantu cek status order pelanggan.
  • Tim dev ingin AI bisa membaca ticket Jira dan membuat branch otomatis.
  • Tim data ingin AI meng-query data warehouse dengan guardrail.

Kalau semua dibuat custom per vendor/model, maintainability cepat hancur. Dengan MCP, kamu bisa:

  • menulis server tool sekali,
  • dipakai lintas client/agent,
  • dan lebih mudah diaudit security-nya.

Tutorial ini akan fokus ke implementasi MCP Server dengan TypeScript yang bisa kamu jalankan lokal hari ini, lalu scale ke production.


2) Prerequisites — Yang Perlu Kamu Siapkan

Sebelum mulai, pastikan environment kamu siap:

Wajib

  • Node.js v20+ (disarankan v22 LTS)
  • npm atau pnpm
  • Pemahaman dasar TypeScript
  • Familiar dengan konsep API dan JSON

Nice to have

  • Pengalaman dengan schema validation (misalnya Zod)
  • Dasar keamanan aplikasi (input validation, rate limit)

Tools yang dipakai

  • @modelcontextprotocol/sdk (SDK MCP)
  • zod untuk validasi input
  • pino untuk structured logging

3) Core Concepts — Fondasi MCP dengan Analogi Sederhana

Sebelum nulis kode, kita samakan mental model.

MCP dalam 1 kalimat

MCP adalah protokol standar agar AI client bisa menemukan dan memanggil tools secara konsisten.

Analogi restoran

  • AI client = pelayan
  • MCP server = dapur
  • Tool = menu
  • Tool schema = daftar bahan + aturan pemesanan

Pelanggan (user) pesan “tolong cek cuaca Surabaya”. Pelayan tidak masak sendiri; dia kirim pesanan terstruktur ke dapur. Dapur validasi pesanan, masak, lalu kirim hasil yang formatnya konsisten.

Konsep penting

  1. Tool discovery

    • Client bisa tahu tool apa saja yang tersedia.
  2. Typed input schema

    • Setiap tool mendefinisikan input yang valid.
    • Mengurangi hallucination dan runtime error.
  3. Deterministic output shape

    • Output punya struktur jelas agar mudah diproses lanjut.
  4. Transport layer

    • Umumnya stdio untuk local/dev.
    • Bisa diperluas ke transport lain sesuai kebutuhan.

4) Architecture / Diagram

Berikut arsitektur minimal untuk MCP server production-ready:

+-------------------+ MCP Protocol +------------------------+ | AI Client/Agent | <------------------------> | MCP Server (TypeScript)| | (IDE, Chat, CLI) | | - Tool registry | +-------------------+ | - Input validation | | | - Error handling | | user intent | - Logging | v +-----------+------------+ +-------------------+ | | Prompt/Task | | +-------------------+ v +-------------------------------+ | Business Layer | | - call internal API | | - query DB | | - read/write trusted files | +-------------------------------+

Flow ringkas:

  1. User memberi instruksi ke AI client.
  2. Client memilih tool dari MCP server.
  3. MCP server memvalidasi input.
  4. Business logic dieksekusi.
  5. Result + error context dikembalikan dalam format aman.

5) Step-by-Step Implementation (Complete Runnable)

Kita akan buat MCP server dengan 2 tools:

  1. generate_slug — membuat URL slug aman.
  2. estimate_reading_time — estimasi menit baca artikel.

Kenapa dua tool ini? Karena sederhana, real-world, dan langsung bisa dipakai untuk content workflow.

5.1 Inisialisasi project

mkdir mcp-content-tools && cd mcp-content-tools npm init -y npm install @modelcontextprotocol/sdk zod pino npm install -D typescript tsx @types/node npx tsc --init

5.2 package.json

Ganti isi package.json jadi:

{ "name": "mcp-content-tools", "version": "1.0.0", "private": true, "type": "module", "scripts": { "dev": "tsx src/index.ts", "build": "tsc -p .", "start": "node dist/index.js" }, "dependencies": { "@modelcontextprotocol/sdk": "^1.12.0", "pino": "^9.3.2", "zod": "^3.23.8" }, "devDependencies": { "@types/node": "^22.7.5", "tsx": "^4.19.1", "typescript": "^5.6.2" } }

5.3 tsconfig.json

{ "compilerOptions": { "target": "ES2022", "module": "NodeNext", "moduleResolution": "NodeNext", "outDir": "dist", "rootDir": "src", "strict": true, "skipLibCheck": true, "esModuleInterop": true, "forceConsistentCasingInFileNames": true }, "include": ["src"] }

5.4 Implementasi server src/index.ts

import pino from "pino"; import { z } from "zod"; import { Server } from "@modelcontextprotocol/sdk/server/index.js"; import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"; import { CallToolRequestSchema, ListToolsRequestSchema, } from "@modelcontextprotocol/sdk/types.js"; const logger = pino({ level: process.env.LOG_LEVEL ?? "info" }); // ---------- Schemas ---------- const generateSlugInput = z.object({ title: z.string().min(3).max(180), }); const estimateReadingTimeInput = z.object({ text: z.string().min(20), wordsPerMinute: z.number().int().min(100).max(400).optional().default(200), }); // ---------- Helpers ---------- function toSafeErrorMessage(error: unknown): string { if (error instanceof Error) return error.message; return "Unknown error"; } function createSlug(title: string): string { return title .toLowerCase() .trim() .replace(/[^a-z0-9\s-]/g, "") .replace(/\s+/g, "-") .replace(/-+/g, "-"); } function estimateMinutes(text: string, wpm: number): number { const words = text.trim().split(/\s+/).filter(Boolean).length; return Math.max(1, Math.ceil(words / wpm)); } // ---------- MCP Server ---------- const server = new Server( { name: "mcp-content-tools", version: "1.0.0", }, { capabilities: { tools: {}, }, } ); server.setRequestHandler(ListToolsRequestSchema, async () => { return { tools: [ { name: "generate_slug", description: "Generate SEO-friendly slug from article title.", inputSchema: { type: "object", properties: { title: { type: "string", description: "Article title", }, }, required: ["title"], additionalProperties: false, }, }, { name: "estimate_reading_time", description: "Estimate reading time in minutes.", inputSchema: { type: "object", properties: { text: { type: "string", description: "Full article text", }, wordsPerMinute: { type: "number", description: "Reading speed, default 200", }, }, required: ["text"], additionalProperties: false, }, }, ], }; }); server.setRequestHandler(CallToolRequestSchema, async (request) => { const { name, arguments: args } = request.params; try { if (name === "generate_slug") { const input = generateSlugInput.parse(args); const slug = createSlug(input.title); return { content: [ { type: "text", text: JSON.stringify({ slug }, null, 2), }, ], }; } if (name === "estimate_reading_time") { const input = estimateReadingTimeInput.parse(args); const minutes = estimateMinutes(input.text, input.wordsPerMinute); return { content: [ { type: "text", text: JSON.stringify( { minutes, wordsPerMinute: input.wordsPerMinute, }, null, 2 ), }, ], }; } return { isError: true, content: [ { type: "text", text: `Unknown tool: ${name}`, }, ], }; } catch (error) { logger.error({ err: error, tool: name }, "Tool execution failed"); return { isError: true, content: [ { type: "text", text: `Tool failed: ${toSafeErrorMessage(error)}`, }, ], }; } }); async function main() { try { const transport = new StdioServerTransport(); await server.connect(transport); logger.info("MCP Content Tools server started on stdio"); } catch (error) { logger.fatal({ err: error }, "Failed to start MCP server"); process.exit(1); } } void main();

5.5 Jalankan server

npm run dev

Kalau sukses, server siap menerima request dari MCP-compatible client.

5.6 Contoh pengujian cepat

Untuk test logika core (tanpa client penuh), kamu bisa unit-test function createSlug dan estimateMinutes.

Contoh singkat dengan Node REPL/ts-node:

// quick-test.ts import assert from "node:assert/strict"; function createSlug(title: string): string { return title .toLowerCase() .trim() .replace(/[^a-z0-9\s-]/g, "") .replace(/\s+/g, "-") .replace(/-+/g, "-"); } function estimateMinutes(text: string, wpm: number): number { const words = text.trim().split(/\s+/).filter(Boolean).length; return Math.max(1, Math.ceil(words / wpm)); } try { assert.equal(createSlug("Belajar MCP Server dari Nol!"), "belajar-mcp-server-dari-nol"); assert.equal(estimateMinutes("halo ".repeat(450), 200), 3); console.log("All tests passed ✅"); } catch (err) { console.error("Test failed:", err); process.exit(1); }

6) Best Practices — Praktik Terbaik dari Industri

Berikut kebiasaan yang sangat membantu saat MCP server mulai dipakai tim lain:

1. Validasi input ketat, jangan percaya client

Walaupun client “resmi”, tetap validasi semua input. Schema-based validation (Zod/JSON Schema) wajib untuk mencegah crash, behavior aneh, dan potensi abuse.

2. Gunakan output yang stabil

Jangan mengubah format output seenaknya. Jika perlu perubahan, versioning tool (v2) lebih aman daripada breaking change diam-diam.

3. Pisahkan transport vs business logic

Transport (MCP plumbing) harus tipis. Logic utama simpan di service layer agar mudah di-test dan dipakai ulang.

4. Structured logging dari hari pertama

Log plain text cepat bikin pusing saat debugging. Pakai JSON log (pino) supaya mudah dicari di observability stack.

5. Terapkan principle of least privilege

Kalau ada tool yang menyentuh file system atau API sensitif, batasi scope. Contoh: hanya folder tertentu, hanya endpoint tertentu.

6. Timeout dan retry policy jelas

Tool eksternal (HTTP/DB) pasti sesekali lambat atau gagal. Definisikan timeout eksplisit dan retry terbatas (dengan backoff).

7. Document contract

Setiap tool harus punya:

  • deskripsi use case,
  • input example,
  • output example,
  • error mode.

Ini menghemat banyak waktu onboarding.


7) Common Mistakes — Kesalahan yang Sering Terjadi

Mistake #1: Tool terlalu “god object”

Satu tool melakukan 10 hal sekaligus. Akibatnya susah validasi, susah audit, dan prompt AI sering salah pakai.

Solusi: pecah jadi tool kecil dengan tanggung jawab tunggal.

Mistake #2: Tidak membedakan user-facing error dan internal error

Semua stack trace dikirim ke client = risiko bocor informasi sensitif.

Solusi: tampilkan error aman ke client, detail lengkap simpan di log.

Mistake #3: Tanpa guardrail pada input string panjang

Input besar bisa bikin memory bengkak atau biaya inference naik.

Solusi: batasi panjang input, sanitasi whitespace, dan tambahkan hard limit.

Mistake #4: Menganggap “local = aman”

Server lokal tetap bisa dipanggil oleh workflow yang tidak kamu duga.

Solusi: tetap desain dengan mindset security-first.

Mistake #5: Tidak punya test untuk contract

Saat refactor, format output berubah dan client downstream rusak.

Solusi: tambah contract tests untuk setiap tool.


8) Advanced Tips — Kalau Kamu Mau Naik Level

A. Tambahkan authentication/authorization layer

Untuk deployment team/shared environment, jangan biarkan semua tool terbuka. Tambahkan token-based policy atau service identity.

B. Instrumentasi metrics

Pantau metrik:

  • tool calls per minute,
  • success rate,
  • P95 latency,
  • top failure reasons.

Dengan ini kamu bisa tahu bottleneck sebelum user komplain.

C. Implement caching untuk tool read-heavy

Contoh tool “fetch docs summary” bisa diberi TTL cache 1-5 menit agar respons lebih cepat dan biaya turun.

D. Versioning strategy

Gunakan naming eksplisit seperti:

  • search_docs_v1
  • search_docs_v2

Saat client sudah migrasi, baru deprecate versi lama.

E. Hybrid pattern: MCP + event-driven backend

Untuk operasi lama (misalnya generate report 2 menit), jangan blok request sync. Kembalikan job ID, proses async di worker, lalu expose tool status checker.


9) Summary & Next Steps

Kita sudah membahas end-to-end cara membangun MCP server modern dengan TypeScript:

  • paham konsep dasar MCP,
  • setup project,
  • implementasi tool dengan validasi + error handling,
  • best practices produksi,
  • dan strategi scale lanjutan.

Kalau kamu baru mulai, target sederhana dulu:

  1. Buat 2-3 tool kecil yang jelas fungsinya.
  2. Tambahkan test contract.
  3. Integrasikan ke satu AI client.
  4. Pantau log dan perbaiki reliability.

Setelah stabil, kamu bisa ekspansi ke tool internal perusahaan (ticketing, analytics, CRM) dengan security policy yang ketat.

Intinya: MCP bukan sekadar tren AI 2026, tapi fondasi integrasi agent yang maintainable dan vendor-agnostic.


10) References


Catatan riset tren (ringkas)

Berdasarkan observasi sumber publik (GitHub Trending dan DEV), topik yang paling menonjol adalah:

  • AI coding agents & multi-agent orchestration
  • MCP/tool integration untuk agent
  • Praktik production readiness (security, observability, reliability)

Karena itu, tutorial ini dipilih agar relevan untuk kebutuhan developer saat ini: bukan hanya “bisa demo”, tapi siap dipakai di workflow nyata.