Files
novi-lessons/Les16-MCP/Les16-Lesstof.md
2026-06-03 16:58:25 +02:00

524 lines
13 KiB
Markdown

# Les 16 — Lesstof
## MCP — Model Context Protocol
**Vak:** AI-Assisted Development
**Opleiding:** NOVI Hogeschool Utrecht
**Vorige les:** Les 15 — Cursor + Vercel deploy
**Volgende les:** Les 17 — Externe APIs in diepte
---
## Inhoud
1. [Wat is MCP en waarom](#1-wat-is-mcp-en-waarom)
2. [Architectuur — client / server / transport](#2-architectuur--client--server--transport)
3. [De drie primitieven](#3-de-drie-primitieven)
4. [Bestaande MCP servers](#4-bestaande-mcp-servers)
5. [Eigen server bouwen — TypeScript SDK](#5-eigen-server-bouwen--typescript-sdk)
6. [Laden in Cursor + Claude Desktop](#6-laden-in-cursor--claude-desktop)
7. [Resources + Prompts](#7-resources--prompts)
8. [MCP Inspector](#8-mcp-inspector)
9. [MCP vs Tool Calling](#9-mcp-vs-tool-calling)
10. [Productie + distributie](#10-productie--distributie)
---
## 1. Wat is MCP en waarom
**Model Context Protocol** is een open standaard van Anthropic (gelanceerd november 2024) voor de communicatie tussen AI-assistenten en externe data/tools.
### Het probleem dat MCP oplost
Stel je hebt een handige tool — bijvoorbeeld 'zoek bands in onze database'. Je wilt 'm gebruiken in:
- Je eigen Next.js chat-app
- Cursor (tijdens coden vragen stellen over je data)
- Claude Desktop (research-werkflow)
- ChatGPT plugins (in de toekomst)
**Zonder MCP:** vier integraties, vier configuraties, vier onderhouds-aspecten.
**Met MCP:** één server, alle clients begrijpen het protocol.
> MCP is voor AI-tools wat USB-C is voor apparaten — één standaard connector.
### Waarom dit nu hot is
- Anthropic Claude Desktop ondersteunt het out-of-the-box
- Cursor ondersteunt MCP sinds early 2025
- OpenAI heeft mei 2025 MCP-support in ChatGPT aangekondigd
- Honderden bedrijven publiceren MCP servers (GitHub, Stripe, Linear, Notion, ...)
Voor jouw eindopdracht: optionele bonus, maar erg handig om interne tools te bouwen die je in elke AI-client kunt gebruiken.
---
## 2. Architectuur — client / server / transport
```
┌──────────────┐ JSON-RPC ┌──────────────┐
│ MCP Client │ ◄────────────────────► │ MCP Server │
│ │ stdio / HTTP/SSE │ (jouw code) │
│ Cursor, │ │ │
│ Claude │ │ exposes: │
│ Desktop, │ │ - tools │
│ custom apps │ │ - resources │
│ │ │ - prompts │
└──────────────┘ └──────────────┘
```
### Drie rollen
- **MCP Client** — de AI-assistent die jouw server gebruikt. Cursor, Claude Desktop, of een custom app die jij bouwt.
- **MCP Server** — JOUW code. Een proces dat tools, data, of prompts beschikbaar maakt.
- **Transport** — hoe ze communiceren. Twee opties:
- **stdio** (default) — server runt lokaal als child-process, communicatie via stdin/stdout
- **HTTP/SSE** — server runt remote, communicatie over HTTP met Server-Sent Events
### Protocol
JSON-RPC 2.0 onder de motorkap. Je hoeft dat niet zelf te schrijven — de SDK regelt het. Wat je wel zou kunnen zien als je inspecteert:
```json
{
"jsonrpc": "2.0",
"method": "tools/call",
"params": {
"name": "searchBands",
"arguments": { "day": "Vrijdag" }
},
"id": 1
}
```
---
## 3. De drie primitieven
Een MCP server kan drie soorten dingen exposeren.
### 3.1 Tools
Uitvoerbare functies. Vergelijkbaar met tool calling uit Les 12.
```typescript
server.tool(
"searchBands", // naam
"Zoek bands op dag, stage of genre", // beschrijving
{ // input schema (Zod)
day: z.enum(["Vrijdag", "Zaterdag", "Zondag"]).optional(),
stage: z.string().optional(),
},
async ({ day, stage }) => { // execute
const bands = await query(day, stage);
return {
content: [{ type: "text", text: JSON.stringify(bands) }],
};
}
);
```
AI kan deze aanroepen tijdens een conversatie.
### 3.2 Resources
Read-only data die AI mag inladen als context.
```typescript
server.resource(
"bands-list", // naam
"bands://list", // URI scheme
async () => ({
contents: [{
uri: "bands://list",
mimeType: "application/json",
text: JSON.stringify(allBands),
}],
})
);
```
In Cursor type je `@polderfest:bands-list` om resource toe te voegen aan context.
### 3.3 Prompts
Herbruikbare prompt-templates.
```typescript
server.prompt(
"daily-recap",
"Genereer een samenvatting van een festivaldag",
{ day: z.string() },
({ day }) => ({
messages: [{
role: "user",
content: {
type: "text",
text: `Geef een gedetailleerde recap van ${day}:
- Top 3 acts
- Drukke / rustige momenten
- Bijzonderheden`,
},
}],
})
);
```
In Cursor commando palette of Claude Desktop slash-menu krijg je deze prompts.
---
## 4. Bestaande MCP servers
### Officieel (Anthropic)
Geïnstalleerd via npm:
- `@modelcontextprotocol/server-filesystem` — file system access
- `@modelcontextprotocol/server-github` — repos, issues, PRs
- `@modelcontextprotocol/server-slack` — Slack workspace
- `@modelcontextprotocol/server-postgres` — Postgres queries
- `@modelcontextprotocol/server-puppeteer` — browser automation
- `@modelcontextprotocol/server-memory` — persistent memory
### Community
- `linear-mcp`, `notion-mcp`, `asana-mcp`, `figma-mcp`, `stripe-mcp`
- `youtube-mcp`, `arxiv-mcp`, `wikipedia-mcp`
- Lijst: https://github.com/punkpeye/awesome-mcp-servers (~500+ servers)
### Gebruik
Voorbeeld Cursor config (`~/.cursor/mcp.json`):
```json
{
"mcpServers": {
"github": {
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-github"],
"env": { "GITHUB_PERSONAL_ACCESS_TOKEN": "ghp_..." }
},
"filesystem": {
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-filesystem", "/Users/tim/Documents"]
}
}
}
```
Restart Cursor → servers actief.
---
## 5. Eigen server bouwen — TypeScript SDK
### Setup
```bash
mkdir mcp-polderfest && cd mcp-polderfest
pnpm init
pnpm add @modelcontextprotocol/sdk zod
pnpm add -D typescript @types/node tsx
```
`tsconfig.json`:
```json
{
"compilerOptions": {
"target": "ES2022",
"module": "Node16",
"moduleResolution": "Node16",
"outDir": "./dist",
"strict": true,
"esModuleInterop": true
},
"include": ["src/**/*"]
}
```
### Minimal server
`src/index.ts`:
```typescript
#!/usr/bin/env node
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import { z } from "zod";
const server = new McpServer({
name: "polderfest-server",
version: "1.0.0",
});
server.tool(
"searchBands",
"Zoek bands op dag, stage, genre",
{
day: z.enum(["Vrijdag", "Zaterdag", "Zondag"]).optional(),
stage: z.string().optional(),
},
async ({ day, stage }) => {
// Echte DB query of mock
const bands = MOCK_BANDS.filter(b =>
(!day || b.day === day) && (!stage || b.stage === stage)
);
return {
content: [{ type: "text", text: JSON.stringify(bands, null, 2) }],
};
}
);
const transport = new StdioServerTransport();
await server.connect(transport);
```
### Build + run
```bash
pnpm tsc # build → dist/index.js
node dist/index.js # runt server (wacht op stdio input)
```
Eerste keer: niets gebeurt zichtbaar — server wacht op JSON-RPC over stdio. Test via Inspector (zie sectie 8).
### Best practices
- **Logging via `console.error`** — `stdout` is gereserveerd voor protocol
- **Errors als data** — return `{ content: [...], isError: true }`
- **Schema's zo strict mogelijk** — Zod schema = AI weet exact wat het mag invullen
- **Description = belangrijk** — AI kiest tools op basis van description
---
## 6. Laden in Cursor + Claude Desktop
### Cursor
`~/.cursor/mcp.json`:
```json
{
"mcpServers": {
"polderfest": {
"command": "node",
"args": ["/Users/jouw-naam/dev/mcp-polderfest/dist/index.js"],
"env": {
"SUPABASE_URL": "https://...supabase.co",
"SUPABASE_KEY": "..."
}
}
}
}
```
Belangrijk: gebruik **absolute paths** (geen `~` of relative).
Cursor → Settings → MCP → check server-status (groen = werkt).
### Claude Desktop
`~/Library/Application Support/Claude/claude_desktop_config.json` (macOS):
```json
{
"mcpServers": {
"polderfest": {
"command": "node",
"args": ["/Users/jouw-naam/dev/mcp-polderfest/dist/index.js"]
}
}
}
```
Op Windows: `%APPDATA%\Claude\claude_desktop_config.json`.
Restart Claude Desktop → MCP icon zichtbaar in chat input.
### Beide tegelijk
Zelfde server, beide configs. Eén keer onderhouden, beide AI-clients gebruiken hem.
---
## 7. Resources + Prompts
### Resources gebruik-cases
- **Documentatie** — handleiding, RFCs, design docs
- **Database snapshots** — read-only views
- **API responses** — gecachede externe data
- **Logs** — recent errors voor debugging
```typescript
server.resource(
"recent-logs",
"logs://recent",
async () => ({
contents: [{
uri: "logs://recent",
mimeType: "text/plain",
text: await fs.readFile("/var/log/app.log", "utf-8"),
}],
})
);
```
In Cursor: `@polderfest:recent-logs` voegt logs toe aan chat context. AI kan vragen erover beantwoorden.
### Prompts gebruik-cases
- **Code review template**
- **Bug report opmaak**
- **Vergader-recap structuur**
```typescript
server.prompt(
"code-review",
"Doe een grondige code review",
{ file: z.string() },
({ file }) => ({
messages: [{
role: "user",
content: { type: "text", text: `Review ${file} op:
1. Bugs / edge cases
2. Naming / readability
3. Performance
4. Security
Geef per punt concrete suggesties.` },
}],
})
);
```
Cursor command palette → "MCP: code-review" → file selecteren → AI start met die exacte prompt.
---
## 8. MCP Inspector
Debug-tool om je server te testen zonder Cursor/Claude.
```bash
npx @modelcontextprotocol/inspector dist/index.js
```
Opent browser-UI op `http://localhost:5173`:
- Linker panel: server tools/resources/prompts lijst
- Hoofdvenster: parameters invullen + call uitvoeren
- Result + raw JSON-RPC zichtbaar
**Workflow:**
1. Schrijf nieuwe tool
2. Build (`pnpm tsc`)
3. Test in Inspector
4. Werkt? Restart Cursor en gebruik daar
5. Werkt niet? Inspector toont errors direct
---
## 9. MCP vs Tool Calling
| Aspect | Tool Calling (Les 12) | MCP (Les 16) |
|--------|----------------------|--------------|
| Waar leeft tool | In jouw Next.js app | Aparte server, los proces |
| Clients | Alleen jouw chat | Alle MCP-clients |
| Setup | Function definitie in code | Server proces + config |
| Distributie | Niet — alleen in app | npm publish |
| State | Per-request, geen state | Server proces heeft state |
| Best voor | App-specifieke features | Herbruikbare tools |
### Mentale model
- **Tool calling** = function in mijn app
- **MCP server** = library die elke AI-client kan importeren
### Wanneer welke
- App-feature (alleen voor jouw users) → tool calling
- Interne dev-tools (jij + collega's) → MCP server
- Open-source tool voor de community → MCP server (publish naar npm)
- Beide patronen zijn complementair — productie-teams gebruiken vaak beide
---
## 10. Productie + distributie
### npm publish
Maak je server beschikbaar voor anderen:
```json
// package.json
{
"name": "@jouw-org/mcp-polderfest",
"version": "1.0.0",
"bin": {
"mcp-polderfest": "./dist/index.js"
},
"files": ["dist"]
}
```
```bash
pnpm publish --access public
```
Anderen installeren:
```json
{
"mcpServers": {
"polderfest": {
"command": "npx",
"args": ["-y", "@jouw-org/mcp-polderfest"]
}
}
}
```
### Remote servers (HTTP/SSE)
Voor cloud deploys — anders dan stdio:
```typescript
import { SSEServerTransport } from "@modelcontextprotocol/sdk/server/sse.js";
import express from "express";
const app = express();
app.get("/sse", (req, res) => {
const transport = new SSEServerTransport("/messages", res);
server.connect(transport);
});
app.listen(3001);
```
Cursor config:
```json
{
"mcpServers": {
"polderfest-remote": {
"url": "https://mcp.example.com/sse"
}
}
}
```
### Security
- **Authenticate** — als server gevoelige data exposeert, auth-token in env-var
- **Validate input** — Zod schema's strict
- **Audit log** — log elke tool-call
- **Rate limit** — server is gewoon een proces, gebruik standaard rate-limit libs
- **Geen secrets in code** — env vars only
---
## Bronnen
- **MCP officiële site:** https://modelcontextprotocol.io/
- **Spec:** https://spec.modelcontextprotocol.io/
- **TS SDK:** https://github.com/modelcontextprotocol/typescript-sdk
- **MCP Inspector:** https://github.com/modelcontextprotocol/inspector
- **Cursor MCP docs:** https://docs.cursor.com/context/model-context-protocol
- **Claude Desktop MCP:** https://docs.anthropic.com/en/docs/build-with-claude/mcp
- **Anthropic launch post:** https://www.anthropic.com/news/model-context-protocol
- **Awesome MCP:** https://github.com/punkpeye/awesome-mcp-servers