diff --git a/dotnet/samples/04-hosting/DurableWorkflows/AzureFunctions/04_WorkflowMcpTool/local.settings.json b/dotnet/samples/04-hosting/DurableWorkflows/AzureFunctions/04_WorkflowMcpTool/local.settings.json deleted file mode 100644 index fcb6658e92..0000000000 --- a/dotnet/samples/04-hosting/DurableWorkflows/AzureFunctions/04_WorkflowMcpTool/local.settings.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "IsEncrypted": false, - "Values": { - "FUNCTIONS_WORKER_RUNTIME": "dotnet-isolated", - "AzureWebJobsStorage": "UseDevelopmentStorage=true", - "DURABLE_TASK_SCHEDULER_CONNECTION_STRING": "Endpoint=http://localhost:8080;TaskHub=default;Authentication=None" - } -} diff --git a/dotnet/samples/04-hosting/DurableWorkflows/AzureFunctions/05_WorkflowAndAgents/local.settings.json b/dotnet/samples/04-hosting/DurableWorkflows/AzureFunctions/05_WorkflowAndAgents/local.settings.json deleted file mode 100644 index 5f6d7d3340..0000000000 --- a/dotnet/samples/04-hosting/DurableWorkflows/AzureFunctions/05_WorkflowAndAgents/local.settings.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "IsEncrypted": false, - "Values": { - "FUNCTIONS_WORKER_RUNTIME": "dotnet-isolated", - "AzureWebJobsStorage": "UseDevelopmentStorage=true", - "DURABLE_TASK_SCHEDULER_CONNECTION_STRING": "Endpoint=http://localhost:8080;TaskHub=default;Authentication=None", - "AZURE_OPENAI_ENDPOINT": "", - "AZURE_OPENAI_DEPLOYMENT_NAME": "" - } -} diff --git a/python/packages/openai/tests/openai/test_openai_chat_completion_client.py b/python/packages/openai/tests/openai/test_openai_chat_completion_client.py index 391432958f..f4804534c7 100644 --- a/python/packages/openai/tests/openai/test_openai_chat_completion_client.py +++ b/python/packages/openai/tests/openai/test_openai_chat_completion_client.py @@ -188,6 +188,63 @@ class UnsupportedTool: assert result["tools"] == [dict_tool] +def test_mcp_tool_dict_passed_through_to_chat_api(openai_unit_test_env: dict[str, str]) -> None: + """Test that MCP tool dicts are passed through unchanged by the chat client. + + The Chat Completions API does not support "type": "mcp" tools. MCP tools + should be used with the Responses API client instead. This test documents + that the chat client passes dict-based tools through without filtering, + so callers must use the correct client for MCP tools. + """ + client = OpenAIChatCompletionClient() + + mcp_tool = { + "type": "mcp", + "server_label": "Microsoft_Learn_MCP", + "server_url": "https://learn.microsoft.com/api/mcp", + } + + result = client._prepare_tools_for_openai(mcp_tool) + assert "tools" in result + assert len(result["tools"]) == 1 + # The chat client passes dict tools through unchanged, including unsupported types + assert result["tools"][0]["type"] == "mcp" + + +@pytest.mark.asyncio +async def test_mcp_tool_dict_causes_api_rejection(openai_unit_test_env: dict[str, str]) -> None: + """Test that MCP tool dicts passed to the Chat Completions API cause a rejection. + + The Chat Completions API only supports "type": "function" tools. + When an MCP tool dict reaches the API, it returns a 400 error. + This regression test for #4861 verifies the chat client does not + silently drop or transform MCP dicts, so callers get a clear error + rather than a silent no-op. + """ + client = OpenAIChatCompletionClient() + messages = [Message(role="user", text="test message")] + + mcp_tool = { + "type": "mcp", + "server_label": "Microsoft_Learn_MCP", + "server_url": "https://learn.microsoft.com/api/mcp", + } + + mock_response = MagicMock() + mock_error = BadRequestError( + message="Invalid tool type: mcp", + response=mock_response, + body={"error": {"code": "invalid_request", "message": "Invalid tool type: mcp"}}, + ) + mock_error.code = "invalid_request" + + with ( + patch.object(client.client.chat.completions, "create", side_effect=mock_error), + pytest.raises(ChatClientException), + ): + await client._inner_get_response(messages=messages, options={"tools": mcp_tool}) # type: ignore + + def test_prepare_tools_with_single_function_tool( openai_unit_test_env: dict[str, str], ) -> None: diff --git a/python/samples/05-end-to-end/hosted_agents/agent_with_hosted_mcp/agent.yaml b/python/samples/05-end-to-end/hosted_agents/agent_with_hosted_mcp/agent.yaml index 5a0f58554d..d68b32cbb4 100644 --- a/python/samples/05-end-to-end/hosted_agents/agent_with_hosted_mcp/agent.yaml +++ b/python/samples/05-end-to-end/hosted_agents/agent_with_hosted_mcp/agent.yaml @@ -22,7 +22,7 @@ template: environment_variables: - name: AZURE_OPENAI_ENDPOINT value: ${AZURE_OPENAI_ENDPOINT} - - name: AZURE_OPENAI_CHAT_DEPLOYMENT_NAME + - name: AZURE_OPENAI_RESPONSES_DEPLOYMENT_NAME value: "{{chat}}" resources: - kind: model diff --git a/python/samples/05-end-to-end/hosted_agents/agent_with_hosted_mcp/main.py b/python/samples/05-end-to-end/hosted_agents/agent_with_hosted_mcp/main.py index fe6d4648c9..8d87046fa3 100644 --- a/python/samples/05-end-to-end/hosted_agents/agent_with_hosted_mcp/main.py +++ b/python/samples/05-end-to-end/hosted_agents/agent_with_hosted_mcp/main.py @@ -11,18 +11,20 @@ def main(): + client = FoundryChatClient(credential=AzureCliCredential()) + # Create MCP tool configuration as dict - mcp_tool = { - "type": "mcp", - "server_label": "Microsoft_Learn_MCP", - "server_url": "https://learn.microsoft.com/api/mcp", - } + mcp_tool = client.get_mcp_tool( + name="Microsoft_Learn_MCP", + url="https://learn.microsoft.com/api/mcp", + ) + # Create an Agent using the Azure OpenAI Chat Client with a MCP Tool that connects to Microsoft Learn MCP agent = Agent( - client=FoundryChatClient(credential=AzureCliCredential()), + client=client, name="DocsAgent", instructions="You are a helpful assistant that can help with microsoft documentation questions.", - tools=mcp_tool, + tools=[mcp_tool], ) # Run the agent as a hosted agent from_agent_framework(agent).run() diff --git a/python/samples/05-end-to-end/hosted_agents/agent_with_hosted_mcp/requirements.txt b/python/samples/05-end-to-end/hosted_agents/agent_with_hosted_mcp/requirements.txt index d05845588a..250c059d77 100644 --- a/python/samples/05-end-to-end/hosted_agents/agent_with_hosted_mcp/requirements.txt +++ b/python/samples/05-end-to-end/hosted_agents/agent_with_hosted_mcp/requirements.txt @@ -1,2 +1,2 @@ -azure-ai-agentserver-agentframework==1.0.0b3 -agent-framework \ No newline at end of file +azure-ai-agentserver-agentframework==1.0.0b16 +agent-framework