mcp-node-tasks-02-primitives
README.md
# MCP node tasks 02 - primitives
Dette projekt er anden del af vores praktiske introduktion til Model Context Protocol, forkortet MCP.
I del 1 havde vi en almindelig Node.js-applikation, der læste tasks fra en JSON-fil.
I denne del laver vi projektet om til en MCP-server.
Serveren udstiller:
| Type | Navn | Funktion |
|---|---|---|
| Resource | `tasks://all` | Læser alle tasks |
| Tool | `add_task` | Opretter en ny task |
| Prompt | `analyze_tasks` | Giver en fast struktur til task-analyse |
## Formål
Efter denne del skal du kunne forklare:
- Hvad resources, tools og prompts er
- Hvorfor resources normalt er read-only
- Hvorfor tools kræver mere omtanke
- Hvordan en lokal MCP-server kan køre med stdio
- Hvorfor `console.log()` kan give problemer i en stdio-baseret MCP-server
- Hvordan serveren kan testes med MCP Inspector
- Hvordan serveren kan kobles på Claude Desktop eller Cursor
## Projektstruktur
```text
mcp-node-tasks-02-primitives/
├── data/
│ └── tasks.json
├── docs/
│ └── images/
│ ├── Screenshot-2025-05-28-182048-1.png
│ └── lifecyclemcp-1.svg
├── src/
│ ├── server.js
│ └── taskStore.js
├── package.json
└── README.md
```
## Billeder
Kopier disse billeder fra zip-filen til projektet:
```text
docs/images/Screenshot-2025-05-28-182048-1.png
docs/images/lifecyclemcp-1.svg
```
## MCP primitives
En MCP-server kan udstille capabilities.
I dette projekt bruger vi tre centrale capabilities:

| Capability | Forklaring | Eksempel i projektet |
|---|---|---|
| Resource | Read-only data | `tasks://all` |
| Tool | En handling | `add_task` |
| Prompt | En arbejdsgang | `analyze_tasks` |
Den vigtigste huskeregel er:
```text
Resources giver AI'en noget at vide.
Tools får AI'en til at gøre noget.
Prompts giver AI'en en arbejdsform.
```
## Resource: tasks://all
En resource er data, som kan læses uden at ændre noget.
I dette projekt er resource:
```text
tasks://all
```
Den læser alle tasks fra:
```text
data/tasks.json
```
Resource-koden ændrer ikke filen. Den giver kun AI’en kontekst.
## Tool: add_task
Et tool er en funktion, der udfører en handling.
I dette projekt er tool:
```text
add_task
```
Det opretter en ny task i:
```text
data/tasks.json
```
Tool’et tager to input:
| Parameter | Forklaring |
|---|---|
| `title` | Titlen på den nye task |
| `priority` | `low`, `medium` eller `high` |
Eksempel på input:
```json
{
"title": "Lav demo til undervisning",
"priority": "high"
}
```
Fordi tool’et ændrer data, er det mere følsomt end en resource.
## Prompt: analyze_tasks
En prompt er en genbrugelig promptskabelon eller arbejdsgang.
I dette projekt er prompten:
```text
analyze_tasks
```
Den beder AI’en om at læse tasklisten og analysere, hvilke opgaver der bør prioriteres først.
Prompten ændrer ikke data. Den giver modellen en arbejdsform.
## Resource, tool og prompt i samme case
| Behov | MCP-type | Hvorfor |
|---|---|---|
| AI’en skal kende tasklisten | Resource | Det er viden |
| AI’en skal oprette en ny task | Tool | Det er en handling |
| AI’en skal analysere opgaverne | Prompt | Det er en arbejdsgang |
## Hvordan hænger Claude, MCP og koden sammen?
```mermaid
flowchart TD
A["Claude Desktop<br>MCP host"]
B["claude_desktop_config.json<br>Starter serveren"]
C["src/server.js<br>MCP-server"]
D["Resource: tasks://all<br>Læs alle tasks"]
E["Tool: add_task<br>Opret ny task"]
F["Prompt: analyze_tasks<br>Fast analyse"]
G["src/taskStore.js<br>Node.js fil-logik"]
H["data/tasks.json<br>Projektets data"]
A --> B
B -->|"node src/server.js"| C
C --> D
C --> E
C --> F
D --> G
E --> G
G --> H
F --> A
```
Diagrammet viser, at Claude ikke læser `tasks.json` direkte.
Claude starter først vores MCP-server ud fra `claude_desktop_config.json`.
`src/server.js` er MCP-laget. Her definerer vi, hvad Claude må bruge:
- `tasks://all` som resource
- `add_task` som tool
- `analyze_tasks` som prompt
`src/taskStore.js` indeholder den almindelige Node.js-logik til at læse og skrive tasks.
`data/tasks.json` er kun datafilen.
Det vigtige er opdelingen af ansvar:
| Del | Ansvar |
|---|---|
| Claude Desktop | Host, hvor brugeren arbejder |
| Claude config | Starter MCP-serveren |
| `server.js` | Udstiller MCP capabilities |
| `taskStore.js` | Håndterer fil-logik |
| `tasks.json` | Indeholder data |
Claude taler altså med MCP-serveren. MCP-serveren bruger derefter vores Node.js-kode til at læse eller ændre data.
## Lifecycle
Et typisk MCP-flow kan forklares i fire faser:

| Fase | Hvad sker der? |
|---|---|
| Initialization | Client og server etablerer forbindelse |
| Discovery | Clienten spørger serveren, hvilke capabilities der findes |
| Execution | Clienten kalder en resource, et tool eller en prompt |
| Termination | Forbindelsen lukkes pænt |
Discovery er vigtig, fordi clienten kan spørge serveren, hvad den kan, i stedet for at alt er hardcoded.
## Installation
Kør:
```bash
npm install
```
## Vigtig pointe om npm start
Du kan godt køre:
```bash
npm start
```
Men serveren vil se ud som om, den ikke gør noget.
Det er normalt.
En MCP-server med stdio venter på, at en MCP-client taler med den. Derfor tester vi den med MCP Inspector, Claude Desktop eller Cursor.
## Test med MCP Inspector
Kør:
```bash
npm run inspect
```
I Inspector kan du teste:
1. Resource: `tasks://all`
2. Tool: `add_task`
3. Prompt: `analyze_tasks`
## Denne server bruger stdio
Stdio betyder, at MCP-clienten og MCP-serveren kommunikerer via standard input og standard output.
Derfor må serveren ikke skrive almindelige logs med:
```js
console.log("Server startet");
```
Det kan ødelægge MCP-kommunikationen, fordi stdout bruges til MCP-beskeder.
Brug i stedet:
```js
console.error("Server startet");
```
`console.error()` skriver til stderr og forstyrrer ikke MCP-kommunikationen.
## Claude eller Cursor konfiguration
Når projektet virker i MCP Inspector, kan det kobles på Claude Desktop eller Cursor.
Eksempel:
```json
{
"mcpServers": {
"mcp-node-tasks-02": {
"command": "node",
"args": [
"C:\\Users\\mikc\\IdeaProjects\\mcp-node-tasks-02-primitives\\src\\server.js"
]
}
}
}
```
Ret stien, så den passer til din egen computer.
På Windows skal du enten bruge dobbelt backslash:
```text
C:\\Users\\mikc\\IdeaProjects\\mcp-node-tasks-02-primitives\\src\\server.js
```
eller forward slashes:
```text
C:/Users/mikc/IdeaProjects/mcp-node-tasks-02-primitives/src/server.js
```
## Miniøvelse
Åbn `src/server.js`.
Find:
1. Resource-koden
2. Tool-koden
3. Prompt-koden
Svar derefter på:
1. Hvad er resource i projektet?
2. Hvad er tool i projektet?
3. Hvad er prompt i projektet?
4. Hvorfor er `add_task` mere risikabel end `tasks://all`?
5. Hvorfor er det en god idé at starte med stdio?
## Forslag til svar
`tasks://all` er en resource, fordi den kun læser data.
`add_task` er et tool, fordi det ændrer data.
`analyze_tasks` er en prompt, fordi den giver AI’en en fast arbejdsgang.
`add_task` er mere risikabel end `tasks://all`, fordi den skriver til `data/tasks.json`.
Stdio er godt til lokal undervisning, fordi det ikke kræver port, Express-server eller deployment.
## Ekstra øvelse
Tilføj en ny task med MCP Inspector.
Kontroller bagefter, at filen er ændret:
```text
data/tasks.json
```
Spørgsmål:
- Hvor kan du se side effect?
- Hvorfor er det vigtigt, at tool’et har tydelige input?
- Hvad kunne gå galt, hvis `priority` ikke blev valideret?
## Næste trin
I næste del bygger vi en custom MCP-client i Node.js.
Den skal kunne:
1. Starte MCP-serveren via stdio
2. Lave discovery
3. Liste tools, resources og prompts
4. Kalde `tasks://all`
5. Kalde `add_task`
6. Hente prompten `analyze_tasks`TDQS
A3.6/5.0
Scored across 1 tool
Disambiguation5/5
Only one tool exists, so there is no risk of ambiguity.
Naming Consistency5/5
With a single tool, naming consistency is trivially perfect. The name 'add_task' follows a clear verb_noun pattern.
Tool Count2/5
A single tool for task management is too few for reasonable functionality, making the server feel underdeveloped.
Completeness1/5
Only a create operation is provided, with no tools for listing, updating, deleting, or reading tasks, severely limiting usability.
Maintenance
ActivityInactive
ResponsivenessNo issues