token-filter-mcp
by VMexicano
README.md
<div align="center">
# π§Ή token-filter-mcp
**Your LLM is wasting 80% of its context window on noise.**<br>
**This fixes that.**
[](https://www.npmjs.com/package/token-filter-mcp)
[](./LICENSE)
[](https://nodejs.org)
[](https://modelcontextprotocol.io)
<br>
<img src="https://img.shields.io/badge/test_runners-92%25_savings-success?style=for-the-badge" alt="test runners 92% savings"/>
<img src="https://img.shields.io/badge/file_reads-94%25_savings-success?style=for-the-badge" alt="file reads 94% savings"/>
<img src="https://img.shields.io/badge/git_ops-89%25_savings-success?style=for-the-badge" alt="git ops 89% savings"/>
<br><br>
An MCP server that sits between your AI coding assistant and its tools,<br>
intelligently compressing outputs before they consume your precious context.<br>
**Longer sessions. Better reasoning. Lower costs.**
</div>
---
<br>
## πΈ The Problem Nobody Talks About
Every time your AI assistant runs a command, it dumps the **entire raw output** into its context window:
```diff
+ β src/auth.test.ts (14 tests) β you don't need this
+ β src/utils.test.ts (8 tests) β or this
+ β src/payments.test.ts (12 tests) β or this
+ β src/users.test.ts (10 tests) β or this
- β src/orders.test.ts (3 tests) β THIS is what matters
- β should validate quantity > 0
- Expected: error
- Received: success
```
The vast majority of tool output is noise: tests that pass, git headers, resolution trees, progress bars, whitespace. **~80% of what goes into the context window is information the LLM will never act on.**
That noise eats your context window, degrades reasoning quality, and costs you money.
<br>
## β‘ The Solution
<table>
<tr>
<td width="50%">
### β Without token-filter-mcp
- Context fills up fast
- LLM loses track of conversation
- Paying for tokens it ignores
- Sessions hit context limit early
- Reads 14 lines to find 1 failure
</td>
<td width="50%">
### β
With token-filter-mcp
- Context stays lean
- LLM maintains coherence longer
- Only paying for useful tokens
- Sessions last significantly longer
- Reads exactly the failure, acts immediately
</td>
</tr>
</table>
> **token-filter-mcp** intercepts every tool output and applies intelligent, context-aware filtering β returning only what the LLM actually needs to make decisions.
>
> **No configuration needed. No changes to your workflow. Just plug it in.**
<br>
## π― Real Results
<table>
<tr>
<th>Scenario</th>
<th>Without filter</th>
<th>With filter</th>
<th>Savings</th>
</tr>
<tr>
<td><code>npm test</code> (57 tests, all pass)</td>
<td>295 chars / 14 lines</td>
<td>23 chars / 1 line</td>
<td><b>π’ 92%</b></td>
</tr>
<tr>
<td><code>npm test</code> (3 failures)</td>
<td>~5,200 chars</td>
<td>~480 chars</td>
<td><b>π’ 91%</b></td>
</tr>
<tr>
<td>File read (signatures mode)</td>
<td>7,992 chars / 243 lines</td>
<td>483 chars / 9 lines</td>
<td><b>π’ 94%</b></td>
</tr>
<tr>
<td>20 repeated log lines</td>
<td>312 chars / 22 lines</td>
<td>33 chars / 2 lines</td>
<td><b>π’ 89%</b></td>
</tr>
<tr>
<td>Long unknown command (150 lines)</td>
<td>3,492 chars / 151 lines</td>
<td>2,342 chars / 101 lines</td>
<td><b>π‘ 33%</b></td>
</tr>
</table>
> Average savings across real-world tool outputs: **60-90% fewer tokens consumed**
<br>
## π§ How It Works
```mermaid
flowchart LR
A[π€ LLM Agent] -->|tool call| B[π§Ή token-filter-mcp]
B -->|execute| C[π» System]
C -->|raw output| B
B -->|filtered output| A
style B fill:#7c3aed,stroke:#5b21b6,color:#fff
style A fill:#2563eb,stroke:#1d4ed8,color:#fff
style C fill:#059669,stroke:#047857,color:#fff
```
<table>
<tr>
<td>
**1οΈβ£ Detect** β Identifies what command was run (test runner? git? linter?)
**2οΈβ£ Execute** β Runs the command and captures full output
**3οΈβ£ Filter** β Applies the optimal strategy for that command type
**4οΈβ£ Verify** β Ensures no errors or actionable info was removed
**5οΈβ£ Return** β Sends compressed output to the LLM
</td>
</tr>
</table>
### π¨ Contextual Detection
The server doesn't blindly truncate. It **understands what you ran** and applies the right strategy:
| It detects... | And does this... |
|:---|:---|
| π§ͺ Test runners (jest, vitest, pytest, cargo test, go test) | Strips passing tests. Shows only failures with location + expected/received |
| π `git status` | Converts to `M 3 \| A 1 \| D 0 \| ? 2` + file list |
| π `git diff` | Removes repeated headers, keeps only hunks with Β±3 context |
| π `git log` | One-liner: `abc1234 feat: add auth (2h ago)` Γ 15 max |
| π Linters (tsc, eslint, biome, ruff) | Groups errors by rule/file, omits clean files |
| π¦ Package installs | Returns `ok + 847 packages` instead of the resolution tree |
| β Unknown commands | Conservative: deduplicate + truncate to 100 lines |
### π‘οΈ Zero Information Loss
The #1 design principle: **never hide an error.**
```
β
Lines matching error patterns (FAIL, Error:, TypeError, panic...) β NEVER removed
β
Non-zero exit codes β full error output preserved
β
Parser can't understand format β returns raw output
β
passthrough mode available for when you need everything
```
<br>
## π Installation
<details open>
<summary><b>Using npx (recommended, zero install)</b></summary>
Add this to your MCP client config β that's it:
```json
{
"mcpServers": {
"token-filter": {
"command": "npx",
"args": ["-y", "token-filter-mcp"]
}
}
}
```
</details>
<details>
<summary><b>Global install</b></summary>
```bash
npm install -g token-filter-mcp
```
```json
{
"mcpServers": {
"token-filter": {
"command": "token-filter-mcp"
}
}
}
```
</details>
<br>
### π Where does the config go?
| Client | Config file |
|:---|:---|
| **Kiro** | `.kiro/settings/mcp.json` or `~/.kiro/settings/mcp.json` |
| **Claude Desktop** | `claude_desktop_config.json` |
| **Cursor** | `.cursor/mcp.json` |
| **Any MCP client** | Wherever it reads `mcpServers` config |
<br>
## π§ 7 Tools, One Purpose
<details open>
<summary><h3>β‘ <code>filtered_shell</code> β Run anything, get only what matters</h3></summary>
```json
{ "command": "npm test", "filter_level": "normal" }
```
| Level | Behavior |
|:---|:---|
| `normal` | Smart filtering with sensible defaults |
| `aggressive` | 50% additional reduction for tight context budgets |
| `passthrough` | Raw output when you need everything (capped at 200KB) |
</details>
<details>
<summary><h3>π <code>filtered_read</code> β Read files without the bloat</h3></summary>
```json
{ "path": "src/app.ts", "mode": "signatures" }
```
| Mode | What it returns |
|:---|:---|
| `full` | Content minus blank blocks, license headers, grouped imports |
| `signatures` | Only declarations β no implementation bodies |
| `relevant` | Only sections matching `focus` pattern with Β±10 lines context |
Supports: TypeScript, JavaScript, Python, Rust, Go
</details>
<details>
<summary><h3>π <code>filtered_grep</code> β Search without the wall of text</h3></summary>
```json
{ "pattern": "useState", "path": "src", "group_by": "file", "max_results": 20 }
```
Results grouped by file, deduplicated, with context lines. Uses ripgrep when available.
</details>
<details>
<summary><h3>π§ͺ <code>smart_test</code> β Tests that report only what broke</h3></summary>
```json
{ "command": "npm test" }
```
**All pass:**
```
[PASS] 47/47 tests passed (3.2s)
```
**Failures:**
```
[PASS] 44/47 tests passed
[FAIL] 3 failures:
1. src/auth.test.ts:42 β "should refresh token"
Expected: 200
Received: 401
2. src/payments.test.ts:89 β "should validate 3DS"
TypeError: Cannot read property 'status' of undefined
at processPayment (src/payments.ts:156)
```
Auto-detects: Jest, Vitest, pytest, cargo test, go test
</details>
<details>
<summary><h3>πΏ <code>smart_git</code> β Git without the verbosity</h3></summary>
```json
{ "operation": "status" }
```
| Operation | What you get |
|:---|:---|
| `status` | `M 3 \| A 1 \| D 0 \| ? 2` + file list |
| `diff` | Only hunks with changes, no header spam |
| `log` | `abc1234 feat: add auth (2h ago)` Γ 15 |
| `commit` | `ok abc1234` |
| `push` | `ok main β origin/main` |
| `pull` | `ok +3 files, 47 insertions` |
</details>
<details>
<summary><h3>π± <code>smart_adb</code> β Drive Android without screenshots + vision</h3></summary>
```json
{ "operation": "dump", "device": "emulator-5554" }
```
| Operation | What it does |
|:---|:---|
| `dump` | Compact accessibility tree: resource-id, text, clickable, tap-center |
| `tap` | Resolve `resource_id`/`text`/`content_desc` to its bounds center and tap it |
| `tap_xy` | Tap raw coordinates (last resort, e.g. a map/canvas view) |
| `key` | Symbolic `KEYCODE_*` keyevent only β raw numeric codes are rejected |
| `type` | Send text to the focused field |
| `swipe` | Swipe from `(start_x,start_y)` to `(end_x,end_y)` |
| `long_press` | Long-press a locator (`resource_id`/`text`/`content_desc`) or raw x/y |
| `install` / `uninstall` | Install an APK from a local path / remove by package name |
| `logcat` | Recent logcat output pre-filtered to noteworthy lines (error/warning/fatal/assert level, plus known failure patterns) |
Replaces the "screenshot β vision β guess coordinates β tap β screenshot again" loop with cheap structured text.
</details>
<details>
<summary><h3>π <code>metrics_summary</code> β Check your actual savings on demand</h3></summary>
```json
{ "tool": "smart_git", "limit": 100 }
```
Aggregates `~/.config/token-filter-mcp/metrics.jsonl` (plus rotated history) into invocation count, raw vs filtered chars, overall savings %, and a per-tool breakdown sorted by chars saved β without reading the JSONL file by hand.
</details>
<br>
## βοΈ Configuration (Optional)
> Works great out of the box. Customize only if you want to.
<details>
<summary><b>Per-project config</b> β <code>.token-filter.json</code></summary>
```json
{
"defaults": {
"max_output_lines": 100,
"test_show_passes": false,
"git_log_max": 15,
"diff_context_lines": 3,
"dedup_threshold": 3
},
"commands": {
"my-custom-script.sh": { "filter_level": "passthrough" }
},
"metrics": { "enabled": true }
}
```
</details>
<details>
<summary><b>Global config</b> β <code>~/.config/token-filter-mcp/config.json</code></summary>
Same schema. Project config overrides global. Global overrides built-in defaults.
</details>
<br>
## π Built-in Observability
<details>
<summary>View metrics details</summary>
When enabled, every invocation is logged to `~/.config/token-filter-mcp/metrics.jsonl`:
```json
{
"tool": "smart_test",
"command": "npm test",
"rawChars": 5200,
"filteredChars": 480,
"savingsPercent": 90.7,
"strategy": "test_result_filter",
"filterDurationMs": 3,
"timestamp": "2026-06-30T15:30:00Z"
}
```
Auto-rotated at 5MB, max 5 history files.
**What it tracks:**
- Real savings per tool and command type
- Which filters are most effective
- Passthrough re-invocations (signal that a filter might be too aggressive)
Query it anytime with the `metrics_summary` tool instead of reading the JSONL by hand.
</details>
<br>
## π‘οΈ Guarantees
| Guarantee | Detail |
|:---|:---|
| π **Zero loss** | Errors, test failures, and changes are never filtered out |
| β‘ **< 50ms overhead** | Filtering adds negligible latency vs raw execution |
| πͺ **Safe fallback** | Unknown commands get conservative treatment, not silence |
| π **No lock-in** | Standard MCP protocol β works with any compliant client |
| π **No network** | Everything runs locally over stdio. Your code never leaves your machine |
<br>
## π οΈ Development
```bash
git clone https://github.com/VMexicano/token-filter-mcp
cd token-filter-mcp
npm install
npm run build
npm test # 57 tests, all passing
```
<br>
---
<div align="center">
**The best token is the one you never spend.**
<br>
Made with π by [Victor Mexicano](https://github.com/VMexicano)
</div>
TDQS
A3.9/5.0
Scored across 5 tools
Disambiguation5/5
Each tool targets a distinct operation: grep (search), read (file reading), shell (command execution), git (version control), test (test execution). No overlap in purpose.
Naming Consistency3/5
Tools use two different prefixes: 'filtered_' for grep/read/shell and 'smart_' for git/test. While each group is internally consistent, the mix of prefixes reduces overall consistency.
Tool Count5/5
With 5 tools, the server covers essential development operations without being bloated. Each tool serves a clear, non-redundant purpose.
Completeness4/5
The tool set covers search, reading, shell execution, git, and testingβcore developer tasks. Minor gaps like file writing or editing are acceptable given the focus on token-efficient inspection.
Maintenance
ActivityMaintained
ResponsivenessNo issues