fix: update lessons
This commit is contained in:
218
Les16-MCP/Les16-Lesopdracht.md
Normal file
218
Les16-MCP/Les16-Lesopdracht.md
Normal file
@@ -0,0 +1,218 @@
|
||||
# Les 16 — Lesopdracht
|
||||
## Eerste MCP server bouwen + laden in Cursor
|
||||
|
||||
**Vak:** AI-Assisted Development
|
||||
**Duur:** 30 min in-class
|
||||
|
||||
---
|
||||
|
||||
## Doel
|
||||
|
||||
Werkende MCP server met 1 tool, geladen in Cursor of Claude Desktop, en getest met een echte chat-vraag.
|
||||
|
||||
---
|
||||
|
||||
## Stap 1 — Setup
|
||||
|
||||
```bash
|
||||
mkdir mcp-demo && cd mcp-demo
|
||||
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/**/*"]
|
||||
}
|
||||
```
|
||||
|
||||
`package.json` — voeg `"type": "module"` toe.
|
||||
|
||||
---
|
||||
|
||||
## Stap 2 — 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: "demo-server",
|
||||
version: "1.0.0",
|
||||
});
|
||||
|
||||
// Mock data
|
||||
const BANDS = [
|
||||
{ name: "Lost Tigers", day: "Vrijdag", stage: "Main Stage", genre: "rock" },
|
||||
{ name: "Polderfunk", day: "Zaterdag", stage: "Main Stage", genre: "funk" },
|
||||
{ name: "Jazz Collective", day: "Zaterdag", stage: "Tent", genre: "jazz" },
|
||||
{ name: "Echo Bay", day: "Zondag", stage: "Beach Stage", genre: "indie" },
|
||||
// ... voeg er een paar toe
|
||||
];
|
||||
|
||||
server.tool(
|
||||
"searchBands",
|
||||
"Zoek bands op dag, stage of genre",
|
||||
{
|
||||
day: z.enum(["Vrijdag", "Zaterdag", "Zondag"]).optional(),
|
||||
stage: z.string().optional(),
|
||||
genre: z.string().optional(),
|
||||
},
|
||||
async ({ day, stage, genre }) => {
|
||||
const results = BANDS.filter(b =>
|
||||
(!day || b.day === day) &&
|
||||
(!stage || b.stage === stage) &&
|
||||
(!genre || b.genre === genre)
|
||||
);
|
||||
return {
|
||||
content: [{
|
||||
type: "text",
|
||||
text: JSON.stringify(results, null, 2),
|
||||
}],
|
||||
};
|
||||
}
|
||||
);
|
||||
|
||||
const transport = new StdioServerTransport();
|
||||
await server.connect(transport);
|
||||
console.error("MCP server started");
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Stap 3 — Build
|
||||
|
||||
```bash
|
||||
pnpm tsc
|
||||
# resultaat: dist/index.js
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Stap 4 — Test met Inspector
|
||||
|
||||
```bash
|
||||
npx @modelcontextprotocol/inspector node dist/index.js
|
||||
```
|
||||
|
||||
Browser opent automatisch op `http://localhost:5173`:
|
||||
|
||||
1. Klik "Tools" tab
|
||||
2. Zie `searchBands` in de lijst
|
||||
3. Klik "Call Tool"
|
||||
4. Vul `day: Zaterdag` in
|
||||
5. Verwacht: JSON met 2 bands
|
||||
|
||||
Werkt? Door naar Cursor.
|
||||
|
||||
---
|
||||
|
||||
## Stap 5 — Laden in Cursor
|
||||
|
||||
Open `~/.cursor/mcp.json` (maak aan als 'ie nog niet bestaat):
|
||||
|
||||
```json
|
||||
{
|
||||
"mcpServers": {
|
||||
"demo": {
|
||||
"command": "node",
|
||||
"args": ["/FULL/PATH/TO/mcp-demo/dist/index.js"]
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Belangrijk:**
|
||||
- Vervang `/FULL/PATH/TO/` met je echte absolute path (`pwd` in terminal)
|
||||
- Geen `~`, geen relative paths
|
||||
|
||||
Restart Cursor (Cmd+Q + opnieuw openen).
|
||||
|
||||
Check: Cursor Settings → MCP → server "demo" zichtbaar met groen vinkje.
|
||||
|
||||
---
|
||||
|
||||
## Stap 6 — Test in Cursor chat
|
||||
|
||||
In Cursor chat (Cmd+L of Cmd+I):
|
||||
|
||||
> "Welke bands spelen op zaterdag?"
|
||||
|
||||
Cursor roept `searchBands` aan en toont resultaat. Werkt? Klaar.
|
||||
|
||||
---
|
||||
|
||||
## Alternatief — Claude Desktop
|
||||
|
||||
Als Cursor niet wil:
|
||||
|
||||
`~/Library/Application Support/Claude/claude_desktop_config.json` (macOS):
|
||||
```json
|
||||
{
|
||||
"mcpServers": {
|
||||
"demo": {
|
||||
"command": "node",
|
||||
"args": ["/FULL/PATH/TO/mcp-demo/dist/index.js"]
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Restart Claude Desktop. Chat input toont MCP-icon. Vraag stellen werkt identiek.
|
||||
|
||||
---
|
||||
|
||||
## Eisen
|
||||
|
||||
- [ ] Project opgezet (package.json, tsconfig, ts source)
|
||||
- [ ] Build succesvol (`dist/index.js` bestaat)
|
||||
- [ ] MCP Inspector toont tool + tool werkt
|
||||
- [ ] Geladen in Cursor of Claude Desktop
|
||||
- [ ] Chat-vraag werkt — AI roept tool aan, geeft antwoord
|
||||
|
||||
---
|
||||
|
||||
## Veelvoorkomende problemen
|
||||
|
||||
| Symptoom | Oplossing |
|
||||
|----------|-----------|
|
||||
| `cannot find module` | Check `"type": "module"` in package.json + `.js` extensies in imports |
|
||||
| Cursor toont server niet | Restart Cursor volledig (Cmd+Q). Check absolute path. Check JSON valid. |
|
||||
| Tool niet aanroepbaar | Check tool name + parameters in Inspector eerst |
|
||||
| Stdout pollution | `console.log` → `console.error` (stdout = protocol) |
|
||||
| `tsc` errors | Check tsconfig en moduleResolution |
|
||||
|
||||
---
|
||||
|
||||
## Klaar?
|
||||
|
||||
Verder met huiswerk (`Les16-Huiswerk.md`):
|
||||
- 3 tools + 1 write-tool naar Supabase
|
||||
- 1 resource toevoegen
|
||||
- `MCP.md` met tool-lijst + voorbeeldprompts
|
||||
|
||||
---
|
||||
|
||||
## Tijdsindeling (30 min)
|
||||
|
||||
| Stap | Tijd |
|
||||
|------|------|
|
||||
| 1-3 — Setup + minimal + build | 10 min |
|
||||
| 4 — Inspector test | 5 min |
|
||||
| 5 — Cursor config | 5 min |
|
||||
| 6 — Chat test | 5 min |
|
||||
| Buffer | 5 min |
|
||||
Reference in New Issue
Block a user