Skip to main content
Glama
conorluddy

XC-MCP: XCode CLI wrapper

by conorluddy

Compare Screenshots (Pixel Diff)

visual-diff
Idempotent

Compare two PNG screenshots pixel-by-pixel to detect visual regressions. Generates a highlighted diff image and a JSON report, and passes or fails based on a configurable threshold.

Instructions

visual-diff

Compare two PNG screenshots pixel-by-pixel using pixelmatch to detect visual regressions. Writes a highlighted diff image and a JSON report to the output directory.

What it does

Reads two PNG files, compares them pixel-by-pixel, and:

  • Reports the number and percentage of differing pixels

  • Determines pass/fail against a configurable threshold

  • Writes diff.png with highlighted differences (red pixels where images differ)

  • Writes diff-report.json with full metrics

Parameters

  • baselinePath (string, required): Path to the baseline (reference) PNG

  • currentPath (string, required): Path to the current (test) PNG

  • outputDir (string, optional): Directory for diff.png and diff-report.json. Defaults to the directory containing currentPath

  • threshold (number, optional): Maximum acceptable ratio of different pixels (0.01 = 1%). Default: 0.01

Returns

Text summary and structuredContent:

  • differentPixels: Count of pixels that differ

  • differencePercentage: Ratio of different pixels to total pixels (0–1)

  • passed: true if differencePercentage <= threshold

Artifacts Written

  • diff.png: Diff image highlighting changed pixels (pixelmatch output)

  • diff-report.json: JSON with baseline, current, dimensions, totalPixels, differentPixels, differencePercentage, thresholdPercentage, passed

Errors

Throws McpError(InvalidRequest) for:

  • Missing baseline or current file

  • Dimension mismatch between images

  • PNG read failures

Examples

Basic diff

await visualDiffTool({
  baselinePath: '/tmp/before.png',
  currentPath: '/tmp/after.png'
})

Custom output directory and strict threshold

await visualDiffTool({
  baselinePath: '/tmp/before.png',
  currentPath: '/tmp/after.png',
  outputDir: '/tmp/diffs',
  threshold: 0.001
})

Zero-tolerance regression check

await visualDiffTool({
  baselinePath: '/snapshots/login-baseline.png',
  currentPath: '/snapshots/login-current.png',
  threshold: 0
})

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
outputDirNo
thresholdNo
currentPathYes
baselinePathYes

Output Schema

TableJSON Schema
NameRequiredDescriptionDefault
passedYes
differentPixelsYes
differencePercentageYes

Schema Changelog

Changes observed during successful MCP inspections.

  1. Addedv4.1.0

TDQS

A4.8/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Beyond the annotations, it discloses concrete side effects: it writes diff.png and diff-report.json, defaults outputDir to currentPath's directory, computes pass/fail against a threshold, and throws errors on missing files, dimension mismatches, or PNG failures. This gives the agent a strong model of the tool's full behavior.

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?

The description is long, but it is well-structured and front-loaded with the core purpose, followed by what-it-does bullets, parameter details, output details, error behavior, and examples. Each section and example adds selection or invocation value, so the length is justified.

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

Completeness5/5

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

For a tool with 4 parameters, side-effect file outputs, return values, and error conditions, the description is fully complete: parameters, defaults, structuredContent fields, artifacts, failure modes, and example invocations are all covered without leaving an agent to infer required behavior.

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

Parameters5/5

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

Schema description coverage is 0%, so the description must fully explain the parameters. It does so for all four: baselinePath and currentPath are described as required path inputs, outputDir gets a default, and threshold gets both a definition and an example ratio. This completely compensates for the bare JSON schema.

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 opens with a specific action and resource: 'Compare two PNG screenshots pixel-by-pixel... to detect visual regressions.' It also states what artifacts are produced, making it clearly distinct from the sibling screenshot-acquisition tools such as 'screenshot' or 'simctl-io'.

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?

The description gives clear context: use this tool when comparing two PNGs for pixel-level visual regressions, and the examples reinforce typical scenarios. It does not explicitly list alternatives or state when not to use the tool, so it stops short of the best possible guidance.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.