Skip to main content
Glama

json_dry_run

Analyze JSON data size by field using a shape object to identify storage usage patterns and optimize data structure efficiency.

Instructions

Analyze the size breakdown of JSON data using a shape object to determine granularity. Returns size information in bytes for each specified field, mirroring the shape structure but with size values instead of data.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
filePathYesPath to the JSON file (local) or HTTP/HTTPS URL to analyze
shapeNoShape object (formatted as valid JSON) defining what to analyze for size. Use 'true' to get total size of a field, or nested objects for detailed breakdown. Examples: 1. Get size of single field: {"name": true} 2. Get sizes of multiple fields: {"name": true, "email": true, "age": true} 3. Get detailed breakdown: {"user": {"name": true, "profile": {"bio": true}}} 4. Analyze arrays: {"posts": {"title": true, "content": true}} - gets total size of all matching elements 5. Complex analysis: { "metadata": true, "users": { "name": true, "settings": { "theme": true } }, "posts": { "title": true, "tags": true } } Note: - Returns size in bytes for each specified field - Output structure mirrors the shape but with size values - Array analysis returns total size of all matching elements - Use json_schema tool to understand the JSON structure first

Implementation Reference

  • Core handler function that ingests JSON from file/URL, parses it, computes size breakdown according to the provided shape, total and filtered sizes, and recommends number of chunks.
    async function processJsonDryRun(input: JsonDryRunInput): Promise<JsonDryRunResult> {
      try {
        // Use strategy pattern to ingest JSON content
        const ingestionResult = await jsonIngestionContext.ingest(input.filePath);
        
        if (!ingestionResult.success) {
          // Map strategy errors to existing error format for backward compatibility
          return {
            success: false,
            error: ingestionResult.error
          };
        }
    
        // Parse JSON
        let parsedData: any;
        try {
          parsedData = JSON.parse(ingestionResult.content);
        } catch (error) {
          return {
            success: false,
            error: {
              type: 'invalid_json',
              message: 'Invalid JSON format in content',
              details: error
            }
          };
        }
    
        // Calculate size breakdown based on shape
        try {
          const sizeBreakdown = calculateSizeWithShape(parsedData, input.shape);
          
          // Calculate total size of the entire parsed data
          const totalSize = calculateValueSize(parsedData);
          
          // Calculate filtered data size
          const filteredData = extractWithShape(parsedData, input.shape);
          const filteredJson = JSON.stringify(filteredData, null, 2);
          const filteredSize = new TextEncoder().encode(filteredJson).length;
          
          // Calculate recommended chunks (400KB threshold)
          const CHUNK_THRESHOLD = 400 * 1024;
          const recommendedChunks = Math.ceil(filteredSize / CHUNK_THRESHOLD);
          
          return {
            success: true,
            sizeBreakdown,
            totalSize,
            filteredSize,
            recommendedChunks
          };
        } catch (error) {
          return {
            success: false,
            error: {
              type: 'validation_error',
              message: 'Failed to calculate size breakdown',
              details: error
            }
          };
        }
      } catch (error) {
        return {
          success: false,
          error: {
            type: 'validation_error',
            message: 'Unexpected error during processing',
            details: error
          }
        };
      }
    }
  • src/index.ts:683-784 (registration)
    MCP server registration of the json_dry_run tool, including Zod input schema in parameters, detailed description, and thin wrapper handler that parses shape if string, validates with JsonDryRunInputSchema, calls processJsonDryRun, and formats results.
    server.tool(
        "json_dry_run",
        "Analyze the size breakdown of JSON data using a shape object to determine granularity. Returns size information in bytes for each specified field, mirroring the shape structure but with size values instead of data.",
        {
            filePath: z.string().describe("Path to the JSON file (local) or HTTP/HTTPS URL to analyze"),
            shape: z.unknown().describe(`Shape object (formatted as valid JSON) defining what to analyze for size. Use 'true' to get total size of a field, or nested objects for detailed breakdown.
    
    Examples:
    1. Get size of single field: {"name": true}
    2. Get sizes of multiple fields: {"name": true, "email": true, "age": true}
    3. Get detailed breakdown: {"user": {"name": true, "profile": {"bio": true}}}
    4. Analyze arrays: {"posts": {"title": true, "content": true}} - gets total size of all matching elements
    5. Complex analysis: {
       "metadata": true,
       "users": {
         "name": true,
         "settings": {
           "theme": true
         }
       },
       "posts": {
         "title": true,
         "tags": true
       }
    }
    
    Note: 
    - Returns size in bytes for each specified field
    - Output structure mirrors the shape but with size values
    - Array analysis returns total size of all matching elements
    - Use json_schema tool to understand the JSON structure first`)
        },
        async ({ filePath, shape }) => {
            try {
                // If shape is a string, parse it as JSON
                let parsedShape = shape;
                if (typeof shape === 'string') {
                    try {
                        parsedShape = JSON.parse(shape);
                    } catch (e) {
                        return {
                            content: [
                                {
                                    type: "text",
                                    text: `Error: Invalid JSON in shape parameter: ${e instanceof Error ? e.message : String(e)}`
                                }
                            ],
                            isError: true
                        };
                    }
                }
    
                const validatedInput = JsonDryRunInputSchema.parse({
                    filePath,
                    shape: parsedShape
                });
                
                const result = await processJsonDryRun(validatedInput);
                
                if (result.success) {
                    // Format the response with total size and breakdown
                    const formatSize = (bytes: number): string => {
                        if (bytes < 1024) return `${bytes} bytes`;
                        if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;
                        return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
                    };
    
                    const header = `Total file size: ${formatSize(result.totalSize)} (${result.totalSize} bytes)\nFiltered size: ${formatSize(result.filteredSize)} (${result.filteredSize} bytes)\nRecommended chunks: ${result.recommendedChunks}\n\nSize breakdown:\n`;
                    const breakdown = JSON.stringify(result.sizeBreakdown, null, 2);
                    
                    return {
                        content: [
                            {
                                type: "text",
                                text: header + breakdown
                            }
                        ]
                    };
                } else {
                    return {
                        content: [
                            {
                                type: "text",
                                text: `Error: ${result.error.message}`
                            }
                        ],
                        isError: true
                    };
                }
            } catch (error) {
                return {
                    content: [
                        {
                            type: "text",
                            text: `Validation error: ${error instanceof Error ? error.message : String(error)}`
                        }
                    ],
                    isError: true
                };
            }
        }
    );
  • Input schema (JsonDryRunInputSchema) using Zod for validation, input type alias, Shape type, and output result type (JsonDryRunResult).
    const JsonDryRunInputSchema = z.object({
      filePath: z.string().min(1, "File path or HTTP/HTTPS URL is required").refine(
        (val) => val.length > 0 && (val.startsWith('./') || val.startsWith('/') || val.startsWith('http://') || val.startsWith('https://') || !val.includes('/')),
        "Must be a valid file path or HTTP/HTTPS URL"
      ),
      shape: z.any().describe("Shape object defining what to analyze")
    });
    
    type JsonSchemaInput = z.infer<typeof JsonSchemaInputSchema>;
    type JsonFilterInput = z.infer<typeof JsonFilterInputSchema>;
    type JsonDryRunInput = z.infer<typeof JsonDryRunInputSchema>;
    type Shape = { [key: string]: true | Shape };
    
    // Define error types (extended to support new ingestion strategies and edge cases)
    interface JsonSchemaError {
      readonly type: 'file_not_found' | 'invalid_json' | 'network_error' | 'invalid_url' | 'unsupported_content_type' | 'rate_limit_exceeded' | 'validation_error' | 'authentication_required' | 'server_error' | 'content_too_large' | 'quicktype_error';
      readonly message: string;
      readonly details?: unknown;
    }
    
    // Result type for better type safety
    type JsonSchemaResult = {
      readonly success: true;
      readonly schema: string;
      readonly fileSizeBytes: number;
    } | {
      readonly success: false;
      readonly error: JsonSchemaError;
    };
    
    type JsonFilterResult = {
      readonly success: true;
      readonly filteredData: any;
      readonly chunkInfo?: {
        readonly chunkIndex: number;
        readonly totalChunks: number;
      };
    } | {
      readonly success: false;
      readonly error: JsonSchemaError;
    };
    
    type JsonDryRunResult = {
      readonly success: true;
      readonly sizeBreakdown: any;
      readonly totalSize: number;
      readonly filteredSize: number;
      readonly recommendedChunks: number;
    } | {
      readonly success: false;
      readonly error: JsonSchemaError;
    };
  • Key helper function to recursively compute size breakdown of JSON data matching the shape definition, handling arrays by summing sizes across elements.
    function calculateSizeWithShape(data: any, shape: Shape): any {
      if (Array.isArray(data)) {
        // For arrays, apply the shape to each element and sum the results
        let totalSizeBreakdown: any = {};
        let isFirstElement = true;
        
        for (const item of data) {
          const itemSizeBreakdown = calculateSizeWithShape(item, shape);
          
          if (isFirstElement) {
            totalSizeBreakdown = itemSizeBreakdown;
            isFirstElement = false;
          } else {
            // Sum up the sizes
            totalSizeBreakdown = addSizeBreakdowns(totalSizeBreakdown, itemSizeBreakdown);
          }
        }
        
        return totalSizeBreakdown;
      }
    
      const result: any = {};
      for (const key in shape) {
        const rule = shape[key];
        if (data[key] === undefined) {
          // If the key doesn't exist in data, skip it or set to 0
          continue;
        }
        
        if (rule === true) {
          // Calculate total size of this key's value
          result[key] = calculateValueSize(data[key]);
        } else if (typeof rule === 'object') {
          // Recursively break down this key's value
          result[key] = calculateSizeWithShape(data[key], rule);
        }
      }
      return result;
    }
  • Fundamental helper to compute exact JSON-serialized byte size of any value, accounting for formatting, escaping, brackets, commas, etc. Used recursively in size breakdown.
    function calculateValueSize(value: any): number {
      if (value === null) {
        return new TextEncoder().encode('null').length; // 4 bytes for "null"
      }
      
      if (value === undefined) {
        // undefined values are omitted in JSON.stringify, so they have 0 size
        return 0;
      }
      
      if (typeof value === 'string') {
        // Use JSON.stringify to handle escape characters properly
        return new TextEncoder().encode(JSON.stringify(value)).length;
      }
      
      if (typeof value === 'number') {
        return new TextEncoder().encode(value.toString()).length;
      }
      
      if (typeof value === 'boolean') {
        return new TextEncoder().encode(value.toString()).length; // "true" = 4, "false" = 5
      }
      
      if (Array.isArray(value)) {
        // Calculate size of array including JSON formatting (brackets, commas)
        let totalSize = 2; // Opening and closing brackets []
        for (let i = 0; i < value.length; i++) {
          totalSize += calculateValueSize(value[i]);
          if (i < value.length - 1) {
            totalSize += 1; // Comma separator
          }
        }
        return totalSize;
      }
      
      if (typeof value === 'object') {
        // Calculate size of object including JSON formatting (braces, colons, commas, quotes)
        let totalSize = 2; // Opening and closing braces {}
        const entries = Object.entries(value).filter(([, val]) => val !== undefined);
        for (let i = 0; i < entries.length; i++) {
          const [key, val] = entries[i];
          totalSize += new TextEncoder().encode(`"${key}"`).length; // Key with quotes
          totalSize += 1; // Colon
          totalSize += calculateValueSize(val); // Value
          if (i < entries.length - 1) {
            totalSize += 1; // Comma separator
          }
        }
        return totalSize;
      }
      
      return 0;
    }
