NAME
MCP::Run::Compress::Filters - Command Output Compression Reference
VERSION
version 0.107
DESCRIPTION
This document lists all commands that MCP::Run::Compress filters and how they are compressed. Each filter removes noise, truncates verbose output, and limits lines to reduce token count while preserving essential information.
The file holds no code. It is a promise about another file's behaviour, and kept honest by t/60-filters-doc.t, which compares every command named in an =item below against the filters MCP::Run::Compress actually registers, and fails on drift in either direction. Two rules follow from that, and both matter when adding an entry:
The command named in an
=itemis the filter's identity -- the shortest command line that makes it match -- and nothing else. A filter registered for the programiptablesis documented asiptables, not asiptables -L, even though-Lis what one usually types; the-Lbelongs in the prose. Flags appear in the name only when the filter genuinely requires them, asgit diff --statdoes.An entry documents a filter that exists. A command listed here is a command the compressor really compresses. Anything else makes this reference worse than silence: someone checking whether their tool is supported reads exactly this file.
COMMANDS
File System Commands
ls-
Long listing format (
-l,-la, etc.) is detected automatically from the output. When detected, the filter strips permissions, owner, group, size, date, inode, and device information. Only the file type letter and the filename are preserved.Every type
ls -lprints is recognised (-bcdDlps), as is the character some systems append to the mode column for the file's alternate access method:.for an SELinux context,+for a POSIX ACL,@for macOS extended attributes. For a symlink the preserved name is the wholelink -> target, because the target is the only thing the entry actually states.The date column is recognised in every shape
ls --time-style=produces: the locale default (Aug 14 08:44, andMar 12 2024for an older file),iso(08-23 10:00),long-iso(2026-08-23 10:00),full-iso(2026-08-23 10:00:00.123456789 +0200) and the date alone, as in+%Y-%m-%d(2026-08-23). A strftime format that prints neither an ISO date nor an ISO time is not recognised, and such a line stays uncollapsed.For non-long listings, common noise directories are filtered: node_modules, .git, .target, .next, .nuxt, .cache, __pycache__, .DS_Store, vendor/bundle.
# Before: drwxr-xr-x. 14 getty getty 4096 Apr 24 02:32 .build # After: d .build # Before: lrwxrwxrwx 1 getty getty 9 Apr 24 02:32 link -> target # After: l link -> target stat-
Strips Device, Inode, and Birth lines.
# Before: # Device: 801h/2049d Inode: 1234567 Links: 1 # Birth: 2026-03-09 10:00:00.000000000 +0100 # After: (lines removed) find-
Strips
permission deniederrors and limits results. df-
Truncates columns at 80 characters, limits to 20 lines.
du-
Strips .git and node_modules directories, truncates at 150 characters, max 50 lines.
Git Commands
git status-
Strips branch information, keeps changed/untracked files.
git diff-
Strips diff headers (
diff --git,index,---,+++). Keeps actual-and+lines with content. git diff --stat-
Transforms to compact "N+M- filename" format (additions+deletions-filename). Strips summary lines (X files changed, insertions(+), deletions(-)).
# Before: # file1.txt | 5 +++ --- 2 deletions(-) # file2.rb | 3 +++ --- 1 deletion(-) # 2 files changed, 8 insertions(+), 3 deletions(-) # After: # 5+2-file1.txt # 3+1-file2.rb git log-
Shows first 20 and last 10 lines (with total count), strips commit hashes, author, and date noise.
git branch-
Strips blank lines, max 30 lines.
git stash-
Strips blank lines, max 30 lines.
git commit-
The one filter that rewrites the command instead of its output. When
CO_AUTHORED_BYorANTHROPIC_MODELis set, the Co-Authored-By trailer in the commit message is replaced, or added to the last-m/--messageargument when none is present. SetMCP_RUN_COMPRESS_NO_CO_AUTHOREDto disable it entirely.Unlike every other git entry here this one matches inside compound commands, so
cd project && git add . && git commit -m "..."is rewritten too. The output ofgit commititself is left untouched.
Build & Compile Commands
make-
Strips
make[N]: Entering directory,Leaving directory, andNothing to be donemessages.# On empty output: "make: ok" cargo build-
Strips
Compiling,FreshandFinishedlines. Keeps errors. cargo test-
Strips compilation and running noise. Max 100 lines.
gcc,g++-
Merges stderr into stdout -- a compiler says everything there -- then strips the include chain, the
note:lines and the echoed source with its caret markers. The diagnostics themselves are kept: file, line, column, message.# Before: # In file included from /usr/include/stdio.h:42: # main.c:10:5: error: use of undeclared identifier 'foo' # 10 | foo(); # | ^ # After: # main.c:10:5: error: use of undeclared identifier 'foo' swift build-
Strips the build chatter (
[N/M],Compiling,Fetching, resolution andBuild complete!), so that what remains is exactly the warnings and errors. On a clean build nothing remains and the output becomesswift build: ok (build complete). mix compile-
Elixir Mix compiler. Strips
Compiling N files,Generated ... appand Hex dependency resolution lines. On empty output:mix compile: ok. pio run-
PlatformIO build. Strips the environment report (CONFIGURATION, PLATFORM, HARDWARE, DEBUG, PACKAGES), the library dependency finder, and the compiling, archiving, linking and size checking lines. The
RAM:/Flash:usage lines are kept. On empty output:pio run: ok. mvn-
Strips the
[INFO]bookkeeping -- separators, plugin banners, downloads,Total time,Finished at-- but not every[INFO]line: surefire reports its test results there.[WARNING]and[ERROR]are untouched. gradle-
Strips
> Task :lines for tasks that succeeded, were up to date, skipped or came from the cache, plus daemon and download noise. A task line carryingFAILEDis kept.
Container Commands
docker ps,docker images-
Truncates columns at 120 characters, max 30 lines.
docker build-
Strips build progress (
# N [M/N],Step N/M:). docker run-
Strips image pulling and status messages.
kubectl get-
Truncates columns at 150 characters, max 50 lines.
kubectl describe-
Strips name, namespace, labels, annotations noise. Max 100 lines.
docker-compose,docker compose-
Both the v1 binary and the v2 subcommand. Strips network, volume and container lifecycle lines (
Creating,Started,Healthy, ...),PullingandAttaching to. Service log output is kept.
Cloud & Infrastructure Commands
terraform plan,terraform apply-
Strips
Refreshing state...and progress messages. helm install,helm upgrade-
Strips NAME, NAMESPACE, STATUS, REVISION, NOTES noise.
ansible-playbook-
Strips PLAY/TASK banners, running handlers, and recap headers. Max 100 lines.
tofu plan,tofu apply-
OpenTofu is a Terraform fork and prints the same lines; these filters mirror the
terraformones above. tofu init-
Short-circuits a successful init to
tofu init: ok-- there is nothing else in it. A failing init keeps its output, minus provider discovery (- Finding,- Installing,- Installed).
Package Managers
cpanm-
Strips
--Working on,OK,FAILnoise. Shows only essential progress. npm install-
Strips added/found packages confirmation and warnings.
yarn install,yarn add,pnpm install,pnpm add-
Strips
Done in...,Resolving completed,Linking completed. pip install-
Strips
Collecting,Downloading,Installing collected packages. cpan-
Strips the CPAN shell's narration:
Reading '...',Database was generated on,Fetching with,Checksum for,Running make/test/install for. cpm-
Strips the per-distribution
DONE ...lines and keeps the summary. On empty output:cpm: ok. composer install-
Strips repository loading, dependency updating, the per-package operation lines, lock file writing and autoload generation. On empty output:
composer install: ok. brew install-
Strips
==> Downloading,==> Pouring,==> Fetching, auto-update noise andAlready downloaded:.==> Installing dependencies for ...goes,==> Installing ...stays. poetry install-
Strips
Installing dependencies from lock file,Package operations:and the per-package bullet lines. On empty output:poetry install: ok. uv sync-
Strips the
Resolved/Prepared/Audited N packages in ...timings and the+/-package list;Installed N packagesis kept. On empty output:uv sync: ok.
System Commands
ps-
Truncates columns at 120 characters, max 30 lines.
iptables-
Any invocation,
iptables -Lin particular: truncates columns at 150 characters, max 50 lines. ping-
Strips PING header, replies, and statistics.
rsync-
Strips sent/received bytes and total size summary.
netstat-
Truncates columns at 150 characters, max 50 lines.
ip addr,ip route,ip link-
ip addrtruncates at 150 characters, max 50 lines;ip routeandip linkstrip blank lines, max 30 lines. mount-
Truncates columns at 200 characters, max 50 lines.
lsblk-
Lists block devices in tree format. Truncates at 150 characters, max 50 lines.
blkid-
Lists block device attributes. Truncates at 200 characters, max 50 lines.
systemctl status-
Removes the state glyph from the unit line and strips the accounting block: Loaded, Docs, Main PID, Tasks, Memory, CPU, CGroup and the process tree under it.
Active:and the recent log lines are kept --Active:also carries the state the glyph stood for. journalctl-
Strips
-- Reboot --,-- Logs begin at ...,-- Journal begins at ...,-- No entries --and boot markers. Max 100 lines. fail2ban-client-
Strips blank lines, max 30 lines.
Development Tools
grep-
Truncates lines at 150 characters, max 100 lines.
cat-
Strips blank lines, truncates at 500 characters, max 100 lines.
curl-
Merges stderr into stdout, strips progress (% Total, Resolving, Connected to, HTTP/... responses).
wget-
Strips timestamp, resolving, connecting, length, saving, and progress bar lines.
pytest-
Strips coverage and HTML report generation lines.
ollama run-
Strips ANSI escapes and the braille spinner frames. Nothing else: the output is the model's answer, so no line of it is dropped, truncated or counted.
quarto render-
Short-circuits on
Output created:toquarto render: ok (output created). Otherwise strips processing, validating and resolving messages and the percentage progress lines.
Version Control Systems
jj-
Jujutsu VCS. Strips
Hint:lines,Working copy now at:,Parent commit:and rebase counts, all of which arrive on stderr. Max 30 lines. shopify theme push,shopify theme pull-
Keeps only the last 5 lines -- the result and the preview URL. Deliberately not registered for
shopify themeas a whole:shopify theme listis nothing but its answer, and a tail of 5 would cut it.
FILTER STAGES
Each filter applies output through this pipeline, in this order:
filter_stderr - Merges stderr into stdout if configured
strip_ansi - Removes ANSI escape codes (colors, cursor control)
collapse_cr - Reduces carriage-return overwrites to the last state on each line, which is what a terminal would have shown. Unconditional, with no filter attribute: a progress bar carries no newlines at all, so to every stage below it is a single line that
max_linescannot shorten. Runs for commands no filter matches, too: normalising\ris display semantics rather than filtering.match_output - Short-circuits on pattern match, replacing the entire output with a fixed message. Only ever honest for success, when there is nothing left to say: a diagnostic short-circuit deletes precisely what the output was being read for. Patterns want
/m, since they are matched against the whole text rather than line by line.transform - Line-by-line transformation (e.g., strip ls permissions)
strip_lines_matching - Removes lines matching regex patterns
keep_lines_matching - Keeps only lines matching patterns
truncate_lines_at - Truncates each line to N characters, appending
...head_lines / tail_lines - Keeps first/last N lines, and says so:
... N lines omitted ...goes after the kept lines when only the head is kept, and before them when only the tail is kept. Truncating without a marker would leave the model holding a fragment it has no reason to doubt.max_lines - Absolute line limit, appending
... N more lines .... This counts separately from the marker above: two markers in one output are normal and their numbers do not add up to a single total.on_empty - Fallback message when output is empty after filtering
ADDING CUSTOM FILTERS
use MCP::Run::Compress;
my $compressor = MCP::Run::Compress->new;
# Legacy regex-based matching
$compressor->register_filter(
command => '^my-command\b',
strip_lines_matching => [
qr(^\s*$),
qr(^Verbose:),
],
truncate_lines_at => 100,
max_lines => 30,
on_empty => 'my-command: ok',
);
# New parsed_command matching (order-independent flags)
$compressor->register_filter(
parsed_command => {
program => 'my-tool',
subcommand => 'process',
flags => { verbose => 1, output => 1 },
},
strip_lines_matching => [qr(^\s*$)],
max_lines => 50,
);
A filter added to the default table in MCP::Run::Compress belongs in the COMMANDS section above; t/60-filters-doc.t fails until it is there.
PARSED COMMAND APPROACH
Filters can use either regex-based command matching (legacy) or the new parsed_command approach. The parsed approach extracts program, subcommand, and flags using Getopt::Long, enabling order-independent flag matching.
# Matches: git diff --stat, git diff --stat -w 5, git -C /path diff --stat
$compressor->register_filter(
parsed_command => {
program => 'git',
subcommand => 'diff',
flags => { stat => 1 },
},
transform => sub { ... },
);
The flags hash specifies which flags must be present. Flag values are ignored - only presence matters for matching.
Matching a program without a subcommand matches every invocation of that program, so such a filter shadows any program+subcommand filter for the same program: the compressor stops at the first matching parsed filter, and which one that is depends on hash order. kubectl get and a bare kubectl cannot both exist as long as that is true.
SEE ALSO
SUPPORT
Issues
Please report bugs and feature requests on GitHub at https://github.com/Getty/p5-mcp-run/issues.
CONTRIBUTING
Contributions are welcome! Please fork the repository and submit a pull request.
AUTHOR
Torsten Raudssus <getty@cpan.org>
COPYRIGHT AND LICENSE
This software is copyright (c) 2026 by Torsten Raudssus <torsten@raudssus.de> https://raudssus.de/.
This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself.