Azure / Azure/azure-sdk-for-python
MCP tool approval in multi-step workflow with Anthropic model
- Dominant language
- Python
- Stars
- 5.6k
- Forks
- 3.4k
- Avg merge
- 1d 21h
- Merged PRs (30d)
- 193
Description
- **Package Name**: azure-ai-projects, azure-identity, openai
- **Package Version**:
- azure-ai-projects version: 2.3.0
- azure-identity version: 1.25.3
- openai version: 2.44.0
- **Operating System**: Windows 11
- **Python Version**: Python 3.14.5
**Describe the bug**
When using Azure AI Foundry Agents with an MCP tool configured with `require_approval="always"` and the `claude-sonnet-4-6` model, the first MCP approval succeeds, but a subsequent MCP approval request in the same response chain fails with HTTP 400.
The same workflow succeeds when `require_approval="never"` is used.
The issue appears when Claude performs a multi-step MCP interaction:
1. Request MCP approval.
2. Execute MCP tool call.
3. Request approval for a second MCP tool call.
4. Approval response for the second request returns HTTP 400.
The identical approval payload format works for the first approval request.
**To Reproduce**
I was following and adjusted the code for `agent.py` slightly to handle multi-step approvals.
Steps to reproduce the behavior:
agent.py
```python
import os
from dotenv import load_dotenv
import json
# Add references
import azure.identity as azure_identity
import azure.ai.projects as azure_ai_projects
import openai as openai
from azure.identity import DefaultAzureCredential
from azure.ai.projects import AIProjectClient
from azure.ai.projects.models import PromptAgentDefinition, MCPTool
from openai.types.responses.response_input_param import (
McpApprovalResponse,
ResponseInputParam,
)
from openai import BadRequestError
# Load environment variables from .env file
load_dotenv()
project_endpoint = os.getenv("PROJECT_ENDPOINT")
model_deployment = os.getenv("MODEL_DEPLOYMENT_NAME")
print("=" * 80)
print(f"azure-ai-projects version: {azure_ai_projects.__version__}")
print(f"azure-identity version: {azure_identity.__version__}")
print(f"openai version: {openai.__version__}")
print("=" * 80)
# Connect to the agents client
with (
DefaultAzureCredential() as credential,
AIProjectClient(endpoint=project_endpoint, credential=credential) as project_client,
project_client.get_openai_client() as openai_client,
):
# Initialize agent MCP tool
mcp_tool = MCPTool(
server_label="api-specs",
server_url="https://learn.microsoft.com/api/mcp",
require_approval="always",
)
# Create a new agent with the MCP tool
agent = project_client.agents.create_version(
agent_name="MyAgent",
definition=PromptAgentDefinition(
model=model_deployment,
instructions="You are a helpful agent that can use MCP tools to assist users. Use the available MCP tools to answer questions and perform tasks.",
tools=[mcp_tool],
),
)
print(
f"Agent created (id: {agent.id}, name: {agent.name}, version: {agent.version})"
)
# Create conversation thread
conversation = openai_client.conversations.create()
print(f"Created conversation (id: {conversation.id})")
# Send initial request that will trigger the MCP tool
response = openai_client.responses.create(
conversation=conversation.id,
input="Give me the Azure CLI commands to create an Azure Container App with a managed identity.",
extra_body={"agent_reference": {"name": agent.name, "type": "agent_reference"}},
)
response_nr = 1
# Process any MCP approval requests that were generated
# The agent may issue several tool calls, each needing its own approval,
# so we loop until there are none left.
# # I had to change this from the instructions,
# # because my model iterated over tools instead of providing a list of tool calls.
while not response.output_text:
print("=" * 80)
print(
f"Response {response_nr}: {json.dumps(response.model_dump(), indent=2, sort_keys=True)}"
)
print("=" * 80)
# Collect any MCP approval requests from the latest response
input_list: ResponseInputParam = []
item_nr = 1
for item in response.output:
print(
f"Input Item {response_nr}.{item_nr}: {json.dumps(item.model_dump(), indent=2, sort_keys=True)}"
)
if item.type == "mcp_approval_request":
if item.server_label == "api-specs" and item.id:
# Automatically approve the MCP request to allow the agent to proceed
result = McpApprovalResponse(
type="mcp_approval_response",
approve=True,
approval_request_id=item.id,
)
print(
f"Output Item {response_nr}.{item_nr}: {json.dumps(result, indent=2, sort_keys=True)}"
)
input_list.append(result)
item_nr += 1
response_nr += 1
if not input_list:
break
try:
response = openai_client.responses.create(
input=input_list,
previous_response_id=response.id,
extra_body={
"agent_reference": {"name": agent.name, "type": "agent_reference"}
},
)
except BadRequestError as e:
print("Status:", e.status_code)
if hasattr(e, "response") and e.response:
print("Headers:", e.response.headers)
try:
print("JSON:", e.response.json())
except Exception:
print("TEXT:", e.response.text)
raise
print(f"\nAgent response: {response.output_text}")
# Clean up resources by deleting the agent version
project_client.agents.delete_version(
agent_name=agent.name, agent_version=agent.version
)
print("Agent deleted")
```
output structure
```bash
Response 1: {...}
Input Item 1.1: {type: mcp_list_tools}
Input Item 1.2: {type: mcp_approval_request}
Output Item 1.2: {type: mcp_approval_response}
Response 2: {...}
Input Item 2.1: {type: mcp_call}
Input Item 2.2: {type: mcp_approval_request}
Output Item 2.2: {type: mcp_approval_response}
...
openai.BadRequestError: Error code: 400 - {'error': {'message': 'There was an issue with your request. Please check your inputs and try again', 'type': 'invalid_request_error', 'param': None, 'code': None}}
```
**Expected behavior**
The second MCP approval should be accepted and the agent should continue execution, eventually producing a final response.
Contributor guide
Assessment
This issue has not been assessed yet.