Skip to content

fix(mcp): semantic tool filter now transforms tools to Chat Completions format - #32606

Open
unfitcoder101 wants to merge 4 commits into
BerriAI:litellm_internal_stagingfrom
unfitcoder101:fix/mcp-semantic-filter-clean
Open

fix(mcp): semantic tool filter now transforms tools to Chat Completions format#32606
unfitcoder101 wants to merge 4 commits into
BerriAI:litellm_internal_stagingfrom
unfitcoder101:fix/mcp-semantic-filter-clean

Conversation

@unfitcoder101

Copy link
Copy Markdown

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_format calls _transform_mcp_tools_to_openai without passing target_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_format param (default preserved for existing callers) and have the semantic filter hook explicitly pass target_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": {...}}.

_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-apps

greptile-apps Bot commented Jul 9, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR fixes a schema mismatch in the MCP semantic tool filter path: tools were being transformed to the flat Responses API shape ({"name": ..., "parameters": ...}) instead of the Chat Completions wrapper shape ({"type": "function", "function": {...}}) required by /v1/chat/completions providers such as hosted_vllm.

  • Adds a target_format: Literal["responses", "chat"] parameter (defaulting to "responses") to _process_mcp_tools_to_openai_format, preserving backwards compatibility for all existing callers.
  • The semantic filter hook now explicitly passes target_format="chat", ensuring tools exit the pipeline in the correct shape for strict-schema-validating providers.

Confidence Score: 4/5

The 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: _transform_mcp_tools_to_openai already supported target_format and the test suite covers both branches. No test is added specifically verifying that the semantic filter hook now produces the wrapped shape — a targeted test for hook.py would increase confidence that this exact code path stays correct under future refactors.

litellm/proxy/hooks/mcp_semantic_filter/hook.py — the fix is applied here but no new unit test guards the target_format="chat" call in this file.

Important Files Changed

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

codecov Bot commented Jul 9, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 25.00000% with 3 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
litellm/proxy/hooks/mcp_semantic_filter/hook.py 0.00% 2 Missing ⚠️
litellm/responses/mcp/litellm_proxy_mcp_handler.py 50.00% 1 Missing ⚠️

📢 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.
@unfitcoder101

Copy link
Copy Markdown
Author

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.
@unfitcoder101

Copy link
Copy Markdown
Author

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.

@codspeed-hq

codspeed-hq Bot commented Jul 9, 2026

Copy link
Copy Markdown
Contributor

Merging this PR will not alter performance

✅ 31 untouched benchmarks


Comparing unfitcoder101:fix/mcp-semantic-filter-clean (24076a2) with litellm_internal_staging (3bba363)

Open in CodSpeed

… fix/mcp-semantic-filter-clean

# Conflicts:
#	tests/test_litellm/responses/mcp/test_litellm_proxy_mcp_handler.py
@unfitcoder101

Copy link
Copy Markdown
Author

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.

@unfitcoder101

Copy link
Copy Markdown
Author

@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.

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.

1 participant