Belajar MCP - Transport Deep Dive
Series/Belajar MCP/Episode 13
Episode 13 of 23

Belajar MCP - Transport Deep Dive

Episode ini membongkar lapisan transport MCP: Streamable HTTP yang menggabungkan request/response JSON-RPC dengan stream SSE untuk notifikasi, kriteria kapan memilihnya dibanding stdio, serta stdio untuk proses lokal — interop dengan editor dan CLI agents, ditambah lifecycle process dari spawn sampai exit.

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

Pendahuluan

Di episode 12 kalian menangani pekerjaan panjang dengan MCP Tasks. Semua request itu — tools/list, tools/call, tasks/update — harus sampai ke server lewat sesuatu. Sesuatu itulah yang kita bedah sekarang: transport. Kalian pernah melihat sekilas stdio dan SSE di episode 2; episode 13 ini mengupas detailnya karena pilihan transport menentukan arsitektur, operasional, dan batas keamanan seluruh server kalian.

Roadmap episode ini: peta transport di MCP modern, kerja Streamable HTTP (request/response JSON-RPC plus stream SSE untuk notifikasi), kriteria memilih Streamable HTTP versus stdio, cara stdio berinterop dengan editor dan CLI agents, dan lifecycle proses dari spawn sampai exit.

Peta Transport MCP

MCP resmi mendukung tiga transport, dan dua di antaranya masih relevan di era stateless 2026-07-28:

  • stdio — server dijalankan sebagai subprocess lokal, komunikasi lewat stdin/stdout. Tanpa jaringan, tanpa port, tanpa autentikasi.
  • Streamable HTTP — server adalah endpoint HTTP; client mengirim JSON-RPC sebagai request, dan membaca notifikasi dari stream SSE.
  • SSE (legacy) — transport SSE lama dari spec 2024-11-05, memakai dua koneksi HTTP terpisah dan mengandalkan state session. Sudah digantikan Streamable HTTP sejak spec 2025-03-26 dan tidak disarankan untuk server baru.

Fokus kita adalah dua yang modern. Aturan praktis yang akan terus kita pakai: stdio untuk integrasi lokal dan satu-pengguna, Streamable HTTP untuk layanan bersama, multi-klien, dan produksi.

Streamable HTTP: Request/Response + SSE

Pada Streamable HTTP, satu endpoint menerima semua pesan JSON-RPC sebagai POST. Client memanggil tools/call dengan payload biasa:

Memanggil method tools/call lewat curl
curl -X POST https://mcp.example.com/mcp \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer $MCP_TOKEN" \
  -d '{"jsonrpc":"2.0","id":1,"method":"tools/call",
       "params":{"name":"get_weather","arguments":{"city":"Bandung"}}}'

Yang membedakan Streamable HTTP dari HTTP API biasa adalah lapisan kedua: stream SSE. Ketika sebuah request menghasilkan notifikasi — misalnya progress tasks/update dari episode 12 atau pembaruan status MRTR dari episode 8 — server membuka stream Server-Sent Events di response yang sama. Client membaca aliran data yang formatnya satu baris per event:

Format event SSE yang diterima client
event: message
data: {"jsonrpc":"2.0","method":"tasks/update",
       "params":{"taskId":"task_7f3a91c2","state":"running","progress":55}}
 
event: message
data: {"jsonrpc":"2.0","id":1,
       "result":{"content":[{"type":"text","text":"Bandung 29C, berawan"}]}}

Dengan kata lain: kalian dapat request/response JSON-RPC klasik untuk method yang sinkron, dan stream SSE untuk notifikasi serta streaming hasil yang panjang. Keduanya berbagi satu endpoint dan satu model stateless — setiap request membawa identitas dan capability-nya sendiri, persis seperti yang kalian pelajari di episode 3.

Kapan Memilih Streamable HTTP

Streamable HTTP adalah pilihan default untuk produksi. Beberapa alasan konkret:

  • Server bisa dipanggil banyak client sekaligus — arsitektur HTTP yang stateless memungkinkan horizontal scaling dengan load balancer tanpa session affinity (episode 9).
  • Autentikasi standar — header Authorization dan alur OAuth 2.1 dari episode 10 bekerja alami di atas HTTP.
  • Opsional untuk integrasi antar-mesin — client di server lain, container, atau CI bisa memanggil endpoint tanpa proses bersama.

Kekurangannya juga nyata: kalian harus mengelola keamanan (allowlist origin, rate limiting), operasional (health checks, observability), dan tetap menyediakan mekanisme SSE untuk notifikasi. Untuk skenario satu mesin dan satu proses yang hidup bersama, ini semua beban tanpa manfaat — dan di situlah stdio menang.

stdio: Proses Lokal & Interop

stdio menempatkan server sebagai subprocess yang di-spawn host. JSON-RPC dikirim sebagai baris ke stdin server, dan respons/notifikasi dibaca dari stdout-nya. Tidak ada port, tidak ada koneksi jaringan, tidak ada autentikasi — keamanannya ditentukan sepenuhnya oleh izin file sistem dan konfigurasi host.

Inilah transport yang paling banyak dipakai integrasi harian:

  • IDE agents seperti VS Code menjalankan server MCP lokal lewat stdio.
  • CLI agents (Claude Code, Codex) melakukan hal yang sama — setiap konfigurasi tool lokal adalah definisi subprocess.
  • Skrip dan pipeline lokal mendapat akses tools tanpa harus menjalankan server web.

Karena berkomunikasi lewat stdin/stdout, server stdio punya kontrak ketat: jangan pernah mencetak log ke stdout — kalian akan merusak protokol. Semua log harus ke stderr atau file.

Lifecycle Process pada stdio

Host mengatur umur server. Alur khasnya:

  1. Host membaca konfigurasi (command + argumen + environment), lalu memanggil spawn.
  2. Host melakukan handshake initialize dan memverifikasi capability server.
  3. Selama hidup, request JSON-RPC dikirim ke stdin; server membalas di stdout.
  4. Host mengirim notifications/exit atau menutup stdin untuk menandakan akhir sesi.
  5. Server membersihkan sumber daya dan keluar; host menunggu kode exit dan menangkap pesan error dari stderr.

Contoh spawn dari sisi host di Node.js:

host.ts - spawn server stdio
import { spawn } from "node:child_process";
 
const child = spawn("npx", ["-y", "mcp-server-git"], {
  stdio: ["pipe", "pipe", "pipe"],
  env: { ...process.env }
});
 
child.stdin.write(JSON.stringify({
  jsonrpc: "2.0", id: 1, method: "initialize", params: {
    protocolVersion: "2026-07-28",
    capabilities: {},
    clientInfo: { name: "my-host", version: "1.0.0" }
  }
}) + "\n");
 
child.stderr.on("data", (chunk) => console.error(chunk.toString()));

Karena server mati bersama host-nya, operasi stateful — misalnya task dari episode 12 — tidak boleh hidup hanya di memori proses. Jika server stdio di-restart, semua task yang belum selesai ikut hilang. Untuk pekerjaan yang harus bertahan, pakai Streamable HTTP dengan penyimpanan persisten.

Warning

Dua jebakan klasik stdio: pertama, menulis log ke stdout — ini memotong protokol dan membuat host macet atau salah parsing. Kedua, konfigurasi environment yang tidak meneruskan variabel penting (token, path) ke subprocess. Periksa keduanya saat debugging server yang "tidak responsif" padahal hidup.

Membandingkan Dua Transport

AspekStreamable HTTPstdio
LokasiJaringan (endpoint HTTP)Lokal (subprocess)
ScalingHorizontal, tanpa affinitySatu proses per host
AutentikasiOAuth 2.1, header AuthorizationTidak ada (kepercayaan sistem file)
NotifikasiStream SSEstdout
Pakai untukLayanan multi-klien, produksiEditor/CLI agents, satu user

Keputusan tidak harus eksklusif: banyak server produksi dibungkus dua transport sekaligus — mode stdio untuk developer lokal dan mode HTTP untuk lingkungan bersama. SDK resmi mendukung keduanya dari satu logika bisnis yang sama.

Penutup

Episode 13 menutup celah pemahaman di lapisan paling bawah: transport. Kalian mengenal peta tiga transport (stdio, Streamable HTTP, dan SSE legacy), memahami cara Streamable HTTP memadukan request/response JSON-RPC dengan stream SSE untuk notifikasi, memiliki kriteria memilih antara HTTP dan stdio, melihat interop stdio dengan editor serta CLI agents, dan memahami lifecycle subprocess dari spawn sampai exit.

Inti yang harus dibawa pulang:

  • Streamable HTTP memakai satu endpoint untuk JSON-RPC request/response, dengan stream SSE sebagai kanal notifikasi dan streaming.
  • Pilih Streamable HTTP untuk produksi — multi-klien, scaling horizontal, dan OAuth 2.1 bekerja di atasnya secara alami.
  • Pilih stdio untuk integrasi lokal — IDE agents dan CLI agents menjalankan server sebagai subprocess tanpa jaringan.
  • stdio punya kontrak ketat: komunikasi lewat stdin/stdout, dan stdout tidak boleh dipakai untuk log — selalu pakai stderr.
  • Lifecycle dikendalikan host; state yang harus bertahan hidup dari satu proses jangan disimpan di memori.

Episode 14 berikutnya giliran keamanan naik ke tingkat berikutnya: Security Hardening Server — dari threat model untrusted tool input dan prompt injection, sampai SSRF dan teknik mitigasi berlapisnya. Sampai jumpa!

Belajar MCP - Transport Deep Dive | Belajar MCP