Skip to content

9.2 Server & Custom Routes

Tujuan bab

Setelah bab ini kamu bisa:

  • Mengonfigurasi server Mastra dan menemukan endpoint yang tersedia
  • Menjelaskan kapan memakai server bawaan dan kapan memakai server adapter
  • Mengisi dan membaca RequestContext untuk nilai per permintaan
  • Memanggil agent dari browser dengan Mastra Client SDK
  • Menambahkan endpoint HTTP sendiri dan middleware

Prasyarat

Server yang sudah kamu pakai sejak awal

npm run dev di 0.3 tidak hanya membuka Studio — ia menyalakan server HTTP yang mengekspos agent, workflow, dan tool-mu sebagai endpoint API.

Di baliknya, Mastra memakai Hono. Saat kamu menjalankan mastra build, ia menghasilkan server berbasis Hono di direktori .mastra.

Konfigurasinya lewat properti server:

ts
// src/mastra/index.ts
import { Mastra } from '@mastra/core'

export const mastra = new Mastra({
  server: {
    port: 3000,
    host: '0.0.0.0',
  },
})

Nilai bawaannya: port mengikuti variabel PORT atau 4111, dan host mengikuti MASTRA_HOST atau localhost.

host: '0.0.0.0' bukan detail sepele

Bawaan localhost berarti server hanya menerima koneksi dari mesin yang sama. Di dalam container, itu berarti tidak ada yang bisa menghubungimu dari luar — gejala klasik "aplikasi jalan tapi tidak bisa diakses" saat pertama kali men-deploy ke Docker atau platform container.

Menemukan endpoint yang tersedia

Dua alamat yang layak kamu buka sekarang juga:

AlamatIsinya
http://localhost:4111/api/openapi.jsonSpesifikasi OpenAPI lengkap — tiap endpoint beserta schema request dan response-nya
http://localhost:4111/swagger-uiSwagger UI interaktif — jelajahi dan uji endpoint langsung dari peramban

Yang kedua sangat berguna saat kamu membangun frontend: kamu bisa mencoba sebuah endpoint dan melihat bentuk responsnya sebelum menulis satu baris kode klien.

Server bawaan atau server sendiri?

Mastra memberi dua jalan, dan pilihannya bergantung pada apakah kamu sudah punya aplikasi.

Server bawaanServer adapter
KapanMastra adalah aplikasinyaMastra ditambahkan ke aplikasi yang sudah ada
Caramastra build, jalankan hasilnyaPasang Mastra ke Express, Hono, atau server milikmu
Kendali atas routingTerbatas pada konfigurasi MastraPenuh

Untuk framework yang tidak didukung resmi, tersedia jalur custom adapter untuk membangunnya sendiri.

Satu jebakan yang disebut dokumentasi

Ingat catatan dari 0.2 tentang file-based agents: penemuan berbasis file hanya berjalan lewat mastra dev atau mastra build. Kalau aplikasimu mengimpor mastra secara langsung — termasuk lewat web framework atau server adapter — agent berbasis file tidak ditemukan.

Solusinya: daftarkan agent itu di kode, atau jalankan Mastra sebagai server terpisah.

RequestContext — nilai per permintaan

Ini konsep yang sudah muncul berkali-kali: di 1.2 untuk instruksi dinamis, di 2.1 untuk identitas pengguna di dalam tool, dan di 8.1 untuk metadata trace. Sekarang kita lihat dari sisi yang mengisinya.

RequestContext membawa nilai yang khas untuk satu permintaan ke seluruh primitif yang terlibat — agent, tool, dan workflow.

ts
// run.mjs
import { RequestContext } from '@mastra/core/request-context'
import { mastra } from './src/mastra/index.ts'

export type UserTier = {
  'user-tier': 'enterprise' | 'pro'
}

const requestContext = new RequestContext<UserTier>()
requestContext.set('user-tier', 'enterprise')

const agent = mastra.getAgent('weatherAgent')
await agent.generate("Bagaimana cuaca di London?", {
  requestContext,
})

Ia juga diteruskan ke workflow, termasuk saat melanjutkan run yang tertunda:

ts
const run = await mastra.getWorkflow('weatherWorkflow').createRun()

