From cfe8855f5559fafb517edaf60e4fabea7879233a Mon Sep 17 00:00:00 2001 From: Manohar Paturi <186662190+ManoharPaturi@users.noreply.github.com> Date: Sun, 18 Oct 2026 19:58:43 +0530 Subject: [PATCH] Python: merge both approval lists in get_mcp_tool Signed-off-by: Manohar Paturi <186662190+ManoharPaturi@users.noreply.github.com> --- .../agent_framework_openai/_chat_client.py | 10 ++++++++-- .../tests/openai/test_openai_chat_client.py | 17 +++++++++++++++++ 2 files changed, 25 insertions(+), 2 deletions(-) diff --git a/python/packages/openai/agent_framework_openai/_chat_client.py b/python/packages/openai/agent_framework_openai/_chat_client.py index a5c18ebda8..34d00c1d14 100644 --- a/python/packages/openai/agent_framework_openai/_chat_client.py +++ b/python/packages/openai/agent_framework_openai/_chat_client.py @@ -1619,10 +1619,16 @@ def get_mcp_tool( if isinstance(approval_mode, str): mcp["require_approval"] = "always" if approval_mode == "always_require" else "never" else: + # Both keys can be supplied together ("and/or" per the docstring), so build + # one combined mapping instead of letting the second assignment overwrite + # the first, which silently dropped the always-approval tool list. + require_approval: dict[str, Any] = {} if always_require := approval_mode.get("always_require_approval"): - mcp["require_approval"] = {"always": {"tool_names": always_require}} + require_approval["always"] = {"tool_names": always_require} if never_require := approval_mode.get("never_require_approval"): - mcp["require_approval"] = {"never": {"tool_names": never_require}} + require_approval["never"] = {"tool_names": never_require} + if require_approval: + mcp["require_approval"] = require_approval return mcp diff --git a/python/packages/openai/tests/openai/test_openai_chat_client.py b/python/packages/openai/tests/openai/test_openai_chat_client.py index 15cadc9d9b..41949ba4d3 100644 --- a/python/packages/openai/tests/openai/test_openai_chat_client.py +++ b/python/packages/openai/tests/openai/test_openai_chat_client.py @@ -6476,6 +6476,23 @@ def test_prepare_tools_for_openai_with_mcp() -> None: assert "require_approval" in mcp +def test_get_mcp_tool_merges_both_approval_lists() -> None: + """Both approval lists must survive: overwriting the first with the second would + silently auto-approve tools the caller asked to gate.""" + tool_config = OpenAIChatClient.get_mcp_tool( + name="MCP", + url="https://mcp.example", + approval_mode={ + "always_require_approval": ["dangerous_tool"], + "never_require_approval": ["safe_tool"], + }, + ) + assert tool_config["require_approval"] == { + "always": {"tool_names": ["dangerous_tool"]}, + "never": {"tool_names": ["safe_tool"]}, + } + + @pytest.mark.parametrize("allowed_tools", [None, [], ["read_only"]], ids=["omitted", "empty", "nonempty"]) async def test_get_mcp_tool_preserves_allowed_tools_in_request(allowed_tools: list[str] | None) -> None: tool_config = OpenAIChatClient.get_mcp_tool(