Laravel MCP: Bikin Server AI untuk Aplikasi Laravel

Diperbaharui 10 November 2026 6:05 AM

Laravel MCP adalah package resmi untuk membuat MCP server di dalam aplikasi Laravel: satu endpoint yang bisa dipanggil aplikasi AI seperti Claude Desktop, Cursor, atau agen buatan sendiri untuk membaca data dan menjalankan aksi di aplikasimu. Kalau selama ini kamu menulis API lalu menyalin deskripsinya ke prompt, MCP memindahkan deskripsi itu ke dalam kode—terstruktur, bisa diuji, dan tidak perlu diperbarui setiap ganti model.

Semua nama class dan perintah di bawah diverifikasi dari dokumentasi resmi Laravel dan Packagist.

Apa Itu Laravel MCP

MCP (Model Context Protocol) mendefinisikan bagaimana model bahasa menemukan dan memanggil kemampuan di luar dirinya lewat tiga primitif: tools (fungsi yang dieksekusi), resources (data yang dibaca sebagai konteks), dan prompts (template instruksi). Laravel MCP menyediakan kelas dasar untuk ketiganya plus facade Mcp untuk pendaftaran server. Versi stabil terakhir di Packagist adalah v1.1.2 (26 Oktober 2026), dengan requirement PHP ^8.2 dan framework ^11.45.3, ^12.41.1, atau ^13.0.

Bedanya dengan REST API: klien AI tidak perlu tahu URL tiap endpoint. Ia meminta daftar tool, membaca skema inputnya, lalu memilih sendiri—sehingga kualitas deskripsi jauh lebih menentukan daripada di API konvensional.

Instalasi dan Dua Jenis Server

Perintah kedua menerbitkan routes/ai.php—file terpisah dari web.php supaya rute agen tidak tercampur rute aplikasi.

composer require laravel/mcp

php artisan vendor:publish --tag=ai-routes

php artisan make:mcp-server WeatherServer

Perintah terakhir membuat kelas di app/Mcp/Servers/WeatherServer.php yang mewarisi Laravel\Mcp\Server, lengkap dengan tiga properti: $tools, $resources, dan $prompts.

Web server diakses lewat HTTP POST dan cocok untuk klien jarak jauh, sedangkan local server berjalan sebagai perintah Artisan untuk asisten di mesin developer.

<?php

use App\Mcp\Servers\WeatherServer;
use Laravel\Mcp\Facades\Mcp;

Mcp::web('/mcp/weather', WeatherServer::class)
    ->middleware(['throttle:mcp']);

Mcp::local('weather', WeatherServer::class);

Karena Mcp::web mengembalikan objek rute biasa, middleware Laravel tetap berlaku. Ini penting—endpoint MCP adalah pintu masuk ke data aplikasimu, bukan halaman publik.

Membuat Tool Pertama

Satu tool = satu kelas yang mewarisi Laravel\Mcp\Server\Tool, dengan dua method wajib: schema() untuk mendeskripsikan argumen dan handle() untuk mengeksekusi.

<?php

namespace App\Mcp\Tools;

use App\Models\Order;
use Illuminate\Contracts\JsonSchema\JsonSchema;
use Laravel\Mcp\Request;
use Laravel\Mcp\Response;
use Laravel\Mcp\Server\Attributes\Description;
use Laravel\Mcp\Server\Attributes\IsReadOnly;
use Laravel\Mcp\Server\Tool;

#[Description('Menghitung total nilai order milik satu pelanggan pada rentang tanggal.')]
#[IsReadOnly]
class OrderTotalTool extends Tool
{
    public function handle(Request $request): Response
    {
        $validated = $request->validate([
            'customer_id' => 'required|integer|exists:customers,id',
            'from' => 'required|date',
            'to' => 'required|date|after_or_equal:from',
        ]);

        $total = Order::query()
            ->where('customer_id', $validated['customer_id'])
            ->whereBetween('created_at', [$validated['from'], $validated['to']])
            ->sum('total');

        return Response::text('Total order: Rp '.number_format($total, 0, ',', '.'));
    }

