fix(mcp_semantic_filter): keep tool names whole in filter response header - #32282
Conversation
…ader The x-litellm-semantic-filter-tools response header was sliced mid-name at MAX_MCP_SEMANTIC_FILTER_TOOLS_HEADER_LENGTH with a trailing "...", so the admin UI test panel rendered the last selected tool name chopped. Truncate the CSV at a tool name boundary instead so the header only ever carries complete names, and note in the test panel how many selected tools did not fit in the header
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
Greptile SummaryThis PR fixes the
Confidence Score: 5/5Safe to merge — the change is narrowly scoped to header truncation logic with no impact on the request/response path or authentication. The truncation helper is mathematically correct across all boundary cases (exact fit, mid-name cut, single name exceeding cap, empty input), the hook wiring is a straightforward replacement, the UI addition is a single conditional render, and the new tests are fully mocked and cover the regression path. No auth, database, or critical-path code is touched. No files require special attention.
|
| Filename | Overview |
|---|---|
| litellm/proxy/hooks/mcp_semantic_filter/hook.py | Adds _truncate_csv_at_tool_name_boundary helper and replaces mid-name slice+ellipsis with it; logic is correct for all boundary cases. |
| tests/test_litellm/proxy/_experimental/mcp_server/test_semantic_tool_filter.py | Adds two new unit tests: one async regression test for the hook and one synchronous boundary-case test for the helper; all mocked, no real network calls. |
| ui/litellm-dashboard/src/components/Settings/AdminSettings/MCPSemanticFilterSettings/MCPSemanticFilterTestPanel.tsx | Adds a '+N more selected tools not shown' note when the header list is shorter than the reported selected count; straightforward conditional render. |
| ui/litellm-dashboard/src/components/Settings/AdminSettings/MCPSemanticFilterSettings/MCPSemanticFilterTestPanel.test.tsx | Extends existing test with a negative assertion and adds a new test for the '+N more' note; no existing assertions are weakened. |
Reviews (2): Last reviewed commit: "fix(mcp_semantic_filter): keep tool name..." | Re-trigger Greptile
|
Note on the "+N more selected tools not shown" text this PR adds to the test panel: it is a static note, deliberately. The browser only receives the capped header and the names past the 150 char limit are dropped server side, so there is nothing client side to expand into. LIT-4228 tracks the follow-up of returning the full selected tool list in a response body (a dedicated test endpoint or a field on the response the panel already reads) so the panel can list every selected tool, while the header stays capped and whole-name-only for curl and script consumers |
Relevant issues
Linear ticket
Resolves LIT-4215
Pre-Submission checklist
Please complete all items before asking a LiteLLM maintainer to review your PR
@greptileaiand received a Confidence Score of at least 4/5 before requesting a maintainer reviewDelays in PR merge?
If you're seeing a delay in your PR being merged, ping the LiteLLM Team on Slack (#pr-review).
Screenshots / Proof of Fix
The
x-litellm-semantic-filter-toolsresponse header is capped atMAX_MCP_SEMANTIC_FILTER_TOOLS_HEADER_LENGTH(default 150) characters. Before this change the cap sliced the CSV mid-name and appended..., so the semantic filter test panel in the admin UI rendered the last Selected Tools entry as a chopped name such asSP.... After this change the header only carries complete tool names and the panel says how many selected names did not fitReproduced and verified on a live proxy on localhost:4000 backed by Postgres, hitting the real Bedrock and OpenAI APIs (Claude Haiku 4.5 for the completion, text-embedding-3-small for the semantic router). Proxy config:
mcp_semantic_tool_filterenabled withtop_k: 8,similarity_threshold: 0.05, and two MCP servers with long aliases (network_metrics_query_mcp,site_inventory_lookup_mcp, both pointing athttps://mcp.deepwiki.com/mcp) so the selected tool name CSV exceeds 150 charspython litellm/proxy/proxy_cli.py --config lit4215_repro_config.yaml --detailed_debugBefore (unfixed
litellm_internal_staging, header is exactly 150 chars and the 4th name is chopped tonetwork_metrics_query_mc...):After (this branch, same request; header is 122 chars, every name complete, the two names that do not fit are dropped whole):
Both runs returned a real completion from Bedrock (
"model":"bedrock-invoke-haiku-4-5", finish_reason stop)UI check for the admin panel (Settings, Admin Settings, MCP Semantic Filter, Test tab): the Selected Tools list renders each header entry verbatim. The two screenshots below drive the real
MCPSemanticFilterTestPanelwith the before/after header from the curl run above (x-litellm-semantic-filter: 6->5plus the tools CSV), since the live panel test flow emits these headers through the responses MCP path that LIT-4214 restores. Before the fix the list ends in the chopped entrynetwork_metrics_query_mc...with no explanation; after the fix every listed name is complete and a "+2 more selected tools not shown" note accounts for the two names the capped header droppedBefore (chopped final tool name, no explanation):
After (whole tool names plus a note for the ones that did not fit):
Type
🐛 Bug Fix
Changes
SemanticToolFilterHook.async_post_call_response_headers_hookused to enforce the nginx safe header cap by slicing the tool names CSV mid-name and appending.... The new module level helper_truncate_csv_at_tool_name_boundarydrops any name that does not fit whole, so the header always carries complete names in their original order; when not even one name fits the header is omitted rather than emitting a partial nameMCPSemanticFilterTestPanelnow renders a secondary "+N more selected tools not shown" note when the parsed header carries fewer names than the selected tool count fromx-litellm-semantic-filter, so the shortened list reads as intentional instead of looking truncatedRegression tests:
test_semantic_filter_headers_hook_emits_only_complete_tool_namesfails on the old slicing behavior (the last emitted entry was a chopped name) and passes with the fix;test_truncate_csv_at_tool_name_boundary_edgespins the boundary cases (exact fit at a comma, mid-name cut, single name longer than the cap). The panel test asserts the note appears when names are missing and stays hidden when the list is completeLink to Devin session: https://app.devin.ai/sessions/f03da2725ec94d28b3facf766871b102