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.

BeginnerPrep: 3 minCook: 15 minServes: JSON data manipulation via AI (starter recipe)

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

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.