    public function schema(JsonSchema $schema): array
    {
        return [
            'customer_id' => $schema->integer()
                ->description('ID pelanggan yang mau dihitung.')
                ->required(),

            'from' => $schema->string()
                ->description('Tanggal awal format YYYY-MM-DD.')
                ->required(),

            'to' => $schema->string()
                ->description('Tanggal akhir format YYYY-MM-DD.')
                ->required(),
        ];
    }
}

Nama tool diturunkan otomatis dari nama kelas: OrderTotalTool menjadi order-total. Deskripsi tidak otomatis, jadi atribut #[Description] wajib diisi. Satu kalimat tentang kapan tool dipakai lebih berguna daripada paragraf tentang cara kerjanya. Setelah itu daftarkan kelasnya di properti $tools milik server.

Kalau tool sudah puluhan, jangan tampilkan semuanya—context window penuh sebelum percakapan dimulai. Laravel MCP menyediakan ToolSearch sebagai kunci array di $tools: tool di dalamnya bisa ditemukan lewat search_tools lalu dijalankan lewat execute_tools. Batasnya diatur konfigurasi mcp.tool_search.max_tool_calls dan mcp.tool_search.max_output_bytes.

Validasi Argumen

JSON Schema hanya memberi tahu bentuk data, bukan aturan bisnis. Karena handle() menerima objek Request milik Laravel MCP, validator Laravel bisa dipakai seperti di controller—termasuk pesan kustom seperti pada cara mengganti attribute validation error di Laravel.

Pesan error di sini dibaca model, bukan manusia. Tulis yang memberi jalan keluar: “sebutkan ID pelanggan berupa angka, contoh 42” lebih berguna daripada “field invalid”.

Bentuk Respons Tool

Semua tool mengembalikan instance Laravel\Mcp\Response. Yang sering dipakai: Response::text(), Response::error() saat gagal, Response::image() atau Response::audio() untuk konten biner, dan Response::fromStorage() untuk file di disk Laravel—MIME type dideteksi sendiri dan bisa dioverride lewat parameter disk atau mimeType.

Kalau klien butuh data yang bisa diparse, gunakan Response::structured([...]): konten terstruktur plus representasi teks berisi JSON, sehingga klien lama tetap jalan. Untuk teks naratif sekaligus data, ada Response::make(Response::text('...'))->withStructuredContent([...]). Operasi panjang sebaiknya mengembalikan Generator: setiap yield bisa berupa Response::text() atau Response::notification('processing/progress', [...]), dan pada web server Laravel otomatis membuka stream SSE.

Anotasi Tool

Anotasi memberi tahu model seberapa berisiko sebuah tool: #[IsReadOnly] untuk yang tidak mengubah apa pun, #[IsDestructive] untuk operasi yang bisa merusak data, #[IsIdempotent] untuk pemanggilan berulang tanpa efek tambahan, dan #[IsOpenWorld] untuk yang menyentuh sistem eksternal.

Anggap ini sabuk pengaman, bukan formalitas. Tool delete-order tanpa #[IsDestructive] akan terlihat sama amannya dengan tool baca data, dan sebagian klien memakai anotasi itu untuk menentukan perlu konfirmasi pengguna atau tidak.

Prompt dan Resource

Prompt dibuat dengan php artisan make:mcp-prompt untuk template instruksi berulang; argumennya dideklarasikan lewat method arguments() yang mengembalikan daftar Argument. Resource dibuat dengan make:mcp-resource dan mewakili data yang dibaca sebagai konteks, misalnya dokumentasi internal.

Resource dinamis memakai antarmuka HasUriTemplate dengan method uriTemplate() yang mengembalikan UriTemplate, misalnya file://users/{userId}/files/{fileId}. Nilai variabel diambil di handle() lewat $request->get('userId'), dan atribut #[MimeType] menentukan tipe konten balasan.

Aturan praktisnya: kalau model harus melakukan sesuatu, itu tool; kalau hanya perlu membaca, itu resource.

Keamanan Server MCP

