Een MCP-server bouwen (Stap voor stap)

Gebouwd voor snelheid: ~10ms latentie, zelfs onder belasting
De razendsnelle manier om je modellen te bouwen, volgen en implementeren!
- Verwerkt 350+ RPS op slechts 1 vCPU — geen tuning nodig
- Productieklaar met volledige enterprise-ondersteuning
Het Model Context Protocol geeft een LLM een standaardmanier om tools aan te roepen, context te lezen en prompts te hergebruiken in elke conforme client. Het bouwen van een server die dit spreekt is niet moeilijk; het bouwen van een server die correct is, veilig om te ontsluiten en prettig is voor een model om te gebruiken, vereist wat meer beslissingen dan de quickstart-tutorials behandelen. Deze gids doorloopt het volledige traject: wat een server ontsluit, welk transport je moet kiezen en waarom, hoe je een tool definieert die het model daadwerkelijk goed zal gebruiken, hoe je een remote server authenticeert, hoe je deze test en wat er verandert als je van een laptop naar productie gaat.
De lopende voorbeelden zijn structurele pseudocode in een Python-achtige stijl. Ze tonen de juiste vorm (namen, schema's, handler-signatures) zonder je vast te pinnen op een specifieke SDK-versie, omdat de vorm hetgeen is wat overdraagbaar is. Als je eerst de conceptuele basis wilt begrijpen, behandelt wat is een MCP-server het model; deze post gaat over het bouwen.
Een MCP-server gebouwd? Plaats deze achter een gateway voor auth, registry en audit. Boek een demo.
Wat een MCP-server ontsluit
Een MCP-server biedt drie soorten functionaliteiten aan een client. Het juist krijgen van dit onderscheid tijdens de ontwerpfase voorkomt de meest voorkomende fout: alles in tools proppen.

Tools zijn functies die door het model worden aangeroepen. Het model beslist tijdens een gesprek om een tool aan te roepen om iets gedaan te krijgen: een database bevragen, een ticket aanmaken, een verzoek sturen naar een interne API. Tools kunnen neveneffecten hebben. Ze zijn het primitief waar je naar grijpt wanneer het model moet handelen. Een tool heeft een naam, een beschrijving en een JSON Schema voor de invoer, en retourneert gestructureerde inhoud.
Resources zijn door de applicatie beheerde, read-only contexten die worden geïdentificeerd door een URI. Een resource is data die de client kan lezen en als context aan het model kan doorgeven: een bestand, een configuratiedocument, de huidige inhoud van een record. Het belangrijkste verschil met een tool is controle en intentie. Een resource is read-only en wordt doorgaans geselecteerd door de applicatie of de gebruiker ("voeg dit document toe"), niet midden in een redeneerproces door het model aangeroepen om een effect te weeg te brengen. Als hetgeen je ontsluit nooit van status verandert en eigenlijk alleen "hier is wat context om te lezen" is, is het een resource, geen tool.
Prompts zijn door de gebruiker aangeroepen sjablonen. Een prompt is een herbruikbaar, geparametriseerd bericht (of een reeks berichten) dat een gebruiker expliciet activeert, vaak getoond in een client als een slash-commando of een menu-item. "Vat deze PR samen in onze huisstijl" met een pr_url-parameter is een prompt. Prompts worden beheerd door de gebruiker, niet autonoom gekozen door het model.
Een praktische regel: als het model moet beslissen wanneer het moet worden gebruikt, bouw dan een tool. Als de gebruiker of app beslist welke context moet worden geladen, bouw dan een resource. Als de gebruiker een herhaalbare, vaste instructie wil, bouw dan een prompt. De meeste servers leveren terecht alleen tools, maar een server die bijvoorbeeld je interne runbooks ontsluit, kan beter worden gemodelleerd met resources dan met een get_runbook-tool waarvan het model moet gissen hoe het deze moet aanroepen.
Kies een transport
Het protocol definieert hoe een client en server JSON-RPC-berichten uitwisselen. Twee transporten zijn van belang, en de keuze bepaalt vrijwel alles over hoe je implementeert.
Lokale stdio voert de server uit als een subproces van de client en wisselt berichten uit via standard input en output. Het is de juiste keuze voor ontwikkeling en voor desktopclients zoals een IDE of een lokale assistent, waar de server op dezelfde machine draait als de gebruiker. Er is geen netwerk, geen auth om te configureren, en de client beheert de levenscyclus van het proces. Zie voor het specifiek uitvoeren van lokale servers in een coding client MCP-servers in Claude Code. De beperking is duidelijk: stdio bedient precies één lokale gebruiker en kan niet worden gedeeld, load-balanced of via een netwerk worden bereikt.
Remote Streamable HTTP voert de server uit als een netwerkdienst die clients via HTTP bereiken, met server-to-client streaming voor meldingen en voortgang. Dit is het transport voor alles wat multi-user, hosted of productie is. De protocolrevisie van 2026-07-28 is hier belangrijk: Streamable HTTP ondersteunt een stateless modus, waarbij de server een client niet hoeft vast te pinnen op een langdurige sessie op één instantie. Stateless werking is wat je in staat stelt om veel identieke replica's achter een load balancer uit te voeren en horizontaal te schalen zonder sticky sessions, wat de belangrijkste eigenschap is voor productiehosting. Dezelfde revisie gestandaardiseerde de Mcp-Method- en Mcp-Name-headers op verzoeken, die het JSON-RPC-type en de tool- of resourcenaam op de HTTP-laag ontsluiten. Dat klinkt als iets kleins; dat is het niet. Het betekent dat een gateway, proxy of load balancer per tool kan routen, rate-limiten, autoriseren en loggen zonder de JSON-RPC-body te parsen, wat precies is wat je nodig hebt om een server op schaal te beheren.

Bouw en debug op stdio; lever op Streamable HTTP. Door je server zo te schrijven dat het transport een dunne buitenste laag is (handlers die er niet om geven hoe ze zijn bereikt), kun je ertussen wisselen zonder de logica te herschrijven.
Definieer een tool die het model daadwerkelijk zal gebruiken
Een tooldefinitie bestaat uit drie delen, en het gedrag van het model wordt door alle drie bepaald. Dit is waar de meeste "mijn server werkt niet"-problemen daadwerkelijk ontstaan.
# Structural pseudocode — shape, not a specific SDK version.
@server.tool()
def search_orders(
customer_id: str, # required
status: str = "any", # enum: open | shipped | cancelled | any
limit: int = 20, # 1..100
) -> list[Order]:
"""Search a customer's orders by status.
Use this when the user asks about the state, history, or
contents of orders for a known customer_id. Returns up to
`limit` orders, newest first. Does NOT create or modify
orders. If the customer_id is unknown, ask the user for it
rather than guessing.
"""
...
De drie delen:
Naam. Kort, beginnend met een werkwoord, ondubbelzinnig. search_orders, niet orders of do_order_stuff. Het model leest eerst de naam bij het kiezen uit tientallen beschikbare tools.
Beschrijving. Dit is de belangrijkste tekst die je zult schrijven, en het is prompt engineering, geen documentatie. Het model beslist vrijwel volledig op basis van de beschrijving of het de tool moet aanroepen en hoe het de argumenten moet invullen. Vermeld wat de tool doet, wanneer deze moet worden gebruikt, wanneer niet, wat deze retourneert en hoe om te gaan met ontbrekende invoer. Het bovenstaande voorbeeld vertelt het model dat het read-only is ("Does NOT create or modify") en geeft het een terugvalgedrag ("ask the user rather than guessing"). Vage beschrijvingen leiden tot een model dat de verkeerde tool aanroept, de juiste tool aanroept met verkeerde argumenten, of deze aanroept wanneer dat niet zou moeten. Behandel elke beschrijving als een mini-systeemprompt.
Inputschema. Een nauwkeurig JSON Schema. Markeer verplichte velden als vereist. Gebruik enums voor gesloten sets (status is een van de vier waarden) zodat het model geen "in_progress" kan verzinnen. Stel grenzen in (limit tussen 1 en 100). Geef elk veld een beschrijving. Een strak schema beperkt zowel het model als dat het de server, of een gateway ervoor, in staat stelt invoer te valideren voordat er een handler draait.
Twee addertjes onder het gras waar iedereen mee te maken krijgt:
- Idempotentie voor retries. Remote calls worden opnieuw geprobeerd, door clients, door netwerken en door elke gateway die fallback uitvoert. Een tool met neveneffecten (
create_refund) moet kunnen verdragen dat deze twee keer met dezelfde invoer wordt aangeroepen zonder dat het effect dubbel wordt uitgevoerd. Accepteer een idempotentie-sleutel of maak de operatie van nature idempotent. Ontwerp voor at-least-once levering, want dat is wat je zult krijgen. - Omgang met geheimen. De server, niet het model en niet de client, beheert de inloggegevens voor de systemen waarmee hij communiceert. Retourneer nooit geheimen in een toolresultaat, plaats ze nooit in een resource en verwacht nooit dat het model ze als argumenten doorgeeft. Laad ze vanuit de omgeving van de server of een secret store, afgestemd op het serverproces.
Authenticeer een remote server
Een lokale stdio-server erft het vertrouwen van de machine van de gebruiker en heeft geen auth nodig. Zodra je een server via HTTP ontsluit, heeft deze echte authenticatie nodig, en het protocol is specifiek over wat "echt" betekent.
Het MCP-autorisatiemodel bouwt voort op OAuth 2.1. Twee onderdelen zijn in het bijzonder van belang. Ten eerste is de server een door OAuth beschermde resource: clients verkrijgen een toegangstoken van een autorisatieserver en tonen dit als een bearer-token. Ten tweede, en makkelijk over het hoofd te zien, vereist de specificatie resource-indicatoren (RFC 8707), zodat een token gebonden is aan de specifieke MCP-server waarvoor het is uitgegeven (de resource), in plaats van een algemeen token te zijn. Zonder resource-indicatoren kan een token dat is gegenereerd voor server A opnieuw worden gebruikt tegen server B die dezelfde autorisatieserver vertrouwt — een confused-deputy probleem. Met deze indicatoren geeft de autorisatieserver een token uit dat is afgestemd op de beoogde resource, en weigert elke server tokens die niet voor hem zijn bestemd.
In de praktijk maak je dit niet zelf. Je plaatst de server achter iets wat OAuth correct afhandelt en de audience van elk token valideert. Dat is een van de taken van een MCP gateway. De diepere mechanica, tokenvalidatie, scopes en de confused-deputy-foutmodus worden behandeld in MCP-authenticatie. De regel voor deze gids: een remote MCP-server die beveiligd wordt door een statische gedeelde API-sleutel is niet geauthenticeerd, hij is geobfusticeerd. Gebruik OAuth 2.1 met audience-gebonden tokens.

Bekijk hoe TrueFoundry je remote MCP-servers host en beheert. Boek een demo.
Test de server met een echte client
Voordat je iets ontsluit, test je de server via een MCP-client en bekijk je de daadwerkelijke berichtenstroom.
- Lijst met mogelijkheden opvragen. Verbind een client en controleer of de server de tools, resources en prompts adverteert die je verwacht, met de namen en schema's die je bedoeld had. Een verrassend aantal bugs valt onder "de tool is geregistreerd onder de verkeerde naam" of "het schema heeft de enum niet geparst."
- Roep elke tool aan met goede en slechte invoer. Roep elke tool aan met geldige argumenten, daarna met ontbrekende verplichte velden, waarden buiten het bereik en verkeerde typen. Controleer of de server slechte invoer weigert met een duidelijke foutmelding in plaats van te crashen of stilzwijgend het verkeerde te doen. Als je schemagrenzen hebt ingesteld, controleer dan of deze worden afgedwongen.
- Laat een model het aansturen. De echte test is of een model, met alleen je namen, beschrijvingen en schema's, de juiste tool aanroept met de juiste argumenten voor een realistisch verzoek. Let op of het model de verkeerde tool kiest, een argumentwaarde hallucineert of nalaat te vragen om een ontbrekend verplicht veld. Elk van die gevallen is meestal een beschrijvings- of schemafix, geen codefix.
- Test het streamingpad. Controleer voor Streamable HTTP of voortgangsmeldingen en gestreamde resultaten incrementeel binnenkomen, en niet gebufferd worden tot het einde.
- Forceer fouten. Zorg ervoor dat een upstream-afhankelijkheid een timeout of fout geeft, en controleer of de tool een gestructureerde fout retourneert waar het model over kan redeneren, in plaats van een ondoorzichtige 500-fout.
De door het model aangestuurde test in stap 3 is degene die teams overslaan en degene die er het meest toe doet. Een server die technisch correct is maar zijn tools slecht beschrijft, zal precies zo falen dat het het moeilijkst te debuggen is vanuit de logs: het model gebruikt de tool gewoon verkeerd.
Van een werkende server naar productie
Een server die op je laptop draait via stdio en een server die veilig is om te ontsluiten voor echt verkeer zijn verschillende dingen. Dit is wat zich in het gat daartussen bevindt.
Hosting en levenscyclus. De server wordt een dienst die je uitrolt, monitort en waarvan je updates en rollback uitvoert. Deze heeft health checks, resourcelimieten en een deployment-target nodig. MCP-server hosting behandelt de opties en afwegingen.
Stateless schalen. Om meerdere replica's achter een load balancer uit te voeren, houd je de server stateless per verzoek, waar de 2026-07-28 Streamable HTTP stateless modus voor is ontworpen. Eventuele sessiestatus moet in een gedeelde store worden opgeslagen, niet in het geheugen van de instantie, anders zal een vervolgverzoek van een client dat naar een andere replica wordt geleid, mislukken.
Authenticatie en autorisatie. OAuth 2.1 met resource-indicatoren voor authenticatie, en vervolgens autorisatie: welke gebruikers en welke agents mogen welke tools aanroepen. Behandel de agent als een volwaardige identiteit, niet alleen de mens erachter; AI-agentidentiteit en fijnmazige autorisatie per tool voorkomen dat een krachtige server een risico wordt.
Ontdekking via een registry. Clients en platformteams moeten de server kunnen vinden, weten welke versie het is en weten wat deze ontsluit. Een registry is de catalogus die servers ontdekbaar en beheerbaar maakt binnen een organisatie; zie wat is een MCP registry. Zonder registry herontdekt en herconfigureert elk team dezelfde servers handmatig.
Observeerbaarheid. Je hebt zichtbaarheid per aanroep nodig: wie heeft welke tool aangeroepen, met welke argumenten, hoe lang het duurde, of er een fout optrad en wat het kostte. Ruwe servers zenden niets hiervan op een gestandaardiseerde manier uit.
Guardrails. Toolinvoer en -uitvoer kunnen PII, geheimen of prompt-injection-payloads bevatten die via geretourneerde inhoud zijn binnengesmokkeld. Het inspecteren hiervan is een overkoepelend belang dat je niet in elke server opnieuw wilt implementeren.
Het patroon dat dit beheersbaar maakt, is om die laag niet per server opnieuw op te bouwen. Bouw je server om zijn ene taak goed uit te voeren via Streamable HTTP, en plaats deze achter een MCP gateway die uniform zorgt voor authenticatie, autorisatie, de registry, observeerbaarheid en guardrails. Dat is het verschil tussen het ontsluiten van een ruwe server en het beheren van een hele vloot. Wat is een MCP gateway legt het model uit, en enterprise MCP-governance behandelt de controle-, audit- en toegangseisen die daarbij horen. TrueFoundry biedt dit als een MCP gateway en registry met toegangsbeheer (RBAC, SSO, SCIM) en guardrails, te implementeren als SaaS, in-VPC, on-prem of air-gapped, zodat het datavlak in je eigen netwerk blijft.
Waar teams de mist in gaan
Ze maken van alles een tool. Read-only context wordt gepropt in get_*-tools waarvan het model moet gissen hoe ze aangeroepen moeten worden, terwijl het een resource had moeten zijn die de applicatie toevoegt. Herhaalde vaste instructies worden hardgecodeerd, terwijl het prompts hadden moeten zijn die de gebruiker aanroept. Modelleer de drie primitieven bewust.
Ze schrijven beknopte toolbeschrijvingen. Een beschrijving van één regel laat het model gissen wanneer en hoe het de tool moet aanroepen, en het gokt verkeerd. De beschrijving bepaalt het gedrag; schrijf het zoals een systeemprompt, inclusief wanneer de tool niet gebruikt moet worden.
Ze zetten een remote server in productie achter een gedeelde sleutel. Een statische API-sleutel is geen authenticatie. Remote servers hebben OAuth 2.1 nodig met audience-gebonden tokens (resource-indicatoren), zodat een token voor de ene server niet opnieuw kan worden gebruikt tegen een andere server. Het overslaan hiervan veroorzaakt een confused-deputy-lek.
Ze negeren idempotentie. Clients, netwerken en gateway-fallbacks voeren allemaal retries uit. Een tool met neveneffecten die niet idempotent is, zal dubbele kosten maken, dubbele items aanmaken of dubbel verzenden onder volstrekt normale retry-omstandigheden. Ontwerp voor at-least-once levering.
Ze behandelen "het draait" als "het is productie." Een werkende server is slechts het begin. Hosting, stateless schalen, auth, een registry, observeerbaarheid en guardrails vormen het daadwerkelijke werk om het veilig te maken om te ontsluiten. Dat per server opnieuw opbouwen is hoe organisaties eindigen met tientallen onbeheerde eindpunten.
Conclusie
Het bouwen van een MCP-server is een korte wandeling met een lange staart. De wandeling is de quickstart: kies een transport, registreer een tool met een naam, beschrijving en schema, en test het met een client. Je kunt in één middag een werkende server hebben. De staart is alles wat het correct en veilig maakt: tools versus resources versus prompts bewust modelleren, beschrijvingen schrijven waar het model op kan handelen, tools met neveneffecten idempotent maken, remote toegang authenticeeren met OAuth 2.1 en resource-indicatoren, en stateless schalen.
De stap die de meeste teams onderschatten, is de sprong van "draait op mijn laptop" naar "ontsloten voor echt verkeer." Die sprong omvat hosting, auth, autorisatie, ontdekking, observeerbaarheid en guardrails, en de winst zit hem in het niet opnieuw opbouwen van die laag per server. Bouw de server om zijn taak uit te voeren via Streamable HTTP, plaats deze achter een MCP gateway en registry voor de governance, en je hebt iets wat je daadwerkelijk kunt beheren in plaats van een eenmalig eindpunt dat niemand kan beveiligen of vinden.
Breng je MCP-server van lokaal naar productiebeheerd. Boek een demo.
TrueFoundry AI Gateway levert een latentie van ~3–4 ms, verwerkt 350+ RPS op 1 vCPU, schaalt moeiteloos horizontaal en is klaar voor productie, terwijl LiteLLM last heeft van hoge latentie, moeite heeft boven een gemiddeld aantal RPS, geen ingebouwde schaling heeft en het meest geschikt is voor lichte workloads of prototypes.



Eén gateway voor elk LLM, elke agent en elke MCP-server
Recente blogs
Veelgestelde vragen
Wat stelt een MCP-server beschikbaar?
Drie primitieven: tools (door het model aangeroepen functies die neveneffecten kunnen hebben, zoals het bevragen van een API of het aanmaken van een record), resources (alleen-lezen context geadresseerd via URI die de applicatie of gebruiker toevoegt), en prompts (door de gebruiker aangeroepen, sjabloonmatige instructies, vaak zichtbaar als slash-commando's). Kies tools wanneer het model zelf moet beslissen om te handelen, resources wanneer de app of gebruiker context aanlevert, en prompts voor herbruikbare, kant-en-klare instructies.
Moet ik stdio of Streamable HTTP gebruiken voor mijn MCP-server?
Gebruik lokale stdio voor ontwikkeling en desktop- of IDE-clients, waarbij de server op de machine van de gebruiker draait en geen netwerk of authenticatie nodig heeft. Gebruik externe Streamable HTTP voor alles wat multi-user of productie is; de stateless modus (gestandaardiseerd in de revisie van 28-07-2026) laat u veel replica's achter een load balancer draaien, en de headers Mcp-Method en Mcp-Name laten een gateway per tool routeren en reguleren.
Hoe schrijf ik een goede beschrijving voor een MCP-tool?
Behandel het als prompt engineering, want het model bepaalt bijna volledig op basis van de beschrijving of en hoe het de tool aanroept. Vermeld wat de tool doet, wanneer deze te gebruiken, wanneer niet, wat deze retourneert, en hoe om te gaan met ontbrekende invoer. Combineer dit met een strak JSON Schema met verplichte velden, enums voor gesloten verzamelingen, en grenswaarden, zodat het model geen ongeldige argumenten kan verzinnen.
Hoe authenticeer ik een externe MCP-server?
Gebruik OAuth 2.1, waarbij clients een accesstoken overleggen dat van een autorisatieserver is verkregen, en vereis resource-indicatoren (RFC 8707) zodat elke token is gebonden aan de specifieke server waarvoor deze is uitgegeven. Dit voorkomt dat een token die voor de ene server is gemaakt, wordt hergebruikt tegen een andere. Een statische, gedeelde API-sleutel is geen echte authenticatie voor een externe server.
Heb ik een MCP Gateway nodig om een server te draaien?
Niet om zelf één server te draaien, maar u heeft de mogelijkheden van een gateway nodig zodra de server multi-user of productie wordt: OAuth-afhandeling met audience-validatie, autorisatie per tool, een register voor discovery, observability, en guardrails voor persoonsgegevens en prompt-injectie. Een gateway levert die laag op uniforme wijze, zodat u deze niet in elke server opnieuw hoeft te bouwen.












.png)

.png)
.webp)
.webp)
.webp)
.webp)

.webp)



.webp)








.webp)





