From c96576cb0460edcdc8bc0c949bfd735cf7380f09 Mon Sep 17 00:00:00 2001 From: Igal Boxerman Date: Sun, 15 Mar 2026 19:53:22 +0200 Subject: [PATCH] fix: support MCP tools in Generic Guardrail API The `tools` field in `GenericGuardrailAPIRequest`, `GenericGuardrailAPIResponse`, and `GenericGuardrailAPIInputs` was typed as `List[ChatCompletionToolParam]`, which requires a `function` field. MCP tools (`type: "mcp"`) don't have this field, causing a Pydantic validation error: tools.0.function - Field required [type=missing] Changed `tools` to `List[Union[ChatCompletionToolParam, OpenAIMcpServerTool]]`, aligned with the Responses API pattern (transformation.py). This supports both function tools and MCP tools with proper type validation. Fixes #23695 --- .../guardrails/guardrail_hooks/generic_guardrail_api.py | 9 +++++---- litellm/types/utils.py | 3 ++- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/litellm/types/proxy/guardrails/guardrail_hooks/generic_guardrail_api.py b/litellm/types/proxy/guardrails/guardrail_hooks/generic_guardrail_api.py index c87086bdce2..0510c5bc3ef 100644 --- a/litellm/types/proxy/guardrails/guardrail_hooks/generic_guardrail_api.py +++ b/litellm/types/proxy/guardrails/guardrail_hooks/generic_guardrail_api.py @@ -1,12 +1,13 @@ from typing import Any, Dict, List, Literal, Optional, Union from pydantic import BaseModel, Field -from typing_extensions import TYPE_CHECKING, TypedDict +from typing_extensions import TypedDict from litellm.types.llms.openai import ( AllMessageValues, ChatCompletionToolCallChunk, ChatCompletionToolParam, + OpenAIMcpServerTool, ) from litellm.types.proxy.guardrails.guardrail_hooks.base import GuardrailConfigModel from litellm.types.utils import ChatCompletionMessageToolCall @@ -65,7 +66,7 @@ class GenericGuardrailAPIRequest(BaseModel): ] = None # the trace id of the LLM call - useful if there are multiple LLM calls for the same conversation structured_messages: Optional[List[AllMessageValues]] = None images: Optional[List[str]] = None - tools: Optional[List[ChatCompletionToolParam]] = None + tools: Optional[List[Union[ChatCompletionToolParam, OpenAIMcpServerTool]]] = None texts: Optional[List[str]] = None request_data: GenericGuardrailAPIMetadata request_headers: Optional[Dict[str, str]] = Field( @@ -88,7 +89,7 @@ class GenericGuardrailAPIResponse: texts: Optional[List[str]] images: Optional[List[str]] - tools: Optional[List[ChatCompletionToolParam]] + tools: Optional[List[Union[ChatCompletionToolParam, OpenAIMcpServerTool]]] action: str blocked_reason: Optional[str] @@ -98,7 +99,7 @@ class GenericGuardrailAPIResponse: texts: Optional[List[str]] = None, blocked_reason: Optional[str] = None, images: Optional[List[str]] = None, - tools: Optional[List[ChatCompletionToolParam]] = None, + tools: Optional[List[Union[ChatCompletionToolParam, OpenAIMcpServerTool]]] = None, ): self.action = action self.blocked_reason = blocked_reason diff --git a/litellm/types/utils.py b/litellm/types/utils.py index 892c9578b94..6ff02b6bb3f 100644 --- a/litellm/types/utils.py +++ b/litellm/types/utils.py @@ -69,6 +69,7 @@ from .llms.openai import ( OpenAIChatCompletionChunk, OpenAIChatCompletionFinishReason, OpenAIFileObject, + OpenAIMcpServerTool, OpenAIRealtimeStreamList, ResponsesAPIResponse, WebSearchOptions, @@ -3564,7 +3565,7 @@ class PriorityReservationSettings(BaseModel): class GenericGuardrailAPIInputs(TypedDict, total=False): texts: List[str] # extracted text from the LLM response - for basic text guardrails images: List[str] # extracted images from the LLM response - for image guardrails - tools: List[ChatCompletionToolParam] # tools sent to the LLM + tools: List[Union[ChatCompletionToolParam, OpenAIMcpServerTool]] # tools sent to the LLM tool_calls: Union[ List[ChatCompletionToolCallChunk], List[ChatCompletionMessageToolCall] ] # tool calls sent from the LLM