MCP budget: describe_custom_view_catalog groups measures by source, under the response budget (#4198) - #4272
Merged
Conversation
…ource (#4198) Default default-argument call was 98,173 bytes (#4198's own measurement), three times the tool's 32 KB budget. It is pure static reference data (no server/store read), so the cut groups the 179 measures by source and keeps only key/displayName/kind/unitFamily/validAggregates per measure; source=<name> drills into one source's full detail, full_detail=true returns the original shape unfiltered. /api/catalog (the web Custom Views editor) calls the underlying builder directly, never this MCP method, so it is unaffected - pinned in DarlingComposeTests. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TszxYhJJbTEh4LrZ56NYo3
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FVjn4PBJN71NQXdFo6ZxNQ
…ld CI GitHub did not fire pull_request events for this draft-opened PR. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FVjn4PBJN71NQXdFo6ZxNQ
Merged: dev 172,367 + TC's +472 (describe_custom_view_catalog) = 172,839. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FVjn4PBJN71NQXdFo6ZxNQ
…dDimensions, source=<name> returns it Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TszxYhJJbTEh4LrZ56NYo3
…atalog-default Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TszxYhJJbTEh4LrZ56NYo3
Measured with McpToolsListBudgetTests after merging origin/dev (#4261, #4258, #4265, #4267, #4264, #4266 and #4268) plus this PR's catalog changes. Budget, census and tool-guide classes: 219/219. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FVjn4PBJN71NQXdFo6ZxNQ
erikdarlingdata
enabled auto-merge (squash)
September 25, 2026 13:08
erikdarlingdata
added a commit
that referenced
this pull request
Sep 25, 2026
Resolves the #4198 train's conflicts after #4272 landed: - McpToolsListBudgetTests (Darling and Lite): keep every change-log line; TotalCeilingBytes re-measured on the merged tree (Darling 174,373, Lite 92,041). - McpPayloadContractCensusTests: query_text_truncated keeps dev's files and adds DarlingMcpDataTools.cs for get_query_store_top. - Lite McpQueryTools: dev's get_query_store_regressions preview constant and this branch's get_query_store_top one shared a name in one class; the regressions one is now RegressionsQueryTextPreviewLength. - QueryStoreRegressionsWebDefaultTests: its "no full_text false" check is scoped to the regressions dispatch entry, since get_query_store_top's web entry keeps full_text off by default on purpose. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FVjn4PBJN71NQXdFo6ZxNQ
erikdarlingdata
added a commit
that referenced
this pull request
Sep 25, 2026
…sclosure McpToolsListBudgetTests: keep every change-log line. #4231 adds no head bytes, so TotalCeilingBytes is dev's measured total after #4272 and #4273 (174,373), re-measured on the merged tree. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FVjn4PBJN71NQXdFo6ZxNQ
erikdarlingdata
added a commit
that referenced
this pull request
Sep 25, 2026
…as merged After merging dev, the per-tool fixes for get_blocking (#4267), get_collection_log (#4265), get_query_store_regressions (#4264), get_collection_health (#4268), describe_custom_view_catalog (#4272) and get_query_store_top (#4273) are all in, and get_fleet_overview already fit (CI's stale-exemption message). Every row goes; CI's live run decides. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FVjn4PBJN71NQXdFo6ZxNQ
erikdarlingdata
added a commit
that referenced
this pull request
Sep 25, 2026
…t-read McpToolsListBudgetTests: keep every change-log line. TotalCeilingBytes re-measured on the merged tree: dev after #4272 and #4273 (174,373) plus get_store_host's 616 bytes = 174,989. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FVjn4PBJN71NQXdFo6ZxNQ
This was referenced Sep 25, 2026
erikdarlingdata
added a commit
that referenced
this pull request
Sep 25, 2026
* Add the #4198 MCP read-tool budget pin (part of #4198) McpReadToolBudgetLiveTests reflects over every [McpServerTool] method on every [McpServerToolType] class in the Darling service assembly, excludes write tools/analyze_*/compare_*/audit_config, binds each tool's DI services and server_name generically, and asserts the reply stays under McpResponseBudget.DefaultBytes unless the tool is named in an explicit, byte-stamped exemption roster. A fix lands by deleting its row. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TszxYhJJbTEh4LrZ56NYo3 * MCP budget pin: empty ExemptOffenders now every #4198 per-tool lane has merged After merging dev, the per-tool fixes for get_blocking (#4267), get_collection_log (#4265), get_query_store_regressions (#4264), get_collection_health (#4268), describe_custom_view_catalog (#4272) and get_query_store_top (#4273) are all in, and get_fleet_overview already fit (CI's stale-exemption message). Every row goes; CI's live run decides. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FVjn4PBJN71NQXdFo6ZxNQ * MCP budget pin: get_collection_health is still over on this fixture CI on 08e6e81 measured get_collection_health at 35,145 B, over the 32 KB default. #4268 compacts only healthy collectors with nothing to report, and this fixture's collectors are not healthy, so nothing compacts. The row goes back, under #4198, which stays open for it. Every other exempt tool fits. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FVjn4PBJN71NQXdFo6ZxNQ --------- Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
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.
Part of #4198.
Why
describe_custom_view_catalogreturned 98,173 bytes at default arguments (measured on both the SQL Server and PostgreSQL-target production stores). This tool reads no store: it is static reference data. It is the Custom Views compose catalog: the measures, dimensions, aggregates, units, and viz vocabulary an author needs to build a valid panel. A naive cut risked hiding a real measure or its legal aggregates.What changes
key,displayName,kind,unitFamily, andvalidAggregates.validAggregatesstays per-measure (not hoisted to the source level) because it varies within a source. Measuring all 179 measures: 9 of 52 sources have more than one distinctvalidAggregatesset. No source varies inallowedDimensions.source(new, optional string): drills into one source's full per-measure detail (category, archetype, native/default unit, default aggregate,allowedDimensions,appliesTo) plus that source's own dimensions. An unmatched name returns emptymeasures/dimensionsand anotepointing back at the default call, not an error. This tool has never returned an error, and a typo returns the same shape a caller parses.full_detail(new, optional bool, default false): returns the complete catalog as before: the same flat{measures, dimensions, annotationSources, universalDimensions, unitFamilies, aggregates, timeBuckets, filterOps, viz}shape, every field. Byte-identical to the pre-fix 98,173 bytes (pinned by test).allowedDimensionsis dropped from the compact default, not hoisted. It is uniform across every measure of a source (verified for all 179 measures, 52 sources), sosource=recovers it.appliesTogates nothing at compose time: it is a UI greying hint for the web composer (design D4) and never blocked panel-building.<<GUIDE>>marker (get_tool_guide). The served (tools/list) description stays small.validate_custom_view,create_custom_view, and two other places that point authors at this tool (a custom-alert-rule tool, the MCP system instructions) say only "calldescribe_custom_view_catalogfirst". None assert its shape, so none needed a text change.The web viewer is unaffected
/api/catalog(the Custom Views editor's only catalog fetch, inwwwroot/js/views-api.js) callsDarlingWebEndpoints.BuildCatalogNode()thenBuildComposeCatalogNode()directly. It never calls the MCP tool method (describe_custom_view_catalogis in the/api/readexclusion list). The web editor still gets every measure at full detail, unfiltered and ungrouped.BuildComposeCatalogNode()itself is untouched. The new compact/source-filter logic is a pure re-shape of its output, one layer up, in the MCP tool method only.Extended the existing no-rig
Catalog_CarriesTheComposeSectionpin inDarlingComposeTests.cs. The assertions confirm/api/catalog's compose section still carriesappliesTo,allowedDimensions, andcategoryper measure, with nocompactmarker.#4224 (McpReadToolBudgetLiveTests)
This tool is on #4224's
ExemptOffendersroster (it has no server/store argument to seed a payload from, so it does not fit that live-store harness). #4224 has not merged and is stalled, so the coordinator lifted the wait for this lane.McpReadToolBudgetLiveTestsis not ondev, so this PR does not create or touch it. Whichever of #4224 or this PR merges second must removedescribe_custom_view_catalog's row from that roster. It is redundant with the dedicated coverage this PR adds (DarlingMcpCustomViewCatalogSizeTests). The roster file does not exist until #4224 lands.No Lite twin
Custom Views (and this catalog tool) are Darling-only. Lite has no
DescribeCustomViewCatalogor Custom Views MCP surface (confirmed: no match inLite/Mcp/*.cs). Skipped the common brief's Lite steps and the Lite.Tests full run.Test plan
Rig: reused the stopped
rig-th(port 55983, already UTC), started in the background, confirmed "ready to accept connections". Dropped and recreateddarlingtest/probefirst (this tool needs no rig itself but the full suite does).dotnet build Darling.Tests, 0 Warning(s), 0 Error(s).DarlingMcpCustomViewCatalogSizeTests(new file):full_detail=true: 98,173 bytes, exact match to the MCP read tools have no default response-size budget: at default arguments 12 tools return >50 KB and 3 return >100 KB for one server, more than an agent client's per-result cap #4198 issue's own pre-fix measurement.source=<the widest source>(full detail, one source): under budget too (same test file).DarlingMcpCustomViewToolsSurfaceTests: 31 tests, all pass. Includes 5 new or rewritten tests: compact default shape,full_detailreproducing the original shape,sourcedrill-down, unknownsource, and a losslessness check. The losslessness check verifies every compact-default measure key is reachable at full detail and every source name is a working filter.McpToolsListBudgetTests: updatedDarlingMcpCustomViewTools.txt(measured, not hand-computed) and raisedTotalCeilingBytesby the exact measured growth (+472 bytes), with its own change-log line.DarlingComposeTests.Catalog_CarriesTheComposeSection(extended):/api/catalogstill serves full per-measure detail. Passes.Darling.Testssuite, once, after mergingorigin/devand recreatingdarlingtest: 13,892 total, 0 errors, 0 failed, 47 skipped (pre-existing, env-gated), 1 not-run (same reason).Rig stopped (
pg_ctl stop -m fast) after the run.CHANGELOG entry
SECTION: Fixed
ENTRY:
describe_custom_view_catalogstays under the MCP response budget ([MCP read tools have no default response-size budget: at default arguments 12 tools return >50 KB and 3 return >100 KB for one server, more than an agent client's per-result cap #4198]): The Custom Views compose catalog returned 98 KB by default, three times the budget. It now returns a compact, source-grouped list by default (name, purpose, aggregate/unit vocabulary only). A newsourceargument drills into one source's full detail. A newfull_detailargument returns the complete catalog as before. The web Custom Views editor is unaffected: it reads the full catalog through its own endpoint.REF:
[MCP read tools have no default response-size budget: at default arguments 12 tools return >50 KB and 3 return >100 KB for one server, more than an agent client's per-result cap #4198]: MCP read tools have no default response-size budget: at default arguments 12 tools return >50 KB and 3 return >100 KB for one server, more than an agent client's per-result cap #4198
Generated with Claude Code
https://claude.ai/code/session_01FVjn4PBJN71NQXdFo6ZxNQ