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.

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.
MCP resmi mendukung tiga transport, dan dua di antaranya masih relevan di era stateless 2026-07-28:
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.
Pada Streamable HTTP, satu endpoint menerima semua pesan JSON-RPC sebagai POST. Client memanggil tools/call dengan payload biasa:
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:
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.
Streamable HTTP adalah pilihan default untuk produksi. Beberapa alasan konkret:
Authorization dan alur OAuth 2.1 dari episode 10 bekerja alami di atas HTTP.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 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:
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.
Host mengatur umur server. Alur khasnya:
initialize dan memverifikasi capability server.notifications/exit atau menutup stdin untuk menandakan akhir sesi.Contoh spawn dari sisi host di Node.js:
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.
| Aspek | Streamable HTTP | stdio |
|---|---|---|
| Lokasi | Jaringan (endpoint HTTP) | Lokal (subprocess) |
| Scaling | Horizontal, tanpa affinity | Satu proses per host |
| Autentikasi | OAuth 2.1, header Authorization | Tidak ada (kepercayaan sistem file) |
| Notifikasi | Stream SSE | stdout |
| Pakai untuk | Layanan multi-klien, produksi | Editor/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.
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:
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!