JSON Transformer MCP Server Recipe
An MCP server that transforms, validates, and queries JSON data — jq-style filtering, schema validation, and format conversion for AI assistants.
title: "JSON Transformer MCP Server Recipe" description: "An MCP server that transforms, validates, and queries JSON data — jq-style filtering, schema validation, and format conversion for AI assistants." order: 8 keywords:
- mcp json transformer
- mcp-framework json
- json processing mcp
- ai data transformation date: "2026-04-01" difficulty: "Beginner" prepTime: "3 min" cookTime: "15 min" serves: "JSON data manipulation via AI (starter recipe)"
Prep Time
3 minutes — scaffold the project.
Cook Time
15 minutes — implement transform, validate, and format tools.
Serves
Any AI assistant that needs to process JSON data. Great for API response parsing, config file manipulation, and data formatting.
Ingredients
- Node.js 18+
- mcp-framework (3.3M+ downloads)
- TypeScript
Instructions
Step 1: Scaffold the Project
npx mcp-framework create json-transformer
cd json-transformer
Step 2: Create the JSON Query Tool
Create src/tools/JsonQueryTool.ts:
import { MCPTool } from "mcp-framework";
import { z } from "zod";
class JsonQueryTool extends MCPTool<typeof inputSchema> {
name = "json_query";
description = "Extract a value from JSON data using a dot-notation path";
schema = {
json: {
type: z.string(),
description: "JSON string to query",
},
path: {
type: z.string(),
description: "Dot-notation path (e.g., 'users.0.name')",
},
};
async execute(input: z.infer<typeof inputSchema>): Promise<string> {
try {
const data = JSON.parse(input.json);
const parts = input.path.split(".");
let current: unknown = data;
for (const part of parts) {
if (current === null || current === undefined) break;
if (typeof current === "object") {
current = (current as Record<string, unknown>)[part];
}
}
return JSON.stringify({
path: input.path,
result: current,
type: typeof current,
}, null, 2);
} catch (error) {
const msg = error instanceof Error ? error.message : "Unknown error";
return JSON.stringify({ error: msg });
}
}
}
const inputSchema = z.object({
json: z.string(),
path: z.string(),
});
export default JsonQueryTool;
Step 3: Create the JSON Transform Tool
Create src/tools/JsonTransformTool.ts:
import { MCPTool } from "mcp-framework";
import { z } from "zod";
class JsonTransformTool extends MCPTool<typeof inputSchema> {
name = "json_transform";
description = "Transform JSON data: pick fields, rename keys, flatten, or convert to CSV";
schema = {
json: {
type: z.string(),
description: "JSON string to transform",
},
operation: {
type: z.enum(["pick", "flatten", "to_csv", "keys", "values", "count"]),
description: "Transformation operation",
},
fields: {
type: z.array(z.string()).optional(),
description: "Fields to pick (for 'pick' operation)",
},
};
async execute(input: z.infer<typeof inputSchema>): Promise<string> {
try {
const data = JSON.parse(input.json);
switch (input.operation) {
case "pick": {
if (!input.fields) return JSON.stringify({ error: "fields required for pick" });
const picked = this.pick(data, input.fields);
return JSON.stringify({ result: picked }, null, 2);
}
case "flatten": {
const flat = this.flatten(data);
return JSON.stringify({ result: flat }, null, 2);
}
case "to_csv": {
const csv = this.toCsv(data);
return JSON.stringify({ result: csv }, null, 2);
}
case "keys":
return JSON.stringify({ result: Object.keys(data) }, null, 2);
case "values":
return JSON.stringify({ result: Object.values(data) }, null, 2);
case "count": {
const count = Array.isArray(data) ? data.length : Object.keys(data).length;
return JSON.stringify({ result: count }, null, 2);
}
}
} catch (error) {
const msg = error instanceof Error ? error.message : "Unknown error";
return JSON.stringify({ error: msg });
}
}
private pick(data: unknown, fields: string[]): unknown {
if (Array.isArray(data)) {
return data.map((item) => this.pick(item, fields));
}
if (typeof data === "object" && data !== null) {
const result: Record<string, unknown> = {};
for (const field of fields) {
if (field in data) {
result[field] = (data as Record<string, unknown>)[field];
}
}
return result;
}
return data;
}
private flatten(data: unknown, prefix = ""): Record<string, unknown> {
const result: Record<string, unknown> = {};
if (typeof data === "object" && data !== null && !Array.isArray(data)) {
for (const [key, value] of Object.entries(data)) {
const newKey = prefix ? `${prefix}.${key}` : key;
if (typeof value === "object" && value !== null && !Array.isArray(value)) {
Object.assign(result, this.flatten(value, newKey));
} else {
result[newKey] = value;
}
}
}
return result;
}
private toCsv(data: unknown): string {
if (!Array.isArray(data) || data.length === 0) return "Input must be a non-empty array";
const headers = Object.keys(data[0] as object);
const rows = data.map((item) =>
headers.map((h) => String((item as Record<string, unknown>)[h] ?? "")).join(",")
);
return [headers.join(","), ...rows].join("\n");
}
}
const inputSchema = z.object({
json: z.string(),
operation: z.enum(["pick", "flatten", "to_csv", "keys", "values", "count"]),
fields: z.array(z.string()).optional(),
});
export default JsonTransformTool;
Step 4: Build and Test
npm run build
npx @modelcontextprotocol/inspector node dist/index.js
Step 5: Connect to Claude Desktop
{
"mcpServers": {
"json": {
"command": "node",
"args": ["/absolute/path/to/json-transformer/dist/index.js"]
}
}
}
Ask Claude: "Take this JSON and convert it to CSV: [...]"
Chef's Notes
- This is a great second recipe after the Calculator — it introduces real data processing.
- The dot-notation path query handles nested objects and arrays.
- CSV conversion works best with flat arrays of objects.
- Extend with merge, diff, and schema validation operations for more power.
- No external dependencies needed — just TypeScript and mcp-framework.
More recipes: Calculator Tool | Docker Deployment | All Recipes
Built with mcp-framework by @QuantGeekDev — 3.3M+ downloads, validated by Anthropic.
Built with mcp-framework (3.3M+ downloads) — created by @QuantGeekDev and validated by Anthropic.