Zelf MCP-servers bouwen in Laravel
AI-assistenten zoals Claude worden pas écht nuttig op het moment dat ze bij jouw data en jouw systemen kunnen. Een taalmodel dat alleen praat is leuk; een taalmodel dat een offerte in je eigen administratie kan opzoeken, een klant kan inschrijven of een afbeelding uit je beeldbank kan ophalen, dát levert tijd op. De brug daartussen heet het Model Context Protocol (MCP). En als je je applicatie in Laravel hebt gebouwd, ligt zo'n brug dichterbij dan je denkt.
In dit artikel lopen we praktisch door wat MCP is, waarom Laravel een prettige basis is, en hoe je stap voor stap je eerste werkende MCP-server bouwt.
Wat is MCP eigenlijk?
Het Model Context Protocol is een open standaard die beschrijft hoe een AI-client (bijvoorbeeld Claude) praat met een externe server die tools, resources en prompts aanbiedt. Je kunt het zien als een stekkerdoos: het model weet niet hoe jouw systeem van binnen werkt, het ziet alleen een lijst met handelingen die het mag uitvoeren, met een nette beschrijving en een vast formaat voor in- en uitvoer.
Concreet biedt een MCP-server drie soorten dingen aan:
- Tools — handelingen die het model kan aanroepen, zoals
zoek-klant,maak-factuurofverstuur-mail. Dit is verreweg het meest gebruikte onderdeel. - Resources — leesbare brokken context die het model kan opvragen, zoals een document of een recordset.
- Prompts — herbruikbare prompt-sjablonen die je aan de gebruiker kunt aanbieden.
De kracht zit in de afspraak: zolang jij je tools netjes beschrijft, kan elke MCP-compatibele client ermee overweg, zonder dat jij iets van die client hoeft te weten.
Waarom Laravel een fijne basis is
Veel bedrijven hebben hun kernlogica al in een Laravel-app staan: modellen, policies, queue-jobs, validatie, een nette servicelaag. Een MCP-server is in de praktijk niets anders dan een nieuwe ingang naar diezelfde logica — naast je web-controllers en je API.
Dat betekent dat je niet opnieuw begint. Je hergebruikt:
- je Eloquent-modellen voor de data;
- je policies en gates om af te dwingen wie wat mag;
- je form requests / validatieregels om invoer te controleren;
- je service- en action-classes voor de daadwerkelijke handeling.
Een MCP-tool wordt dan een dun laagje dat een binnenkomend verzoek vertaalt naar een aanroep van logica die je al vertrouwt en getest hebt.
De bouwstenen
Een MCP-server bestaat technisch uit een paar vaste onderdelen:
- Een transport — de manier waarop client en server berichten uitwisselen. De twee gangbare opties zijn stdio (de server draait als los proces, handig voor lokaal gebruik) en HTTP met server-sent events (handig als je server al online staat — precies wat een Laravel-app van nature is).
- De JSON-RPC-laag — MCP gebruikt JSON-RPC 2.0 als berichtenformaat. Berichten als
initialize,tools/listentools/calllopen hier overheen. - De tool-definities — per tool een naam, een beschrijving en een JSON-schema voor de invoer.
- De handlers — de code die daadwerkelijk draait als een tool wordt aangeroepen.
Je kunt dit volledig zelf optuigen, maar voor Laravel zijn er inmiddels packages die het JSON-RPC- en transport-werk uit handen nemen, zodat jij je op de tools kunt richten. Het loont om eerst in de package-ecosystemen (Composer) te kijken voordat je alles handmatig schrijft.
Stap 1 — Bepaal je eerste tool
Begin klein en concreet. Niet "geef AI toegang tot mijn hele systeem", maar één duidelijke handeling met waarde. Een goed eerste voorbeeld: zoek een klant op naam.
Denk vooraf na over drie dingen:
- Naam en beschrijving. Het model kiest een tool puur op basis van de beschrijving. Schrijf die dus voor een lezer, niet voor een compiler: "Zoekt klanten op (deel van) hun naam en geeft naam, e-mail en klantnummer terug."
- Invoer. Welke parameters heeft de tool nodig? Houd het minimaal. Hier: een zoekterm.
- Uitvoer. Geef compacte, voorspelbare data terug. Geen rauwe database-dump, maar precies de velden die nuttig zijn.
Stap 2 — Definieer de tool
Een tooldefinitie is in essentie metadata plus een schema. Conceptueel ziet dat er zo uit:
class ZoekKlantTool
{
public string $name = 'zoek-klant';
public string $description =
'Zoekt klanten op (deel van) hun naam en geeft naam, e-mail en klantnummer terug.';
public array $inputSchema = [
'type' => 'object',
'properties' => [
'zoekterm' => [
'type' => 'string',
'description' => 'Naam of deel van de naam van de klant.',
],
],
'required' => ['zoekterm'],
];
}
Het inputSchema is gewoon JSON-schema. Dit schema is je contract én je documentatie: de client gebruikt het om het model te vertellen welke argumenten geldig zijn.
Stap 3 — Schrijf de handler
Hier komt de Laravel-kracht naar boven. De handler valideert de invoer en leunt verder volledig op bestaande logica:
public function handle(array $arguments): array
{
$data = validator($arguments, [
'zoekterm' => ['required', 'string', 'min:2'],
])->validate();
$klanten = Klant::query()
->where('naam', 'like', '%'.$data['zoekterm'].'%')
->limit(10)
->get(['id', 'naam', 'email']);
return [
'content' => [[
'type' => 'text',
'text' => $klanten
->map(fn ($k) => "{$k->naam} — {$k->email} (#{$k->id})")
->implode("\n"),
]],
];
}
Let op het uitvoerformaat: MCP verwacht een content-array met getypeerde blokken (hier text). Je kunt ook gestructureerde data of zelfs afbeeldingen teruggeven, afhankelijk van wat de tool doet.
Stap 4 — Kies je transport
Draait je tool lokaal voor één ontwikkelaar? Dan is stdio het simpelst: een Artisan-commando dat de MCP-server start en via standard-in/standard-out communiceert.
Wil je dat collega's of een gehoste AI-client erbij kunnen? Dan bied je de server aan over HTTP. Je registreert een route, laat het MCP-package de JSON-RPC-berichten afhandelen, en je server is bereikbaar als een normaal endpoint van je applicatie. Voor een bestaande Laravel-app online is dit meestal de natuurlijke keuze.
Stap 5 — Beveilig het goed
Dit is het onderdeel dat je niet mag overslaan. Een MCP-server geeft een AI-model de mogelijkheid om handelingen in jouw systeem uit te voeren. Behandel hem dus met dezelfde argwaan als een publieke API:
- Authenticatie. Gebruik tokens (bijvoorbeeld via Sanctum) zodat alleen geautoriseerde clients verbinding maken. Elke gebruiker zijn eigen token.
- Autorisatie per tool. Laat je bestaande policies bepalen wat een specifieke gebruiker mag zien en doen. De tool respecteert de rol van de ingelogde gebruiker — niet meer dan dat.
- Validatie. Vertrouw geen enkel argument dat binnenkomt. Het model kan zich vergissen of misleid worden; jouw validatie is je vangnet.
- Voorzichtig met onomkeerbare acties. Verwijderen, geld overmaken, mail versturen: bouw bevestigingsstappen in en log alles.
- Behandel tool-invoer als data, niet als instructie. Tekst die via een tool binnenkomt mag nooit zomaar als nieuwe opdracht worden uitgevoerd.
Veelgemaakte valkuilen
- Te grote tools. Eén tool die tien dingen kan, kiest het model slecht. Splits op in kleine, duidelijke handelingen.
- Vage beschrijvingen. "Doet iets met klanten" leidt tot verkeerde keuzes. Wees concreet over wat de tool doet en wanneer je hem gebruikt.
- Te veel data teruggeven. Een rauwe dump van 200 records vult het venster en helpt niemand. Filter en vat samen.
- Beveiliging als bijzaak. Bouw authenticatie en autorisatie vanaf het begin in, niet achteraf.
Tot slot
Een MCP-server bouwen in Laravel is vooral een oefening in hergebruik: je bestaande modellen, policies en services krijgen er simpelweg een nieuwe, AI-vriendelijke ingang bij. Begin met één concrete tool, beveilig hem goed, test hem met een echte client, en breid pas daarna uit. Zo geef je AI stap voor stap toegang tot je eigen systeem — op een manier die je volledig in de hand houdt.
Wil je hierover sparren of een keer live meekijken hoe zo'n koppeling werkt? Schuif aan bij een AI-Tafel.