structdiff
Server Configuration
Describes the environment variables required to run the server.
| Name | Required | Description | Default |
|---|---|---|---|
| --dir | No | Folder the server is allowed to read. May be repeated; relative file paths resolve against the first --dir. Without it, the server can read only the folder it was started in. |
Instructions
Guidance the server publishes about itself, which clients place ahead of the tool catalog so the model reads it before choosing anything.
Semantic diffs of structured files. Unlike a line diff, these ignore key order and formatting and report what changed by path. diff_files / diff_text compare two JSON, JSONC, YAML, TOML, .env or INI documents (formats may differ between a and b). Lists of objects are matched by an id/name/key field when possible (array_match='auto'), so reordering shows as 'moved' instead of dozens of edits. csv_diff compares CSV files row by row using key_columns. as_json_patch returns an RFC 6902 patch that turns a into b; apply_preview shows the result of a patch. inspect_file checks how a file parses (format, warnings) before diffing. All file access is read-only and limited to the directories the server was started with.
Capabilities
Features and capabilities supported by this server
Protocol revision2025-11-25
| Capability | Details |
|---|---|
| tools | {
"listChanged": false
} |
| prompts | {
"listChanged": false
} |
| resources | {
"subscribe": false,
"listChanged": false
} |
Tools
Functions exposed to the LLM to take actions
| Name | Description |
|---|---|
| diff_filesA | Semantic diff of two files: what changed, by path, ignoring key order and formatting. Reads JSON, JSONC, YAML (safe subset, multi-document supported), TOML, .env and INI files (format is detected from the file name; a and b may be different formats). Returns {identical, summary{added, removed, changed, type_changed, moved, total}, changes[], warnings[]}. Each change has an op ('added', 'removed', 'changed', 'type_changed', 'moved'), a JSONPath-like path such as $.servers[id=3].port, and old/new values (truncated to max_value_chars). A value going from 1 to "1" is type_changed; null versus a missing key is reported as a key that was added or removed, never as a change. Args: a, b: file paths (relative paths resolve against the first --dir). format: json, jsonc, yaml, toml, env, ini, csv, or auto (from the extension). array_match: how list items are paired. 'auto' (default) matches lists of objects by the first of array_keys that is present and unique in every item, and falls back to position; 'index' pairs by position; 'key' is like auto but warns when no key works; 'set' ignores order and duplicates-aware compares items by value (good for tag lists). Items matched by key that changed position are reported as 'moved'. array_keys: candidate key fields, default ["id", "name", "key"]. ignore: patterns of paths to skip. '' matches any text, including dots and brackets: '$.metadata.updatedAt', '$.items[].etag', '.timestamp'. Must start with '$' or ''. abs_tol, rel_tol: numbers within these tolerances are treated as equal (0.1+0.2 vs 0.3 needs abs_tol=1e-9). 1 and 1.0 are always equal; big integers stay exact. strip_comments: remove // and /* */ comments and trailing commas before parsing JSON (always on for .jsonc). encoding: 'auto' honours UTF-8/16/32 BOMs, otherwise UTF-8; or give e.g. 'cp1252'. max_changes: cap on listed changes; summary counts are always complete. |
| diff_textA | Semantic diff of two pasted strings (same output and options as diff_files). Use this for content that is not on disk. 'format' is required because it cannot be guessed from a name. Both strings must be in the same format. See diff_files for the output shape and for array_match, array_keys, ignore, abs_tol, rel_tol and strip_comments. For CSV text each row becomes an object, so array_keys can match rows by id; use csv_diff on files for large CSVs. |
| csv_diffA | Row-level diff of two CSV/TSV files: added, removed and changed rows, per-cell changes, columns. Rows are paired by key_columns (e.g. ["id"] or ["country", "year"]); without key_columns whole rows are compared as an unordered set, so an edited row appears as one removed plus one added row. Reports added/removed columns separately (cells of those columns are not compared) and whether the common columns were reordered. Duplicate keys are paired in file order and reported as a warning. The delimiter (, ; tab |) and BOM/UTF-16 encodings are detected automatically. File a is indexed in memory (limit 2 million rows); file b is streamed. Args: a, b: file paths. key_columns: column names identifying a row; they must exist in both files. ignore_columns: column names or globs (e.g. "updated_*") whose cells are not compared. delimiter: a single character; auto-detected when omitted. abs_tol, rel_tol: numeric cells (both sides parse as numbers) within tolerance are equal; requires key_columns. max_changes: cap on entries in each of added_rows, removed_rows and changed_rows; summary counts are always complete. |
| as_json_patchA | Generate an RFC 6902 JSON Patch that transforms document a into document b. The patch is verified before it is returned: it is applied to a and the result is re-diffed against b (using the same options), so a patch that does not reproduce b is never returned. Lists are patched with remove/add/move so keyed items keep their identity. With ignore or tolerance options the patched a equals b only up to those options. NaN/Infinity cannot be expressed in JSON and are rejected. Args: a, b: file paths, or the documents themselves when inputs='text'. inputs: 'files' (default) or 'text'; text requires an explicit format. format, array_match, array_keys, ignore, abs_tol, rel_tol, strip_comments, encoding: as in diff_files. |
| apply_previewA | Preview what an RFC 6902 JSON Patch does to a document, without writing anything. Supports add, remove, replace, move, copy and test. Returns the patched document and a semantic summary of what changed versus the original. A failing operation is reported with its index and reason, and nothing is returned in that case. Args: a: file path, or the document itself when inputs='text'. patch: the patch as a JSON array (or a JSON string of one). inputs, format, strip_comments, encoding: as in diff_files. max_result_chars: the result is cut off after this many characters (the summary is not). |
| inspect_fileA | Check how a file parses before diffing it: format, encoding, top-level shape, warnings. Surfaces things that make diffs surprising: duplicate keys (JSON, YAML, .env), multi-document YAML, comments in JSON, an unexpected delimiter or encoding in CSV. For CSV it reports the columns, the detected delimiter and the row count (streamed, so large files are fine). |
Prompts
Interactive templates invoked by user choice
| Name | Description |
|---|---|
No prompts | |
Resources
Contextual data attached and managed by the client
| Name | Description |
|---|---|
No resources | |
TDQS
Scored across 6 tools
Most tools occupy distinct niches: inspect_file (parse check), diff_files/diff_text (same engine, different input source), csv_diff (row-level/keyed CSV), and the as_json_patch/apply_preview pair (inverse operations). The only real overlap is csv_diff versus diff_files with format=csv, but the descriptions explicitly route large CSVs to csv_diff and pasted content to diff_text, so an agent can choose correctly. Minor residual risk that an agent picks diff_files over diff_text (or vice versa) purely on where its data lives.
All names are snake_case and self-describing, with a clear verb_noun pattern in diff_files, diff_text, inspect_file and apply_preview. Two names break the pattern — csv_diff (noun-first instead of diff_csv) and as_json_patch (prepositional) — which is a minor but noticeable inconsistency in an otherwise tight set.
Six tools is a well-scoped surface for a structural-diff server: each one covers a distinct input mode (files, text, CSV), a pre-flight check, or one direction of the patch lifecycle. No tool looks redundant or tacked on.
The lifecycle inspect -> diff -> generate patch -> preview patch is covered, with rich options for matching, tolerance and ignores across all supported formats. The notable gap is that nothing writes: apply_preview only previews, so patch application on disk (and any directory-level or multi-file diff) is a dead end an agent must work around.