json_extract
Extract specific data from JSON files using paths, filters, patterns, or slices to retrieve targeted values, filter by conditions, or transform JSON elements for focused analysis.
Instructions
Extract specific data using paths, filters, patterns, or slices from JSON files. Always use this tool when you need to retrieve particular values, filter arrays/objects by conditions, search for patterns, or slice data. Ideal for targeted data extraction, data transformation, and focused analysis of specific JSON elements.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| default_value | No | Fallback if path not found | |
| end | No | Array slice end index | |
| file_path | Yes | Path to the JSON file | |
| filter | No | JS condition to filter results (e.g., 'item.age > 18') | |
| keys | No | Specific object keys to extract | |
| path | No | Dot notation path to target | |
| pattern | No | Regex pattern to search for | |
| search_type | No | What to search when using pattern | |
| start | No | Array slice start index |
Input Schema (JSON Schema)
{
"properties": {
"default_value": {
"description": "Fallback if path not found"
},
"end": {
"description": "Array slice end index",
"type": "number"
},
"file_path": {
"description": "Path to the JSON file",
"type": "string"
},
"filter": {
"description": "JS condition to filter results (e.g., 'item.age > 18')",
"type": "string"
},
"keys": {
"description": "Specific object keys to extract",
"items": {
"type": "string"
},
"type": "array"
},
"path": {
"description": "Dot notation path to target",
"type": "string"
},
"pattern": {
"description": "Regex pattern to search for",
"type": "string"
},
"search_type": {
"description": "What to search when using pattern",
"enum": [
"key",
"value",
"both"
],
"type": "string"
},
"start": {
"description": "Array slice start index",
"type": "number"
}
},
"required": [
"file_path"
],
"type": "object"
}
Implementation Reference
- src/index.ts:322-455 (handler)The core handler function for the "json_extract" tool. It processes the input parameters to load a JSON file, navigate to a specific path, apply optional filters (using JS conditions), regex pattern searches (on keys/values), array slicing, specific key extraction, handles default values, truncates large outputs, and returns the result as a formatted JSON string in a text content block.file_path, path, filter, pattern, search_type, start, end, keys, default_value, }) => { try { const data = readJSONFile(file_path); let target = path ? getValueByPath(data, path) : data; // If path was specified but not found, return default value if (path && target === undefined) { const output = default_value !== undefined ? default_value : null; return { content: [ { type: "text", text: JSON.stringify( { result: output, message: `Path not found: ${path}, returning default value`, }, null, 2 ), }, ], }; } // Apply filter if specified if (filter) { target = filterObject(target, filter); } // Apply pattern search if specified if (pattern) { const results: any[] = []; const flags = "gi"; // Case-insensitive by default const regex = new RegExp(pattern, flags); const searchFor = search_type || "both"; function searchObject(obj: any, currentPath: string = ""): void { if (Array.isArray(obj)) { obj.forEach((item, index) => { searchObject(item, `${currentPath}[${index}]`); }); } else if (typeof obj === "object" && obj !== null) { Object.entries(obj).forEach(([key, value]) => { const newPath = currentPath ? `${currentPath}.${key}` : key; if ( (searchFor === "key" || searchFor === "both") && regex.test(key) ) { results.push({ type: "key", path: newPath, key, value }); } if (searchFor === "value" || searchFor === "both") { if (value === null && pattern === "null") { results.push({ type: "value", path: newPath, key, value }); } else if (typeof value === "string" && regex.test(value)) { results.push({ type: "value", path: newPath, key, value }); } else if ( typeof value === "number" && regex.test(value.toString()) ) { results.push({ type: "value", path: newPath, key, value }); } else if ( typeof value === "boolean" && regex.test(value.toString()) ) { results.push({ type: "value", path: newPath, key, value }); } } searchObject(value, newPath); }); } } searchObject(target); target = results; } // Apply slicing if specified if ((start !== undefined || end !== undefined) && Array.isArray(target)) { const sliceStart = start || 0; const sliceEnd = end || target.length; target = target.slice(sliceStart, sliceEnd); } // Extract specific keys if specified if ( keys && typeof target === "object" && target !== null && !Array.isArray(target) ) { const extracted: any = {}; keys.forEach((key) => { if (key in target) { extracted[key] = target[key]; } }); target = extracted; } const truncatedTarget = truncateForOutput(target); let outputText = JSON.stringify(truncatedTarget, null, 2); // Replace quoted truncation messages with unquoted text for markdown-like output outputText = outputText.replace( /"\.\.\.(\d+) more items"/g, "...$1 more items" ); outputText = outputText.replace( /"\.\.\.(\d+) more properties": "\.\.\.?"/g, "...$1 more properties" ); return { content: [{ type: "text", text: outputText }], }; } catch (error: any) { return { content: [{ type: "text", text: `Error: ${error.message}` }], }; } }
- src/index.ts:301-321 (schema)Zod input schema defining all parameters for the json_extract tool, including required file_path and optional path, filter, pattern, search_type, slicing indices, keys to extract, and default_value.{ file_path: z.string().describe("Path to the JSON file"), path: z.string().optional().describe("Dot notation path to target"), filter: z .string() .optional() .describe("JS condition to filter results (e.g., 'item.age > 18')"), pattern: z.string().optional().describe("Regex pattern to search for"), search_type: z .enum(["key", "value", "both"]) .optional() .describe("What to search when using pattern"), start: z.number().optional().describe("Array slice start index"), end: z.number().optional().describe("Array slice end index"), keys: z .array(z.string()) .optional() .describe("Specific object keys to extract"), default_value: z.any().optional().describe("Fallback if path not found"), }, async ({
- src/index.ts:298-456 (registration)Registration of the json_extract tool on the MCP server using server.tool(), including the tool name, detailed description, input schema, and handler function.server.tool( "json_extract", "Extract specific data using paths, filters, patterns, or slices from JSON files. Always use this tool when you need to retrieve particular values, filter arrays/objects by conditions, search for patterns, or slice data. Ideal for targeted data extraction, data transformation, and focused analysis of specific JSON elements.", { file_path: z.string().describe("Path to the JSON file"), path: z.string().optional().describe("Dot notation path to target"), filter: z .string() .optional() .describe("JS condition to filter results (e.g., 'item.age > 18')"), pattern: z.string().optional().describe("Regex pattern to search for"), search_type: z .enum(["key", "value", "both"]) .optional() .describe("What to search when using pattern"), start: z.number().optional().describe("Array slice start index"), end: z.number().optional().describe("Array slice end index"), keys: z .array(z.string()) .optional() .describe("Specific object keys to extract"), default_value: z.any().optional().describe("Fallback if path not found"), }, async ({ file_path, path, filter, pattern, search_type, start, end, keys, default_value, }) => { try { const data = readJSONFile(file_path); let target = path ? getValueByPath(data, path) : data; // If path was specified but not found, return default value if (path && target === undefined) { const output = default_value !== undefined ? default_value : null; return { content: [ { type: "text", text: JSON.stringify( { result: output, message: `Path not found: ${path}, returning default value`, }, null, 2 ), }, ], }; } // Apply filter if specified if (filter) { target = filterObject(target, filter); } // Apply pattern search if specified if (pattern) { const results: any[] = []; const flags = "gi"; // Case-insensitive by default const regex = new RegExp(pattern, flags); const searchFor = search_type || "both"; function searchObject(obj: any, currentPath: string = ""): void { if (Array.isArray(obj)) { obj.forEach((item, index) => { searchObject(item, `${currentPath}[${index}]`); }); } else if (typeof obj === "object" && obj !== null) { Object.entries(obj).forEach(([key, value]) => { const newPath = currentPath ? `${currentPath}.${key}` : key; if ( (searchFor === "key" || searchFor === "both") && regex.test(key) ) { results.push({ type: "key", path: newPath, key, value }); } if (searchFor === "value" || searchFor === "both") { if (value === null && pattern === "null") { results.push({ type: "value", path: newPath, key, value }); } else if (typeof value === "string" && regex.test(value)) { results.push({ type: "value", path: newPath, key, value }); } else if ( typeof value === "number" && regex.test(value.toString()) ) { results.push({ type: "value", path: newPath, key, value }); } else if ( typeof value === "boolean" && regex.test(value.toString()) ) { results.push({ type: "value", path: newPath, key, value }); } } searchObject(value, newPath); }); } } searchObject(target); target = results; } // Apply slicing if specified if ((start !== undefined || end !== undefined) && Array.isArray(target)) { const sliceStart = start || 0; const sliceEnd = end || target.length; target = target.slice(sliceStart, sliceEnd); } // Extract specific keys if specified if ( keys && typeof target === "object" && target !== null && !Array.isArray(target) ) { const extracted: any = {}; keys.forEach((key) => { if (key in target) { extracted[key] = target[key]; } }); target = extracted; } const truncatedTarget = truncateForOutput(target); let outputText = JSON.stringify(truncatedTarget, null, 2); // Replace quoted truncation messages with unquoted text for markdown-like output outputText = outputText.replace( /"\.\.\.(\d+) more items"/g, "...$1 more items" ); outputText = outputText.replace( /"\.\.\.(\d+) more properties": "\.\.\.?"/g, "...$1 more properties" ); return { content: [{ type: "text", text: outputText }], }; } catch (error: any) { return { content: [{ type: "text", text: `Error: ${error.message}` }], }; } } );
- src/index.ts:88-117 (helper)Helper function filterObject used by json_extract to filter arrays or objects based on a JavaScript condition string (e.g., 'item.age > 18').function filterObject(obj: any, condition: string): any { try { // For arrays: item, index are available // For objects: value, key, index are available const conditionFn = new Function( "item", "key", "index", "value", `return ${condition}` ); if (Array.isArray(obj)) { return obj.filter((item, index) => conditionFn(item, undefined, index, item) ); } else if (typeof obj === "object" && obj !== null) { const result: any = {}; Object.entries(obj).forEach(([key, value], index) => { if (conditionFn(value, key, index, value)) { result[key] = value; } }); return result; } return obj; } catch (error: any) { throw new Error(`Invalid filter condition: ${error.message}`); } }
- src/index.ts:34-42 (helper)Helper function getValueByPath used by json_extract to navigate to a nested value using dot notation path (e.g., 'users.0.name').function getValueByPath(obj: any, path: string): any { return path.split(".").reduce((current, key) => { if (current === null || current === undefined) return undefined; if (Array.isArray(current) && !isNaN(Number(key))) { return current[Number(key)]; } return current[key]; }, obj); }