fix: les
This commit is contained in:
325
Les15-MCP/Les15-Lesstof.md
Normal file
325
Les15-MCP/Les15-Lesstof.md
Normal file
@@ -0,0 +1,325 @@
|
||||
# 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.
|
||||
Reference in New Issue
Block a user