Skip to content

Commit 4cb88c9

Browse files
committed
mcp_tool_registration_service.py — threaded auth, auth_handler_name, context from add_tool_servers_to_agent into _get_mcp_tool_definitions_and_resources, which now passes them as keyword args to list_tool_servers() so _attach_per_audience_tokens() runs for V2 servers. Header injection reads server.headers (per-audience token) with fallback to the shared auth_token.
test_mcp_tool_registration_service.py — 7 tests covering: auth context forwarding, per-audience token used over shared token, fallback when headers empty, no double Bearer prefix, User-Agent header, and per-server isolation across multiple servers.
1 parent b1f6a3b commit 4cb88c9

2 files changed

Lines changed: 416 additions & 10 deletions

File tree

libraries/microsoft-agents-a365-tooling-extensions-azureaifoundry/microsoft_agents_a365/tooling/extensions/azureaifoundry/services/mcp_tool_registration_service.py

Lines changed: 30 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -106,9 +106,10 @@ async def add_tool_servers_to_agent(
106106

107107
try:
108108
agentic_app_id = Utility.resolve_agent_identity(context, auth_token)
109-
# Get the tool definitions and resources using the async implementation
109+
# Get the tool definitions and resources — pass auth context so each server receives
110+
# its own per-audience Authorization token (V1 = shared ATG, V2 = per-GUID).
110111
tool_definitions, tool_resources = await self._get_mcp_tool_definitions_and_resources(
111-
agentic_app_id, auth_token or ""
112+
agentic_app_id, auth_token or "", auth, auth_handler_name, context
112113
)
113114

114115
# Update the agent with the tools
@@ -127,7 +128,12 @@ async def add_tool_servers_to_agent(
127128
raise
128129

129130
async def _get_mcp_tool_definitions_and_resources(
130-
self, agentic_app_id: str, auth_token: str
131+
self,
132+
agentic_app_id: str,
133+
auth_token: str,
134+
authorization: Authorization,
135+
auth_handler_name: str,
136+
turn_context: TurnContext,
131137
) -> Tuple[List[McpTool], Optional[ToolResources]]:
132138
"""
133139
Internal method to get MCP tool definitions and resources.
@@ -136,7 +142,10 @@ async def _get_mcp_tool_definitions_and_resources(
136142
137143
Args:
138144
agentic_app_id: Agentic App ID for the agent.
139-
auth_token: Authentication token to access the MCP servers.
145+
auth_token: Authentication token used for gateway discovery.
146+
authorization: Authorization context for per-audience token exchange.
147+
auth_handler_name: Auth handler name for per-audience token exchange.
148+
turn_context: TurnContext for per-audience token exchange.
140149
141150
Returns:
142151
Tuple containing tool definitions and resources.
@@ -145,11 +154,17 @@ async def _get_mcp_tool_definitions_and_resources(
145154
self._logger.error("MCP server configuration service is not available")
146155
return ([], None)
147156

148-
# Get MCP server configurations
157+
# Get MCP server configurations — pass auth context so each server receives
158+
# its own per-audience Authorization token (V1 = shared ATG, V2 = per-GUID).
149159
options = ToolOptions(orchestrator_name=self._orchestrator_name)
150160
try:
151161
servers = await self._mcp_server_configuration_service.list_tool_servers(
152-
agentic_app_id, auth_token, options
162+
agentic_app_id,
163+
auth_token,
164+
options,
165+
authorization=authorization,
166+
auth_handler_name=auth_handler_name,
167+
turn_context=turn_context,
153168
)
154169
except Exception as ex:
155170
self._logger.error(
@@ -191,14 +206,19 @@ async def _get_mcp_tool_definitions_and_resources(
191206
# Configure the tool
192207
mcp_tool.set_approval_mode("never")
193208

194-
# Set up authorization header
195-
if auth_token:
196-
header_value = (
209+
# Set per-server headers: use per-audience token from list_tool_servers
210+
# (V1 servers get the shared ATG token, V2 servers get their own audience token).
211+
# Fall back to the shared discovery auth_token only if no per-server header is set.
212+
server_headers = dict(server.headers) if server.headers else {}
213+
auth_header = server_headers.get(Constants.Headers.AUTHORIZATION)
214+
if not auth_header and auth_token:
215+
auth_header = (
197216
auth_token
198217
if auth_token.lower().startswith(f"{Constants.Headers.BEARER_PREFIX.lower()} ")
199218
else f"{Constants.Headers.BEARER_PREFIX} {auth_token}"
200219
)
201-
mcp_tool.update_headers(Constants.Headers.AUTHORIZATION, header_value)
220+
if auth_header:
221+
mcp_tool.update_headers(Constants.Headers.AUTHORIZATION, auth_header)
202222

203223
mcp_tool.update_headers(
204224
Constants.Headers.USER_AGENT, Utility.get_user_agent_header(self._orchestrator_name)

0 commit comments

Comments
 (0)