Episode ini membangun sisi klien MCP: koneksi ke server via stdio dan HTTP di TypeScript serta Python, pola handling error dan streaming, lalu eksplorasi MCP Inspector untuk testing interaktif, debug transport, dan validasi skema.

Episode 6 kemarin kita sudah punya server MCP — currency-tools di TypeScript dan weather-server di Python — yang berjalan lewat transport stdio dan siap diuji. Tapi server tidak berarti apa-apa tanpa sesuatu yang memanggilnya. Di episode ini kita bangun sisi kliennya: Client SDK yang menghubungi server, menampilkan daftar tool, memanggilnya, dan menangani error maupun streaming.
Roadmap episode ini: pahami posisi client dalam arsitektur MCP, implementasi client di TypeScript (stdio dan HTTP) dan Python, pola handling error dan streaming, lalu kenalan dengan MCP Inspector — alat resmi untuk menguji server secara interaktif tanpa menulis kode sama sekali.
Ingat kembali arsitektur di episode 2: Host (aplikasi user-facing), Client (koneksi satu-ke-satu dengan sebuah server), dan Server. Satu host seperti editor atau CLI agent bisa menyalakan banyak client, satu untuk tiap server. Karena koneksinya satu-ke-satu, client-lah yang memegang transport, mengirim request JSON-RPC, dan menerima respons maupun notifikasi dari server.
Tugas utama client: membangun koneksi ke server (via stdio untuk proses lokal, atau HTTP untuk server remote), menampilkan katalog tool/resources/prompts yang diekspos server, menjalankan tools/call dengan argumen hasil parsing, serta menangani error JSON-RPC dan pesan streaming.
Info
Satu aturan emas: client dan server boleh berasal dari SDK yang berbeda. Client TypeScript tidak peduli server-nya Python — yang penting keduanya berbicara JSON-RPC sesuai spesifikasi yang sama.
Untuk server lokal (subprocess), pakai StdioClientTransport:
import { Client } from "@modelcontextprotocol/sdk/client/index.js";
import { StdioClientTransport } from "@modelcontextprotocol/sdk/client/stdio.js";
const transport = new StdioClientTransport({
command: "node",
args: ["dist/server.js"],
});
const client = new Client({ name: "test-client", version: "1.0.0" });
await client.connect(transport);
const { tools } = await client.listTools();
console.log(tools.map((tool) => tool.name));
const result = await client.callTool({
name: "convert-currency",
arguments: { from: "USD", to: "IDR", amount: 100 },
});
console.log(result.content);
await client.close();Alurnya: buat transport yang mengelola proses child node dist/server.js, buat objek Client dengan identitas, sambungkan dengan client.connect(transport), lalu telusuri client.listTools() dan eksekusi client.callTool({:ts}...). Jangan lupa client.close() untuk melepas proses child dan koneksi dengan rapi.
Server remote (kita deploy di episode 9) tidak bisa dipanggil lewat stdio. Gantinya, gunakan StreamableHTTPClientTransport yang mengirim request JSON-RPC lewat POST dan menerima respons atau streaming lewat SSE:
import { Client } from "@modelcontextprotocol/sdk/client/index.js";
import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/streamableHttp.js";
const transport = new StreamableHTTPClientTransport(
new URL("https://mcp.example.com/mcp"),
{
requestInit: {
headers: { Authorization: "Bearer access-token" },
},
}
);
const client = new Client({ name: "web-client", version: "1.0.0" });
await client.connect(transport);Setelah connect, kode selanjutnya identik dengan versi stdio — listTools, callTool, dan teman-temannya tidak peduli transport di balik layar. Perhatikan opsi requestInit untuk menyisipkan header HTTP seperti Authorization; ini penting saat server remote dilindungi OAuth yang akan kita bahas di episode 10.
Di Python, pola yang lazim adalah async with untuk mengelola lifecycle koneksi sekaligus sesi:
import asyncio
from mcp import ClientSession, StdioServerParameters
from mcp.client.stdio import stdio_client
async def main():
params = StdioServerParameters(
command="python", args=["weather_server.py"]
)
async with stdio_client(params) as (read, write):
async with ClientSession(read, write) as session:
await session.initialize()
tools = await session.list_tools()
print([tool.name for tool in tools.tools])
result = await session.call_tool(
"get_weather", {"city": "Jakarta"}
)
print(result.content)
asyncio.run(main())stdio_client(params) membuka proses child, lalu ClientSession membungkusnya dengan layer JSON-RPC. session.initialize() menyepakati versi dan capability sebelum request lain boleh dikirim — di era stateless 2026-07-28 informasi ini ikut dikirim per-request, tetapi SDK tetap menanganinya transparan untuk kalian. Untuk server HTTP, ganti transport dengan streamable_http_client(url) dari modul mcp.client.streamable_http; sisanya sama.
Koneksi jaringan selalu bisa gagal, dan server bisa menolak argumen. Selalu bungkus pemanggilan tool dengan try/catch dan periksa error JSON-RPC:
try {
const result = await client.callTool({
name: "convert-currency",
arguments: { from: "USD", to: "IDR", amount: -100 },
});
console.log(result.content);
} catch (error) {
console.error("Panggilan gagal:", error);
}Server yang sehat mengembalikan error berstruktur JSON-RPC: code, message, dan data. Bedakan jenis kegagalan — -32700 parse error, -32601 method tidak dikenal, -32602 argumen invalid, dan kode khusus aplikasi yang didefinisikan server — supaya pesan yang disampaikan ke user akurat.
Untuk hasil yang berjalan lama, server bisa mengirim notifikasi progress. Daftarkan handler notifikasi sekali, lalu biarkan SDK memanggilnya tiap ada pesan masuk:
client.setNotificationHandler((notification) => {
console.log("Notifikasi dari server:", notification);
});Notifikasi tidak punya id — ini panggilan satu arah. Gunakan untuk progress, log, atau update status; jangan berasumsi notifikasi selalu tiba sebelum respons utama selesai.
MCP Inspector adalah tool resmi untuk menguji server tanpa menulis client sama sekali. Ia menjalankan server kalian, menyajikan UI web di browser, dan membiarkan kalian mengeksplorasi semua capability.
npx @modelcontextprotocol/inspector python weather_server.pynpx @modelcontextprotocol/inspector membuka halaman seperti dashboard yang menampilkan: daftar Tools / Resources / Prompts berikut skema inputnya, form Call tool yang digenerate dari skema (sekaligus validasi skema — argumen invalid langsung ditolak), panel raw request/response JSON-RPC untuk debug transport, serta log server yang tampil live.
Success
Sebelum mengintegrasikan server ke aplikasi apa pun, biasakan mengujinya dulu di Inspector. Kalau server lolos di Inspector, mayoritas masalah integrasi dengan client lain sudah bisa dicegah.
Episode 7 melengkapi sisi klien dari cerita MCP: StdioClientTransport dan StreamableHTTPClientTransport di TypeScript, ClientSession asinkron di Python, pola handling error JSON-RPC dan notifikasi, plus MCP Inspector sebagai senjata utama debugging. Sekarang kalian bisa memanggil server yang dibangun di episode 6 dari dua bahasa berbeda.
Inti yang harus dibawa pulang:
stdio untuk proses lokal, streamable HTTP untuk remote.Di episode 8 berikutnya kita naik ke fitur modern spesifikasi 2026-07-28: Multi-Round-Trip Requests (MRTR) — bagaimana server bisa meminta konfirmasi atau otorisasi tambahan di tengah pemanggilan tool, menggantikan ketergantungan pada streaming SSE panjang. Sampai jumpa!