11# Copyright (c) Microsoft Corporation.
22# Licensed under the MIT License.
33
4+ from __future__ import annotations
5+
46import logging
57import uuid
68from datetime import datetime , timezone
7- from typing import Any , List , Optional , Sequence , Union
9+ from typing import TYPE_CHECKING , List , Optional , Sequence
810
9- from agent_framework import RawAgent , Message , BaseHistoryProvider , MCPStreamableHTTPTool
10- from agent_framework .azure import AzureOpenAIChatClient
11- from agent_framework .openai import OpenAIChatClient
11+ from agent_framework import RawAgent , Message , HistoryProvider , MCPStreamableHTTPTool
1212import httpx
1313
14+ if TYPE_CHECKING :
15+ from agent_framework .openai import OpenAIChatClient
16+
1417from microsoft_agents .hosting .core import Authorization , TurnContext
1518
1619from microsoft_agents_a365 .runtime import OperationResult
2225from microsoft_agents_a365 .tooling .utils .constants import Constants
2326from microsoft_agents_a365 .tooling .utils .utility import (
2427 get_mcp_platform_authentication_scope ,
28+ is_development_environment ,
2529)
2630
2731
@@ -55,9 +59,9 @@ def __init__(self, logger: Optional[logging.Logger] = None):
5559
5660 async def add_tool_servers_to_agent (
5761 self ,
58- chat_client : Union [ OpenAIChatClient , AzureOpenAIChatClient ] ,
62+ chat_client : OpenAIChatClient ,
5963 agent_instructions : str ,
60- initial_tools : List [Any ],
64+ initial_tools : List [object ],
6165 auth : Authorization ,
6266 auth_handler_name : str ,
6367 turn_context : TurnContext ,
@@ -67,7 +71,7 @@ async def add_tool_servers_to_agent(
6771 Add MCP tool servers to a RawAgent (mirrors .NET implementation).
6872
6973 Args:
70- chat_client: The chat client instance (Union[ OpenAIChatClient, AzureOpenAIChatClient] )
74+ chat_client: The chat client instance (OpenAIChatClient supports both OpenAI and Azure OpenAI )
7175 agent_instructions: Instructions for the agent behavior
7276 initial_tools: List of initial tools to add to the agent
7377 auth: Authorization context for token exchange
@@ -82,23 +86,31 @@ async def add_tool_servers_to_agent(
8286 Exception: If agent creation fails.
8387 """
8488 try :
85- # Exchange token if not provided
86- if not auth_token :
89+ is_dev = is_development_environment ()
90+ if not auth_token and not is_dev :
91+ # Only exchange a token in production; dev mode uses BEARER_TOKEN* env vars instead.
8792 scopes = get_mcp_platform_authentication_scope ()
8893 authToken = await auth .exchange_token (turn_context , scopes , auth_handler_name )
8994 auth_token = authToken .token
9095
91- agentic_app_id = Utility .resolve_agent_identity (turn_context , auth_token )
96+ # In dev mode, agentic_app_id is not needed for manifest-based discovery.
97+ agentic_app_id = (
98+ "" if is_dev else Utility .resolve_agent_identity (turn_context , auth_token )
99+ )
92100
93101 self ._logger .info (f"Listing MCP tool servers for agent { agentic_app_id } " )
94102
95103 options = ToolOptions (orchestrator_name = self ._orchestrator_name )
96104
97- # Get MCP server configurations
105+ # Get MCP server configurations — pass auth context so each server receives
106+ # its own per-audience Authorization token (V1 = shared ATG, V2 = per-GUID).
98107 server_configs = await self ._mcp_server_configuration_service .list_tool_servers (
99108 agentic_app_id = agentic_app_id ,
100109 auth_token = auth_token ,
101110 options = options ,
111+ authorization = auth ,
112+ auth_handler_name = auth_handler_name ,
113+ turn_context = turn_context ,
102114 )
103115
104116 self ._logger .info (f"Loaded { len (server_configs )} MCP server configurations" )
@@ -112,16 +124,26 @@ async def add_tool_servers_to_agent(
112124 server_name = config .mcp_server_name or config .mcp_server_unique_name
113125
114126 try :
115- # Prepare auth headers
116- headers = {}
117- if auth_token :
118- headers [ Constants .Headers .AUTHORIZATION ] = (
119- f" { Constants . Headers . BEARER_PREFIX } { auth_token } "
127+ # Merge base (non- auth) headers with per-server headers from list_tool_servers.
128+ # server. headers already contains the correct per-audience Authorization token.
129+ base_headers = {
130+ Constants .Headers .USER_AGENT : Utility . get_user_agent_header (
131+ self . _orchestrator_name
120132 )
121-
122- headers [Constants .Headers .USER_AGENT ] = Utility .get_user_agent_header (
123- self ._orchestrator_name
124- )
133+ }
134+ server_headers = dict (config .headers ) if config .headers else {}
135+ # Fall back to the shared discovery token when no per-server
136+ # Authorization header was attached (e.g. dev mode without
137+ # BEARER_TOKEN* env vars, or legacy V1 callers).
138+ if Constants .Headers .AUTHORIZATION not in server_headers and auth_token :
139+ server_headers [Constants .Headers .AUTHORIZATION ] = (
140+ auth_token
141+ if auth_token .lower ().startswith (
142+ f"{ Constants .Headers .BEARER_PREFIX .lower ()} "
143+ )
144+ else f"{ Constants .Headers .BEARER_PREFIX } { auth_token } "
145+ )
146+ headers = {** base_headers , ** server_headers } # server auth takes precedence
125147
126148 # Create httpx client with auth headers configured
127149 http_client = httpx .AsyncClient (
@@ -307,18 +329,18 @@ async def send_chat_history_messages(
307329
308330 async def send_chat_history_from_store (
309331 self ,
310- chat_message_store : BaseHistoryProvider ,
332+ chat_message_store : HistoryProvider ,
311333 turn_context : TurnContext ,
312334 tool_options : Optional [ToolOptions ] = None ,
313335 ) -> OperationResult :
314336 """
315- Send chat history from a BaseHistoryProvider to the MCP platform.
337+ Send chat history from a HistoryProvider to the MCP platform.
316338
317339 This is a convenience method that extracts messages from the store
318340 and delegates to send_chat_history_messages().
319341
320342 Args:
321- chat_message_store: BaseHistoryProvider containing the conversation history.
343+ chat_message_store: HistoryProvider containing the conversation history.
322344 turn_context: TurnContext from the Agents SDK containing conversation info.
323345 tool_options: Optional configuration for the request.
324346
0 commit comments