Token Meter

Token Meter / Guides / Reduce large MCP responses

Cut your MCP
responses down to size.

Knowing which MCP tool is heavy is only half the job — see which MCP server is eating your tokens for that half. This guide is the other half: the exact, code-verified fix menu behind Token Meter's oversized_tool_response audit detector and trim-suggestions.ts, and how to prove a fix actually shrank the average instead of just assuming it did.

Updated 2026-07-15 · Covers token-meter audit's D2 detector and trim-suggestions.ts's LARGE_RESPONSE / REPEATED_BINARY patterns

Problem

You've identified the tool — maybe [fs-mcp] read_file, maybe your own Read tool on a directory of screenshots — and you know it's averaging thousands of tokens per call. Now what? "Make it return less" isn't an action you can type into a config file. Different tools need different fixes: a search tool needs a narrower query, a file reader needs field filtering, a directory full of PNGs needs an exclude pattern — and Token Meter never saw the arguments those calls were made with, so it can't just tell you "add limit: 20 here." You need to know which fix applies to this tool's shape, and then a way to confirm the average actually dropped a week later, not just a feeling that it should have.

Cause

Every tool call's response size is estimated at ingest (response_tokens_est, stored per row in tool_events). computeTrimSuggestions()'s LARGE_RESPONSE query (src/trim-suggestions.ts) groups those rows by (tool_name, mcp_server) and flags any pair averaging ≥5,000 tokens/call over ≥5 calls in the window. The oversized_tool_response detector (D2 of 6 in token-meter audit, src/audit/detectors/oversized-tool-response.ts) doesn't re-run that query — it calls the same function and turns its large_response-kind results into ranked findings, so "large" means the identical thing in both the free CLI audit and the Pro dashboard's trim-suggestions panel.

src/audit/config.ts also pre-declares OVERSIZED_RESPONSE_PERCENTILE (0.95) next to the absolute floor, apparently anticipating a second, relative check — "large for what this specific project usually sees," not just "large in absolute terms." That check does not exist yet: computeTrimSuggestions() computes no percentile at all, so the detector only ever applies the flat 5,000-token/5-call bar. A tool that's unusually large for your project but still under 5,000 tokens on average won't be flagged — see Limitations.

The reason the fixes below are "shaped like the tool's name" rather than "here's the exact argument to change" is a deliberate privacy invariant: tool_events never stores the arguments a call was made with (see ToolEvent in src/types.ts) — only tool_name, mcp_server, response size/latency, and (for path-like arguments only) file_ext. Token Meter can prove a tool runs large; it cannot see the query/limit/filter arguments that produced that size, so it infers a fix from the tool's name instead of an inspected schema.

Command

1. Rank the candidates — token-meter audit

Flags verified against src/cli.ts. --days defaults to 7 and is clamped to your tier's history cap; --limit defaults to 5 in terminal mode, 20 with --json:

token-meter audit --days 7 --source all --limit 10

# machine-readable, keeps every finding's metrics field for scripting
token-meter audit --days 7 --source all --limit 10 --json

A pair reaches high confidence only at ≥20 calls in the window; below that it's capped at medium, because a couple of unusually large calls can still swing a small-sample average.

2. See the binary/asset-file variant the CLI doesn't surface — Pro dashboard

computeTrimSuggestions() actually returns three suggestion kinds — large_response, repeated_binary, high_latency — but D2 filters to only large_response (.filter((s) => s.kind === 'large_response') in oversized-tool-response.ts). The repeated_binary kind — reading .png/.jpg/.pdf/etc. files as text repeatedly — never reaches the free CLI audit at all. It's only reachable through the Pro dashboard's endpoint (local machine, no cloud call, gated by getEntitlement()):

curl -s "http://localhost:8765/api/trim-suggestions?days=7"

Requires token-meter serve running and a Pro/Pro+ license activated — Free returns HTTP 402.

3. Verify the fix, a week later — same command, compare the numbers

Re-run the exact audit command from step 1 after you apply a fix. Match findings by toolName + mcpServer in the two reports, not by idcomputeFindingId() (src/audit/finding-id.ts) hashes periodStart/periodEnd into every id, so the same tool audited over two different 7-day windows always produces two different ids even when nothing about the tool changed. Compare metrics.meanTokens across the two runs instead — that's the number the fix should have moved.

Synthetic output

Fabricated example numbers below — not real user data — to show the shape of each command's output.

token-meter audit --days 7 (terminal, 2 of 4 findings shown)

TOKEN METER AUDIT — LAST 7 DAYS

Sources
claude-code: available (2104 records analyzed, 100% of window covered)
codex: unavailable — no data ingested yet

Confirmed usage
Tokens: 540.2k total (in 195.0k, out 76.0k, cache 269.2k)
Estimated cost: $8.1200

Efficiency signals
Findings: 4
Cost associated: $0.9325
Confidence: medium

1. [fs-mcp] read_file responses averaging 8k tokens
Source: claude-code
Project: /home/you/projects/docs-bot
Session: -
Tool: read_file
Evidence: [fs-mcp] read_file returns ~8,000 tokens/call on average (62 calls in 7d window; max 21,000). Configure `fields` or `limit` on [fs-mcp] read_file to reduce response size (est. 198,400 tokens/week saved).
Confidence: high
Suggested action: Pre-filter [fs-mcp] read_file's output to only the fields/lines actually needed (e.g. request specific fields, or pipe through `grep`/`head`) instead of returning the full payload.

