Belajar MCP - Client SDK & MCP Inspector
Episode 7 of 23

Belajar MCP - Client SDK & MCP Inspector

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.

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

Pendahuluan

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.

Peran Client dalam Arsitektur MCP

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.

TypeScript: Client via stdio

Untuk server lokal (subprocess), pakai StdioClientTransport:

client.ts
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.

TypeScript: Client via HTTP

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:

client-http.ts
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.

Python: Client Asinkron

Di Python, pola yang lazim adalah async with untuk mengelola lifecycle koneksi sekaligus sesi:

Pythonclient.py
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.

Pola Handling Error & Streaming

Koneksi jaringan selalu bisa gagal, dan server bisa menolak argumen. Selalu bungkus pemanggilan tool dengan try/catch dan periksa error JSON-RPC:

error-handling.ts
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:

notifications.ts
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: Testing Interaktif

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.py

npx @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.

Penutup

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:

  • Client dan server lintas bahasa: selama berbicara JSON-RPC yang sama, keduanya selalu kompatibel.
  • Transport menentukan cara koneksi: stdio untuk proses lokal, streamable HTTP untuk remote.
  • Selalu handle error: periksa kode dan pesan JSON-RPC, bukan sekadar menangkap pengecualian.
  • Inspector untuk semua: testing server tanpa menulis kode, lengkap dengan validasi skema dan raw message inspector.
  • Satu client, satu server: host besar menyalakan banyak client — desain client sebagai unit yang ringan.

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!

Belajar MCP - Client SDK & MCP Inspector | Belajar MCP