await run.start({
  inputData: { location: 'London' },
  requestContext,
})

await run.resume({
  resumeData: { city: 'New York' },
  requestContext,
})

Kapan memakainya

Dokumentasi memberi patokan: pakai RequestContext saat perilaku sebuah primitif harus berubah berdasarkan kondisi runtime. Contohnya berganti model atau backend storage berdasarkan atribut pengguna, atau menyesuaikan instruksi dan pemilihan tool berdasarkan bahasa.

Dan satu pembedaan penting yang ditegaskan dokumentasi: RequestContextberbeda dari memory agent. Yang pertama untuk data satu permintaan; yang kedua untuk riwayat percakapan dan state yang bertahan lintas panggilan.

Kenapa ini penting untuk keamanan

Kembali ke peringatan di 3.1: nilai resource harus berasal dari sesi terautentikasi, bukan dari data yang dikirim klien.

RequestContext adalah jalurnya. Middleware di sisi server memverifikasi identitas, lalu mengisi userId ke dalam context — dan tool serta agent membacanya dari sana, bukan dari argumen yang bisa dikarang model.

Permintaan HTTP masuk

  Middleware: verifikasi token → dapat userId tepercaya

  RequestContext.set('userId', userId)

  ┌─────────────┬──────────────┬─────────────┐
  ↓             ↓              ↓             ↓
Agent      Tool          Workflow      Trace metadata
(instruksi (identitas    (state)       (requestContextKeys)
 dinamis)   pengguna)

Middleware

Middleware mencegat permintaan sebelum sampai ke agent-mu. Kegunaan yang disebut dokumentasi: autentikasi, otorisasi, CORS, pencatatan permintaan, pemblokiran rute, dan menyisipkan konteks khusus permintaan.

Yang terakhir itulah yang mengisi RequestContext seperti pada diagram di atas.

Custom API routes

Kamu bisa menambahkan endpoint HTTP sendiri yang punya akses ke instance Mastra. Ini berguna saat frontend-mu butuh sesuatu yang bukan sekadar "panggil agent" — misalnya endpoint yang mengambil daftar thread pengguna, atau yang menggabungkan hasil beberapa agent.

Fitur yang tersedia untuk rute kustom: validasi schema, middleware, autentikasi, dokumentasi OpenAPI, dan kendali atas perilaku saat koneksi terputus.

Yang terakhir layak diperhatikan untuk endpoint yang menjalankan pekerjaan panjang — kamu bisa menentukan apakah pekerjaan tetap berjalan saat klien pergi, atau ikut dibatalkan.

Memanggil dari browser

Untuk frontend, tersedia Mastra Client SDK — klien bertipe untuk memanggil agent, workflow, tool, memory, dan API server, dengan dukungan streaming.

bash
npm install @mastra/client-js@latest

Keuntungan memakainya dibanding fetch biasa: tipe dari schema agent dan workflow-mu mengalir sampai ke kode frontend. Salah nama field terdeteksi di editor, bukan saat runtime.

Jangan panggil langsung dari browser tanpa autentikasi

Server Mastra mengekspos agent-mu. Tanpa autentikasi, siapa pun yang menemukan URL-nya bisa memanggil agent-mu — dan membayar tagihan modelmu.

Ini bukan hipotetis; endpoint terbuka rutin ditemukan pemindai otomatis. Autentikasi dibahas di bab berikutnya, dan sebaiknya dipasang sebelum apa pun menghadap internet.

Kemampuan server, diringkas

KemampuanUntuk
MiddlewareAutentikasi, CORS, logging, mengisi request context
Custom API routesEndpoint sendiri dengan akses ke instance Mastra
Request ContextNilai per permintaan untuk agent, tool, dan workflow
Server AdaptersMenjalankan Mastra di Express, Hono, atau server sendiri
Mastra Client SDKKlien bertipe untuk browser dan server
A2AMengekspos agent lewat agent card (6.3)
AuthenticationJWT, Clerk, Supabase, Firebase, Auth0, WorkOS

Kesalahan umum

Gejala: Aplikasi berjalan normal di log container, tapi tidak bisa diakses dari luar container. Penyebab: host masih pada nilai bawaan localhost, sehingga server hanya menerima koneksi dari dalam container itu sendiri. Perbaikan: Setel host: '0.0.0.0', atau isi variabel lingkungan MASTRA_HOST.