2. [internal-search] search_docs responses averaging 6.2k tokens
Source: claude-code
Project: /home/you/projects/docs-bot
Session: -
Tool: search_docs
Evidence: [internal-search] search_docs returns ~6,200 tokens/call on average (14 calls in 7d window; max 9,800). Configure `fields` or `limit` on [internal-search] search_docs to reduce response size (est. 34,720 tokens/week saved).
Confidence: medium
Suggested action: Narrow [internal-search] search_docs's query/filter scope instead of searching or listing broadly.

token-meter audit --days 7 --json (one finding, full shape)

{
  "id": "3f7a9c21b6d40e18",
  "rank": 1,
  "type": "oversized_tool_response",
  "title": "[fs-mcp] read_file responses averaging 8k tokens",
  "description": "[fs-mcp] read_file returns ~8,000 tokens/call on average (62 calls in 7d window; max 21,000). Configure `fields` or `limit` on [fs-mcp] read_file to reduce response size (est. 198,400 tokens/week saved).",
  "source": "claude-code",
  "project": "/home/you/projects/docs-bot",
  "sessionId": null,
  "toolName": "read_file",
  "metrics": {
    "toolName": "read_file",
    "mcpServer": "fs-mcp",
    "callCount": 62,
    "meanTokens": 8000,
    "maxTokens": 21000
  },
  "estimatedCostUsd": 0.7936,
  "costLabel": "cost_associated",
  "confidence": "high",
  "evidence": [
    "[fs-mcp] read_file returns ~8,000 tokens/call on average (62 calls in 7d window; max 21,000).",
    "Configure `fields` or `limit` on [fs-mcp] read_file to reduce response size (est. 198,400 tokens/week saved)."
  ],
  "recommendations": [
    "Pre-filter [fs-mcp] read_file's output to only the fields/lines actually needed (e.g. request specific fields, or pipe through `grep`/`head`) instead of returning the full payload.",
    "Summarize or post-process [fs-mcp] read_file's response before it enters the model context, if the full payload isn't needed downstream.",
    "Check whether repeated [fs-mcp] read_file calls return duplicate or already-seen context that could be deduplicated or cached."
  ],
  "costEventIds": ["tool:read_file:fs-mcp"]
}

curl "http://localhost:8765/api/trim-suggestions?days=7" (Pro, repeated_binary kind — not in CLI audit)

{
  "days": 7,
  "count": 3,
  "suggestions": [
    {
      "kind": "repeated_binary",
      "tool_name": "Read",
      "mcp_server": null,
      "evidence": "Read read .jpg, .png files 34 times combined in 7d (avg 3,100 tokens/call). Binary/asset files rarely need to be read as text — consider an exclude pattern.",
      "savings_tokens_per_week": 52700,
      "savings_usd_per_week": 0.2108,
      "action_text": "Add an exclude glob pattern like `**/*.{jpg,png}` to Read in your Claude Code settings to avoid reading .jpg, .png files.",
      "calls": 34,
      "avg_tokens": 3100
    }
  ]
}

Interpretation

Actions

buildRecommendations() (src/audit/detectors/oversized-tool-response.ts) picks a fix set from the tool's name alone — matched against two regexes — because that's the only shape hint available without an argument schema. Check which bucket your flagged tool falls into first:

  1. Search/list-shaped — name matches /search|grep|find|query|list/: narrow the query/filter scope instead of searching broadly; use a limit/ max_results/top_k argument if the tool exposes one; paginate across multiple calls instead of requesting everything at once.
  2. Read/fetch/exec-shaped — name matches /read|get|fetch|cat|show|view|download|export|bash|exec|run|shell|command/: request specific fields instead of the full payload, or pipe through grep/head where the tool supports it.
  3. Neither pattern matches (an opaque or custom-named MCP tool) — Token Meter doesn't guess at arguments it can't confirm exist. The only recommendation you'll get is "review why this returns a large payload and whether the caller can request less of it." That's the honest limit of a name-only heuristic, not a missing feature.
  4. Always, regardless of shape — once a tool is confirmed to run large, ask whether the full response is even used downstream. If it's read once and mostly discarded, a summarization or post-processing pass before the payload enters context is worth more than tuning the call itself.
  5. If the tool matched either shape above, also check whether repeated calls in the same session return duplicate or already-seen context — that's the repeated_similar_tool_calls (D4) signal. Read its argument-approximation caveat in Limitations before treating a D4 finding as proof of an identical call.
  6. Binary/asset files (REPEATED_BINARY, step 2 above) — once file_ext confirms the extensions (png/jpg/pdf/zip/mp4/font files/etc., the full list is BINARY_EXTENSIONS in trim-suggestions.ts), add the exact exclude glob the suggestion's action_text gives you (e.g. **/*.{jpg,png}) to your Claude Code settings. If file_ext is NULL on the flagged rows (older data ingested before that column existed, or a call with no path-like argument to extract an extension from), the same detector falls back to a plain "called ≥10 times" heuristic on read-named tools (HIGH_FREQ_READ_THRESHOLD) instead — re-run token-meter ingest --force to backfill file_ext and get the real extension list rather than a guess.
  7. Verify it worked. Re-run token-meter audit next week. Success looks like either the (toolName, mcpServer) pair dropping out of the report entirely (it fell below the 5-call or 5,000-token bar) or metrics.meanTokens being materially lower than the run before. Match by tool + server, not by finding id — see Command, step 3.

Limitations

← Token Meter home · Source on GitHub · Full MCP server docs