Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 | 17x 17x 17x 17x 17x 17x 17x 17x 17x 17x 17x 17x | /**
* @module parliamentary-data/persistence/mcp-response
* @description Generic MCP tool response persistence with path-segment
* sanitisation. Extracted from the original `data-persistence.ts` monolith.
*
* @author Hack23 AB
* @license Apache-2.0
*/
import crypto from 'node:crypto';
import fs from 'node:fs';
import path from 'node:path';
import { sanitizeDokId, sanitizePathSegment } from './shared/sanitize.js';
import {
DATA_ROOT,
ensureDir,
type MCPToolCall,
type PersistenceMetadata,
} from './shared/meta-sidecar.js';
/**
* Persist a generic MCP tool response. Supports any MCP server (riksdag,
* SCB, World Bank, etc.). Responses are stored under:
* `analysis/data/mcp-responses/{server}/{tool}/{id}.json`
*
* The response data is stored as-is (no metadata injection). A sidecar
* `.meta.json` tracks provenance.
*
* @param call - Description of the MCP tool call
* @param response - Raw response data from the MCP tool
* @param id - Unique identifier for this response (e.g. dok_id, table_id, country code)
* @param dataRoot - Override for the data root directory (for testing)
* @returns The absolute path where the response was written.
*/
export function persistMCPResponse(
call: MCPToolCall,
response: unknown,
id: string,
dataRoot: string = DATA_ROOT,
riksmote?: string,
): string {
const sanitized = sanitizeDokId(id) || `response-${crypto.randomUUID()}`;
const safeServer = sanitizePathSegment(call.server);
const safeTool = sanitizePathSegment(call.tool);
const dir = path.join(dataRoot, 'mcp-responses', safeServer, safeTool);
ensureDir(dir);
const filename = `${sanitized}.json`;
fs.writeFileSync(
path.join(dir, filename),
JSON.stringify(response, null, 2),
'utf8',
);
const resolvedRiksmote = riksmote
?? (typeof call.params.rm === 'string' ? call.params.rm : '');
const metaFilename = `${sanitized}.meta.json`;
const metadata: PersistenceMetadata & { params: Record<string, unknown> } = {
fetchedAt: new Date().toISOString(),
mcpTool: call.tool,
riksmote: resolvedRiksmote,
documentType: call.server,
params: call.params,
};
fs.writeFileSync(
path.join(dir, metaFilename),
JSON.stringify(metadata, null, 2),
'utf8',
);
return path.join(dir, filename);
}
|