Skip to main content
Glama
ethanolivertroy

FedRAMP Docs MCP Server

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
NameRequiredDescriptionDefault
left_pathYes
right_pathYes
id_keyNo

Implementation Reference

  • 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,
      });
    },
  • 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(),
    });
  • 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,
      ]);
    }
  • 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,
      };
    }
Behavior2/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations provided, the description carries the full burden of behavioral disclosure. It states the tool computes a diff, implying a read-only comparison, but doesn't specify if it's destructive, requires authentication, has rate limits, or what the output format is. This leaves significant gaps in understanding the tool's behavior.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is a single, efficient sentence that directly states the tool's purpose without any wasted words. It's appropriately sized and front-loaded, making it easy to grasp quickly.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness2/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the complexity of a diff operation with 3 parameters, 0% schema coverage, no annotations, and no output schema, the description is incomplete. It lacks details on parameter meanings, behavioral traits, and output format, making it inadequate for full contextual understanding.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters2/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The schema description coverage is 0%, so the description must compensate for three undocumented parameters. It mentions 'by identifier' which hints at 'id_key', but doesn't explain 'left_path' or 'right_path' (e.g., file paths or document IDs), nor does it clarify the diff structure. This adds minimal semantic value beyond the schema.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the action ('Compute a structured diff') and the resource ('between two FRMR documents by identifier'), making the purpose understandable. However, it doesn't differentiate from sibling tools like 'list_frmr_documents' or 'get_frmr_document', which might handle FRMR documents differently, so it misses full sibling distinction.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines2/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description provides no guidance on when to use this tool versus alternatives. It doesn't mention prerequisites, such as needing existing FRMR documents, or compare to siblings like 'get_frmr_document' for retrieval, leaving usage context implied at best.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Install Server

Other Tools

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/ethanolivertroy/fedramp-docs-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server