Membongkar Tools di MCP: bagaimana tool didefinisikan dengan JSON Schema, didaftarkan lewat tools/list, dieksekusi lewat tools/call, menghasilkan structured output, hingga makna tool annotation dan kenapa annotations bukan jaminan keamanan.

Setelah memahami lifecycle koneksi di episode 3, sekarang kita masuk ke primitives yang paling sering dipakai: Tools. Ini adalah "tangan" yang memungkinkan model melakukan aksi nyata di dunia eksternal — menulis file, mengirim email, menjalankan query database, memanggil API.
Episode ini membedah seluruh siklus hidup sebuah tool: bagaimana ia didefinisikan, bagaimana model menemukannya, bagaimana ia dieksekusi, bentuk outputnya, dan apa makna sebenarnya dari tool annotation. Di akhir episode kalian akan bisa membaca definisi tool apa pun seperti membaca menu restoran.
Tool adalah fungsi yang bisa dipanggil model untuk melakukan tindakan tertentu. Dua sifat pembeda yang penting:
Bayangkan server sebagai kantor: tools adalah karyawan yang siap menjalankan tugas, resources adalah arsip yang bisa dibaca, dan prompts adalah SOP yang sudah disiapkan. Model adalah manajer yang memilih karyawan mana yang ditugasi.
Setiap tool didefinisikan dengan tiga bagian utama: name (nama unik), description (penjelasan untuk model), dan inputSchema (JSON Schema untuk parameter). Contoh definisi tool:
{
"tools": [
{
"name": "get_weather",
"description": "Ambil cuaca terkini untuk sebuah kota",
"inputSchema": {
"type": "object",
"properties": {
"city": {
"type": "string",
"description": "Nama kota, misalnya Jakarta"
},
"unit": {
"type": "string",
"enum": ["celsius", "fahrenheit"]
}
},
"required": ["city"]
}
}
]
}JSON Schema adalah bahasa deskripsi parameter yang sudah jadi standar. Server bisa mengekspresikan tipe data, enum, nilai minimum/maksimum, dan validasi lainnya. Model memakai description dan skema ini untuk menentukan apakah tool relevan dan bagaimana mengisi argumen yang benar.
Model tidak tahu tool apa yang tersedia sampai server memberitahunya. Method tools/list mengembalikan daftar tool milik server:
{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/list",
"params": {}
}Host biasanya memanggil tools/list sekali di awal (atau berkala untuk caching) dan menyimpan definisi tool-nya. Daftar ini juga bisa mengandung nextCursor untuk pagination — jika server punya banyak tool, client mengambil halaman berikutnya sampai semua tool termuat.
Kalian juga bisa mengamati hasil tools/list secara langsung tanpa menulis client manual — cukup buka MCP Inspector dengan npx @modelcontextprotocol/inspector dan lihat tab tools.
Ketika model memutuskan memakai tool, host memanggil tools/call dengan nama tool dan argumen:
{
"jsonrpc": "2.0",
"id": 2,
"method": "tools/call",
"params": {
"name": "get_weather",
"arguments": {
"city": "Jakarta",
"unit": "celsius"
}
}
}Server mengeksekusi logika tool, lalu mengembalikan hasilnya. Jika eksekusi gagal, server mengirim response berisi isError: true beserta pesan error — alih-alih membiarkan client menebak penyebab kegagalan.
{
"jsonrpc": "2.0",
"id": 2,
"result": {
"content": [
{
"type": "text",
"text": "Jakarta: 30 derajat celsius, berawan"
}
],
"isError": false
}
}Bagian content adalah array items bertipe (typed) — tidak hanya teks mentah. Tipe yang umum:
| Tipe | Deskripsi |
|---|---|
text | Teks biasa yang dibaca model |
image | Gambar (data URL) |
audio | Audio (data URL) |
resource | Referensi ke resource tertentu |
Desain typed ini memungkinkan model menerima hasil dalam bentuk yang sesuai — membaca teks, atau memproses gambar yang dikembalikan tool — tanpa parsing JSON secara manual. Ini yang dimaksud structured output di spesifikasi 2026-07-28: hasil tool bukan cuma string, tapi konten dengan tipe eksplisit.
Info
Kalian mungkin mendengar istilah "tool schema & structured output" sebagai headline spesifikasi 2026-07-28. Intinya: definisi tool memakai JSON Schema yang ketat, dan output tool dibungkus dalam struktur content yang ber-tipe — dua hal yang kita lihat langsung di episode ini.
Server bisa menambahkan annotations pada definisi tool — metadata yang memberi hint ke model tentang sifat tool:
{
"name": "delete_user",
"description": "Hapus akun pengguna berdasarkan ID",
"inputSchema": {
"type": "object",
"properties": {
"userId": { "type": "string" }
},
"required": ["userId"]
},
"annotations": {
"destructiveHint": true,
"readOnlyHint": false,
"idempotentHint": false
}
}Beberapa annotation yang umum dipakai:
| Annotation | Arti untuk Model |
|---|---|
readOnlyHint | Tool tidak mengubah state — aman dipanggil berulang |
destructiveHint | Tool berpotensi menghancurkan data — butuh konfirmasi |
idempotentHint | Panggilan berulang memberi hasil yang sama |
openWorldHint | Tool berinteraksi dengan dunia luar (network, file) |
titleHint | Label pendek yang ramah manusia untuk tool |
Hint ini membantu model mengambil keputusan yang lebih baik — misalnya meminta konfirmasi sebelum memanggil tool destruktif, atau menghindari memanggil tool read-only berulang kali.
Satu pesan penting yang harus kalian pegang teguh: annotations hanyalah petunjuk, bukan jaminan keamanan. Tidak ada yang memaksa server jujur tentang destructiveHint atau readOnlyHint. Sebuah tool berbahaya bisa saja melabeli dirinya readOnlyHint: true untuk menipu model.
Oleh karena itu, validasi keamanan harus datang dari lapisan lain: allowlist tool yang boleh dipanggil, validasi input yang ketat, sandbox eksekusi, dan otorisasi. Jangan pernah menaruh kepercayaan pada annotations dari server yang tidak kalian kenal. Kita akan membahas hardening ini secara menyeluruh di episode 14.
Pada episode 4 ini kalian sudah memahami seluruh siklus hidup tool di MCP: definisi dengan JSON Schema, penemuan lewat tools/list, eksekusi lewat tools/call, output berbentuk content bertipe, dan peran annotations sebagai hint untuk model.
Inti yang harus dibawa pulang:
name, description, inputSchema).tools/list dan mengeksekusinya lewat tools/call.text, image, audio, resource.readOnlyHint, destructiveHint, dan lainnya) membantu model mengambil keputusan.Di episode 5 berikutnya kita akan membahas dua primitives yang tersisa: Resources dan Prompts — bagaimana resource dibaca lewat resources/read, pola resource templates, dan bagaimana prompt template reusable bekerja lewat argument binding. Sampai jumpa di episode 5!