diff --git a/litellm/responses/mcp/litellm_proxy_mcp_handler.py b/litellm/responses/mcp/litellm_proxy_mcp_handler.py index c1cf2d967eb..e03f0296109 100644 --- a/litellm/responses/mcp/litellm_proxy_mcp_handler.py +++ b/litellm/responses/mcp/litellm_proxy_mcp_handler.py @@ -20,7 +20,6 @@ from litellm.proxy._experimental.mcp_server.utils import ( split_server_prefix_from_name, strip_known_server_prefix, ) -from litellm.proxy.litellm_pre_call_utils import LiteLLMProxyRequestSetup from litellm.responses.main import aresponses from litellm.responses.streaming_iterator import BaseResponsesAPIStreamingIterator from litellm.types.llms.openai import ResponsesAPIResponse @@ -705,6 +704,10 @@ class LiteLLM_Proxy_MCP_Handler: if request_tags: logging_request_data["metadata"]["tags"] = request_tags if user_api_key_auth is not None: + from litellm.proxy.litellm_pre_call_utils import ( + LiteLLMProxyRequestSetup, + ) + LiteLLMProxyRequestSetup.add_user_api_key_auth_to_request_metadata( data=logging_request_data, user_api_key_dict=user_api_key_auth, diff --git a/tests/test_litellm/responses/mcp/test_litellm_proxy_mcp_handler.py b/tests/test_litellm/responses/mcp/test_litellm_proxy_mcp_handler.py index 80e2eb48f62..6fdbb0741aa 100644 --- a/tests/test_litellm/responses/mcp/test_litellm_proxy_mcp_handler.py +++ b/tests/test_litellm/responses/mcp/test_litellm_proxy_mcp_handler.py @@ -1,4 +1,6 @@ +import subprocess import sys +import textwrap import types from unittest.mock import AsyncMock, MagicMock @@ -557,3 +559,49 @@ async def test_execute_tool_calls_propagates_request_tags_to_function_setup(monk ) assert captured["metadata"]["tags"] == ["team-a", "prod"] + + +def test_completion_with_function_tools_works_without_fastapi_installed(): + script = textwrap.dedent( + """ + import sys + + class _FastapiBlocker: + def find_spec(self, fullname, path=None, target=None): + if fullname == "fastapi" or fullname.startswith("fastapi."): + raise ModuleNotFoundError("No module named 'fastapi'") + return None + + sys.meta_path.insert(0, _FastapiBlocker()) + + import litellm + + response = litellm.completion( + model="openai/gpt-5.5", + messages=[{"role": "user", "content": "What is the weather in SF?"}], + tools=[ + { + "type": "function", + "function": { + "name": "get_weather", + "description": "Get the current weather for a location", + "parameters": { + "type": "object", + "properties": {"location": {"type": "string"}}, + "required": ["location"], + }, + }, + } + ], + mock_response="sunny", + ) + assert response.choices[0].message.content == "sunny" + """ + ) + result = subprocess.run( + [sys.executable, "-c", script], + capture_output=True, + text=True, + timeout=120, + ) + assert result.returncode == 0, result.stderr