Skip to content
Merged
Show file tree
Hide file tree
Changes from 8 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ def resolve_agent_identity(context: Any, auth_token: Optional[str]) -> str:
return Utility.get_app_id_from_token(auth_token)

@staticmethod
def get_user_agent_header(orchestrator: str = "") -> str:
def get_user_agent_header(orchestrator: Optional[str] = None) -> str:
"""
Generates a User-Agent header string for SDK requests.

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ class McpToolRegistrationService:
tool servers with Agent Framework agents.
"""

_orchestrator_name: str = "AgentFramework"

def __init__(self, logger: Optional[logging.Logger] = None):
"""
Initialize the MCP Tool Registration Service for Agent Framework.
Expand Down Expand Up @@ -81,6 +83,7 @@ async def add_tool_servers_to_agent(
server_configs = await self._mcp_server_configuration_service.list_tool_servers(
agentic_app_id=agentic_app_id,
auth_token=auth_token,
orchestrator_name=self._orchestrator_name,
)

self._logger.info(f"Loaded {len(server_configs)} MCP server configurations")
Expand All @@ -105,6 +108,10 @@ async def add_tool_servers_to_agent(
f"{Constants.Headers.BEARER_PREFIX} {auth_token}"
)

headers[Constants.Headers.USER_AGENT] = Utility.get_user_agent_header(
self._orchestrator_name
)

server_name = getattr(config, "mcp_server_name", "Unknown")

# Create and configure MCPStreamableHTTPTool
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,8 @@ class McpToolRegistrationService:
>>> service.add_tool_servers_to_agent(project_client, agent_id, token)
"""

_orchestrator_name: str = "AzureAIFoundry"

