feat: add row-cap on tool outputs (#249)#305
Closed
dtehan-td wants to merge 2 commits into
Closed
Conversation
Caps tool result sets before they reach the LLM to prevent context blow-ups. Defaults to 1000 rows (DEFAULT_ROW_LIMIT) with a 50000 hard ceiling (MAX_ROW_LIMIT), both env-configurable. Per-tool overrides via YAML (`row_limit`, `max_row_limit`, `bypass_row_cap`, `narrowing_parameters`) or per-profile via `tool_row_limits:` in profiles.yml. Adds a universal `get_all=true` parameter on capped tools as an escape hatch up to the ceiling. Wraps injectable SELECTs with TOP N+1 in handle_base_readQuery and falls back to a Python-side trim for CTEs and registry/cube tools. Truncation metadata (rows_returned, row_limit, hard_ceiling, narrowing_params hint) is attached to the response so clients can prompt the user to narrow. Also adds limits_test_cases.json with `expect:` assertion support in the test runner, unit tests for row_cap helpers, and a README entry for the Graph tools module.
Contributor
|
@remi-td take a look at the code, it turned out to be more complicated that I expected to limit the number of rows. I added a bunch of testing. But if you think the approach is too complicated I will understand. |
Document the row-cap on tool outputs across the three audiences that need it: operators (CONFIGURATION.md — env vars, per-profile tool_row_limits), tool authors (HOW_TO_ADD_YOUR_FUNCTION.md — YAML keys, reserved kwargs, build_truncation_metadata), and client integrators (CLIENT_GUIDE.md — get_all escape hatch and example metadata.truncation payload).
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
DEFAULT_ROW_LIMIT) with a 50000 hard ceiling (MAX_ROW_LIMIT); both are env-configurable.row_limit,max_row_limit,bypass_row_cap,narrowing_parameters) and per-profile overrides viatool_row_limits:inprofiles.yml. A universalget_all=trueparameter is injected on every capped tool as an escape hatch up to the ceiling.handle_base_readQuerywraps injectable SELECTs withTOP N+1, with a Python-side trim fallback for CTEs and registry/cube tools. Truncation metadata (rows_returned,row_limit,hard_ceiling, narrowing-parameter hints) is attached to the response so clients can prompt the user to narrow.Test plan
uv run ruff check src/passesuv run mypy src/passesuv run python -m pytest tests/unit/test_row_cap.pypassesuv run python tests/run_mcp_tests.py "uv run teradata-mcp-server"passes against a live Teradata instance, including the newtests/cases/limits_test_cases.jsonget_all=trueraises the cap toMAX_ROW_LIMITand the truncation metadata appears when results exceed the capbypass_row_cap: trueis not capped and does not exposeget_all