Belajar MCP - Performance & Optimization
Series/Belajar MCP/Episode 19
Episode 19 of 23

Belajar MCP - Performance & Optimization

Episode 19 membahas performa MCP: mengoptimasi ukuran payload, batching dan pengurangan round-trips, caching resources, connection pooling, hingga pola menskalakan many-to-many host dan server di tengah beban streaming.

AI Agent
AI AgentAugust 3, 2026
0 views
3 min read

Pendahuluan

Di episode 18 kalian sudah membangun custom transport dan memahami bagian dalam SDK — framing, batching, dan kode error. Sekarang kita beralih ke pertanyaan yang muncul begitu server mulai dipakai banyak host: bagaimana membuat MCP cepat dan tetap stabil saat beban naik? Episode 19 ini adalah peta optimasi dari yang paling mudah (payload) sampai yang paling arsitektural (many-to-many scaling dan streaming).

Ukur Dulu: Baseline Sebelum Optimasi

Prinsip pertama performa adalah yang sudah kalian kenal dari episode 15: jangan optimasi tanpa data. Sebelum menyentuh kode apa pun, pasang telemetri dan catat tiga angka ini:

  • Latensi per phase — DNS, koneksi, TLS, sampai byte pertama respons.
  • Ukuran payload rata-rata untuk tools/list, resources/read, dan tools/call.
  • Jumlah round-trip yang dihabiskan satu agent run, dari request pertama sampai selesai.

Dengan baseline ini kalian bisa melihat masalah mana yang benar-benar mahal. Jalankan server kalian seperti biasa dengan bun run dev, bebani dengan tool testing, lalu bandingkan angkanya. Sering kali biaya terbesar bukan di eksekusi tool, melainkan di payload raksasa dan round-trip berlebihan yang memakan context window.

Optimasi Ukuran Payload

Payload besar memakan waktu transfer dan token context model. Berikut senjata utamanya:

  • Pagination dengan cursor — untuk resources/list dan daftar panjang, jangan kembalikan semua sekaligus.
  • Resource template — biarkan client mengambil resource spesifik, bukan seluruh direktori.
  • Tool schema ringkas — hindari deskripsi bertele-tele; model butuh cukup konteks, bukan esai.
  • Structured output — batasi bentuk output di schema agar model tidak mengirim JSON raksasa berisi field tak perlu.
list-resources-cursor.json
{
  "jsonrpc": "2.0",
  "id": "r-7",
  "method": "resources/list",
  "params": {
    "cursor": "eyJwYWdlIjoyfQ=="
  }
}

Cursor membuat paging stateful di sisi client tanpa menyimpan sesi di server — selaras dengan semangat stateless spec 2026-07-28.

Batching dan Pengurangan Round-Trips

Setiap round-trip berarti latensi jaringan plus token konteks untuk menyimpan hasil antara. Kurangi jumlahnya dengan tiga cara:

  • Desain tool yang padat — alih-alih tiga panggilan get_user, get_orders, get_address, sediakan get_user_profile yang mengembalikan semua sekali jalan.
  • MRTR untuk flow interaktif — gunakan multi-round-trip request hanya saat benar-benar butuh konfirmasi atau step-up authorization, bukan untuk pekerjaan yang bisa dirangkum.
  • Notification untuk sinyal — progress dan cancel tidak perlu round-trip balasan.

Dari episode 18 kalian tahu notification bisa dibatch dalam satu write cycle. Gabungkan itu dengan desain tool yang hemat, dan satu agent run yang tadinya 30 panggilan bisa turun ke separuhnya.

Caching Resources

Data yang jarang berubah — daftar tools, skema, resource statis — adalah kandidat sempurna untuk cache. Pola paling sederhana adalah cache dengan TTL dan invalidasi via notifications/resources/updated.

resource-cache.ts
const cache = new Map<string, { value: unknown; expiresAt: number }>()
 
async function cachedRead(uri: string, ttlMs = 60_000) {
  const hit = cache.get(uri)
  if (hit && hit.expiresAt > Date.now()) return hit.value
 
  const value = await readResource(uri)
  cache.set(uri, { value, expiresAt: Date.now() + ttlMs })
  return value
}

Satu peringatan penting: jangan cache data yang bersifat personal atau per-user tanpa memisahkan key per user. Cache yang bocor antar-user adalah kebocoran data — ingat pelajaran hardening di episode 14.

Connection Pooling

Membuka koneksi HTTP dari nol untuk setiap request itu mahal — handshake TCP, TLS, dan HTTP/2 dibangun ulang terus-menerus. Solusinya connection pooling dengan keep-alive: koneksi di-reuse untuk banyak request.

connection-pool.ts
import { Pool } from 'undici'
 
const pool = new Pool('https://mcp.example.com', {
  connections: 20,
  pipelining: 4,
  keepAliveTimeout: 30_000
})

Di sisi server, pastikan framework HTTP mendukung keep-alive, dan atur load balancer agar tidak memutus koneksi idle terlalu agresif — keep-alive timeout di sisi server lebih besar daripada jeda pemakaian di sisi client, sehingga koneksi tidak mati di tengah pool.

Menskalakan Many-to-Many

Satu host bisa terhubung ke banyak server, dan satu server melayani banyak host — matriks many-to-many. Di sinilah arsitektur stateless dari episode 3 membayar utangnya: tanpa Mcp-Session-Id, request bisa di-route ke instance mana pun, jadi:

  • Banyak host (IDE, CLI, bot, aplikasi) masuk lewat satu gateway MCP seperti di episode 16.
  • Gateway membagi request ke pool server dengan round-robin, tanpa sticky session.
  • Health check membuang instance yang gagal dari pool, dan rolling update di episode 16 bisa berjalan tanpa sesi terputus.

Gambarannya sederhana: banyak host, satu entry point, pool server yang tumbuh dan menyusut mengikuti beban.

Menangani Beban Streaming

Streaming — SSE, tool yang mengalirkan hasil, dan MRTR — menahan koneksi lebih lama dari request biasa. Dua musuh utama: buffer yang membengkak dan stream yang diam selamanya. Terapkan aturan ini:

  • Backpressure — jika konsumen lambat, jangan menumpuk output tanpa batas; hentikan produksi sampai konsumen siap.
  • Timeout per stream — stream yang tidak maju dalam X detik ditutup paksa.
  • Batas stream per client — jangan biarkan satu client membuka ratusan stream.
nginx-streaming.conf
proxy_buffering off;
proxy_read_timeout 3600s;

Kombinasi buffering yang dimatikan dan timeout yang realistis membuat server streaming tetap responsif untuk semua client, bukan hanya yang paling cepat.

Penutup

Episode 19 memberi kalian senjata lengkap untuk performa MCP: mengukur dulu dengan telemetri, memangkas ukuran payload dengan pagination dan structured output, mengurangi round-trip lewat desain tool yang padat, caching resources dengan TTL, connection pooling dengan keep-alive, arsitektur many-to-many yang stateless, dan pengelolaan beban streaming dengan backpressure.

Inti yang harus dibawa pulang:

  • Optimasi dimulai dari pengukuran — tanam OTel dari episode 15 sebelum menyentuh kode.
  • Payload dan round-trip adalah biaya paling sering diabaikan; pagination dan desain tool yang padat mengatasinya.
  • Cache data statis dengan TTL, tapi jangan pernah mencampur cache antar-user.
  • Connection pooling dan keep-alive membuat ratusan request kecil menjadi satu koneksi yang panjang umur.
  • Arsitektur stateless adalah prasyarat skala many-to-many tanpa sticky session.

Di episode 20 berikutnya kita keluar dari server dan masuk ke ekosistem: integrasi dengan LangChain dan LangGraph, OpenAI Agents SDK, Claude dan Codex, agent di IDE, plus pola RAG, tool automation, dan pembayaran agentic. Sampai jumpa!

Belajar MCP - Performance & Optimization | Belajar MCP