mirror of
https://github.com/microsoft/agent-framework.git
synced 2026-06-16 21:04:09 +08:00
Python: fix(declarative): Fix MCP tool connection not passed from YAML to Azure AI agent creation API (#3248)
* fix(declarative): Fix MCP tool connection not passed from YAML * Add samples to README * Fix mypy * Fix mypy again * Address PR comments
This commit is contained in:
@@ -33,7 +33,7 @@ from azure.core.credentials_async import AsyncTokenCredential
|
||||
from azure.core.exceptions import ResourceNotFoundError
|
||||
from pydantic import ValidationError
|
||||
|
||||
from ._shared import AzureAISettings, create_text_format_config
|
||||
from ._shared import AzureAISettings, _extract_project_connection_id, create_text_format_config
|
||||
|
||||
if sys.version_info >= (3, 13):
|
||||
from typing import TypeVar # type: ignore # pragma: no cover
|
||||
@@ -510,6 +510,17 @@ class AzureAIClient(OpenAIBaseResponsesClient[TAzureAIClientOptions], Generic[TA
|
||||
"""Get MCP tool from HostedMCPTool."""
|
||||
mcp = MCPTool(server_label=tool.name.replace(" ", "_"), server_url=str(tool.url))
|
||||
|
||||
if tool.description:
|
||||
mcp["server_description"] = tool.description
|
||||
|
||||
# Check for project_connection_id in additional_properties (for Azure AI Foundry connections)
|
||||
project_connection_id = _extract_project_connection_id(tool.additional_properties)
|
||||
if project_connection_id:
|
||||
mcp["project_connection_id"] = project_connection_id
|
||||
elif tool.headers:
|
||||
# Only use headers if no project_connection_id is available
|
||||
mcp["headers"] = tool.headers
|
||||
|
||||
if tool.allowed_tools:
|
||||
mcp["allowed_tools"] = list(tool.allowed_tools)
|
||||
|
||||
|
||||
@@ -87,6 +87,37 @@ class AzureAISettings(AFBaseSettings):
|
||||
model_deployment_name: str | None = None
|
||||
|
||||
|
||||
def _extract_project_connection_id(additional_properties: dict[str, Any] | None) -> str | None:
|
||||
"""Extract project_connection_id from HostedMCPTool additional_properties.
|
||||
|
||||
Checks for both direct 'project_connection_id' key (programmatic usage)
|
||||
and 'connection.name' structure (declarative/YAML usage).
|
||||
|
||||
Args:
|
||||
additional_properties: The additional_properties dict from a HostedMCPTool.
|
||||
|
||||
Returns:
|
||||
The project_connection_id if found, None otherwise.
|
||||
"""
|
||||
if not additional_properties:
|
||||
return None
|
||||
|
||||
# Check for direct project_connection_id (programmatic usage)
|
||||
project_connection_id = additional_properties.get("project_connection_id")
|
||||
if isinstance(project_connection_id, str):
|
||||
return project_connection_id
|
||||
|
||||
# Check for connection.name structure (declarative/YAML usage)
|
||||
if "connection" in additional_properties:
|
||||
conn = additional_properties["connection"]
|
||||
if isinstance(conn, dict):
|
||||
name = conn.get("name")
|
||||
if isinstance(name, str):
|
||||
return name
|
||||
|
||||
return None
|
||||
|
||||
|
||||
def to_azure_ai_agent_tools(
|
||||
tools: Sequence[ToolProtocol | MutableMapping[str, Any]] | None,
|
||||
run_options: dict[str, Any] | None = None,
|
||||
@@ -322,6 +353,11 @@ def from_azure_ai_tools(tools: Sequence[Tool | dict[str, Any]] | None) -> list[T
|
||||
if "never" in require_approval:
|
||||
approval_mode["never_require_approval"] = set(require_approval["never"].get("tool_names", [])) # type: ignore
|
||||
|
||||
# Preserve project_connection_id in additional_properties
|
||||
additional_props: dict[str, Any] | None = None
|
||||
if project_connection_id := mcp_tool.get("project_connection_id"):
|
||||
additional_props = {"connection": {"name": project_connection_id}}
|
||||
|
||||
agent_tools.append(
|
||||
HostedMCPTool(
|
||||
name=mcp_tool.get("server_label", "").replace("_", " "),
|
||||
@@ -330,6 +366,7 @@ def from_azure_ai_tools(tools: Sequence[Tool | dict[str, Any]] | None) -> list[T
|
||||
headers=mcp_tool.get("headers"),
|
||||
allowed_tools=mcp_tool.get("allowed_tools"),
|
||||
approval_mode=approval_mode, # type: ignore
|
||||
additional_properties=additional_props,
|
||||
)
|
||||
)
|
||||
elif tool_type == "code_interpreter":
|
||||
@@ -466,7 +503,13 @@ def _prepare_mcp_tool_for_azure_ai(tool: HostedMCPTool) -> MCPTool:
|
||||
if tool.description:
|
||||
mcp["server_description"] = tool.description
|
||||
|
||||
if tool.headers:
|
||||
# Check for project_connection_id in additional_properties (for Azure AI Foundry connections)
|
||||
project_connection_id = _extract_project_connection_id(tool.additional_properties)
|
||||
if project_connection_id:
|
||||
mcp["project_connection_id"] = project_connection_id
|
||||
elif tool.headers:
|
||||
# Only use headers if no project_connection_id is available
|
||||
# Note: Azure AI Agent Service may reject headers with sensitive info
|
||||
mcp["headers"] = tool.headers
|
||||
|
||||
if tool.allowed_tools:
|
||||
|
||||
Reference in New Issue
Block a user