Skip to content

feat: add tool response compression for token optimization (closes #11) - #49

Open
Suhasrv2403 wants to merge 12 commits into
traceloop:mainfrom
Suhasrv2403:feat/tool-response-compression
Open

feat: add tool response compression for token optimization (closes #11)#49
Suhasrv2403 wants to merge 12 commits into
traceloop:mainfrom
Suhasrv2403:feat/tool-response-compression

Conversation

@Suhasrv2403

@Suhasrv2403 Suhasrv2403 commented Jun 22, 2026

Copy link
Copy Markdown

Summary

Implements tool response compression by converting uniform arrays of objects
into a column/row tabular format, reducing token consumption by an estimated
30-60% for large responses.

Problem

All tool functions return arrays of uniform objects where field names repeat
on every row. For a response with 100 traces, field names like model,
provider, and count are duplicated 100 times — wasting tokens on every
AI agent call.

Before:

[
  {"model": "gpt-4", "provider": "openai", "count": 48},
  {"model": "gpt-3.5", "provider": "openai", "count": 12}
]

After:

{
  "columns": ["model", "provider", "count"],
  "rows": [["gpt-4", "openai", 48], ["gpt-3.5", "openai", 12]]
}

Changes

  • src/opentelemetry_mcp/tools/compression.py — new compact_json() utility
    that recursively converts uniform arrays into tabular format
  • src/opentelemetry_mcp/config.py — added compress_responses: bool = True
    to ServerConfig, reads from COMPRESS_RESPONSES env var
  • src/opentelemetry_mcp/server.py — passes config to all 8 tool calls
  • 8 tool files — hooked compact_json() before final json.dumps()
  • tests/test_compression.py — 17 new unit tests
  • .env.example — documented COMPRESS_RESPONSES option

Configuration

Compression is enabled by default. To disable:

COMPRESS_RESPONSES=false

Testing

  • 17 new unit tests covering: basic compression, losslessness, pass-through
    edge cases, nested structures, threshold behavior, and real tool response shapes
  • All 92 tests pass, 2 skipped (pre-existing)
  • ruff format, ruff check, mypy, pytest all green

Notes

  • Compression only applies when savings exceed 5% threshold to avoid overhead
    on small responses
  • Non-uniform arrays (different keys per object) pass through unchanged
  • Recursive implementation handles nested arrays independently

Summary by CodeRabbit

  • New Features

    • Added an optional response-compression setting for trace and search-related outputs.
    • Response payloads can now be returned in a more compact format to reduce size and improve readability in some cases.
    • Updated the example environment file with the new compression option.
  • Bug Fixes

    • Preserved the existing output format when compression is disabled.

@CLAassistant

CLAassistant commented Jun 22, 2026

Copy link
Copy Markdown

CLA assistant check
All committers have signed the CLA.

@coderabbitai

coderabbitai Bot commented Jun 22, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@Suhasrv2403, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 13 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: f7605c70-2c35-44d9-ab7d-4619b97a1b54

📥 Commits

Reviewing files that changed from the base of the PR and between d0e2b98 and 0a9fdc4.

📒 Files selected for processing (3)
  • src/opentelemetry_mcp/config.py
  • src/opentelemetry_mcp/tools/compression.py
  • tests/test_compression.py
📝 Walkthrough

Walkthrough

Adds optional JSON response compression to all MCP tool functions. A new compact_json utility converts uniform lists of dicts into a columnar {columns, rows} format. A compress_responses boolean field is added to ServerConfig (read from COMPRESS_RESPONSES env var, default true). All eight tool functions receive an optional config parameter and apply compression conditionally.

Changes

Response Compression Feature

Layer / File(s) Summary
Config field and compact_json utility
.env.example, src/opentelemetry_mcp/config.py, src/opentelemetry_mcp/tools/compression.py
Adds compress_responses: bool = True to ServerConfig with env parsing, and implements compact_json that rewrites uniform dict lists into {columns, rows} when savings meet the threshold.
Compression wired into all tool functions
src/opentelemetry_mcp/tools/errors.py, src/opentelemetry_mcp/tools/expensive_traces.py, src/opentelemetry_mcp/tools/list_llm_tools.py, src/opentelemetry_mcp/tools/list_models.py, src/opentelemetry_mcp/tools/search.py, src/opentelemetry_mcp/tools/search_spans.py, src/opentelemetry_mcp/tools/slow_traces.py, src/opentelemetry_mcp/tools/trace.py
Each tool function gains an optional config: ServerConfig | None = None parameter and conditionally calls compact_json(result) before returning the JSON string.
Compression tests
tests/test_compression.py
Covers basic tabularization, round-trip reconstruction, pass-through cases (non-uniform keys, thresholds, primitives), recursive nesting, threshold controls, realistic tool response shapes, and config-driven disable.

IDE Project Files

Layer / File(s) Summary
IntelliJ .idea project files
.idea/.gitignore, .idea/inspectionProfiles/profiles_settings.xml, .idea/misc.xml, .idea/modules.xml, .idea/opentelemetry-mcp-server.iml, .idea/vcs.xml
Adds standard IntelliJ/WebStorm project configuration files for the repository.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Poem

🐇 Hop hop, the JSON grows lean,
Columns and rows, a tidy scene!
Uniform dicts? We'll squish them flat,
compact_json takes care of that.
With a env var flag, compress with ease—
This bunny's code aims to please! 🥕

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main change: adding response compression to reduce token usage.
Docstring Coverage ✅ Passed Docstring coverage is 96.15% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@Suhasrv2403
Suhasrv2403 marked this pull request as ready for review June 29, 2026 19:39

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

🧹 Nitpick comments (1)
.idea/misc.xml (1)

3-6: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Machine-specific SDK names may cause portability issues.

The SDK names Python 3.11 (localDEEnv) and Python 3.11 (Quantum) appear to be developer-local environment names. Other contributors opening this project in IntelliJ will need to reconfigure their Python SDK. Consider using a more generic SDK name or documenting the expected local setup. If the team commits .idea/ files, misc.xml is often the most problematic for portability.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.idea/misc.xml around lines 3 - 6, The misc.xml configuration is using
machine-specific Python SDK names, which makes the project settings hard to
share across contributors. Update the Black component and ProjectRootManager
entries so they do not depend on local environment-specific SDK labels, and
align them with a portable project setup or a documented generic SDK name. Check
the IntelliJ project settings entries for Black and ProjectRootManager to ensure
the committed configuration is reusable on other machines.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/opentelemetry_mcp/config.py`:
- Around line 83-84: The COMPRESS_RESPONSES parsing in the config loader is too
permissive because it treats any non-"true" value as False, hiding typos and
malformed input. Update the configuration parsing in the relevant config
initialization code to explicitly validate the COMPRESS_RESPONSES environment
value, accept only recognized boolean strings, and raise or surface a clear
error for invalid values instead of defaulting them to False; use the existing
compression config logic around COMPRESS_RESPONSES in config.py to locate the
fix.

In `@src/opentelemetry_mcp/tools/compression.py`:
- Around line 11-24: The compression logic in the list-handling branch of the
compression helper is skipping nested arrays, so the recursive compression
contract is not being met. Update the compression flow in the function that
inspects list payloads so it does not just copy raw item values into rows;
instead, recursively process nested dict/list values before building the
compressed structure, and make sure the fallback path also preserves recursive
handling for non-uniform lists.

In `@src/opentelemetry_mcp/tools/errors.py`:
- Around line 123-125: The success payload shape is being changed in place by
calling compact_json(result), which can alter fields like error_traces and make
the tool response vary between list[object] and {columns, rows}. Update the
logic in the errors tool so compression produces an explicit alternate
representation instead of mutating the existing payload structure, and keep the
original success contract stable for callers while still honoring
config.compress_responses.

In `@tests/test_compression.py`:
- Around line 254-271: The test in test_compress_responses_disabled should
verify the environment parsing path instead of mutating ServerConfig after
creation. Update ServerConfig.from_env usage so the test sets COMPRESS_RESPONSES
in the environment first, asserts that the parsed config.compress_responses is
False, and then checks the passthrough behavior without compression; use the
ServerConfig.from_env and compact_json symbols to keep the test focused on the
env contract.

---

Nitpick comments:
In @.idea/misc.xml:
- Around line 3-6: The misc.xml configuration is using machine-specific Python
SDK names, which makes the project settings hard to share across contributors.
Update the Black component and ProjectRootManager entries so they do not depend
on local environment-specific SDK labels, and align them with a portable project
setup or a documented generic SDK name. Check the IntelliJ project settings
entries for Black and ProjectRootManager to ensure the committed configuration
is reusable on other machines.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: d235e02c-27ee-4f56-94d7-08e0481b7b42

📥 Commits

Reviewing files that changed from the base of the PR and between 92ff4ca and d0e2b98.

📒 Files selected for processing (18)
  • .env.example
  • .idea/.gitignore
  • .idea/inspectionProfiles/profiles_settings.xml
  • .idea/misc.xml
  • .idea/modules.xml
  • .idea/opentelemetry-mcp-server.iml
  • .idea/vcs.xml
  • src/opentelemetry_mcp/config.py
  • src/opentelemetry_mcp/tools/compression.py
  • src/opentelemetry_mcp/tools/errors.py
  • src/opentelemetry_mcp/tools/expensive_traces.py
  • src/opentelemetry_mcp/tools/list_llm_tools.py
  • src/opentelemetry_mcp/tools/list_models.py
  • src/opentelemetry_mcp/tools/search.py
  • src/opentelemetry_mcp/tools/search_spans.py
  • src/opentelemetry_mcp/tools/slow_traces.py
  • src/opentelemetry_mcp/tools/trace.py
  • tests/test_compression.py

Comment thread src/opentelemetry_mcp/config.py Outdated
Comment thread src/opentelemetry_mcp/tools/compression.py Outdated
Comment on lines +123 to +125
if config and config.compress_responses:
result = compact_json(result)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🗄️ Data Integrity & Integration | 🟠 Major | 🏗️ Heavy lift

Keep the success payload shape stable.

compact_json(result) replaces fields like error_traces in place, so the same tool can return either list[object] or {columns, rows} depending on the payload and savings threshold. The PR context says the server enables this by default, which turns an existing response contract into a data-dependent one for every caller. Make the compact form explicit instead of overwriting the current arrays in place.

🧰 Tools
🪛 ast-grep (0.44.0)

[info] 125-125: use jsonify instead of json.dumps for JSON output
Context: json.dumps(result, indent=2, default=str)
Note: [CWE-116] Improper Encoding or Escaping of Output.

(use-jsonify)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/opentelemetry_mcp/tools/errors.py` around lines 123 - 125, The success
payload shape is being changed in place by calling compact_json(result), which
can alter fields like error_traces and make the tool response vary between
list[object] and {columns, rows}. Update the logic in the errors tool so
compression produces an explicit alternate representation instead of mutating
the existing payload structure, and keep the original success contract stable
for callers while still honoring config.compress_responses.

Comment thread tests/test_compression.py Outdated
Suhasrv2403 and others added 4 commits June 29, 2026 13:11
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants