# Betrouwbare MCP-tools ontwerpen voor AI-agents Een AI-agent kiest zelf welke tools hij wanneer gebruikt. Via het **Model Context Protocol (MCP)** bied je die tools aan vanuit een server. De kwaliteit van je toolontwerp bepaalt grotendeels of de agent de juiste keuzes maakt. Een vaag omschreven tool wordt op het verkeerde moment ingezet, terwijl een goed ontworpen tool betrouwbaar en voorspelbaar wordt gebruikt. Dit artikel gaat over het ontwerp van de tools zelf. De architectuur van MCP komt aan bod in het artikel over aan de slag gaan met MCP. ## Een tool is een contract Elke MCP-tool bestaat uit een paar vaste onderdelen die samen een contract vormen tussen agent en server: - **Naam**: kort en eenduidig, zodat duidelijk is wat de tool doet. De spec staat letters, cijfers, underscore, koppelteken en punt toe, tot 128 tekens, bijvoorbeeld `get_weather` of `data.export`. - **Beschrijving**: legt uit wat de tool doet en, minstens zo belangrijk, wanneer je hem wel en niet gebruikt. - **Invoerschema** (`inputSchema`): een JSON Schema dat beschrijft welke parameters de tool verwacht, inclusief types en welke verplicht zijn. - **Uitvoer**: wat de tool teruggeeft. Sinds de recente spec kun je hier ook een `outputSchema` aan toevoegen, zodat de vorm van het resultaat vastligt en de agent het makkelijker kan verwerken. De agent ziet alleen deze beschrijving, niet je broncode. Schrijf de beschrijving dus voor de lezer die de beslissing neemt: het model zelf. ## Schrijf beschrijvingen voor het model De beschrijving is je belangrijkste sturingsmiddel. Een paar richtlijnen: - Begin met wat de tool doet in één zin, en voeg daarna toe wanneer hij geschikt is. - Benoem expliciet wanneer een tool **niet** gebruikt moet worden als er verwarring kan ontstaan met een andere tool. - Vermeld belangrijke aannames, zoals het verwachte formaat van een datum of de vorm van een identifier. - Beschrijf ook per parameter kort wat hij betekent. Het model leest die veldbeschrijvingen mee en levert dan netter aan. :::tip title="Lees je beschrijving als het model" Test je beschrijving door alleen die tekst te lezen en je af te vragen: zou ik op basis hiervan weten wanneer ik deze tool moet kiezen? Zo niet, dan weet het model het ook niet. ::: ## Houd de invoer strak Een helder invoerschema is je goedkoopste en sterkste verdedigingslinie. Definieer per parameter een duidelijk type en markeer welke verplicht zijn. Beperk waar mogelijk de toegestane waarden: kan een parameter een vaste lijst opties zijn (een enum), maak er dan geen vrije tekst van. Heeft een identifier een vaste vorm, leg die dan vast in het schema. Hoe specifieker het schema, hoe minder ruimte de agent heeft om iets onbedoelds aan te leveren. :::info title="Valideer altijd opnieuw in de server" Vertrouw er niet op dat het model zich exact aan het schema houdt. Behandel elke aanroep als externe invoer: valideer types, lengtes, formaten en bereiken in de server zelf voordat je er iets mee doet. ::: ## Maak foutmeldingen bruikbaar Een agent kan zich herstellen van een fout, maar alleen als de foutmelding hem vertelt wat er misging. De MCP-spec onderscheidt twee soorten fouten, en dat verschil is praktisch belangrijk: - **Protocolfouten**, zoals een onbekende tool of een verzoek dat niet aan het schema voldoet. Deze gaan over de structuur van de aanroep en zijn voor het model meestal lastig zelf te corrigeren. - **Uitvoeringsfouten**, zoals een datum in het verkeerde formaat of een waarde buiten bereik. Geef die terug als een leesbaar resultaat met `isError: true`, en schrijf precies wat er fout was en wat een mogelijke vervolgstap is. Geef dus geen kale technische code terug. Een goede uitvoeringsfout, bijvoorbeeld "Ongeldige vertrekdatum: moet in de toekomst liggen", stelt de agent in staat de aanroep te corrigeren in plaats van blind opnieuw te proberen. :::howto title="Een tool stap voor stap opbouwen" 1. Kies een **eenduidige naam** die precies één handeling beschrijft. 2. Schrijf een **beschrijving** met wat de tool doet en wanneer je hem wel en niet gebruikt. 3. Stel een **strak invoerschema** op met types, verplichte velden en enums waar mogelijk. 4. Voeg eventueel een **outputSchema** toe zodat het resultaat een vaste vorm heeft. 5. Bouw **validatie en duidelijke foutmeldingen** in de server, en geef herstelbare fouten terug met `isError: true`. ::: ## Ontwerp met veiligheid in gedachten Tools die acties uitvoeren verdienen extra zorg, want een agent kan ze autonoom aanroepen: - Geef een tool niet meer reikwijdte dan nodig. Een tool die alleen hoeft te lezen, hoort niet te kunnen schrijven. - Scheid lezen en schrijven in aparte tools, zodat je per stuk kunt bepalen wat is toegestaan. - Bouw een bevestigingsstap of expliciete grens in voor handelingen die niet terug te draaien zijn. De spec adviseert nadrukkelijk een mens in de lus die een aanroep kan weigeren. - Wees voorzichtig met invoer die in een onderliggend systeem terechtkomt, zoals commando's, bestandspaden of queries, om injectie te voorkomen. :::warn title="Beschouw elke aanroep als onbetrouwbaar" Beschouw elke aanroep door een agent als potentieel onjuist of misbruikt. Een tool die ongecontroleerd verwijdert of verstuurt is een risico, ongeacht hoe goed je beschrijving is. Vertrouw ook tool-annotaties alleen als ze van een betrouwbare server komen. ::: ## Samengevat Een betrouwbare MCP-tool combineert een duidelijke beschrijving, een strak invoerschema, bruikbare foutmeldingen en een veilige reikwijdte. Investeer je tijd in dit ontwerp, dan gebruikt de AI-agent je tools precies zoals bedoeld en blijft de uitkomst voorspelbaar. :::faq ### Wat is het verschil tussen de naam en de beschrijving van een tool? De naam is een korte, technische identifier waarmee de agent de tool aanroept, bijvoorbeeld `get_weather`. De beschrijving is de uitleg in gewone taal die het model leest om te beslissen of en wanneer het de tool inzet. De beschrijving is dus je belangrijkste sturingsmiddel. ### Waarom moet ik invoer in de server valideren als er al een invoerschema is? Het invoerschema helpt het model om netjes aan te leveren, maar garandeert niets. Een model kan zich vergissen, en een tool kan ook door andere clients worden aangeroepen. Behandel elke aanroep daarom als externe invoer en valideer types, lengtes, formaten en bereiken opnieuw in de server. ### Hoe geef ik een fout terug die de agent kan herstellen? Geef herstelbare fouten terug als een tool-resultaat met `isError: true` en een leesbare melding die zegt wat er misging en wat een vervolgstap is. Vermijd kale codes. Structuurfouten, zoals een onbekende tool, zijn protocolfouten en kan het model meestal niet zelf oplossen. ### Moet ik lezen en schrijven in dezelfde tool stoppen? Liever niet. Splits ze in aparte tools, zodat je per tool kunt bepalen wat is toegestaan en je een lees-tool nooit per ongeluk laat schrijven. Dat maakt het toekennen van rechten en het beoordelen van risico's veel eenvoudiger. ### Heeft een tool zonder parameters ook een invoerschema nodig? Ja. Volgens de spec moet `inputSchema` altijd een geldig JSON Schema-object zijn. Voor een tool zonder parameters gebruik je bij voorkeur `{ "type": "object", "additionalProperties": false }`, zodat alleen een leeg object wordt geaccepteerd. ### Kan ik vertrouwen op tool-annotaties zoals hints over of een tool alleen leest? Alleen als de tool van een betrouwbare server komt. De spec zegt expliciet dat clients annotaties als onbetrouwbaar moeten beschouwen tenzij de bron vertrouwd is. Bouw je beveiliging dus niet alleen op die hints, maar ook op echte controles in de server. :::