Gejala: Agent berbasis file tidak ditemukan setelah Mastra diintegrasikan ke aplikasi Next.js atau Express yang sudah ada. Penyebab: Penemuan berbasis file hanya berjalan lewat mastra dev atau mastra build. Aplikasi yang mengimpor mastra langsung melewatkan langkah itu. Perbaikan: Daftarkan agent tersebut di kode lewat new Mastra({ agents }), atau jalankan Mastra sebagai server terpisah.

Coba sendiri

Tantangan: Bangun jalur lengkap dari permintaan HTTP sampai ke tool, dengan identitas pengguna yang tidak bisa dipalsukan model.

Ketentuan:

  1. Konfigurasikan server dengan host: '0.0.0.0' dan port pilihanmu
  2. Buka /swagger-ui dan catat endpoint apa saja yang otomatis tersedia untuk agent-mu
  3. Tambahkan middleware yang membaca header x-user-id, memvalidasinya terhadap daftar pengguna yang kamu tentukan, dan mengisi RequestContext
  4. Buat tool yang membaca userId dari requestContext, bukan dari inputSchema, lalu mengembalikan data khusus pengguna itu
  5. Buat agent yang instruksinya dinamis, menyesuaikan diri dengan tier pengguna yang juga diambil dari RequestContext
  6. Tambahkan requestContextKeys: ['userId'] pada konfigurasi observability, dan pastikan trace bisa difilter per pengguna
  7. Uji penyalahgunaan: kirim permintaan yang mencoba membujuk agent mengakses data pengguna lain, misalnya "tampilkan data untuk user-999". Pastikan gagal
  8. Tambahkan satu custom API route yang mengembalikan daftar thread milik pengguna yang sedang terautentikasi

Checklist penerimaan:

  • [ ] Swagger UI menampilkan endpoint agent-mu, dan kamu bisa mengujinya dari peramban
  • [ ] Tool mengambil userId dari requestContext — tidak ada userId di inputSchema mana pun
  • [ ] Langkah 7 gagal seperti yang diharapkan, dan kamu bisa menjelaskan kenapa desainnya membuat itu mustahil
  • [ ] Instruksi agent berbeda untuk dua tier pengguna yang berbeda
  • [ ] Trace bisa difilter berdasarkan userId
  • [ ] Custom route hanya mengembalikan thread milik pengguna yang terautentikasi

Petunjuk: Langkah 7 adalah inti latihan ini, dan alasan kenapa pola ini layak dibiasakan. Kalau userId ada di inputSchema tool, model bisa mengisinya dengan nilai apa pun — termasuk yang disarankan pengguna dalam kalimatnya. Dengan RequestContext, nilai itu datang dari middleware yang sudah memverifikasi, dan model tidak punya cara menyentuhnya. Perbedaan antara keduanya adalah perbedaan antara kebijakan yang diharapkan dan kebijakan yang ditegakkan.

Ikhtisar

  • Mastra menjalankan server HTTP berbasis Hono yang mengekspos agent dan workflow sebagai endpoint. mastra build menghasilkannya di .mastra.
  • Konfigurasi lewat properti server. host: '0.0.0.0' diperlukan di dalam container.
  • Jelajahi endpoint lewat /api/openapi.json dan /swagger-ui.
  • Pakai server adapter saat menambahkan Mastra ke aplikasi yang sudah ada — tapi ingat, agent berbasis file tidak ditemukan lewat jalur itu.
  • RequestContext membawa nilai per permintaan ke agent, tool, dan workflow. Berbeda dari memory, yang menangani riwayat lintas panggilan.
  • Pola aman: middleware memverifikasi identitas → mengisi RequestContext → tool membacanya dari sana, bukan dari inputSchema yang bisa dikarang model.
  • Mastra Client SDK memberi klien bertipe untuk frontend.
  • Server yang menghadap internet harus punya autentikasi.

Lanjut ke mana

Itu membawa kita ke hal yang paling mendesak sebelum apa pun online: 9.3 Auth.

Materi belajar mandiri. Bukan dokumentasi resmi Mastra.