def __init__(
self,
logger: Optional[logging.Logger] = None,
Expand Down Expand Up @@ -141,7 +143,7 @@ async def _get_mcp_tool_definitions_and_resources(
# Get MCP server configurations
try:
servers = await self._mcp_server_configuration_service.list_tool_servers(
agentic_app_id, auth_token
agentic_app_id, auth_token, self._orchestrator_name
)
except Exception as ex:
self._logger.error(
Expand Down Expand Up @@ -189,6 +191,10 @@ async def _get_mcp_tool_definitions_and_resources(
)
mcp_tool.update_headers(Constants.Headers.AUTHORIZATION, header_value)

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

# Add to collections
tool_definitions.extend(mcp_tool.definitions)
if mcp_tool.resources and mcp_tool.resources.mcp:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
McpToolServerConfigurationService,
)

from microsoft_agents_a365.tooling.utils.constants import Constants
from microsoft_agents_a365.tooling.utils.utility import (
get_mcp_platform_authentication_scope,
)
Expand All @@ -38,6 +39,8 @@ class MCPServerInfo:
class McpToolRegistrationService:
"""Service for managing MCP tools and servers for an agent"""

_orchestrator_name: str = "OpenAI"

def __init__(self, logger: Optional[logging.Logger] = None):
"""
Initialize the MCP Tool Registration Service for OpenAI.
Expand Down Expand Up @@ -88,6 +91,7 @@ async def add_tool_servers_to_agent(
mcp_server_configs = await self.config_service.list_tool_servers(
agentic_app_id=agentic_app_id,
auth_token=auth_token,
orchestrator_name=self._orchestrator_name,
)

self._logger.info(f"Loaded {len(mcp_server_configs)} MCP server configurations")
Expand Down Expand Up @@ -132,7 +136,13 @@ async def add_tool_servers_to_agent(
# Prepare headers with authorization
headers = si.headers or {}
if auth_token:
headers["Authorization"] = f"Bearer {auth_token}"
headers[Constants.Headers.AUTHORIZATION] = (
f"{Constants.Headers.BEARER_PREFIX} {auth_token}"
)

headers[Constants.Headers.USER_AGENT] = Utility.get_user_agent_header(
self._orchestrator_name
)

# Create MCPServerStreamableHttpParams with proper configuration
params = MCPServerStreamableHttpParams(url=si.url, headers=headers)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@ class McpToolRegistrationService:
tool servers with Semantic Kernel agents.
"""

_orchestrator_name: str = "SemanticKernel"

def __init__(
self,
logger: Optional[logging.Logger] = None,
Expand Down Expand Up @@ -108,7 +110,7 @@ async def add_tool_servers_to_agent(

# Get and process servers
servers = await self._mcp_server_configuration_service.list_tool_servers(
agentic_app_id, auth_token
agentic_app_id, auth_token, self._orchestrator_name
)
self._logger.info(f"🔧 Adding MCP tools from {len(servers)} servers")

Expand All @@ -132,6 +134,10 @@ async def add_tool_servers_to_agent(
Constants.Headers.AUTHORIZATION: f"{Constants.Headers.BEARER_PREFIX} {auth_token}",
}

headers[Constants.Headers.USER_AGENT] = Utility.get_user_agent_header(
self._orchestrator_name
)

plugin = MCPStreamableHttpPlugin(
name=server.mcp_server_name,
url=server.mcp_server_unique_name,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,9 @@
from ..utils import Constants
from ..utils.utility import get_tooling_gateway_for_digital_worker, build_mcp_server_url

# Runtime Imports
from microsoft_agents_a365.runtime.utility import Utility as RuntimeUtility


# ==============================================================================
# MAIN SERVICE CLASS
Expand Down Expand Up @@ -66,14 +69,15 @@ def __init__(self, logger: Optional[logging.Logger] = None):
# --------------------------------------------------------------------------

async def list_tool_servers(
self, agentic_app_id: str, auth_token: str
self, agentic_app_id: str, auth_token: str, orchestrator_name: Optional[str] = None
Comment thread
JesuTerraz marked this conversation as resolved.
Outdated
) -> List[MCPServerConfig]:
"""
Gets the list of MCP Servers that are configured for the agent.

Args:
agentic_app_id: Agentic App ID for the agent.
auth_token: Authentication token to access the MCP servers.
orchestrator_name: Optional orchestrator name to include in User-Agent header.

Returns:
List[MCPServerConfig]: Returns the list of MCP Servers that are configured.
Expand All @@ -91,7 +95,9 @@ async def list_tool_servers(
if self._is_development_scenario():
return self._load_servers_from_manifest()
else:
return await self._load_servers_from_gateway(agentic_app_id, auth_token)
return await self._load_servers_from_gateway(
agentic_app_id, auth_token, orchestrator_name
)

# --------------------------------------------------------------------------
# ENVIRONMENT DETECTION
Expand Down Expand Up @@ -275,14 +281,15 @@ def _log_manifest_search_failure(self) -> None:
# --------------------------------------------------------------------------

async def _load_servers_from_gateway(
self, agentic_app_id: str, auth_token: str
self, agentic_app_id: str, auth_token: str, orchestrator_name: Optional[str] = None
) -> List[MCPServerConfig]:
"""
Reads MCP server configurations from tooling gateway endpoint for production scenario.

Args:
agentic_app_id: Agentic App ID for the agent.
auth_token: Authentication token to access the tooling gateway.
orchestrator_name: Optional orchestrator name to include in User-Agent header.
Comment thread
JesuTerraz marked this conversation as resolved.
Outdated

Returns:
List[MCPServerConfig]: List of MCP server configurations from tooling gateway.
Expand All @@ -294,7 +301,7 @@ async def _load_servers_from_gateway(

try:
config_endpoint = get_tooling_gateway_for_digital_worker(agentic_app_id)
headers = self._prepare_gateway_headers(auth_token)
headers = self._prepare_gateway_headers(auth_token, orchestrator_name)

self._logger.info(f"Calling tooling gateway endpoint: {config_endpoint}")

Expand Down Expand Up @@ -323,18 +330,22 @@ async def _load_servers_from_gateway(

return mcp_servers

def _prepare_gateway_headers(self, auth_token: str) -> Dict[str, str]:
def _prepare_gateway_headers(
self, auth_token: str, orchestrator_name: Optional[str] = None
) -> Dict[str, str]:
"""
Prepares headers for tooling gateway requests.
Comment thread
JesuTerraz marked this conversation as resolved.

Args:
auth_token: Authentication token.
orchestrator_name: Optional orchestrator name to include in User-Agent header.

Returns:
Dictionary of HTTP headers.
"""
return {
"Authorization": f"{Constants.Headers.BEARER_PREFIX} {auth_token}",
Constants.Headers.AUTHORIZATION: f"{Constants.Headers.BEARER_PREFIX} {auth_token}",
Constants.Headers.USER_AGENT: RuntimeUtility.get_user_agent_header(orchestrator_name),
}

async def _parse_gateway_response(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,3 +20,6 @@ class Headers:

#: The prefix used for Bearer authentication tokens in HTTP headers.
BEARER_PREFIX = "Bearer"

#: The header name for User-Agent information.
USER_AGENT = "User-Agent"
Loading