diff_frmr
Compare two FRMR documents to identify differences in compliance requirements and security controls for FedRAMP analysis.
Instructions
Compute a structured diff between two FRMR documents by identifier.
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| left_path | Yes | ||
| right_path | Yes | ||
| id_key | No |
Implementation Reference
- src/tools/diff_frmr.ts:20-24 (handler)The execute function implementing the core logic of the 'diff_frmr' tool, which calls diffFrmrDocuments with the input parameters.execute: async (input) => { return diffFrmrDocuments(input.left_path, input.right_path, { idKey: input.id_key, }); },
- src/tools/diff_frmr.ts:6-10 (schema)Zod input schema for the 'diff_frmr' tool defining left_path, right_path, and optional id_key.const schema = z.object({ left_path: z.string(), right_path: z.string(), id_key: z.string().optional(), });
- src/tools/register.ts:24-53 (registration)The registerTools function registers the 'diff_frmr' tool (imported as diffFrmrTool) by including it in the array passed to registerToolDefs.export function registerTools(server: McpServer): void { registerToolDefs(server, [ // Document discovery listFrmrDocumentsTool, getFrmrDocumentTool, listVersionsTool, // KSI tools listKsiTool, getKsiTool, filterByImpactTool, getThemeSummaryTool, getEvidenceExamplesTool, // Control mapping tools listControlsTool, getControlRequirementsTool, analyzeControlCoverageTool, // Search & lookup tools searchMarkdownTool, readMarkdownTool, searchDefinitionsTool, getRequirementByIdTool, // Analysis tools diffFrmrTool, grepControlsTool, significantChangeTool, // System tools healthCheckTool, updateRepositoryTool, ]); }
- src/diff.ts:81-153 (helper)The diffFrmrDocuments helper function that computes the structured diff between two FRMR documents, handling additions, removals, and modifications.export function diffFrmrDocuments( leftPath: string, rightPath: string, options: DiffOptions = {}, ): DiffResult { const leftDoc = resolveFrmrDocument(leftPath); const rightDoc = resolveFrmrDocument(rightPath); if (!leftDoc || !rightDoc) { throw createError({ code: "NOT_FOUND", message: "One or both FRMR documents could not be found in the index.", }); } const idKey = getIdKey(options, leftDoc, rightDoc); const leftItems = extractItems(leftDoc); const rightItems = extractItems(rightDoc); const leftMap = toMap(leftItems, idKey); const rightMap = toMap(rightItems, idKey); const changes: DiffChange[] = []; for (const [id, rightValue] of rightMap.entries()) { if (!leftMap.has(id)) { changes.push({ type: "added", id, title: typeof rightValue.title === "string" ? rightValue.title : undefined, }); } } for (const [id, leftValue] of leftMap.entries()) { if (!rightMap.has(id)) { changes.push({ type: "removed", id, title: typeof leftValue.title === "string" ? leftValue.title : undefined, }); continue; } const rightValue = rightMap.get(id)!; const fields = detectChangedFields(leftValue, rightValue, idKey); if (fields.length) { changes.push({ type: "modified", id, title: typeof rightValue.title === "string" ? rightValue.title : typeof leftValue.title === "string" ? leftValue.title : undefined, fields, }); } } const summary = { added: changes.filter((change) => change.type === "added").length, removed: changes.filter((change) => change.type === "removed").length, modified: changes.filter((change) => change.type === "modified").length, }; return { summary, changes, }; }