Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 8 additions & 2 deletions python/packages/openai/agent_framework_openai/_chat_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
17 changes: 17 additions & 0 deletions python/packages/openai/tests/openai/test_openai_chat_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand Down
Loading