Behavior4/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 effectively describes key behaviors: it returns size information in bytes, mirrors the shape structure in output, and handles arrays by returning total size of all matching elements. However, it lacks details on error handling, performance implications, or rate limits, which could be relevant for a tool processing potentially large JSON files.

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

Conciseness4/5

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

The description is well-structured and front-loaded with the core purpose, followed by detailed parameter explanations. It uses bullet points and examples efficiently, but could be slightly more concise by integrating the 'Note' section into the main text or reducing redundancy in examples.

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

Completeness4/5

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

Given the tool's complexity (analyzing JSON size with shape objects) and lack of output schema, the description does a good job of explaining what the tool returns. It covers input semantics and behavioral traits adequately. However, without annotations or output schema, it could benefit from more detail on error cases or output format specifics to be fully complete.

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

Parameters4/5

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

The schema description coverage is 100%, so the baseline is 3. The description adds significant value by explaining the 'shape' parameter with detailed examples and notes on how it affects output (e.g., using 'true' for total size, nested objects for breakdowns, and array handling). This clarifies semantics beyond the schema's technical definition, though it doesn't add much for 'filePath' beyond what the schema already states.

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

Purpose5/5

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

The description clearly states the tool's purpose: 'Analyze the size breakdown of JSON data using a shape object to determine granularity.' It specifies the verb ('analyze'), resource ('JSON data'), and method ('using a shape object'), distinguishing it from sibling tools like json_filter and json_schema by focusing on size analysis rather than filtering or schema extraction.

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

Usage Guidelines5/5

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

The description provides explicit guidance on when to use this tool: 'Use json_schema tool to understand the JSON structure first.' This indicates a prerequisite step, helping the agent sequence operations correctly and avoid misuse by analyzing data without prior structural understanding.

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/kehvinbehvin/json-mcp-filter'

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