mirror of
https://github.com/BerriAI/litellm.git
synced 2026-10-04 02:31:27 +00:00
fix(mcp-semantic-filter): use chat format when expanding MCP tools for /v1/chat/completions
When mcp_semantic_tool_filter expanded MCP references, it called
_process_mcp_tools_to_openai_format with the default target_format="responses",
which returns flat {"type":"function","name":...} objects (Responses API format).
For /v1/chat/completions backends these must be in the nested
{"type":"function","function":{...}} schema, or strict OpenAI-compatible APIs
(LM Studio, etc.) return 400 BadRequest.
Pass target_format through from _expand_mcp_tools -> _process_mcp_tools_to_openai_format.
In async_pre_call_hook, default to "chat" format and only use "responses" when
call_type=="aresponses". Also fix _get_tool_names_csv to extract tool names from
both the nested (chat) and flat (responses) schemas.
This commit is contained in:
parent
0557321cc2
commit
ff2cfa640b
1 changed files with 25 additions and 7 deletions
|
|
@ -64,12 +64,19 @@ class SemanticToolFilterHook(CustomLogger):
|
|||
self,
|
||||
tools: List[Any],
|
||||
user_api_key_dict: "UserAPIKeyAuth",
|
||||
target_format: str = "chat",
|
||||
) -> List[Dict[str, Any]]:
|
||||
"""
|
||||
Expand MCP references to actual tool definitions.
|
||||
|
||||
Reuses LiteLLM_Proxy_MCP_Handler._process_mcp_tools_to_openai_format
|
||||
which internally does: parse -> fetch -> filter -> deduplicate -> transform
|
||||
|
||||
Args:
|
||||
tools: List of tool objects which may include MCP references.
|
||||
user_api_key_dict: User auth for access control.
|
||||
target_format: "chat" for ChatCompletions nested ``function`` schema
|
||||
(default), "responses" for Responses API flat schema.
|
||||
"""
|
||||
from litellm.responses.mcp.litellm_proxy_mcp_handler import (
|
||||
LiteLLM_Proxy_MCP_Handler,
|
||||
|
|
@ -87,7 +94,9 @@ class SemanticToolFilterHook(CustomLogger):
|
|||
openai_tools,
|
||||
_,
|
||||
) = await LiteLLM_Proxy_MCP_Handler._process_mcp_tools_to_openai_format(
|
||||
user_api_key_auth=user_api_key_dict, mcp_tools_with_litellm_proxy=mcp_tools
|
||||
user_api_key_auth=user_api_key_dict,
|
||||
mcp_tools_with_litellm_proxy=mcp_tools,
|
||||
target_format=target_format, # type: ignore[arg-type]
|
||||
)
|
||||
|
||||
# Convert Pydantic models to dicts for compatibility
|
||||
|
|
@ -171,7 +180,12 @@ class SemanticToolFilterHook(CustomLogger):
|
|||
)
|
||||
|
||||
try:
|
||||
expanded_tools = await self._expand_mcp_tools(tools, user_api_key_dict)
|
||||
# Use "chat" schema (nested function key) for chat completions;
|
||||
# Responses API endpoints expect the flat format.
|
||||
_target_format = "responses" if call_type == "aresponses" else "chat"
|
||||
expanded_tools = await self._expand_mcp_tools(
|
||||
tools, user_api_key_dict, target_format=_target_format
|
||||
)
|
||||
|
||||
if not expanded_tools:
|
||||
verbose_proxy_logger.warning(
|
||||
|
|
@ -293,11 +307,15 @@ class SemanticToolFilterHook(CustomLogger):
|
|||
|
||||
tool_names = []
|
||||
for tool in tools:
|
||||
name = (
|
||||
tool.get("name", "")
|
||||
if isinstance(tool, dict)
|
||||
else getattr(tool, "name", "")
|
||||
)
|
||||
if isinstance(tool, dict):
|
||||
# ChatCompletions format: {"type": "function", "function": {"name": ...}}
|
||||
# Responses API format: {"type": "function", "name": ...}
|
||||
func = tool.get("function")
|
||||
name = (
|
||||
func.get("name", "") if isinstance(func, dict) else tool.get("name", "")
|
||||
)
|
||||
else:
|
||||
name = getattr(tool, "name", "")
|
||||
if name:
|
||||
tool_names.append(name)
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue