Skip to main content
Glama

Image Metadata Stripper

strip_image_metadata

Remove EXIF, GPS, IPTC, XMP, and ICC metadata from images to protect privacy before sharing. Strips sensitive data like location coordinates, camera details, and timestamps from JPEG, PNG, WebP, and TIFF files.

Instructions

Strip EXIF, GPS, IPTC, XMP, and ICC metadata from an image for privacy. Use before uploading or sharing images to remove sensitive embedded data like GPS coordinates, camera model, timestamps, and editing history. Accepts base64-encoded JPEG, PNG, WebP, or TIFF. Returns cleaned base64 image with a removal report.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
imageYesBase64-encoded image (JPEG, PNG, WebP, TIFF). No data URI prefix.
formatNoOutput format ('preserve' keeps original)preserve
qualityNoQuality for lossy formats (1-100)

Implementation Reference

  • The handler function that performs the metadata stripping using the 'sharp' library.
    async function handler(input: Input) {
      const { image, format, quality } = input;
    
      // Decode base64
      let buffer: Buffer;
      try {
        buffer = Buffer.from(image, "base64");
      } catch {
        throw new Error("Invalid base64 image data");
      }
    
      if (buffer.length === 0) throw new Error("Empty image data");
      if (buffer.length > 10 * 1024 * 1024) throw new Error("Image too large (max 10MB)");
    
      // Read metadata before stripping
      let originalMeta: Record<string, unknown> = {};
      try {
        const img = sharp(buffer);
        const meta = await img.metadata();
        originalMeta = {
          format: meta.format,
          width: meta.width,
          height: meta.height,
          channels: meta.channels,
          hasExif: !!meta.exif,
          hasIcc: !!meta.icc,
          hasIptc: !!meta.iptc,
          hasXmp: !!meta.xmp,
          orientation: meta.orientation,
          density: meta.density,
        };
      } catch {
        throw new Error("Could not read image — ensure it is a valid JPEG, PNG, WebP, or TIFF");
      }
    
      // Determine output format
      const outputFormat = format === "preserve" ? (originalMeta.format as string || "jpeg") : format;
    
      // Strip all metadata and re-encode (sharp strips metadata by default when not calling withMetadata)
      let stripped: sharp.Sharp;
      try {
        stripped = sharp(buffer);
    
        switch (outputFormat) {
          case "jpeg":
            stripped = stripped.jpeg({ quality, mozjpeg: true });
            break;
          case "png":
            stripped = stripped.png({ compressionLevel: 9 });
            break;
          case "webp":
            stripped = stripped.webp({ quality });
            break;
          default:
            stripped = stripped.jpeg({ quality });
        }
      } catch {
        throw new Error("Failed to process image");
      }
    
      const outputBuffer = await stripped.toBuffer();
      const outputBase64 = outputBuffer.toString("base64");
    
      const strippedFields: string[] = [];
      if (originalMeta.hasExif) strippedFields.push("EXIF (camera settings, GPS, timestamps)");
      if (originalMeta.hasIcc) strippedFields.push("ICC color profile");
      if (originalMeta.hasIptc) strippedFields.push("IPTC (copyright, captions)");
      if (originalMeta.hasXmp) strippedFields.push("XMP (editing history)");
      if (originalMeta.orientation) strippedFields.push("Orientation data");
    
      return {
        image: outputBase64,
        outputFormat,
        original: {
          sizeBytes: buffer.length,
          ...originalMeta,
        },
        output: {
          sizeBytes: outputBuffer.length,
          reductionBytes: buffer.length - outputBuffer.length,
          reductionPercent: parseFloat(((1 - outputBuffer.length / buffer.length) * 100).toFixed(1)),
        },
        metadataStripped: strippedFields.length > 0,
        strippedFields,
      };
    }
  • Input schema definition for the image metadata stripper tool.
    const inputSchema = z.object({
      image: z
        .string()
        .min(1)
        .describe("Base64-encoded image data (JPEG, PNG, WebP, TIFF). Do not include the data URI prefix."),
      format: z
        .enum(["jpeg", "png", "webp", "preserve"])
        .default("preserve")
        .describe("Output format. 'preserve' keeps the original format."),
      quality: z
        .number()
        .int()
        .min(1)
        .max(100)
        .default(90)
        .describe("Output quality for lossy formats (jpeg, webp). 1-100, default 90."),
    });
  • Tool definition registration for 'image-metadata-stripper'.
    const imageMetadataStripperTool: ToolDefinition<Input> = {
      name: "image-metadata-stripper",
      description:
        "Strip EXIF, GPS, IPTC, XMP, and ICC metadata from images for privacy. Accepts base64-encoded JPEG, PNG, WebP, or TIFF images. Returns a cleaned base64 image with a report of what was removed.",
      version: "1.0.0",
      inputSchema,
      handler,
      metadata: {
        tags: ["image", "exif", "privacy", "metadata", "gps", "security"],
        pricing: "$0.001 per call",
        exampleInput: {
          image: "<base64-encoded-image>",
          format: "preserve",
          quality: 90,
        },
      },
    };
    
    registerTool(imageMetadataStripperTool);
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. It effectively discloses what gets destroyed (specific metadata types like GPS coordinates, camera models) and the return format ('cleaned base64 image with a removal report'). It could mention reversibility or size limits, but covers the essential behavioral traits.

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?

Four sentences efficiently cover: 1) core function, 2) usage context, 3) input specification, and 4) output format. No redundant text or tautology—every sentence earns its place with front-loaded value.

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?

For a 3-parameter image processing tool with 100% schema coverage, the description is complete. It compensates for the missing output schema by describing the return value ('cleaned base64 image with a removal report') and covers the privacy use case comprehensively.

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

Parameters3/5

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

Input schema has 100% description coverage, establishing a baseline of 3. The description reinforces the image parameter requirements ('Accepts base64-encoded JPEG, PNG, WebP, or TIFF') but does not add semantic meaning beyond the schema for the 'format' or 'quality' parameters.

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 explicitly states the tool strips 'EXIF, GPS, IPTC, XMP, and ICC metadata' for 'privacy,' using specific verbs and resources. It clearly distinguishes from siblings (financial analysis, text processing, etc.) by specifying image metadata manipulation.

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

Usage Guidelines4/5

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

Provides clear contextual guidance: 'Use before uploading or sharing images to remove sensitive embedded data.' While it doesn't explicitly state when NOT to use it or name alternatives, the sibling tools are sufficiently distinct that this contextual signal is adequate for selection.

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/marras0914/agent-toolbelt'

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