███╗ ███╗ ██████╗██████╗ ██████╗ ████████╗██╗ ██╗
████╗ ████║██╔════╝██╔══██╗ ██╔══██╗╚══██╔══╝██║ ██╔╝
██╔████╔██║██║ ██████╔╝█████╗██████╔╝ ██║ █████╔╝
██║╚██╔╝██║██║ ██╔═══╝ ╚════╝██╔══██╗ ██║ ██╔═██╗
██║ ╚═╝ ██║╚██████╗██║ ██║ ██║ ██║ ██║ ██╗
╚═╝ ╚═╝ ╚═════╝╚═╝ ╚═╝ ╚═╝ ╚═╝ ╚═╝ ╚═╝
mcp-rtk
MCP proxy that cuts 60-90% of tokens from tool responses
Drop it in front of any MCP server. Same tools, way fewer tokens.
Quick start • Presets • Configuration • Contributing presets
The problem
MCP servers return raw API responses. A single list_issues call from GitLab can dump 180K+ tokens of JSON into your context: full user objects with avatar URLs, null fields everywhere, nested metadata nobody asked for. You pay for all of it.
What mcp-rtk does
It sits between Claude and your MCP server as a transparent proxy. Tool calls go through unchanged, but responses get compressed through an 8-stage filter pipeline before they hit your context window.
Claude ←(stdio)→ mcp-rtk ←(stdio)→ upstream MCP server
The LLM gets the same information in a fraction of the tokens.
Install
Quick start
Wrap your existing MCP server command with mcp-rtk --. One line change in your Claude Code config.
Before (~/.claude.json):
After:
mcp-rtk detects the upstream server from the command and loads the matching preset automatically.
Filter pipeline
Every response passes through 8 stages, in order:
| Stage | Effect |
|---|---|
keep_fields |
Whitelist: only retain specified fields |
strip_fields |
Blacklist: recursively remove fields like avatar_url, _links |
condense_users |
{id, name, username, avatar_url, ...} becomes "username" |
strip_nulls |
Drop all null and empty string values |
flatten |
{"data": [...]} becomes [...] |
truncate_strings |
Cap long strings (descriptions, diffs) at N chars |
collapse_arrays |
Keep first N items, append "... and X more" |
custom_transforms |
Regex-based string replacements |
Even without a preset, generic defaults apply: null stripping, user condensing, flattening, and field removal. This alone typically saves 30-40%.
Presets
Presets are TOML files with tool-specific filter rules. mcp-rtk ships with community-maintained presets and auto-detects which one to use based on the upstream command.
| Preset | Detected from | Tools covered |
|---|---|---|
gitlab |
gitlab-mcp, gitlab |
45+ tools across MRs, issues, pipelines, commits, projects, labels, releases |
grafana |
mcp-grafana, grafana |
15+ tools for dashboards, datasources, Prometheus, Loki |
You can force a specific preset:
What a preset looks like
Each preset defines per-tool rules that get merged on top of the generic defaults. Here's an excerpt from the GitLab preset:
[]
= ["iid", "title", "state", "author", "source_branch", "target_branch", "web_url"]
= 20
= true
[]
= ["old_path", "new_path", "diff", "new_file", "deleted_file"]
= 2000
= 50
[]
= ["iid", "title", "state", "author", "labels", "assignees", "web_url"]
= 20
= true
The full GitLab preset covers merge requests, pipelines, jobs, issues, commits, files, projects, members, labels, releases, and events.
Creating your own preset
If you use an MCP server that doesn't have a built-in preset, you can write your own as a TOML config:
# ~/.config/mcp-rtk/my-server.toml
[]
= true
= true
= 800
= 25
= ["avatar_url", "_links", "metadata"]
= true
[]
= ["id", "name", "status", "created_at"]
= 15
[] # glob pattern — matches all get_ tools
= 1500
= ["internal_id", "legacy_data"]
Then pass it with --config:
Contributing a preset
Found good filter rules for an MCP server you use? Submit a preset so others can benefit too.
- Create a TOML file in
config/presets/named after the server (e.g.,github.toml) - Add your tool-specific filter rules (look at
gitlab.tomlorgrafana.tomlfor reference) - Register it in
src/config.rsin thePRESETSarray with detection keywords - Open a merge request
The more MCP servers get presets, the more tokens everyone saves.
Configuration
For power users who want to tweak filter behavior beyond what presets provide.
[]
= true
= true
= 500
= 20
= ["avatar_url", "_links", "time_stats"]
= true
= [
{ = "https://gitlab\\.com/[^ ]+", = "[link]" }
]
[]
= 2000
[]
= ["iid", "title", "state", "author", "source_branch", "target_branch"]
= 15
[]
= true
= "~/.local/share/mcp-rtk/metrics.db"
User config overrides preset rules. Tool-specific strip_fields and custom_transforms are concatenated with defaults, everything else replaces them.
Tool names support glob patterns: * matches any sequence, ? matches a single character. Exact matches always take priority over patterns.
Commands
mcp-rtk gain
See how many tokens you've saved.
mcp-rtk discover
Scan your Claude Code session logs to find MCP servers that aren't proxied yet and estimate how many tokens you could save.
mcp-rtk presets
Browse the built-in presets without digging through source code.
mcp-rtk validate-preset
Check a preset or config file for syntax errors and potential issues before using it.
mcp-rtk dry-run
Test filters on JSON from stdin without running a proxy. Stats go to stderr, filtered JSON to stdout.
|
|
Safety
Responses are filtered, never blocked. A few guardrails keep things predictable:
- 10 MB response cap: oversized responses get truncated before parsing
- 128-level recursion limit, matching serde_json's default
- String truncation respects UTF-8 character boundaries
- Non-JSON responses pass through with only string truncation applied
- Images and resources are forwarded unchanged