fix(mcp): keep during_mcp_call hooks on name and arguments only

call_tool handed the caller's listed entry to the during-hook task as well, so during_mcp_call
guardrails scanned the description line and schema leaves of any listed tool after the upstream
call had already run, blocking calls that passed before whenever the policy matched the
description, returned a fixed-length texts list, or hit the depth guard on a deep schema. The
listed entry is only disclosed for pre_mcp_call, so the during task no longer receives it and its
request object carries no description or schema, as before
This commit is contained in:
Yucheng He 2026-10-01 02:15:16 -07:00
parent 12947900b6
commit e9b8c0fd5c
2 changed files with 6 additions and 6 deletions

View file

@ -6694,7 +6694,6 @@ class MCPServerManager:
start_time=start_time,
litellm_logging_obj=litellm_logging_obj,
guardrail_context=guardrail_context,
tool=self.get_listed_tool(mcp_server, name, listed_caller),
)
tasks.append(during_hook_task)

View file

@ -7085,7 +7085,9 @@ class TestMCPServerManager:
assert (hook_kwargs["tool_description"], hook_kwargs["tool_input_schema"]) == ("Runs the test tool", schema)
@pytest.mark.asyncio
async def test_call_tool_hands_listed_tool_metadata_to_during_call_hooks_through_real_conversion(self):
async def test_call_tool_hands_during_call_hooks_name_and_arguments_only_even_for_a_listed_tool(self):
"""A during_mcp_call guardrail evaluates the call in flight, so it keeps seeing only the name and
arguments it always did; the listed description and schema go to the pre-call hooks alone."""
schema = {"type": "object", "properties": {"param": {"type": "string"}}}
listed = [MCPTool(name="test_tool", description="Runs the test tool", inputSchema=schema)]
auth = UserAPIKeyAuth(api_key="sk-test")
@ -7103,10 +7105,9 @@ class TestMCPServerManager:
)
during_data = proxy_logging_obj.during_call_hook.call_args.kwargs["data"]
assert (during_data["mcp_tool_description"], during_data["mcp_input_schema"]) == (
"Runs the test tool",
schema,
)
assert during_data["mcp_arguments"] == {"param": "value"}
assert (during_data.get("mcp_tool_description"), during_data.get("mcp_input_schema")) == (None, None)
assert "Description:" not in during_data["messages"][0]["content"]
@pytest.mark.asyncio
async def test_call_tool_passes_no_tool_metadata_when_tool_was_never_listed(self):