// Generated, do not edit. sha256:6e59cd9bc5c34f22b316c129925de56d6e800bca08debd1308bf90cb9f449baa import { randomUUID } from 'node:crypto'; import { CONFIG } from '../../shared/config.js'; import { AI_REFUSALS } from '../ai/gate.js'; import { limitText } from '../ai/limits.js'; import { ENUMS } from '../../shared/config.js'; const PARSE_ERROR = -32700; const INVALID_REQUEST = -32600; const METHOD_NOT_FOUND = -32601; const INVALID_PARAMS = -32602; const fout = (id, code, message) => ({ jsonrpc: '2.0', id: id ?? null, error: { code, message } }); const goed = (id, result) => ({ jsonrpc: '2.0', id, result }); export function createMcpServer({ tools, logCall, onLogError } = {}) { if (typeof logCall !== 'function') { throw new Error('An MCP server without an audit log is not allowed in this project.'); } if (!Array.isArray(tools) || tools.length === 0) { throw new Error('An MCP server without tools is meaningless.'); } const zonderScope = tools.filter(t => !ENUMS.AI_SCOPE.includes(t?.scope)); if (zonderScope.length) { const namen = zonderScope.map(t => t?.name ?? '(naamloos)').join(', '); throw new Error(`Tool without a valid scope: ${namen}. Allowed is ${ENUMS.AI_SCOPE.join(', ')}.`); } const perNaam = new Map(tools.map(t => [t.name, t])); const sessie = { id: randomUUID(), client: null, initialized: false }; async function log(regel, messages) { try { await logCall({ sessionId: sessie.id, client: sessie.client, serverVersion: CONFIG.AI.SERVER_VERSION, ...regel, ...(messages ? { messages } : {}), }); } catch (e) { if (onLogError) onLogError(e); else throw e; } } const gesprek = (binnenAt, args, uit) => [ { kind: 'request', text: JSON.stringify(args ?? {}), occurredAt: binnenAt }, { kind: 'response', text: String(uit ?? ''), occurredAt: new Date().toISOString() }, ]; async function voerUit(naam, args, droog) { const binnenAt = new Date().toISOString(); const tool = perNaam.get(naam); if (!tool) { const regel = { tool: naam, arguments: args, outcome: 'refused', detail: 'Deze tool bestaat niet.' }; if (!droog) await log(regel, gesprek(binnenAt, args, regel.detail)); return { regel, text: regel.detail, onbekend: true }; } try { const { text, fieldsShared } = await tool.run(args, { session: sessie }); const { text: uitvoer, capped } = limitText(String(text ?? '')); const regel = { tool: naam, arguments: args, fieldsShared: fieldsShared ?? [], charactersOut: uitvoer.length, outcome: 'ok', detail: capped ? 'Antwoord liep tegen de tekengrens en is ingekort.' : undefined, }; if (!droog) await log(regel, gesprek(binnenAt, args, uitvoer)); return { regel, text: uitvoer }; } catch (e) { const melding = e && e.message ? e.message : String(e); const soort = e && AI_REFUSALS.includes(e.code) ? 'refused' : 'error'; const regel = { tool: naam, arguments: args, outcome: soort, detail: melding }; if (!droog) await log(regel, gesprek(binnenAt, args, melding)); return { regel, text: melding, mislukt: true }; } } async function toolsCall(id, params) { const naam = params && typeof params.name === 'string' ? params.name : null; const args = params && params.arguments && typeof params.arguments === 'object' ? params.arguments : {}; if (!naam) { await log({ tool: '(geen)', outcome: 'refused', detail: 'Verzoek zonder toolnaam.' }); return fout(id, INVALID_PARAMS, 'Een tools/call-verzoek noemt geen tool.'); } const r = await voerUit(naam, args, false); if (r.onbekend) return fout(id, INVALID_PARAMS, `Onbekende tool '${naam}'.`); if (r.mislukt) return goed(id, { content: [{ type: 'text', text: r.text }], isError: true }); return goed(id, { content: [{ type: 'text', text: r.text }] }); } async function dryRun(naam, args = {}) { const veiligeArgs = args && typeof args === 'object' && !Array.isArray(args) ? args : {}; const r = await voerUit(String(naam ?? ''), veiligeArgs, true); return { ...r.regel, fieldsShared: r.regel.fieldsShared ?? [], charactersOut: r.regel.charactersOut ?? null, detail: r.regel.detail ?? null, text: r.text, }; } async function handle(bericht) { if (!bericht || typeof bericht !== 'object' || Array.isArray(bericht)) { return fout(null, INVALID_REQUEST, 'Geen JSON-RPC-object.'); } const { id, method, params } = bericht; const isNotificatie = id === undefined || id === null; if (typeof method !== 'string') { return isNotificatie ? null : fout(id, INVALID_REQUEST, 'Verzoek zonder methode.'); } switch (method) { case 'initialize': { sessie.client = params?.clientInfo?.name ? String(params.clientInfo.name) : null; sessie.initialized = true; return goed(id, { protocolVersion: typeof params?.protocolVersion === 'string' ? params.protocolVersion : CONFIG.AI.PROTOCOL_VERSION, capabilities: { tools: {} }, serverInfo: { name: CONFIG.AI.SERVER_NAME, version: CONFIG.AI.SERVER_VERSION }, }); } case 'notifications/initialized': case 'initialized': return null; case 'ping': return isNotificatie ? null : goed(id, {}); case 'tools/list': { if (isNotificatie) return null; return goed(id, { tools: tools.map(t => ({ name: t.name, title: t.title, description: t.description, inputSchema: t.inputSchema, })), }); } case 'tools/call': if (isNotificatie) return null; return toolsCall(id, params); default: return isNotificatie ? null : fout(id, METHOD_NOT_FOUND, `Onbekende methode '${method}'.`); } } async function handleRegel(regel) { let bericht; try { bericht = JSON.parse(regel); } catch { return fout(null, PARSE_ERROR, 'Ongeldige JSON.'); } return handle(bericht); } return { handle, handleRegel, dryRun, get session() { return { ...sessie }; } }; }