Het AI-landschap is in 2026 flink op z'n kop gezet. Large Language Models worden steeds krachtiger — daar hoef ik je waarschijnlijk niet meer van te overtuigen — maar er bleef één hardnekkig probleem: hoe verbind je die modellen op een gestandaardiseerde manier met de buitenwereld? Denk aan je database, je API's, je bestandssysteem, je bedrijfstools. Zonder standaard bouw je voor elke combinatie een maatwerkintegratie. En eerlijk gezegd, dat schaalt gewoon niet.
Het antwoord op die vraag is het Model Context Protocol (MCP) — een open standaard die in november 2024 door Anthropic werd geïntroduceerd. Wat begon als een intern protocol, is inmiddels uitgegroeid tot dé universele standaard voor AI-integraties. In december 2025 werd MCP gedoneerd aan de Agentic AI Foundation (AAIF) onder de Linux Foundation. Daarmee werd het een écht open, vendor-neutraal protocol.
De cijfers liegen er niet om: meer dan 10.000 actieve MCP-servers, 97 miljoen maandelijkse SDK-downloads, en adoptie door alle grote spelers — OpenAI, Google DeepMind, Microsoft, Amazon, noem maar op. MCP is niet langer een experiment. Het is de ruggengraat van moderne AI-integraties.
In deze gids loop ik alles met je door: van de architectuur tot het bouwen van je eigen servers in Python en TypeScript, van transportlagen tot productie-implementaties. Of je nu een doorgewinterde developer bent of net begint met AI-integraties — na het lezen van dit artikel kun je aan de slag.
Wat is het Model Context Protocol?
MCP wordt vaak omschreven als "USB-C voor AI" — en eerlijk gezegd, die vergelijking klopt aardig. Net zoals USB-C een universele standaard biedt waarmee je elk apparaat op elke poort kunt aansluiten, biedt MCP een universele standaard waarmee elk AI-model verbinding kan maken met elke externe databron of tool.
Vóór MCP was het een zooitje. Elke AI-provider had eigen API-formaten, eigen tool-calling conventies en eigen integratiemethoden. Wilde je dezelfde tool beschikbaar maken voor Claude, ChatGPT én Gemini? Dan moest je drie verschillende integraties bouwen en onderhouden. Dit leidde tot een M × N-probleem: M AI-modellen maal N tools = M × N integraties. Ouch.
MCP lost dit elegant op door een standaard tussenlaag te bieden. In plaats van directe koppelingen bouw je één MCP-server die je tool of databron beschikbaar maakt via het protocol. Elke AI-client die MCP ondersteunt, kan er vervolgens mee praten. Het M × N-probleem wordt zo gereduceerd tot M + N. Dat scheelt nogal.
De Client-Host-Server Architectuur
MCP hanteert een heldere architectuur met drie lagen:
- Host — De applicatie waarin je werkt, zoals Claude Desktop, VS Code, Cursor of een eigen applicatie. De host beheert de levenscyclus van MCP-verbindingen en handhaaft beveiligingsgrenzen.
- Client — Een MCP-client die draait binnen de host. Elke client onderhoudt een 1-op-1 verbinding met een specifieke MCP-server. De client vertaalt verzoeken van het AI-model naar MCP-berichten en vice versa.
- Server — Een MCP-server die specifieke functionaliteit beschikbaar maakt via het protocol. Servers kunnen tools, resources en prompts aanbieden, en ze kunnen zowel lokaal draaien (als een subprocess) als op afstand via HTTP.
Dit maakt het mogelijk om meerdere MCP-servers tegelijk te gebruiken. Je kunt bijvoorbeeld een server voor database-toegang, een voor GitHub-integratie en een voor Slack-berichten allemaal tegelijkertijd koppelen aan dezelfde AI-client. Best handig.
De communicatie verloopt via het JSON-RPC 2.0 protocol — gestructureerde berichten die voorspelbaar en typeveilig zijn, en makkelijk te debuggen.
De Drie Kernprimitieven van MCP
MCP draait om drie fundamentele bouwstenen (of primitieven) waarmee servers hun functionaliteit ontsluiten: Tools, Resources en Prompts. Elk heeft z'n eigen rol en gebruikspatroon.
Tools: Functies die het AI-model kan Aanroepen
Tools zijn verreweg het meest gebruikte primitief. Een tool is eigenlijk gewoon een functie die het AI-model kan aanroepen om iets te doen of informatie op te halen. Tools zijn model-gestuurd — het AI-model beslist zelf wanneer en welke tool het aanroept, op basis van de gesprekscontext.
Een paar voorbeelden:
- Een
zoek_klanttool die klantgegevens ophaalt uit een CRM-systeem - Een
verstuur_emailtool die een e-mail verstuurt namens de gebruiker - Een
voer_query_uittool die een SQL-query draait op een database - Een
maak_tickettool die een supportticket aanmaakt in Jira
Elke tool wordt gedefinieerd met een naam, een beschrijving (die het AI-model helpt snappen wanneer 'ie ingezet moet worden) en een JSON Schema voor de verwachte parameters. Het model gebruikt die metadata om slim te bepalen welke tool wanneer van pas komt.
Belangrijk om te weten: tools kunnen bijwerkingen hebben. Ze kunnen gegevens wijzigen, berichten versturen of andere acties uitvoeren. Daarom is het écht essentieel om goede beveiligingsmaatregelen te treffen — denk aan bevestiging door de gebruiker voor gevoelige operaties.
Resources: Alleen-lezen Gegevensbronnen
Resources bieden gestructureerde, alleen-lezen toegang tot data. Anders dan tools (die acties uitvoeren) stellen resources gegevens beschikbaar die het AI-model kan lezen om context op te bouwen. Resources zijn applicatie-gestuurd: de hostapplicatie bepaalt welke resources geladen worden, niet het AI-model zelf.
Resources worden geïdentificeerd door URI's en kunnen allerlei typen data bevatten:
file:///pad/naar/document.pdf— Een lokaal bestanddb://klanten/overzicht— Een database-overzichtapi://weer/amsterdam— Live weersgegevens via een APIconfig://app/instellingen— Applicatieconfiguratie
Resources ondersteunen ook templates met variabelen. Zo kun je met een resource-template als db://klanten/{klant_id}/profiel dynamisch het profiel van een specifieke klant ophalen. Servers kunnen clients bovendien notificeren wanneer beschikbare resources veranderen — zodat de client altijd actuele data kan tonen.
Prompts: Herbruikbare Prompttemplates
Prompts zijn herbruikbare templates die veelgebruikte interactiepatronen vastleggen. Ze zijn gebruiker-gestuurd: de gebruiker selecteert een prompt expliciet, bijvoorbeeld via een slash-commando of een menu.
Zie prompts als voorgedefinieerde "workflows" die een complex verzoek verpakken in een gebruiksvriendelijke interface. Denk aan:
- Een
code_reviewprompt die een gestructureerde code-review uitvoert - Een
sql_queryprompt die helpt bij het formuleren van veilige SQL-queries - Een
bug_rapportprompt die een gestructureerd bugrapport genereert - Een
samenvat_documentprompt die een document samenvat volgens een specifiek format
Prompts accepteren argumenten, kunnen meerdere berichten bevatten (inclusief systeemberichten) en kunnen zelfs verwijzen naar resources voor extra context. Dat maakt ze bijzonder krachtig voor het standaardiseren van AI-werkstromen binnen een organisatie.
Een MCP Server Bouwen met Python (FastMCP)
Oké, genoeg theorie. Laten we de handen vuil maken. De eenvoudigste manier om een MCP-server te bouwen in Python is met FastMCP — het officiële Python-framework dat een hoog niveau van abstractie biedt. Als je ooit met Flask of FastAPI hebt gewerkt, voelt FastMCP meteen vertrouwd.
Installatie
Installeer het MCP Python SDK met pip:
pip install "mcp[cli]"
Dit installeert zowel de MCP-bibliotheek als de command-line tools voor het testen en inspecteren van je server.
Een Eenvoudige Server Opzetten
Hieronder een compleet voorbeeld van een MCP-server die weersinformatie aanbiedt. Let op hoe weinig code je eigenlijk nodig hebt:
from mcp.server.fastmcp import FastMCP
import httpx
from datetime import datetime
# Maak een nieuwe MCP-server aan
mcp = FastMCP(
name="weer-service",
version="1.0.0"
)
# Definieer een tool met de @mcp.tool decorator
@mcp.tool()
async def haal_weer_op(stad: str, land: str = "NL") -> dict:
"""Haal de huidige weersinformatie op voor een specifieke stad.
Args:
stad: De naam van de stad (bijv. "Amsterdam")
land: De landcode in ISO 3166-1 alpha-2 formaat (standaard: "NL")
"""
async with httpx.AsyncClient() as client:
response = await client.get(
"https://api.openweathermap.org/data/2.5/weather",
params={
"q": f"{stad},{land}",
"appid": "JOUW_API_SLEUTEL",
"units": "metric",
"lang": "nl"
}
)
data = response.json()
return {
"stad": stad,
"temperatuur": data["main"]["temp"],
"beschrijving": data["weather"][0]["description"],
"luchtvochtigheid": data["main"]["humidity"],
"windsnelheid": data["wind"]["speed"],
"opgevraagd_op": datetime.now().isoformat()
}
@mcp.tool()
async def weer_voorspelling(stad: str, dagen: int = 5) -> dict:
"""Haal de weersvoorspelling op voor de komende dagen.
Args:
stad: De naam van de stad
dagen: Aantal dagen vooruit (1-5, standaard: 5)
"""
if dagen < 1 or dagen > 5:
raise ValueError("Aantal dagen moet tussen 1 en 5 liggen")
async with httpx.AsyncClient() as client:
response = await client.get(
"https://api.openweathermap.org/data/2.5/forecast",
params={
"q": stad,
"appid": "JOUW_API_SLEUTEL",
"units": "metric",
"cnt": dagen * 8,
"lang": "nl"
}
)
data = response.json()
voorspelling = []
for item in data["list"][:dagen]:
voorspelling.append({
"datum": item["dt_txt"],
"temperatuur": item["main"]["temp"],
"beschrijving": item["weather"][0]["description"]
})
return {"stad": stad, "voorspelling": voorspelling}
# Start de server
if __name__ == "__main__":
mcp.run()
Merk op hoe simpel dit is. De @mcp.tool() decorator transformeert een gewone Python-functie automatisch naar een MCP-tool. FastMCP genereert het JSON Schema op basis van je type-annotaties en docstring — je hoeft daar zelf niks voor te doen.
Resources Toevoegen
Laten we resources toevoegen zodat het AI-model ook statische gegevens kan inladen:
from mcp.server.fastmcp import FastMCP
mcp = FastMCP("kennisbank-service")
# Statische resource
@mcp.resource("docs://handleiding/introductie")
def handleiding_intro() -> str:
"""De introductie van de gebruikershandleiding."""
return """
Welkom bij onze applicatie! Deze handleiding helpt je
op weg met de belangrijkste functionaliteiten.
Inhoud:
1. Account aanmaken
2. Dashboard gebruiken
3. Rapporten genereren
4. Instellingen beheren
"""
# Dynamische resource met template
@mcp.resource("db://klanten/{klant_id}/profiel")
def klant_profiel(klant_id: str) -> dict:
"""Haal het profiel op van een specifieke klant."""
# In productie zou je hier een database-query doen
klanten = {
"K001": {
"naam": "Bedrijf A B.V.",
"contactpersoon": "Jan de Vries",
"email": "[email protected]",
"abonnement": "Enterprise"
},
"K002": {
"naam": "Startup B",
"contactpersoon": "Lisa Bakker",
"email": "[email protected]",
"abonnement": "Professional"
}
}
if klant_id not in klanten:
raise ValueError(f"Klant {klant_id} niet gevonden")
return klanten[klant_id]
# Resource die een lijst beschikbare datasets toont
@mcp.resource("data://datasets/overzicht")
def datasets_overzicht() -> dict:
"""Overzicht van alle beschikbare datasets."""
return {
"datasets": [
{"naam": "verkoop_2025", "records": 150000, "laatst_bijgewerkt": "2025-12-31"},
{"naam": "klanten_actief", "records": 8500, "laatst_bijgewerkt": "2026-02-01"},
{"naam": "producten_catalogus", "records": 3200, "laatst_bijgewerkt": "2026-01-15"}
]
}
Prompts Definiëren
Tot slot voegen we herbruikbare prompts toe:
from mcp.server.fastmcp import FastMCP
from mcp.server.fastmcp.prompts import base
mcp = FastMCP("analyse-service")
@mcp.prompt()
def data_analyse(dataset_naam: str, vraag: str) -> list[base.Message]:
"""Voer een gestructureerde data-analyse uit.
Args:
dataset_naam: De naam van de dataset om te analyseren
vraag: De analysevraag die beantwoord moet worden
"""
return [
base.UserMessage(
content=f"""Voer een grondige data-analyse uit op de dataset '{dataset_naam}'.
Beantwoord de volgende vraag: {vraag}
Volg dit stappenplan:
1. Beschrijf de dataset en relevante kolommen
2. Formuleer hypothesen
3. Voer de analyse uit met beschikbare tools
4. Presenteer de resultaten met visualisatie-suggesties
5. Trek conclusies en doe aanbevelingen
Gebruik altijd Nederlandse terminologie in je antwoord."""
)
]
@mcp.prompt()
def code_review(programmeertaal: str, focus_gebieden: str = "beveiliging,prestaties,leesbaarheid") -> list[base.Message]:
"""Template voor een gestructureerde code review.
Args:
programmeertaal: De programmeertaal van de code
focus_gebieden: Kommagescheiden lijst van aandachtsgebieden
"""
gebieden = [g.strip() for g in focus_gebieden.split(",")]
gebieden_tekst = "\n".join([f"- {g.capitalize()}" for g in gebieden])
return [
base.UserMessage(
content=f"""Voer een code review uit voor {programmeertaal} code.
Let specifiek op de volgende gebieden:
{gebieden_tekst}
Gebruik het volgende format voor je review:
## Samenvatting
[Korte samenvatting van de code-kwaliteit]
## Bevindingen
Per bevinding:
- **Ernst**: Kritiek / Waarschuwing / Suggestie
- **Locatie**: Regelnummer of functienaam
- **Beschrijving**: Wat het probleem is
- **Aanbeveling**: Hoe het opgelost kan worden
## Conclusie
[Eindbeoordeling en prioriteiten]"""
)
]
De Server Testen
MCP heeft een ingebouwde inspector waarmee je je server kunt testen zonder eerst een AI-client te hoeven configureren:
# Start de MCP Inspector
mcp dev server.py
# Of test via de command-line
mcp run server.py
De MCP Inspector opent een webinterface waarin je handmatig tools kunt aanroepen, resources bekijken en prompts testen. Onmisbaar tijdens de ontwikkeling — ik zou niet meer zonder willen.
Een MCP Server Bouwen met TypeScript
Voor TypeScript-ontwikkelaars is er de officiële @modelcontextprotocol/sdk package. TypeScript is trouwens bijzonder geschikt voor MCP-servers — de sterke typering en uitstekende Zod-ondersteuning maken het een natuurlijke keuze.
Project Opzetten
# Maak een nieuw project aan
mkdir mcp-taakbeheer-server
cd mcp-taakbeheer-server
# Initialiseer het project
npm init -y
npm install @modelcontextprotocol/sdk zod
npm install -D typescript @types/node tsx
# Initialiseer TypeScript
npx tsc --init
De Server Implementeren
Hier een compleet voorbeeld van een taakbeheer-server. Het is wat langer, maar bekijk even hoe netjes alles in elkaar past:
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import { z } from "zod";
// In-memory opslag voor taken
interface Taak {
id: string;
titel: string;
beschrijving: string;
status: "open" | "in_uitvoering" | "afgerond";
prioriteit: "laag" | "middel" | "hoog" | "kritiek";
toegewezen_aan: string | null;
aangemaakt_op: string;
bijgewerkt_op: string;
}
const taken: Map<string, Taak> = new Map();
let volgendId = 1;
// Maak de MCP-server aan
const server = new McpServer({
name: "taakbeheer",
version: "1.0.0",
});
// Tool: Nieuwe taak aanmaken
server.tool(
"maak_taak",
"Maak een nieuwe taak aan in het taakbeheersysteem",
{
titel: z.string().min(1).describe("De titel van de taak"),
beschrijving: z.string().describe("Gedetailleerde beschrijving van de taak"),
prioriteit: z
.enum(["laag", "middel", "hoog", "kritiek"])
.default("middel")
.describe("De prioriteit van de taak"),
toegewezen_aan: z
.string()
.nullable()
.default(null)
.describe("De naam van de persoon aan wie de taak is toegewezen"),
},
async ({ titel, beschrijving, prioriteit, toegewezen_aan }) => {
const id = `TAAK-${String(volgendId++).padStart(4, "0")}`;
const nu = new Date().toISOString();
const taak: Taak = {
id,
titel,
beschrijving,
status: "open",
prioriteit,
toegewezen_aan,
aangemaakt_op: nu,
bijgewerkt_op: nu,
};
taken.set(id, taak);
return {
content: [
{
type: "text" as const,
text: `Taak succesvol aangemaakt:\n\nID: ${id}\nTitel: ${titel}\nPrioriteit: ${prioriteit}\nStatus: open\nToegewezen aan: ${toegewezen_aan || "Niemand"}`,
},
],
};
}
);
// Tool: Taak bijwerken
server.tool(
"werk_taak_bij",
"Werk de status of details van een bestaande taak bij",
{
taak_id: z.string().describe("Het ID van de taak (bijv. TAAK-0001)"),
status: z
.enum(["open", "in_uitvoering", "afgerond"])
.optional()
.describe("De nieuwe status van de taak"),
prioriteit: z
.enum(["laag", "middel", "hoog", "kritiek"])
.optional()
.describe("De nieuwe prioriteit"),
toegewezen_aan: z
.string()
.optional()
.describe("De nieuwe toegewezen persoon"),
},
async ({ taak_id, status, prioriteit, toegewezen_aan }) => {
const taak = taken.get(taak_id);
if (!taak) {
return {
content: [{ type: "text" as const, text: `Fout: Taak ${taak_id} niet gevonden.` }],
isError: true,
};
}
if (status) taak.status = status;
if (prioriteit) taak.prioriteit = prioriteit;
if (toegewezen_aan !== undefined) taak.toegewezen_aan = toegewezen_aan;
taak.bijgewerkt_op = new Date().toISOString();
return {
content: [
{
type: "text" as const,
text: `Taak ${taak_id} succesvol bijgewerkt:\n\nStatus: ${taak.status}\nPrioriteit: ${taak.prioriteit}\nToegewezen aan: ${taak.toegewezen_aan || "Niemand"}`,
},
],
};
}
);
// Tool: Taken doorzoeken
server.tool(
"zoek_taken",
"Doorzoek taken op basis van filters",
{
status: z.enum(["open", "in_uitvoering", "afgerond"]).optional(),
prioriteit: z.enum(["laag", "middel", "hoog", "kritiek"]).optional(),
toegewezen_aan: z.string().optional(),
},
async ({ status, prioriteit, toegewezen_aan }) => {
let resultaten = Array.from(taken.values());
if (status) resultaten = resultaten.filter((t) => t.status === status);
if (prioriteit)
resultaten = resultaten.filter((t) => t.prioriteit === prioriteit);
if (toegewezen_aan)
resultaten = resultaten.filter(
(t) => t.toegewezen_aan === toegewezen_aan
);
const tekst = resultaten.length === 0
? "Geen taken gevonden die aan de criteria voldoen."
: resultaten
.map(
(t) =>
`[${t.id}] ${t.titel} | Status: ${t.status} | Prioriteit: ${t.prioriteit} | Toegewezen: ${t.toegewezen_aan || "-"}`
)
.join("\n");
return {
content: [{ type: "text" as const, text: tekst }],
};
}
);
// Start de server met stdio transport
async function main() {
const transport = new StdioServerTransport();
await server.connect(transport);
console.error("Taakbeheer MCP-server gestart");
}
main().catch(console.error);
De Server Uitvoeren
Voeg het volgende script toe aan je package.json:
{
"scripts": {
"start": "tsx src/index.ts",
"build": "tsc",
"inspect": "npx @modelcontextprotocol/inspector tsx src/index.ts"
}
}
Test de server met de MCP Inspector:
npm run inspect
MCP Transportlagen
Hoe praten client en server eigenlijk met elkaar? MCP ondersteunt meerdere transportmechanismen, en de keuze hangt af van je situatie: draait de server lokaal of op afstand? Is het een eenmalige interactie of een langlopende verbinding?
stdio (Standard Input/Output)
Het stdio-transport is het eenvoudigste en meest gebruikte mechanisme. De host start de MCP-server als kindproces en communiceert via stdin/stdout. Ideaal voor:
- Lokale ontwikkeling en testen
- Desktop-applicaties zoals Claude Desktop en Cursor
- Situaties waarin server en client op dezelfde machine draaien
- Command-line tools en scripts
Het grote voordeel? Simpelheid. Geen netwerkconfiguratie nodig, en de beveiliging wordt geregeld door het besturingssysteem. Het nadeel is logischerwijs dat het alleen lokaal werkt.
Server-Sent Events (SSE)
SSE was het eerste HTTP-gebaseerde transport in MCP. Het gebruikt een HTTP POST-endpoint voor client-naar-server berichten en een SSE-stream voor de andere richting. SSE was de standaardkeuze voor externe servers, maar wordt inmiddels vervangen door Streamable HTTP.
De beperkingen? Het vereist twee afzonderlijke verbindingen, wat de infrastructuur complexer maakt. En niet alle proxy's en load balancers gaan even goed om met SSE.
Streamable HTTP
Streamable HTTP is het nieuwste en aanbevolen transport voor externe MCP-servers. Het combineert het beste van SSE met de eenvoud van standaard HTTP. De client stuurt POST-verzoeken naar één enkel endpoint, en de server kan reageren met een regulier HTTP-antwoord óf upgraden naar een SSE-stream voor langlopende operaties.
De voordelen op een rij:
- Werkt met standaard HTTP-infrastructuur (proxy's, load balancers, CDN's)
- Ondersteunt zowel synchrone als asynchrone communicatie
- Makkelijker te implementeren en te debuggen dan SSE
- Geschikt voor serverloze omgevingen (stateless modus)
- Kan upgraden naar SSE wanneer streaming nodig is
Mijn advies voor nieuwe projecten: gebruik stdio voor lokale servers en Streamable HTTP voor externe. SSE blijft ondersteund, maar nieuwe implementaties zouden Streamable HTTP moeten prefereren.
Transportkeuze in Code
Zo configureer je verschillende transports in Python:
from mcp.server.fastmcp import FastMCP
mcp = FastMCP("mijn-service")
# Standaard: stdio transport (voor lokaal gebruik)
# mcp.run() -- gebruikt automatisch stdio
# Streamable HTTP transport (voor extern gebruik)
mcp.run(transport="streamable-http", host="0.0.0.0", port=8080)
# SSE transport (legacy, voor achterwaartse compatibiliteit)
# mcp.run(transport="sse", host="0.0.0.0", port=8080)
MCP Integreren met AI-Clients
Een MCP-server is pas nuttig als 'ie verbonden is met een AI-client. Laten we bekijken hoe je dat configureert in de populairste clients.
Claude Desktop
Claude Desktop was de eerste AI-client met MCP-ondersteuning en blijft een van de meest gebruikte. Configuratie gaat via claude_desktop_config.json:
{
"mcpServers": {
"taakbeheer": {
"command": "npx",
"args": ["tsx", "/pad/naar/taakbeheer/src/index.ts"]
},
"weer-service": {
"command": "python",
"args": ["/pad/naar/weer_server.py"],
"env": {
"OPENWEATHER_API_KEY": "jouw-api-sleutel"
}
},
"database": {
"command": "uvx",
"args": ["mcp-server-sqlite", "--db-path", "/pad/naar/database.db"]
}
}
}
Op macOS vind je dit bestand op: ~/Library/Application Support/Claude/claude_desktop_config.json. Op Windows: %APPDATA%\Claude\claude_desktop_config.json.
Visual Studio Code (Copilot)
VS Code ondersteunt MCP-servers via de GitHub Copilot-extensie. Configureer servers in je .vscode/mcp.json of in de gebruikersinstellingen:
{
"servers": {
"taakbeheer": {
"command": "npx",
"args": ["tsx", "${workspaceFolder}/mcp-servers/taakbeheer/src/index.ts"]
},
"git-analyse": {
"command": "uvx",
"args": ["mcp-server-git", "--repository", "${workspaceFolder}"]
},
"externe-api": {
"type": "http",
"url": "https://mcp.mijnbedrijf.nl/api/v1/mcp"
}
}
}
Cursor
Cursor, de populaire AI-gestuurde code-editor, heeft uitgebreide MCP-ondersteuning. Voor projectconfiguratie maak je een .cursor/mcp.json bestand aan:
{
"mcpServers": {
"project-docs": {
"command": "npx",
"args": ["tsx", "tools/docs-server.ts"]
},
"deployment": {
"command": "python",
"args": ["scripts/deploy_mcp_server.py"],
"env": {
"DEPLOY_ENV": "staging"
}
}
}
}
ChatGPT
OpenAI heeft in 2025 MCP-ondersteuning toegevoegd aan ChatGPT. Voor ontwikkelaars die de OpenAI API gebruiken, kan MCP worden geconfigureerd via de Responses API:
{
"tools": [
{
"type": "mcp",
"server_label": "taakbeheer",
"server_url": "https://mcp.mijnbedrijf.nl/taakbeheer",
"require_approval": "always"
}
]
}
Mooi detail: de meeste clients ondersteunen het dynamisch ontdekken van beschikbare tools en resources bij het verbinden met een MCP-server. Je hoeft toolbeschrijvingen dus niet handmatig te synchroniseren — de client vraagt ze automatisch op.
Best Practices en Beveiligingsoverwegingen
Nu wordt het serieus. Het bouwen van MCP-servers brengt beveiligingsverantwoordelijkheden met zich mee. Je geeft AI-modellen immers toegang tot externe systemen — dat moet je niet lichtzinnig aanpakken.
Beveiligingsgrenzen en het Principe van Minimale Rechten
Pas het principe van minimale rechten (least privilege) consequent toe. Een MCP-server zou alleen toegang moeten hebben tot wat strikt noodzakelijk is:
- Gebruik database-accounts met beperkte rechten (alleen-lezen waar mogelijk)
- Beperk bestandssysteemtoegang tot specifieke mappen
- Gebruik API-tokens met minimale scopes
- Implementeer rate limiting om misbruik te voorkomen
Inputvalidatie
Valideer alle invoer die via MCP binnenkomt grondig. Vergeet niet: het AI-model genereert de invoer, en modellen kunnen soms onverwachte (of zelfs kwaadaardige) input produceren. Vertrouw er nooit blindelings op.
from mcp.server.fastmcp import FastMCP
import re
mcp = FastMCP("veilige-service")
@mcp.tool()
async def zoek_in_database(
tabel: str,
zoekterm: str,
limiet: int = 10
) -> dict:
"""Doorzoek een databasetabel op een zoekterm."""
# Valideer tabelnaam tegen whitelist
toegestane_tabellen = {"klanten", "producten", "bestellingen"}
if tabel not in toegestane_tabellen:
raise ValueError(
f"Ongeldige tabel: '{tabel}'. "
f"Toegestane tabellen: {', '.join(toegestane_tabellen)}"
)
# Valideer en sanitize zoekterm
if len(zoekterm) > 200:
raise ValueError("Zoekterm mag maximaal 200 tekens bevatten")
# Verwijder potentiele SQL-injectie patronen
if re.search(r"[;'\"\-\-]", zoekterm):
raise ValueError("Zoekterm bevat ongeldige tekens")
# Beperk limiet
limiet = min(max(1, limiet), 100)
# Gebruik geparameteriseerde queries
# cursor.execute("SELECT * FROM ? WHERE naam LIKE ?", (tabel, f"%{zoekterm}%"))
return {"resultaat": f"Zoekresultaten voor '{zoekterm}' in {tabel}"}
Foutafhandeling
Implementeer foutafhandeling die informatief is zonder gevoelige informatie prijs te geven. Dit is een balans die je bewust moet zoeken:
import logging
import traceback
from mcp.server.fastmcp import FastMCP
mcp = FastMCP("robuuste-service")
logger = logging.getLogger(__name__)
@mcp.tool()
async def verwerk_bestelling(bestelling_id: str) -> dict:
"""Verwerk een bestelling in het systeem."""
try:
# Validatie
if not bestelling_id.startswith("BST-"):
return {
"succes": False,
"fout": "Ongeldig bestelling-ID formaat. Verwacht: BST-XXXX"
}
# Bedrijfslogica
resultaat = await _verwerk_intern(bestelling_id)
return {
"succes": True,
"bestelling_id": bestelling_id,
"status": resultaat["status"]
}
except ConnectionError as e:
logger.error(f"Verbindingsfout bij verwerking {bestelling_id}: {e}")
return {
"succes": False,
"fout": "Kan geen verbinding maken met het bestellingsysteem. Probeer het later opnieuw."
}
except Exception as e:
# Log de volledige fout intern
logger.error(
f"Onverwachte fout bij verwerking {bestelling_id}: "
f"{traceback.format_exc()}"
)
# Geef een generiek bericht terug aan de gebruiker
return {
"succes": False,
"fout": "Er is een onverwachte fout opgetreden. Neem contact op met de beheerder."
}
Logging en Monitoring
Goede logging is écht onmisbaar voor productie-MCP-servers. Een paar tips uit de praktijk:
- Log alle tool-aanroepen met parameters (maar verwijder gevoelige gegevens zoals wachtwoorden of tokens)
- Log fouten met context — welke tool, welke parameters, welke gebruiker
- Gebruik gestructureerde logging (JSON-formaat) voor makkelijke analyse
- Implementeer health checks zodat monitoringsystemen de status kunnen controleren
- Meet prestaties — houd responstijden bij en stel alerts in voor trage responses
Menselijke Bevestiging
Voor tools die gevoelige acties uitvoeren — gegevens wijzigen, e-mails versturen, betalingen verwerken — implementeer altijd een mechanisme voor menselijke bevestiging. MCP ondersteunt dit via het Human-in-the-Loop patroon. Beter een klik te veel dan een onbedoelde actie.
MCP in Productie: Schaalbare Architectuurpatronen
Het draaien van MCP-servers in productie is een ander verhaal dan lokaal ontwikkelen. Hieronder de belangrijkste architectuurpatronen die je moet kennen.
Server Discovery en Registry
Naarmate het aantal MCP-servers in je organisatie groeit, wordt een centraal serverregister onmisbaar. Dit register houdt bij welke servers er zijn, welke tools ze bieden en hoe ze bereikt worden.
Zo'n register kan simpel zijn (een JSON-bestand) of geavanceerd (een service-discovery-systeem à la Consul of etcd). Het belangrijkste is dat AI-clients dynamisch kunnen ontdekken wat er beschikbaar is.
{
"registry_versie": "1.0",
"servers": [
{
"naam": "crm-integratie",
"beschrijving": "Toegang tot klantgegevens en CRM-functionaliteit",
"url": "https://mcp-intern.bedrijf.nl/crm",
"transport": "streamable-http",
"authenticatie": "oauth2",
"status": "actief",
"tools": ["zoek_klant", "maak_klant", "werk_klant_bij"],
"eigenaar": "[email protected]"
},
{
"naam": "rapportage",
"beschrijving": "Genereer en download rapporten",
"url": "https://mcp-intern.bedrijf.nl/rapportage",
"transport": "streamable-http",
"authenticatie": "api-key",
"status": "actief",
"tools": ["genereer_rapport", "download_rapport"],
"eigenaar": "[email protected]"
}
]
}
Monitoring en Observability
In productie wil je inzicht in wat je MCP-servers doen. Implementeer monitoring op meerdere niveaus:
- Infrastructuurmonitoring — CPU, geheugen, netwerkverkeer, beschikbaarheid
- Applicatiemonitoring — Aanroepfrequentie per tool, gemiddelde responstijden, foutpercentages
- Bedrijfsmonitoring — Welke tools het meest worden gebruikt, welke fouten het vaakst voorkomen, gebruikspatronen
Gebruik OpenTelemetry voor gestandaardiseerde tracing en metrics. Zo krijg je een compleet beeld van elk verzoek — van de gebruikersinvoer in de AI-client tot de uiteindelijke actie in het doelsysteem.
Meerdere Servers Schalen
Voor organisaties met tientallen of honderden MCP-servers is een gestructureerde aanpak noodzakelijk:
- Domeingebaseerde organisatie — Groepeer servers per bedrijfsdomein (CRM, financiën, HR, IT-ops)
- Gateway-patroon — Gebruik een API-gateway voor authenticatie, autorisatie, rate limiting en logging op een centraal punt
- Containerisatie — Draai elke MCP-server als container (Docker/Kubernetes) voor schaalbaarheid en isolatie
- Configuratiebeheer — Gebruik Infrastructure-as-Code (Terraform, Pulumi) om de infrastructuur te beheren
- Versiebeheer — Implementeer semantisch versiebeheer zodat clients compatibiliteit kunnen checken
Authenticatie en Autorisatie
In productie moet elke MCP-server beveiligd zijn. De MCP-specificatie beveelt OAuth 2.1 aan als standaardmechanisme voor externe servers. Dit maakt het mogelijk om:
- Gebruikers te authenticeren via bestaande identity providers (Azure AD, Okta, Auth0)
- Fijnmazige autorisatie te implementeren (welke gebruiker welke tools mag aanroepen)
- Tokens veilig te beheren met beperkte levensduur en refresh-mechanismen
- Audit trails bij te houden van alle tool-aanroepen
De Toekomst van MCP
MCP heeft zich in een razend tempo ontwikkeld sinds november 2024, en de plannen voor 2026 en verder zijn nog ambitieuzer. Laten we de belangrijkste trends bekijken.
MCP Apps: Interactieve UI-Componenten
Dit vind ik persoonlijk een van de spannendste ontwikkelingen: MCP Apps. Hiermee kunnen MCP-servers interactieve UI-componenten leveren. In plaats van alleen tekst kunnen servers nu rijke, interactieve elementen terugsturen die de hostapplicatie rendert.
Denk aan:
- Interactieve grafieken en dashboards die direct in de AI-chat verschijnen
- Formulieren voor gegevensinvoer met validatie
- Kaarten en geografische visualisaties
- Tabellen met sorteer- en filterfunctionaliteit
Dit verandert AI-assistenten van tekst-gebaseerde chatbots naar volwaardige applicatieplatformen. Dat is nogal een stap.
Enterprise-adoptie
De adoptie in het bedrijfsleven versnelt flink. Volgens Gartner zal tegen eind 2026 40% van alle enterprise-applicaties AI-agents bevatten die externe tools gebruiken — en MCP is de de facto standaard daarvoor.
Grote enterprise-leveranciers als Salesforce, SAP en ServiceNow bieden inmiddels MCP-servers aan. Dat betekent dat organisaties niet langer eigen integraties hoeven te bouwen voor veelgebruikte bedrijfssoftware. Een enorme tijdsbesparing.
De Rol van de Agentic AI Foundation
Met de donatie aan de Agentic AI Foundation (AAIF) onder de Linux Foundation is MCP niet langer afhankelijk van één leverancier. De AAIF biedt een neutrale governancestructuur waarin alle belanghebbenden — van grote techbedrijven tot onafhankelijke devs — meesturen aan de evolutie van het protocol.
Dat vergroot het vertrouwen van de enterprise-markt in MCP als langetermijninvestering.
Wat Staat Er Nog op de Roadmap?
Naast MCP Apps staan er diverse verbeteringen gepland:
- Verbeterde multi-tenancy — Betere ondersteuning voor het isoleren van meerdere gebruikers op dezelfde server
- Elicitation — Een mechanisme waarmee servers actief informatie opvragen bij de gebruiker als er onvoldoende context is
- Gestandaardiseerde logging en tracing — Ingebouwde OpenTelemetry-compatibele observability
- Verbeterde streaming — Betere ondersteuning voor grote hoeveelheden data, zoals database-resultaten
- Protocol-niveau caching — Ingebouwde caching om prestaties te verbeteren en achterliggende systemen te ontlasten
MCP als Fundament voor de Agentic Toekomst
MCP positioneert zich als hét protocol voor de agentic AI-toekomst — een wereld waarin AI-agents niet alleen vragen beantwoorden, maar actief taken uitvoeren, systemen beheren en complexe workflows orkestreren. Net zoals HTTP het fundament legde voor het web, legt MCP het fundament voor AI-agent-interoperabiliteit.
De visie is helder: een ecosysteem waarin elke tool, databron en dienst beschikbaar is voor elk AI-model via een universele open standaard. Of je nu een klein script bouwt dat lokale bestanden doorzoekt of een enterprise-platform dat duizenden tools orkestreert — MCP maakt het mogelijk.
Voor developers die nu instappen is dit een uitstekend moment. Het protocol is volwassen genoeg voor productie, de tooling is uitgebreid, en het ecosysteem groeit explosief. Begin met een simpele server, experimenteer met de primitieven, en bouw geleidelijk op. De kennis die je nu opdoet, wordt alleen maar waardevoller naarmate AI-agents een steeds grotere rol gaan spelen.
Of je nu kiest voor Python met FastMCP of TypeScript met de officiële SDK — de drempel is laag en de mogelijkheden vrijwel onbeperkt. Succes met het bouwen van je eerste MCP-server!