# Copyright (c) Microsoft. All rights reserved. from unittest.mock import AsyncMock, MagicMock, patch import pytest from agent_framework import Agent, FunctionTool from agent_framework._mcp import MCPTool from azure.ai.projects.models import ( AgentVersionDetails, PromptAgentDefinition, ) from azure.ai.projects.models import ( FunctionTool as AzureFunctionTool, ) from agent_framework_azure_ai import AzureAIProjectAgentProvider @pytest.fixture def mock_project_client() -> MagicMock: """Fixture that provides a mock AIProjectClient.""" mock_client = MagicMock() # Mock agents property mock_client.agents = MagicMock() mock_client.agents.create_version = AsyncMock() # Mock conversations property mock_client.conversations = MagicMock() mock_client.conversations.create = AsyncMock() # Mock telemetry property mock_client.telemetry = MagicMock() mock_client.telemetry.get_application_insights_connection_string = AsyncMock() # Mock get_openai_client method mock_client.get_openai_client = AsyncMock() # Mock close method mock_client.close = AsyncMock() return mock_client @pytest.fixture def mock_azure_credential() -> MagicMock: """Fixture that provides a mock Azure credential.""" return MagicMock() @pytest.fixture def azure_ai_unit_test_env(monkeypatch: pytest.MonkeyPatch) -> dict[str, str]: """Fixture that sets up Azure AI environment variables for unit testing.""" env_vars = { "AZURE_AI_PROJECT_ENDPOINT": "https://test-project.cognitiveservices.azure.com/", "AZURE_AI_MODEL_DEPLOYMENT_NAME": "test-model-deployment", } for key, value in env_vars.items(): monkeypatch.setenv(key, value) return env_vars def test_provider_init_with_project_client(mock_project_client: MagicMock) -> None: """Test AzureAIProjectAgentProvider initialization with existing project_client.""" provider = AzureAIProjectAgentProvider(project_client=mock_project_client) assert provider._project_client is mock_project_client # type: ignore assert not provider._should_close_client # type: ignore def test_provider_init_with_credential_and_endpoint( azure_ai_unit_test_env: dict[str, str], mock_azure_credential: MagicMock, ) -> None: """Test AzureAIProjectAgentProvider initialization with credential and endpoint.""" with patch("agent_framework_azure_ai._project_provider.AIProjectClient") as mock_ai_project_client: mock_client = MagicMock() mock_ai_project_client.return_value = mock_client provider = AzureAIProjectAgentProvider( project_endpoint=azure_ai_unit_test_env["AZURE_AI_PROJECT_ENDPOINT"], credential=mock_azure_credential, ) assert provider._project_client is mock_client # type: ignore assert provider._should_close_client # type: ignore # Verify AIProjectClient was called with correct parameters mock_ai_project_client.assert_called_once() def test_provider_init_missing_endpoint() -> None: """Test AzureAIProjectAgentProvider initialization when endpoint is missing.""" with patch("agent_framework_azure_ai._project_provider.load_settings") as mock_load_settings: mock_load_settings.return_value = {"project_endpoint": None, "model_deployment_name": "test-model"} with pytest.raises(ValueError, match="Azure AI project endpoint is required"): AzureAIProjectAgentProvider(credential=MagicMock()) def test_provider_init_missing_credential(azure_ai_unit_test_env: dict[str, str]) -> None: """Test AzureAIProjectAgentProvider initialization when credential is missing.""" with pytest.raises(ValueError, match="Azure credential is required when project_client is not provided"): AzureAIProjectAgentProvider( project_endpoint=azure_ai_unit_test_env["AZURE_AI_PROJECT_ENDPOINT"], ) async def test_provider_create_agent( mock_project_client: MagicMock, azure_ai_unit_test_env: dict[str, str], ) -> None: """Test AzureAIProjectAgentProvider.create_agent method.""" with patch("agent_framework_azure_ai._project_provider.load_settings") as mock_load_settings: mock_load_settings.return_value = { "project_endpoint": azure_ai_unit_test_env["AZURE_AI_PROJECT_ENDPOINT"], "model_deployment_name": azure_ai_unit_test_env["AZURE_AI_MODEL_DEPLOYMENT_NAME"], } provider = AzureAIProjectAgentProvider(project_client=mock_project_client) # Mock agent creation response mock_agent_version = MagicMock(spec=AgentVersionDetails) mock_agent_version.id = "agent-id" mock_agent_version.name = "test-agent" mock_agent_version.version = "1.0" mock_agent_version.description = "Test Agent" mock_agent_version.definition = MagicMock(spec=PromptAgentDefinition) mock_agent_version.definition.model = "gpt-4" mock_agent_version.definition.instructions = "Test instructions" mock_agent_version.definition.temperature = 0.7 mock_agent_version.definition.top_p = 0.9 mock_agent_version.definition.tools = [] mock_project_client.agents.create_version = AsyncMock(return_value=mock_agent_version) agent = await provider.create_agent( name="test-agent", model="gpt-4", instructions="Test instructions", description="Test Agent", ) assert isinstance(agent, Agent) assert agent.name == "test-agent" mock_project_client.agents.create_version.assert_called_once() async def test_provider_create_agent_with_env_model( mock_project_client: MagicMock, azure_ai_unit_test_env: dict[str, str], ) -> None: """Test AzureAIProjectAgentProvider.create_agent uses model from env var.""" with patch("agent_framework_azure_ai._project_provider.load_settings") as mock_load_settings: mock_load_settings.return_value = { "project_endpoint": azure_ai_unit_test_env["AZURE_AI_PROJECT_ENDPOINT"], "model_deployment_name": azure_ai_unit_test_env["AZURE_AI_MODEL_DEPLOYMENT_NAME"], } provider = AzureAIProjectAgentProvider(project_client=mock_project_client) # Mock agent creation response mock_agent_version = MagicMock(spec=AgentVersionDetails) mock_agent_version.id = "agent-id" mock_agent_version.name = "test-agent" mock_agent_version.version = "1.0" mock_agent_version.description = None mock_agent_version.definition = MagicMock(spec=PromptAgentDefinition) mock_agent_version.definition.model = azure_ai_unit_test_env["AZURE_AI_MODEL_DEPLOYMENT_NAME"] mock_agent_version.definition.instructions = None mock_agent_version.definition.temperature = None mock_agent_version.definition.top_p = None mock_agent_version.definition.tools = [] mock_project_client.agents.create_version = AsyncMock(return_value=mock_agent_version) # Call without model parameter - should use env var agent = await provider.create_agent(name="test-agent") assert isinstance(agent, Agent) # Verify the model from env var was used call_args = mock_project_client.agents.create_version.call_args assert call_args[1]["definition"].model == azure_ai_unit_test_env["AZURE_AI_MODEL_DEPLOYMENT_NAME"] async def test_provider_create_agent_missing_model(mock_project_client: MagicMock) -> None: """Test AzureAIProjectAgentProvider.create_agent raises when model is missing.""" with patch("agent_framework_azure_ai._project_provider.load_settings") as mock_load_settings: mock_load_settings.return_value = {"project_endpoint": "https://test.com", "model_deployment_name": None} provider = AzureAIProjectAgentProvider(project_client=mock_project_client) with pytest.raises(ValueError, match="Model deployment name is required"): await provider.create_agent(name="test-agent") async def test_provider_create_agent_with_rai_config( mock_project_client: MagicMock, azure_ai_unit_test_env: dict[str, str], ) -> None: """Test AzureAIProjectAgentProvider.create_agent passes rai_config from default_options.""" with patch("agent_framework_azure_ai._project_provider.load_settings") as mock_load_settings: mock_load_settings.return_value = { "project_endpoint": azure_ai_unit_test_env["AZURE_AI_PROJECT_ENDPOINT"], "model_deployment_name": azure_ai_unit_test_env["AZURE_AI_MODEL_DEPLOYMENT_NAME"], } provider = AzureAIProjectAgentProvider(project_client=mock_project_client) # Mock agent creation response mock_agent_version = MagicMock(spec=AgentVersionDetails) mock_agent_version.id = "agent-id" mock_agent_version.name = "test-agent" mock_agent_version.version = "1.0" mock_agent_version.description = None mock_agent_version.definition = MagicMock(spec=PromptAgentDefinition) mock_agent_version.definition.model = "gpt-4" mock_agent_version.definition.instructions = None mock_agent_version.definition.temperature = None mock_agent_version.definition.top_p = None mock_agent_version.definition.tools = [] mock_project_client.agents.create_version = AsyncMock(return_value=mock_agent_version) # Create a mock RaiConfig-like object mock_rai_config = MagicMock() mock_rai_config.rai_policy_name = "policy-name" # Call create_agent with rai_config in default_options await provider.create_agent( name="test-agent", model="gpt-4", default_options={"rai_config": mock_rai_config}, ) # Verify rai_config was passed to PromptAgentDefinition call_args = mock_project_client.agents.create_version.call_args definition = call_args[1]["definition"] assert definition.rai_config is mock_rai_config async def test_provider_create_agent_with_reasoning( mock_project_client: MagicMock, azure_ai_unit_test_env: dict[str, str], ) -> None: """Test AzureAIProjectAgentProvider.create_agent passes reasoning from default_options.""" with patch("agent_framework_azure_ai._project_provider.load_settings") as mock_load_settings: mock_load_settings.return_value = { "project_endpoint": azure_ai_unit_test_env["AZURE_AI_PROJECT_ENDPOINT"], "model_deployment_name": azure_ai_unit_test_env["AZURE_AI_MODEL_DEPLOYMENT_NAME"], } provider = AzureAIProjectAgentProvider(project_client=mock_project_client) # Mock agent creation response mock_agent_version = MagicMock(spec=AgentVersionDetails) mock_agent_version.id = "agent-id" mock_agent_version.name = "test-agent" mock_agent_version.version = "1.0" mock_agent_version.description = None mock_agent_version.definition = MagicMock(spec=PromptAgentDefinition) mock_agent_version.definition.model = "gpt-5.2" mock_agent_version.definition.instructions = None mock_agent_version.definition.temperature = None mock_agent_version.definition.top_p = None mock_agent_version.definition.tools = [] mock_project_client.agents.create_version = AsyncMock(return_value=mock_agent_version) # Create a mock Reasoning-like object mock_reasoning = MagicMock() mock_reasoning.effort = "medium" mock_reasoning.summary = "concise" # Call create_agent with reasoning in default_options await provider.create_agent( name="test-agent", model="gpt-5.2", default_options={"reasoning": mock_reasoning}, ) # Verify reasoning was passed to PromptAgentDefinition call_args = mock_project_client.agents.create_version.call_args definition = call_args[1]["definition"] assert definition.reasoning is mock_reasoning async def test_provider_get_agent_with_name(mock_project_client: MagicMock) -> None: """Test AzureAIProjectAgentProvider.get_agent with name parameter.""" provider = AzureAIProjectAgentProvider(project_client=mock_project_client) # Mock agent response mock_agent_version = MagicMock(spec=AgentVersionDetails) mock_agent_version.id = "agent-id" mock_agent_version.name = "test-agent" mock_agent_version.version = "1.0" mock_agent_version.description = "Test Agent" mock_agent_version.definition = MagicMock(spec=PromptAgentDefinition) mock_agent_version.definition.model = "gpt-4" mock_agent_version.definition.instructions = "Test instructions" mock_agent_version.definition.temperature = None mock_agent_version.definition.top_p = None mock_agent_version.definition.tools = [] mock_agent_object = MagicMock() mock_agent_object.versions.latest = mock_agent_version mock_project_client.agents = AsyncMock() mock_project_client.agents.get.return_value = mock_agent_object agent = await provider.get_agent(name="test-agent") assert isinstance(agent, Agent) assert agent.name == "test-agent" mock_project_client.agents.get.assert_called_with(agent_name="test-agent") async def test_provider_get_agent_with_reference(mock_project_client: MagicMock) -> None: """Test AzureAIProjectAgentProvider.get_agent with reference parameter.""" provider = AzureAIProjectAgentProvider(project_client=mock_project_client) # Mock agent response mock_agent_version = MagicMock(spec=AgentVersionDetails) mock_agent_version.id = "agent-id" mock_agent_version.name = "test-agent" mock_agent_version.version = "1.0" mock_agent_version.description = "Test Agent" mock_agent_version.definition = MagicMock(spec=PromptAgentDefinition) mock_agent_version.definition.model = "gpt-4" mock_agent_version.definition.instructions = "Test instructions" mock_agent_version.definition.temperature = None mock_agent_version.definition.top_p = None mock_agent_version.definition.tools = [] mock_project_client.agents = AsyncMock() mock_project_client.agents.get_version.return_value = mock_agent_version agent_reference = {"name": "test-agent", "version": "1.0"} agent = await provider.get_agent(reference=agent_reference) assert isinstance(agent, Agent) assert agent.name == "test-agent" mock_project_client.agents.get_version.assert_called_with(agent_name="test-agent", agent_version="1.0") async def test_provider_get_agent_missing_parameters(mock_project_client: MagicMock) -> None: """Test AzureAIProjectAgentProvider.get_agent raises when no identifier provided.""" provider = AzureAIProjectAgentProvider(project_client=mock_project_client) with pytest.raises(ValueError, match="Either name or reference must be provided"): await provider.get_agent() async def test_provider_get_agent_missing_function_tools(mock_project_client: MagicMock) -> None: """Test AzureAIProjectAgentProvider.get_agent raises when required tools are missing.""" provider = AzureAIProjectAgentProvider(project_client=mock_project_client) # Mock agent with function tools mock_agent_version = MagicMock(spec=AgentVersionDetails) mock_agent_version.id = "agent-id" mock_agent_version.name = "test-agent" mock_agent_version.version = "1.0" mock_agent_version.description = None mock_agent_version.definition = MagicMock(spec=PromptAgentDefinition) mock_agent_version.definition.tools = [ AzureFunctionTool(name="test_tool", parameters=[], strict=True, description="Test tool") ] mock_agent_object = MagicMock() mock_agent_object.versions.latest = mock_agent_version mock_project_client.agents = AsyncMock() mock_project_client.agents.get.return_value = mock_agent_object with pytest.raises( ValueError, match="The following prompt agent definition required tools were not provided: test_tool" ): await provider.get_agent(name="test-agent") def test_provider_as_agent(mock_project_client: MagicMock) -> None: """Test AzureAIProjectAgentProvider.as_agent method.""" provider = AzureAIProjectAgentProvider(project_client=mock_project_client) # Create mock agent version mock_agent_version = MagicMock(spec=AgentVersionDetails) mock_agent_version.id = "agent-id" mock_agent_version.name = "test-agent" mock_agent_version.version = "1.0" mock_agent_version.description = "Test Agent" mock_agent_version.definition = MagicMock(spec=PromptAgentDefinition) mock_agent_version.definition.model = "gpt-4" mock_agent_version.definition.instructions = "Test instructions" mock_agent_version.definition.temperature = 0.7 mock_agent_version.definition.top_p = 0.9 mock_agent_version.definition.tools = [] with patch("agent_framework_azure_ai._project_provider.AzureAIClient") as mock_azure_ai_client: agent = provider.as_agent(mock_agent_version) assert isinstance(agent, Agent) assert agent.name == "test-agent" assert agent.description == "Test Agent" # Verify AzureAIClient was called with correct parameters mock_azure_ai_client.assert_called_once() call_kwargs = mock_azure_ai_client.call_args[1] assert call_kwargs["project_client"] is mock_project_client assert call_kwargs["agent_name"] == "test-agent" assert call_kwargs["agent_version"] == "1.0" assert call_kwargs["agent_description"] == "Test Agent" assert call_kwargs["model_deployment_name"] == "gpt-4" def test_provider_merge_tools_skips_function_tool_dicts(mock_project_client: MagicMock) -> None: """Test that _merge_tools skips function tool dicts but keeps other hosted tools.""" provider = AzureAIProjectAgentProvider(project_client=mock_project_client) # Create a mock FunctionTool to provide as implementation mock_ai_function = create_mock_ai_function("my_function", "My function description") # Definition tools include a function tool (dict) and an MCP tool definition_tools = [ {"type": "function", "name": "my_function", "parameters": {}}, # Should be skipped {"type": "mcp", "server_label": "my_mcp", "server_url": "http://localhost:8080"}, # Should be converted ] # Call _merge_tools with user-provided function implementation merged = provider._merge_tools(definition_tools, [mock_ai_function]) # type: ignore # Should have 2 items: the converted MCP dict and the user-provided FunctionTool assert len(merged) == 2 # Check that the function tool dict was NOT included (it was skipped) function_dicts = [t for t in merged if isinstance(t, dict) and t.get("type") == "function"] assert len(function_dicts) == 0 # Check that the MCP tool was converted to dict mcp_tools = [t for t in merged if isinstance(t, dict) and t.get("type") == "mcp"] assert len(mcp_tools) == 1 assert mcp_tools[0]["server_label"] == "my_mcp" # Check that the user-provided FunctionTool was included ai_functions = [t for t in merged if isinstance(t, FunctionTool)] assert len(ai_functions) == 1 assert ai_functions[0].name == "my_function" async def test_provider_context_manager(mock_project_client: MagicMock) -> None: """Test AzureAIProjectAgentProvider async context manager.""" with patch("agent_framework_azure_ai._project_provider.AIProjectClient") as mock_ai_project_client: mock_client = MagicMock() mock_client.close = AsyncMock() mock_ai_project_client.return_value = mock_client with patch("agent_framework_azure_ai._project_provider.load_settings") as mock_load_settings: mock_load_settings.return_value = { "project_endpoint": "https://test.com", "model_deployment_name": "test-model", } async with AzureAIProjectAgentProvider(credential=MagicMock()) as provider: assert provider._project_client is mock_client # type: ignore # Should call close after exiting context mock_client.close.assert_called_once() async def test_provider_context_manager_with_provided_client(mock_project_client: MagicMock) -> None: """Test AzureAIProjectAgentProvider context manager doesn't close provided client.""" mock_project_client.close = AsyncMock() async with AzureAIProjectAgentProvider(project_client=mock_project_client) as provider: assert provider._project_client is mock_project_client # type: ignore # Should NOT call close when client was provided mock_project_client.close.assert_not_called() async def test_provider_close_method(mock_project_client: MagicMock) -> None: """Test AzureAIProjectAgentProvider.close method.""" with patch("agent_framework_azure_ai._project_provider.AIProjectClient") as mock_ai_project_client: mock_client = MagicMock() mock_client.close = AsyncMock() mock_ai_project_client.return_value = mock_client with patch("agent_framework_azure_ai._project_provider.load_settings") as mock_load_settings: mock_load_settings.return_value = { "project_endpoint": "https://test.com", "model_deployment_name": "test-model", } provider = AzureAIProjectAgentProvider(credential=MagicMock()) await provider.close() mock_client.close.assert_called_once() def test_create_text_format_config_sets_strict_for_pydantic_models() -> None: """Test that create_text_format_config sets strict=True for Pydantic models.""" from pydantic import BaseModel from agent_framework_azure_ai._shared import create_text_format_config class TestSchema(BaseModel): subject: str summary: str result = create_text_format_config(TestSchema) # Verify strict=True is set assert result["strict"] is True assert result["name"] == "TestSchema" assert "schema" in result class MockMCPTool(MCPTool): # pyright: ignore[reportGeneralTypeIssues] """A mock MCPTool subclass for testing that passes isinstance checks. Note: This intentionally does NOT call super().__init__() because MCPTool's constructor requires MCP server connection parameters that aren't needed for unit testing. We only need isinstance(obj, MCPTool) to return True. """ def __init__(self, functions: list[FunctionTool] | None = None) -> None: self.name = "MockMCPTool" self.description = "A mock MCP tool for testing" self.is_connected = False self._mock_functions = functions or [] self._connect_called = False @property def functions(self) -> list[FunctionTool]: return self._mock_functions async def connect(self, *, reset: bool = False) -> None: self._connect_called = True self.is_connected = True @pytest.fixture def mock_mcp_tool() -> MockMCPTool: """Fixture that provides a mock MCPTool.""" mock_functions = [ create_mock_ai_function("mcp_function_1", "First MCP function"), create_mock_ai_function("mcp_function_2", "Second MCP function"), ] return MockMCPTool(functions=mock_functions) def create_mock_ai_function(name: str, description: str = "A mock function") -> FunctionTool: """Create a real FunctionTool for testing.""" def mock_func(arg: str) -> str: return f"Result from {name}: {arg}" return FunctionTool(func=mock_func, name=name, description=description, approval_mode="never_require") async def test_provider_create_agent_with_mcp_tool( mock_project_client: MagicMock, azure_ai_unit_test_env: dict[str, str], mock_mcp_tool: "MockMCPTool", ) -> None: """Test that create_agent connects MCP tools and passes discovered functions to Azure AI.""" # Patch normalize_tools to return tools as-is in a list (avoids callable check) def mock_normalize_tools(tools): if tools is None: return [] if isinstance(tools, list): return tools return [tools] with ( patch("agent_framework_azure_ai._project_provider.load_settings") as mock_load_settings, patch("agent_framework_azure_ai._project_provider.to_azure_ai_tools") as mock_to_azure_tools, patch("agent_framework_azure_ai._project_provider.normalize_tools", side_effect=mock_normalize_tools), ): mock_load_settings.return_value = { "project_endpoint": azure_ai_unit_test_env["AZURE_AI_PROJECT_ENDPOINT"], "model_deployment_name": azure_ai_unit_test_env["AZURE_AI_MODEL_DEPLOYMENT_NAME"], } mock_to_azure_tools.return_value = [{"type": "function", "name": "mcp_function_1"}] provider = AzureAIProjectAgentProvider(project_client=mock_project_client) # Mock agent creation response mock_agent_version = MagicMock(spec=AgentVersionDetails) mock_agent_version.id = "agent-id" mock_agent_version.name = "test-agent" mock_agent_version.version = "1.0" mock_agent_version.description = "Test Agent" mock_agent_version.definition = MagicMock(spec=PromptAgentDefinition) mock_agent_version.definition.model = "gpt-4" mock_agent_version.definition.instructions = "Test instructions" mock_agent_version.definition.tools = [] mock_project_client.agents.create_version = AsyncMock(return_value=mock_agent_version) # Call create_agent with MCP tool await provider.create_agent( name="test-agent", model="gpt-4", instructions="Test instructions", tools=mock_mcp_tool, ) # Verify MCP tool was connected assert mock_mcp_tool._connect_called is True assert mock_mcp_tool.is_connected is True # Verify to_azure_ai_tools was called with the discovered MCP functions mock_to_azure_tools.assert_called_once() tools_passed = mock_to_azure_tools.call_args[0][0] assert len(tools_passed) == 2 assert tools_passed[0].name == "mcp_function_1" assert tools_passed[1].name == "mcp_function_2" async def test_provider_create_agent_with_mcp_and_regular_tools( mock_project_client: MagicMock, azure_ai_unit_test_env: dict[str, str], mock_mcp_tool: "MockMCPTool", ) -> None: """Test that create_agent handles both MCP tools and regular FunctionTools.""" # Create a regular FunctionTool regular_function = create_mock_ai_function("regular_function", "A regular function") # Patch normalize_tools to return tools as-is in a list (avoids callable check) def mock_normalize_tools(tools): if tools is None: return [] if isinstance(tools, list): return tools return [tools] with ( patch("agent_framework_azure_ai._project_provider.load_settings") as mock_load_settings, patch("agent_framework_azure_ai._project_provider.to_azure_ai_tools") as mock_to_azure_tools, patch("agent_framework_azure_ai._project_provider.normalize_tools", side_effect=mock_normalize_tools), ): mock_load_settings.return_value = { "project_endpoint": azure_ai_unit_test_env["AZURE_AI_PROJECT_ENDPOINT"], "model_deployment_name": azure_ai_unit_test_env["AZURE_AI_MODEL_DEPLOYMENT_NAME"], } mock_to_azure_tools.return_value = [] provider = AzureAIProjectAgentProvider(project_client=mock_project_client) # Mock agent creation response mock_agent_version = MagicMock(spec=AgentVersionDetails) mock_agent_version.id = "agent-id" mock_agent_version.name = "test-agent" mock_agent_version.version = "1.0" mock_agent_version.description = None mock_agent_version.definition = MagicMock(spec=PromptAgentDefinition) mock_agent_version.definition.model = "gpt-4" mock_agent_version.definition.instructions = None mock_agent_version.definition.tools = [] mock_project_client.agents.create_version = AsyncMock(return_value=mock_agent_version) # Pass both MCP tool and regular function await provider.create_agent( name="test-agent", model="gpt-4", tools=[mock_mcp_tool, regular_function], ) # Verify to_azure_ai_tools was called with: # - The regular FunctionTool (1) # - The 2 discovered MCP functions mock_to_azure_tools.assert_called_once() tools_passed = mock_to_azure_tools.call_args[0][0] assert len(tools_passed) == 3 # 1 regular + 2 MCP functions # Verify the regular function is in the list tool_names = [t.name for t in tools_passed] assert "regular_function" in tool_names assert "mcp_function_1" in tool_names assert "mcp_function_2" in tool_names