Jalur paling sederhana: pasang middleware auth:sanctum pada rute Mcp::web, lalu klien mengirim header Authorization: Bearer <token>. Jalur kedua adalah OAuth 2.1 lewat Laravel Passport, dan inilah yang direkomendasikan dokumentasi karena paling banyak didukung klien MCP. Panggil Mcp::oauthRoutes() di routes/ai.php, lalu lindungi rute server dengan middleware auth:api. Laravel MCP menambahkan satu scope mcp:use; scope kustom belum didukung.

Satu detail yang mudah terlewat: rute pendaftaran klien dinamis bersifat publik sesuai spesifikasi MCP dan RFC 7591, dan setiap pendaftaran membuat baris baru di tabel OAuth client. Bungkus dengan rate limit, misalnya Route::middleware('throttle:10,1')->group(fn () => Mcp::oauthRoutes()), atau matikan lewat Mcp::oauthRoutes(registration: false) kalau klienmu tidak perlu mendaftar sendiri.

Di dalam tool, $request->user() mengembalikan user terautentikasi sehingga pengecekan policy tetap bisa dilakukan. Jangan andalkan filter di sisi klien—server harus tetap menolak.

Menguji dengan Inspector dan Unit Test

Untuk eksplorasi manual, jalankan php artisan mcp:inspector mcp/weather (web server) atau php artisan mcp:inspector weather (local server). Perintah ini membuka MCP Inspector dan menampilkan pengaturan klien yang bisa disalin.

Untuk test otomatis, panggil primitif langsung dari kelas server tanpa HTTP. Hasilnya objek respons dengan assertion sendiri: assertOk(), assertSee(), assertHasErrors(), sampai assertNotificationCount().

test('order total tool', function () {
    $response = WeatherServer::tool(OrderTotalTool::class, [
        'customer_id' => 42,
        'from' => '2026-11-01',
        'to' => '2026-11-30',
    ]);

    $response->assertOk()->assertSee('Total order');
});

Kalau tool bergantung pada user, sisipkan lewat WeatherServer::actingAs($user)->tool(...). Pola ini membuat regresi skema dan validasi ketahuan sebelum agen AI menemukannya di produksi.

Kapan MCP Tidak Perlu

Kalau aplikasimu hanya butuh satu panggilan terprediksi—misalnya merangkum teks dari user—pemanggilan model langsung lebih sederhana. Untuk banyak penyedia model dengan satu antarmuka, Prism PHP lebih tepat sasaran, sementara Laravel AI SDK sudah menyediakan lapisan agen lengkap.

MCP masuk akal ketika ada klien luar yang perlu menjelajah kemampuan aplikasimu tanpa dokumentasi terpisah—atau ketika satu set tool dipakai beberapa klien: IDE, chat internal, agen otomatis.

FAQ

Apakah Laravel MCP butuh Laravel versi tertentu?

Ya. v1.1.2 mensyaratkan PHP ^8.2 dan framework ^11.45.3, ^12.41.1, atau ^13.0. Proyek Laravel 10 perlu upgrade lebih dulu.

Bisakah satu aplikasi punya beberapa MCP server?

Bisa. Setiap server adalah kelas terpisah pada rute berbeda, misalnya /mcp/sales dan /mcp/support. Memisahkan server mempermudah pembatasan akses per audiens.

Apakah MCP menggantikan REST API yang sudah ada?

Tidak. REST API untuk konsumen yang sudah tahu endpoint-nya; MCP untuk klien yang perlu menemukan sendiri kemampuan aplikasi.

Kesimpulan

Laravel MCP memindahkan integrasi AI dari tempelan prompt ke kode yang bisa diuji, divalidasi, dan diamankan seperti bagian lain aplikasi. Mulai dari satu tool baca data, pasang #[IsReadOnly], tulis pesan validasi yang bisa ditindaklanjuti model, lalu uji lewat Inspector. Setelah itu baru tambah resource, prompt, dan OAuth kalau memang dibutuhkan.

Referensi resmi:

susantokun avatar
susantokun
Hanya seorang programmer yang fokus di bidang web development. Tidak nyaman dengan keramaian dan suka akan keindahan.
Kebijakan Berkomentar :
1. Dilarang berkomentar yang mengandung SPAM, SARA, HOAX, PORNO.2. Mohon sertakan informasi detail saat terjadi error (pesan error, sreenshoot, code, logs, dsb.).