# Resources in MCP beheren [[TOC]] ## Resources versus tools MCP onderscheidt twee manieren waarop een server data kan leveren: tools en resources. Het verschil is semantisch, maar belangrijk: - **Tools** zijn acties die het model uitvoert. Ze kunnen side-effects hebben (schrijven, versturen, aanmaken). - **Resources** zijn data die het model leest. Ze zijn read-only en identificeerbaar via een URI. Resources lijken op bestanden of webpagina's: je haalt ze op via een adres. Het model kan een resource in zijn contextvenster laden om er vragen over te beantwoorden. :::info title="Resource subscriptions" MCP ondersteunt resource subscriptions: de client kan zich abonneren op wijzigingen en ontvangt een notificatie zodra een resource verandert. Dit is optioneel en niet elke client implementeert het. ::: :::warn title="Gebruik registerResource, niet de oude resource-vorm" In recente versies van de TypeScript SDK (geverifieerd tegen `@modelcontextprotocol/sdk` 1.29, juni 2026) is `server.registerResource()` de aanbevolen manier. Oudere voorbeelden gebruiken `server.resource()` met de beschrijving als tweede argument; dat patroon staat niet meer in de officiele docs. Gebruik voor nieuwe code de `register*`-methodes. ::: ## Statische resource registreren `registerResource` neemt een naam, een vaste URI, een metadata-object en een async handler: ```typescript import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; const server = new McpServer({ name: "resource-demo", version: "1.0.0" }); server.registerResource( "app-config", "config://app", { title: "Applicatie-configuratie", description: "Huidige applicatie-configuratie", mimeType: "application/json", }, async (uri) => ({ contents: [ { uri: uri.href, text: JSON.stringify({ environment: "production", version: "2.1.0" }), mimeType: "application/json", }, ], }) ); ``` De URI `config://app` is een vaste identifier. Het model haalt deze resource op via een `resources/read`-verzoek met `{ uri: "config://app" }`. ## Dynamische resources met templates Resource templates gebruiken URI-variabelen tussen accolades, volgens de RFC 6570 URI-template-standaard. De variabelen komen als tweede argument in de handler binnen: ```typescript import { ResourceTemplate } from "@modelcontextprotocol/sdk/server/mcp.js"; server.registerResource( "user-profile", new ResourceTemplate("users://{userId}/profile", { list: undefined }), { title: "Gebruikersprofiel", description: "Profiel van een specifieke gebruiker", mimeType: "application/json", }, async (uri, { userId }) => { const user = await db.users.findById(userId); if (!user) { throw new Error(`Gebruiker ${userId} niet gevonden`); } return { contents: [ { uri: uri.href, text: JSON.stringify({ id: user.id, name: user.name, email: user.email, department: user.department, }), mimeType: "application/json", }, ], }; } ); ``` Het model kan dan `users://42/profile` opvragen en krijgt het profiel van gebruiker 42. ## Resources vindbaar maken met list Geef een `list`-functie mee aan de `ResourceTemplate` zodat clients de beschikbare resources kunnen ontdekken: ```typescript server.registerResource( "monthly-reports", new ResourceTemplate("reports://{year}/{month}", { list: async () => { const reports = await db.reports.findAll(); return { resources: reports.map((r) => ({ uri: `reports://${r.year}/${r.month}`, name: `Rapport ${r.month}-${r.year}`, description: `Maandrapport ${r.month} ${r.year}`, mimeType: "application/pdf", })), }; }, }), { title: "Maandelijkse rapportages", description: "Maandelijkse rapportages als PDF", mimeType: "application/pdf", }, async (uri, { year, month }) => { const pdf = await getReportPdf(Number(year), Number(month)); return { contents: [ { uri: uri.href, blob: pdf.toString("base64"), mimeType: "application/pdf", }, ], }; } ); ``` Binaire content stuur je als base64-gecodeerde string via het `blob`-veld in plaats van `text`. ## Meerdere content-items per resource Een resource kan meerdere content-items teruggeven. Handig voor documenten met bijlagen of gerelateerde bestanden: ```typescript server.registerResource( "project-overview", new ResourceTemplate("projects://{id}", { list: undefined }), { title: "Projectoverzicht", description: "Projectoverzicht inclusief bijlagen", mimeType: "application/json", }, async (uri, { id }) => { const project = await getProject(id); return { contents: [ { uri: `${uri.href}/readme`, text: project.description, mimeType: "text/markdown", }, { uri: `${uri.href}/config`, text: JSON.stringify(project.config), mimeType: "application/json", }, ], }; } ); ``` ## Resource subscriptions implementeren Subscriptions verlopen via de low-level server-handlers. Let op: die bereik je via `server.server`, niet rechtstreeks op de `McpServer`. De `resources.subscribe`-capability wordt automatisch ingeschakeld zodra je resources registreert, dus je hoeft die niet handmatig te zetten: ```typescript import { SubscribeRequestSchema, UnsubscribeRequestSchema, } from "@modelcontextprotocol/sdk/types.js"; const subscriptions = new Set(); server.server.setRequestHandler(SubscribeRequestSchema, async (request) => { subscriptions.add(request.params.uri); return {}; }); server.server.setRequestHandler(UnsubscribeRequestSchema, async (request) => { subscriptions.delete(request.params.uri); return {}; }); async function notifyResourceChange(uri: string) { if (subscriptions.has(uri)) { await server.server.sendResourceUpdated({ uri }); } } ``` Roep `notifyResourceChange` aan zodra de data achter een resource wijzigt. De client kan de resource dan opnieuw ophalen. Gebruik `server.server.sendResourceUpdated()` en geen handmatig samengestelde notificatie, zodat je het juiste `notifications/resources/updated`-bericht stuurt. :::tip title="Gebruik resources voor grote data" Wil je grote hoeveelheden data beschikbaar stellen, gebruik dan resources in plaats van tools. Een tool die een groot JSON-object teruggeeft, vult direct het contextvenster van het model. Met resources bepaalt de client zelf wanneer en wat hij laadt. ::: :::faq ### Wat is het verschil tussen een resource en een prompt? Resources zijn data-objecten die het model leest. Prompts zijn herbruikbare instructie-templates met parameters die het model kan uitvoeren. ### Moet ik registerResource of de oude resource-methode gebruiken? Gebruik `registerResource()`. De SDK noemt de `register*`-methodes de aanbevolen aanpak voor nieuwe code en geeft je een metadata-object met `title`, `description` en `mimeType`. ### Kan een resource andere resources bevatten? Niet direct, maar een resource kan in zijn tekst-inhoud URI-referenties naar andere resources opnemen. Het model kan die dan afzonderlijk opvragen. ### Hoe groot mag een resource-response zijn? Er is geen formeel maximum, maar houd rekening met het contextvenster van het model. Grote resources boven ongeveer 100 KB deel je beter op in pagineerbare chunks. ### Hoe stuur ik binaire data terug? Zet de bytes als base64-gecodeerde string in het `blob`-veld van een content-item, samen met de juiste `mimeType`, in plaats van het `text`-veld. ### Kan ik resources cachen op de client? Dat is de verantwoordelijkheid van de client-implementatie. Het MCP-protocol definieert zelf geen caching-semantiek voor resources. :::