Tampilan
6.1 MCP sebagai Client
Tujuan bab
Setelah bab ini kamu bisa:
- Menyambungkan Mastra ke satu atau beberapa MCP server dengan
MCPClient - Menjelaskan perbedaan transport Stdio dan HTTP, serta bagaimana Mastra memilihnya
- Menyerahkan tool dari MCP server ke agent lewat
listTools() - Menangani server yang gagal terhubung tanpa menjatuhkan seluruh agent
- Menerapkan pengamanan untuk tool yang tidak kamu tulis sendiri
Prasyarat
- Bagian 2 selesai
- Paket
@mastra/mcpterpasang:npm install @mastra/mcp@latest
Kenapa memakai tool orang lain
Ada banyak kemampuan yang tidak masuk akal untuk kamu tulis sendiri: integrasi GitHub, pencarian web, akses basis data, kontrol browser. MCP (Model Context Protocol) adalah standar terbuka yang membuat kemampuan semacam itu bisa dibagikan antar sistem — dan ekosistemnya sudah cukup besar.
Untuk Mastra, memakai MCP server berarti agent-mu mendapat tool tambahan tanpa kamu menulis satu pun createTool().
Menyambung
ts
// src/mastra/mcp/client.ts
import { MCPClient } from '@mastra/mcp'
export const mcp = new MCPClient({
id: 'mcp-eksternal',
servers: {
github: {
command: 'npx',
args: ['-y', '@modelcontextprotocol/server-github'],
env: {
GITHUB_TOKEN: process.env.GITHUB_TOKEN!,
},
},
docs: {
url: new URL('https://contoh.example.com/mcp'),
},
},
timeout: 60_000,
})Beberapa hal yang perlu dipahami dari potongan ini.
servers adalah objek, dan key-nya menjadi nama server. Nama itu dipakai untuk memberi awalan pada nama tool — akan terlihat sebentar lagi.
Transport dipilih otomatis dari bentuk konfigurasinya:
| Kalau kamu memberi | Transport yang dipakai |
|---|---|
command | Stdio — Mastra menjalankan server sebagai subprocess |
url | HTTP — mencoba Streamable HTTP dulu, lalu jatuh ke SSE lama bila gagal |
id bukan sekadar label. Dokumentasi menyebut kegunaannya secara khusus: mencegah kebocoran memori saat kamu membuat beberapa instance dengan konfigurasi yang identik. Isi selalu.
timeout default-nya 60 detik, berlaku untuk semua server kecuali ditimpa per server.
Catatan tentang environment pada server Stdio
Ini detail yang berdampak nyata dan jarang disadari. Untuk server Stdio, subprocess tidak mewarisi seluruh environment prosesmu. Ia memulai dari daftar putih terkurasi milik MCP SDK:
- Di POSIX:
HOME,LOGNAME,PATH,SHELL,TERM,USER - Di Windows:
APPDATA,HOMEDRIVE,HOMEPATH,LOCALAPPDATA,PATH,PROCESSOR_ARCHITECTURE,SYSTEMDRIVE,SYSTEMROOT,TEMP,USERNAME,USERPROFILE
Artinya API key-mu tidak otomatis sampai ke sana — kamu harus menyebutkannya secara eksplisit di env, seperti pada contoh di atas.
Ada juga inheritDefaultEnv yang default-nya true. Menyetelnya ke false berarti hanya variabel di env yang diteruskan. Dokumentasi memberi peringatan yang layak diperhatikan: subprocess tanpa PATH bisa gagal menjalankan perintah yang bukan path absolut.
Menyerahkan tool ke agent
ts
// src/mastra/agents/dev-agent.ts
import { Agent } from '@mastra/core/agent'
import { mcp } from '../mcp/client.ts'
export const devAgent = new Agent({
id: 'dev-agent',
name: 'Dev Agent',
instructions: 'Bantu pengembang mengelola repositori dan mencari dokumentasi.',
model: 'openai/gpt-5.6-sol',
tools: await mcp.listTools(),
})listTools() mengambil semua tool dari semua server yang dikonfigurasi.
Nama tool diberi awalan nama server, dengan format namaServer_namaTool — misalnya github_create_issue. Ini mencegah tabrakan nama saat dua server kebetulan punya tool dengan nama sama.
Menangani server yang gagal
Contoh di atas punya kelemahan yang baru terasa di produksi: kalau salah satu server tidak bisa dihubungi, listTools() bermasalah dan agent-mu ikut gagal dibuat.
Untuk itu ada listToolsWithErrors():
ts
// src/mastra/agents/dev-agent.ts
import { Agent } from '@mastra/core/agent'
import { mcp } from '../mcp/client.ts'
const { tools, errors, errorDetails, durations } = await mcp.listToolsWithErrors({
perServerTimeoutMs: 3_000,
})
if (Object.keys(errors).length > 0) {
console.warn('Sebagian MCP server tidak dapat dihubungi:', errorDetails)
}
export const devAgent = new Agent({
id: 'dev-agent',
name: 'Dev Agent',
instructions: 'Bantu pengembang mengelola repositori dan mencari dokumentasi.',
model: 'openai/gpt-5.6-sol',
tools,
})Yang kamu dapat:
| Nilai | Isinya |
|---|---|
tools | Tool dari server yang berhasil dalam batas waktu |
errors | Peta pesan error per server, berupa string |
errorDetails | Pesan yang sama plus httpStatus dan code transport bila tersedia |
durations | Lama penemuan tiap server dalam milidetik |
perServerTimeoutMs membatasi berapa lama penemuan menunggu tiap server. Server yang selesai dalam batas itu tetap masuk tools; yang melewati batas masuk errors.
Pola ini yang sebaiknya kamu pakai begitu ada lebih dari satu server. Agent yang kehilangan satu dari empat sumber tool masih jauh lebih berguna daripada agent yang gagal dibuat sama sekali.
durations berguna untuk diagnosis
Kalau startup aplikasimu terasa lambat, durations langsung memberitahu server mana yang menahan. Ini jenis informasi yang biasanya harus kamu ukur sendiri dengan susah payah.
Mengamankan tool yang bukan tulisanmu
Ini bagian yang paling penting dari bab ini. Tool dari MCP server eksternal adalah kode yang tidak kamu tulis, tidak kamu tinjau, dan bisa berubah tanpa memberitahumu. Mastra menyediakan beberapa lapis pengamanan.
Persetujuan sebelum eksekusi
ts
export const mcp = new MCPClient({
id: 'mcp-eksternal',
servers: {
github: {
command: 'npx',
args: ['-y', '@modelcontextprotocol/server-github'],
env: { GITHUB_TOKEN: process.env.GITHUB_TOKEN! },
requireToolApproval: true,
},
},
})requireToolApproval bekerja dengan alur human-in-the-loop yang sudah kamu kenal dari 2.3 — tool berhenti, memancarkan permintaan persetujuan, dan menunggu.
Ia juga bisa berupa fungsi, sehingga keputusannya dinamis:
ts
requireToolApproval: ({ toolName }) => toolName.startsWith('delete_'),Fungsi ini menerima nama tool, argumen, request context, dan anotasi yang diiklankan server — cukup untuk memutuskan berdasarkan risiko sebenarnya, bukan menyetujui semuanya atau tidak sama sekali.
Membatasi host yang boleh dihubungi
Untuk server HTTP, allowedHosts adalah daftar putih host yang boleh dihubungi klien atas nama server itu:
ts
docs: {
url: new URL('https://contoh.example.com/mcp'),
allowedHosts: ['contoh.example.com'],
},Beberapa aturan pencocokannya yang perlu diketahui: cocokkan persis, tidak peka huruf besar-kecil pada hostname, tidak mendukung wildcard, dan skema URL tidak diperiksa. Array kosong menolak semua permintaan; kalau tidak diisi sama sekali, tidak ada pembatasan.
forwardInstructions — hati-hati di sini
MCP server bisa mengiklankan instruksi, dan Mastra bisa menambahkannya ke system prompt agent-mu. Fitur ini mati secara default, dan dokumentasi memberi alasan yang tegas:
aktifkan hanya untuk server yang kamu percaya, karena instruksinya disuntikkan ke dalam system prompt agent.
Ini permukaan serangan, bukan sekadar fitur kenyamanan
Menyalakan forwardInstructions berarti pihak ketiga bisa menulis ke dalam system prompt agent-mu. Server yang berniat jahat — atau yang diretas — bisa menyisipkan instruksi yang mengubah perilaku agent, termasuk membujuknya membocorkan data dari tool lain.
Biarkan mati kecuali kamu benar-benar mengendalikan server itu. instructionsMaxLength (default 512 karakter) membatasi panjangnya, tapi batas panjang bukan batas niat.
Gambaran keseluruhan
Kesalahan umum
Gejala: MCP server Stdio gagal jalan atau melaporkan kredensial tidak ditemukan, padahal variabelnya jelas ada di .env aplikasimu. Penyebab: Subprocess Stdio tidak mewarisi seluruh environment prosesmu — hanya daftar putih terkurasi seperti PATH dan HOME. API key-mu tidak termasuk. Perbaikan: Sebutkan variabel yang dibutuhkan secara eksplisit di properti env pada definisi server itu.
Gejala: Seluruh aplikasi gagal dijalankan karena satu MCP server sedang tidak bisa dihubungi. Penyebab: Memakai listTools(), yang tidak memisahkan kegagalan per server. Perbaikan: Ganti ke listToolsWithErrors() dengan perServerTimeoutMs, lalu catat errorDetails dan lanjutkan dengan tool yang berhasil dimuat.
Coba sendiri
Tantangan: Sambungkan agent ke dua MCP server sekaligus — satu Stdio dan satu HTTP — lalu buktikan bahwa aplikasimu tetap hidup saat salah satunya mati.
Ketentuan:
- Pasang
@mastra/mcpdan konfigurasikanMCPClientdenganidyang diisi - Server pertama memakai transport Stdio, dan membutuhkan sebuah environment variable yang kamu teruskan lewat
env - Server kedua memakai
url, dan dibatasi denganallowedHosts - Pakai
listToolsWithErrors()denganperServerTimeoutMs: 3000, dan cetakerrors,errorDetails, sertadurations - Jalankan sekali dengan kedua server sehat, dan catat nama-nama tool yang muncul — perhatikan awalannya
- Rusak sengaja server kedua: ubah URL-nya ke host yang tidak ada. Jalankan lagi, dan pastikan agent tetap terbentuk dengan tool dari server pertama
- Tambahkan
requireToolApprovalberupa fungsi yang hanya meminta persetujuan untuk tool yang namanya mengandung kata berisiko - Hapus satu variabel dari
envserver Stdio dan amati apa yang terjadi
Checklist penerimaan:
- [ ] Nama tool yang muncul berawalan nama server, misalnya
github_... - [ ] Setelah langkah 6, aplikasi tetap jalan dan
errorDetailsmemuat penjelasan kegagalan server kedua - [ ]
durationsmenunjukkan angka berbeda untuk kedua server - [ ] Fungsi
requireToolApprovalbenar-benar memicu jeda hanya untuk tool yang kamu maksud, bukan semuanya - [ ] Langkah 8 memperlihatkan bahwa variabel di
envmemang tidak diwariskan otomatis - [ ] Kamu bisa menjelaskan kenapa
forwardInstructionssebaiknya tetap mati untuk server yang bukan milikmu
Petunjuk: Langkah 6 adalah inti latihan ini. Di lingkungan pengembangan, semua server biasanya sehat, sehingga perbedaan antara listTools() dan listToolsWithErrors() tidak terlihat sama sekali — dan baru terasa di produksi pada saat yang paling tidak tepat. Rusakkan sekarang, selagi murah.
Ikhtisar
MCPClientmenyambungkan Mastra ke satu atau beberapa MCP server. Selalu isiiduntuk mencegah kebocoran memori.- Transport dipilih dari bentuk konfigurasi:
command→ Stdio,url→ HTTP (Streamable HTTP dulu, jatuh ke SSE bila gagal). - Subprocess Stdio tidak mewarisi seluruh environment — hanya daftar putih terkurasi. Kredensial harus disebut eksplisit di
env. listTools()menyerahkan semua tool ke agent, dengan nama berawalannamaServer_.listToolsWithErrors()menambahkan ketahanan terhadap server yang gagal, pluserrorDetailsdandurations.- Tool eksternal adalah kode yang tidak kamu tinjau. Amankan dengan
requireToolApproval(boolean atau fungsi) danallowedHosts— yang cocoknya persis dan tidak mendukung wildcard. forwardInstructionsmati secara default, dan sebaiknya tetap begitu. Menyalakannya berarti mengizinkan pihak ketiga menulis ke system prompt agent-mu.
Lanjut ke mana
Sekarang arah sebaliknya — membuat tool, agent, dan workflow-mu bisa dipakai sistem lain: 6.2 Mastra sebagai MCP Server.