Oct 5, 2026 · 4 min read
Ask an AI coding agent “what changed between these two XML files?” and watch what it does. With small files you usually get a decent answer. With large ones — a generated sitemap, a SOAP envelope, an exported config — you typically get one of two failure modes: a wrong answer delivered with confidence, or a long, expensive hunt for the difference. The Skills and MCP integrations exist to fix both.
The first tool an agent reaches for is usually git diff --no-index (or plain diff). That’s a line-based text diff, and XML is not line-based data.
The worst case is generated XML with no line breaks at all — one line, tens of thousands of characters, which is exactly how sitemaps, SOAP responses, and serialized configs come out of real systems:
$ git diff --no-index base.xml contrast.xml
-<config><server><host>api.internal</host><port>8080</port> ... 40,000 more characters
+<config><server><host>api.internal</host><port>8080</port> ... 40,000 more characters
One attribute changed somewhere in the middle, and the diff reports “the line changed”. The agent still has to locate the actual difference itself — inside a single 40 KB line. Some agents give up and guess, which is where confidently wrong answers come from.
Even with nicely indented files, text diff produces misleading hunks. Attribute order carries no meaning in XML, yet <user id="1" name="Alice"/> and <user name="Alice" id="1"/> diff as a change; one element inserted into a repeated block cascades into dozens of “changed” lines (see what a single insertion does to By-Index-style alignment). A smarter agent will run xmllint --format on both sides first — better, but attribute order and element misalignment still generate noise. The agent faithfully summarizes that noise, and one change gets reported as a dozen.
The other default strategy is to read both files into the context window and look for the difference. On a large file this turns into a marathon: the file gets truncated, the agent re-reads it in chunks, runs a few greps, scrolls back and forth — and several minutes and tens of thousands of tokens later, it announces that config.database.host went from db-01 to db-02.
Correct, but slow, expensive, and fragile. Every extra tool call is another chance to truncate, misalign, or miss a second difference hiding elsewhere in the file.
XML diffing is a solved problem — just not by text tools. Parse both documents into data trees, align elements and attributes by name and repeated elements by a chosen strategy, and report changes as exact paths. Deterministic, immune to formatting, and fast:
$ npx @compare-xml/cli base.xml contrast.xml
valueChanged config.database.host
One line of output, no matter how large the inputs. The agent’s job shrinks from finding the difference to explaining it — which is the part it’s actually good at. That’s the entire reason the skill and the MCP server exist: they put this engine one tool call away, so the comparison takes seconds instead of minutes, and the answer stops depending on how the files happened to be formatted.
Same engine, two delivery mechanisms:
The skill is a single SKILL.md that teaches your agent when and how to invoke @compare-xml/cli. Install it once and any Agent Skills-compatible assistant — Claude Code, Codex CLI, OpenCode, Cursor — will run the CLI locally whenever you ask it to compare XML:
npx skills add unitstack/compare-xml
The MCP server exposes the same comparison as a structured compare_xml tool. The CLI doubles as an MCP server (--mcp), so any MCP-capable client can call it with two file paths or strings and get machine-readable differences back:
{
"differences": [
{
"pathSegments": ["config", "database", "host"],
"pathString": "config.database.host",
"pathBelongsTo": "both",
"diffType": "valueChanged"
}
]
}
Which one should you pick? If your assistant supports Agent Skills, the skill is the lighter touch — no server config, invoked on demand. If your client speaks MCP and you want a permanent, typed tool with structured output, use the MCP server. Both wrap the same engine, so they report identical differences — including the repeated-element comparison strategy and the case-insensitive options.
LLMs are good at reasoning about differences and bad at locating them in raw text. The skill and the MCP server exist to split that work properly: the engine finds every difference in seconds, deterministically, and your agent spends its time — and your tokens — on the part that needs judgment.