Files
novi-lessons/Les15-MCP/Les15-Lesstof.md
2026-06-17 07:15:32 +02:00

326 lines
9.4 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Les 15 — Lesstof
## MCP — Model Context Protocol
**Vak:** AI-Assisted Development
**Opleiding:** NOVI Hogeschool Utrecht
**Vorige les:** Les 14 — Cursor + Vercel
**Volgende les:** Les 16 — RAG + Embeddings
---
## Doel van deze les
Aan het einde van deze les heb je:
- Begrip van wat MCP is en welk probleem het oplost
- Vier MCPs gekoppeld in Cursor: **GitHub, Supabase, Vercel, Polderfest**
- De Polderfest MCP server lokaal gedraaid + via drie chats naar productie:
- **Chat 1:** GitHub MCP — repo aanmaken + remote toevoegen
- **Chat 2:** Polderfest + Supabase MCP — nieuwe feature bouwen
- **Chat 3:** Vercel MCP — project + deploy
- Productie-URL gekoppeld in `mcp.json`
- Optioneel: eigen feature toegevoegd via Cursor + Supabase MCP
---
## 1. Wat is MCP
**Model Context Protocol** = open standaard voor hoe AI-clients (Cursor, Claude Desktop) verbinding maken met externe tools en data.
### Het probleem dat het oplost
Voor MCP had elke AI-client eigen plug-in/extension-systeem:
- Cursor: extension API
- Claude Desktop: plugins
- ChatGPT: GPTs + Custom Actions
- Windsurf, Zed: eigen API's
Eén feature × vier clients = vier integraties.
### De oplossing
**Eén protocol. Eén server. Vele clients.** Anthropic introduceerde MCP in november 2024. Open spec.
**Analogie:** USB-C voor AI — één stekker, elke laptop.
---
## 2. Architectuur + primitives
Drie rollen:
| Rol | Voorbeeld | Wat het doet |
|-----|-----------|--------------|
| **Host** | Cursor, Claude Desktop | de app waarin je werkt |
| **Client** | MCP library | praat met server (zit in host) |
| **Server** | GitHub MCP, jouw Polderfest | biedt tools/resources/prompts |
Drie primitives:
| Primitive | Wat |
|-----------|-----|
| **Tools** | functies (de AI doet iets) |
| **Resources** | read-only data (de AI leest iets) |
| **Prompts** | templates / persona's |
Vandaag focus op **tools**.
---
## 3. Transport
In Cursor 3 is HTTP/SSE de moderne manier:
| Transport | Wanneer |
|-----------|---------|
| **HTTP (remote)** | Server is een webservice (Vercel, mcp.supabase.com, jouw eigen) |
| **HTTP (lokaal)** | `npm run dev` op `localhost:3000` |
| **stdio** | Oud — Cursor start lokaal proces. Vermijden waar mogelijk. |
Alle MCPs van vandaag werken via HTTP — dat is wat we gaan zien.
---
## 4. Vier MCPs vandaag
| MCP | URL | Auth |
|-----|-----|------|
| **GitHub** | `https://api.githubcopilot.com/mcp/` | Bearer (`ghp_...` PAT) |
| **Supabase** | `https://mcp.supabase.com/mcp?project_ref=<id>&read_only=...` | Bearer (`sbp_...` PAT) |
| **Vercel** | `https://mcp.vercel.com` | OAuth (browser-flow) |
| **Polderfest** (eigen) | `http://localhost:3000/api/mcp` | geen |
---
## 5. De `mcp.json` config
Plaats: `~/.cursor/mcp.json` (globaal — werkt overal) of `.cursor/mcp.json` in een project (alleen daar).
```jsonc
{
"mcpServers": {
"supabase": {
"type": "http",
"url": "https://mcp.supabase.com/mcp?project_ref=<JOUW_REF>&read_only=false",
"headers": { "Authorization": "Bearer sbp_..." }
},
"github": {
"type": "http",
"url": "https://api.githubcopilot.com/mcp/",
"headers": { "Authorization": "Bearer ghp_..." }
},
"vercel": {
"type": "http",
"url": "https://mcp.vercel.com"
},
"polderfest": {
"type": "http",
"url": "http://localhost:3000/api/mcp"
}
}
}
```
**Patroon:** `type: http` + `url` + optioneel `headers.Authorization` met Bearer.
**Vercel** heeft geen header — die doet OAuth bij eerste gebruik via een "Needs login" prompt in Cursor.
---
## 6. Tokens regelen
### GitHub PAT (fine-grained)
1. github.com → **Settings****Developer settings****Personal access tokens****Fine-grained**
2. **Repository access:** kies welke repos je MCP mag zien (niet "All" als het niet hoeft)
3. **Permissions:** Contents (read+write), Issues (read+write), Pull requests (read+write)
4. Genereer → kopieer `ghp_...` (éénmalig zichtbaar)
### Supabase Personal Access Token
1. supabase.com → **Account****Access Tokens****Generate new token**
2. Naam: bv. `cursor-mcp`
3. Kopieer `sbp_...` (éénmalig zichtbaar)
> ⚠️ **Dit is NIET** de project anon key of service role key. Dit is een **account-level** token — geeft toegang tot ALLE projecten in je account.
**`project_ref`** vind je in je Supabase project URL: `https://supabase.com/dashboard/project/XXXXXX` — die `XXXXXX` is je ref.
### Vercel OAuth
Geen token vooraf nodig. Bij eerste gebruik in Cursor verschijnt een "Needs login" knop in de MCP-indicator. Klik → autoriseer in browser → klaar.
---
## 7. De drie chats workflow
De climax van de les. Drie aparte Cursor-chats, elk met één focus.
### Chat 1 — GitHub MCP: repo + remote
```
Maak een nieuwe public GitHub repo "polderfest-mcp" aan via GitHub MCP.
Voeg toe als remote `origin` aan deze folder.
Push de main branch.
```
GitHub MCP roept `create_repository` aan. Cursor draait daarna `git remote add` + `git push` in terminal. Geen `gh repo create` zelf typen.
### Chat 2 — Polderfest + Supabase MCP: feature bouwen
```
Ik wil een review-systeem.
Stap 1: vraag Supabase MCP om een tabel band_reviews
(id, band_id FK naar bands, score 1-10, comment, created_at)
Stap 2: voeg twee tools toe aan @file:app/api/mcp/route.ts:
- addReview(bandName, score, comment)
- getReviews(bandName)
```
Drie MCPs samen aan het werk:
- **Supabase MCP** maakt de tabel
- **Cursor** schrijft de tool-code
- **Polderfest MCP** voert de tools uit (na push + auto-deploy)
### Chat 3 — Vercel MCP: project + deploy
```
Maak via Vercel MCP een nieuw project voor mijn GitHub repo polderfest-mcp.
Voeg env vars toe (production): SUPABASE_URL + SUPABASE_SERVICE_ROLE_KEY.
Deploy naar productie.
```
Vercel MCP doet: `create_project` → link GitHub → set env vars → deploy. Productie-URL terug.
**Tot slot:** vervang polderfest entry in `mcp.json` naar de productie-URL. Werkt vanaf dan zonder lokale dev-server.
---
## 8. Polderfest MCP — anatomie
`polderfest-mcp-finished.zip` is een complete Next.js-app:
```
polderfest-mcp/
├── app/
│ ├── api/mcp/route.ts ← MCP server (het echte werk)
│ ├── lib/supabase.ts ← Supabase client + capitalizeDay helper
│ ├── page.tsx ← landingspagina
│ └── layout.tsx
├── package.json ← mcp-handler + @modelcontextprotocol/sdk + zod
├── .env.example
└── README.md
```
### Vier tools
| Tool | Wat |
|------|-----|
| `searchBands` | zoek bands op query / genre / dag |
| `getStageSchedule` | schema voor 1 festivaldag |
| `festivalStats` | totalen + verdeling per genre / dag / stage |
| `getWeather` | Open-Meteo forecast voor festivaldag |
### Tool-anatomie
```typescript
server.tool(
"searchBands",
"Zoek bands op query, genre, of dag.", // ← description voor de AI
{
query: z.string().optional(),
genre: z.string().optional(),
day: z.enum(["vrijdag", "zaterdag", "zondag"]).optional(),
},
async ({ query, genre, day }) => {
let q = supabase.from("bands").select("*").limit(50);
if (query) q = q.ilike("name", `%${query}%`);
if (genre) q = q.ilike("genre", `%${genre}%`);
if (day) q = q.eq("day", capitalizeDay(day));
const { data } = await q;
return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
},
);
```
**Bekend uit Les 12/13:** Zod schemas. **Nieuw:** `server.tool()` signature + return met `content: [...]`.
### Bouwstenen
| Package | Wat |
|---------|-----|
| `@modelcontextprotocol/sdk` | officiële MCP SDK van Anthropic |
| `mcp-handler` | Vercel-adapter voor Next.js |
| `zod` | input schemas |
---
## 9. Lokaal draaien
```bash
unzip polderfest-mcp-finished.zip
cd polderfest-mcp-finished
npm install
cp .env.example .env.local
# vul SUPABASE_URL + SUPABASE_SERVICE_ROLE_KEY (uit Les 11/12)
npm run dev
```
- Landingspagina: `http://localhost:3000`
- MCP endpoint: `http://localhost:3000/api/mcp`
Polderfest entry zit al in je `mcp.json` (lokaal). Herstart Cursor → 4 indicators groen.
---
## 10. Bekende MCP servers
Inspiratie:
- **GitHub** — issues, PRs, repos, commits, code-search
- **Supabase** — DB queries, schema, migrations
- **Vercel** — projects, deployments, env vars
- **Filesystem** — lees/schrijf folders
- **Slack** — kanaal-search, posts
- **Linear / Jira** — tickets vanuit IDE
- **Notion** — pages + databases
- **Brave Search** — web search
- **PostgreSQL** — direct SQL
Zoek op `cursor.com/mcp` of `github.com/modelcontextprotocol/servers`.
---
## 11. Veiligheid
- Tokens niet committen — `~/.cursor/mcp.json` staat al buiten projecten
- Supabase: `read_only=true` voor demo's met productie-data
- GitHub PAT: fine-grained met minimale repo-rechten
- Vercel: OAuth + autoriseer alleen vertrouwde IDE
---
## 12. Verder lezen
- **MCP spec** — `modelcontextprotocol.io`
- **Cursor MCP docs** — `cursor.com/docs/mcp`
- **Supabase MCP** — `supabase.com/docs/guides/getting-started/mcp`
- **Vercel MCP** — `vercel.com/docs/agent-resources/vercel-mcp`
- **GitHub MCP** — `github.com/github/github-mcp-server`
---
## Samenvatting
Vandaag heb je:
- MCP gezien als de open standaard voor AI-clients
- Vier MCPs gekoppeld via HTTP-config in `~/.cursor/mcp.json`
- De drie-chats workflow doorlopen: GitHub repo → Polderfest feature → Vercel deploy
- Je eigen Polderfest MCP live gekregen op Vercel
- Drie MCPs samen zien werken in één chat (Cursor + Supabase + Polderfest)
Volgende les: RAG + Embeddings — AI antwoorden op basis van eigen documenten.