fix(mcp): semantic tool filter now transforms tools to Chat Completions format - #32606
Conversation
_process_mcp_tools_to_openai_format defaulted target_format to
"responses", so tools passed through the semantic filter got the
flat Responses-API shape instead of the nested {type, function}
Chat Completions shape. This broke hosted_vllm's strict schema
validation on /v1/chat/completions.
Add a target_format param (default preserved for existing callers)
and have the semantic filter hook explicitly request "chat".
Fixes BerriAI#32281 (comment from brian-sbc confirming persistence in the
semantic filter path after BerriAI#32285/BerriAI#32282 landed).
Greptile SummaryThis PR fixes a schema mismatch in the MCP semantic tool filter path: tools were being transformed to the flat Responses API shape (
Confidence Score: 4/5The change is narrow, backward-compatible, and addresses a real schema mismatch on the semantic filter path. Existing callers are unaffected by the defaulted parameter. The fix is correct and well-scoped:
|
| Filename | Overview |
|---|---|
| litellm/responses/mcp/litellm_proxy_mcp_handler.py | Adds target_format parameter (default "responses") to _process_mcp_tools_to_openai_format, threading it through to the existing _transform_mcp_tools_to_openai call. Default preserved; no existing callers affected. |
| litellm/proxy/hooks/mcp_semantic_filter/hook.py | Passes target_format="chat" to _process_mcp_tools_to_openai_format so the semantic filter hook receives tools in the Chat Completions shape required by /v1/chat/completions providers. |
Reviews (1): Last reviewed commit: "fix(mcp): semantic tool filter now trans..." | Re-trigger Greptile
Codecov Report❌ Patch coverage is
📢 Thoughts on this report? Let us know! |
Covers _expand_mcp_tools directly with a mocked MCP tool list,
asserting the output uses the Chat Completions wrapper shape
({type, function}) rather than the flat Responses API shape.
Addresses Greptile's test-coverage suggestion on BerriAI#32606.
|
Added a targeted unit test (test_expand_mcp_tools_uses_chat_format) covering _expand_mcp_tools directly with a mocked tool list — asserts the output uses the {type, function} wrapper shape rather than the flat Responses API shape. Passes locally. |
…enai_format Unit test for the coverage-tracked test suite (tests/test_litellm/), since the earlier e2e test in tests/mcp_tests/ isn't part of the coverage-collected suite. Addresses the codecov patch-coverage flag on BerriAI#32606.
|
Added a coverage-tracked unit test in tests/test_litellm/responses/mcp/test_litellm_proxy_mcp_handler.py (test_process_mcp_tools_to_openai_format_forwards_target_format) covering the exact line Codecov flagged. All 20/21 tests in that file pass — the one remaining failure (test_completion_with_function_tools_works_without_fastapi_installed) is a pre-existing local-venv-only failure unrelated to this change, confirmed by reproducing it identically with these commits stashed out. |
… fix/mcp-semantic-filter-clean # Conflicts: # tests/test_litellm/responses/mcp/test_litellm_proxy_mcp_handler.py
|
Heads up on the Codecov patch-coverage flag — the uncovered lines in hook.py (HTTPException import, SemanticToolFilterContextWindowError) came in from upstream commits merged via litellm_internal_staging (53e5b22, 5421fdf, 1e8c2f7, etc.) after this PR was opened, not from this PR's actual change. My fix is isolated to _process_mcp_tools_to_openai_format's target_format forwarding, which already has dedicated regression tests (test_process_mcp_tools_to_openai_format_forwards_target_format, test_expand_mcp_tools_uses_chat_format) — both passing. Happy to discuss if maintainers want coverage added for the newer unrelated code too, but wanted to flag the diff isn't mine. |
|
@ishaan-jaff Hey, this has been open a couple weeks with no review yet — happy to address anything if it needs changes, just let me know. |
Fixes the schema mismatch reported in #32281 (persisted specifically in the MCP Semantic Tool Filter path, confirmed by @brian-sbc on v1.93.0-dev.1 after #32285/#32282 landed).
Root cause:
_process_mcp_tools_to_openai_formatcalls_transform_mcp_tools_to_openaiwithout passingtarget_format, which defaults to"responses"(flat Responses API shape). The semantic filter hook always needs the Chat Completions shape ({"type": "function", "function": {...}}) since it's used on/v1/chat/completions, so tools passed through the filter came out flat and failed strict schema validation on providers like hosted_vllm.Fix: add a
target_formatparam (default preserved for existing callers) and have the semantic filter hook explicitly passtarget_format="chat".Verified locally: reproduced the exact MCP tool → semantic filter → hosted_vllm path with a mocked tool list; confirmed tools now come out correctly wrapped in
{"type": "function", "function": {...}}.