Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 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 @@ -46,16 +46,15 @@ export class McpToolRegistrationService {
Utility.ValidateAuthToken(authToken);

const agenticAppId = RuntimeUtility.ResolveAgentIdentity(turnContext, authToken);
const servers = await this.configService.listToolServers(agenticAppId, authToken);
const channelId = turnContext?.activity?.channelId as string | undefined;
const subChannelId = turnContext?.activity?.channelIdSubChannel as string | undefined;
const servers = await this.configService.listToolServers(agenticAppId, authToken, channelId, subChannelId);
const mcpServers: Record<string, McpServerConfig> = {};
const tools: McpClientTool[] = [];

for (const server of servers) {
// Compose headers if values are available
const headers: Record<string, string> = {};
if (authToken) {
headers['Authorization'] = `Bearer ${authToken}`;
}

Comment thread
fpfp100 marked this conversation as resolved.
Outdated
const headers: Record<string, string> = Utility.GetToolRequestHeaders(authToken, channelId, subChannelId);

// Add each server to the config object
mcpServers[server.mcpServerName] = {
Expand Down Expand Up @@ -87,4 +86,4 @@ export class McpToolRegistrationService {

agentOptions.mcpServers = Object.assign(agentOptions.mcpServers ?? {}, mcpServers);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -49,15 +49,14 @@ export class McpToolRegistrationService {
Utility.ValidateAuthToken(authToken);

const agenticAppId = RuntimeUtility.ResolveAgentIdentity(turnContext, authToken);
const servers = await this.configService.listToolServers(agenticAppId, authToken);
const channelId = turnContext?.activity?.channelId as string | undefined;
const subChannelId = turnContext?.activity?.channelIdSubChannel as string | undefined;
const servers = await this.configService.listToolServers(agenticAppId, authToken, channelId, subChannelId);
const mcpServers: Record<string, Connection> = {};

for (const server of servers) {
// Compose headers if values are available
const headers: Record<string, string> = {};
if (authToken) {
headers['Authorization'] = `Bearer ${authToken}`;
}
const headers: Record<string, string> = Utility.GetToolRequestHeaders(authToken, channelId, subChannelId);

// Create Connection instance for LangChain agents
mcpServers[server.mcpServerName] = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,15 +48,14 @@ export class McpToolRegistrationService {
Utility.ValidateAuthToken(authToken);

const agenticAppId = RuntimeUtility.ResolveAgentIdentity(turnContext, authToken);
const servers = await this.configService.listToolServers(agenticAppId, authToken);
const channelId = turnContext?.activity?.channelId as string | undefined;
const subChannelId = turnContext?.activity?.channelIdSubChannel as string | undefined;
const servers = await this.configService.listToolServers(agenticAppId, authToken, channelId, subChannelId);
const mcpServers: MCPServerStreamableHttp[] = [];

for (const server of servers) {
// Compose headers if values are available
const headers: Record<string, string> = {};
if (authToken) {
headers['Authorization'] = `Bearer ${authToken}`;
}
const headers: Record<string, string> = Utility.GetToolRequestHeaders(authToken, channelId, subChannelId);

// Create MCPServerStreamableHttp instance for OpenAI agents
const mcpServer = new MCPServerStreamableHttp({
Expand All @@ -75,4 +74,4 @@ export class McpToolRegistrationService {

return agent;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,14 @@ export class McpToolServerConfigurationService {
*
* @param agenticAppId The agentic app id for which to discover servers.
* @param authToken Optional bearer token used when querying the remote tooling gateway.
* @param channelId Optional channel identifier header used for routing.
* @param subChannelId Optional sub-channel identifier header used for routing.
* @returns A promise resolving to an array of normalized MCP server configuration objects.
*/
async listToolServers(agenticAppId: string, authToken: string): Promise<MCPServerConfig[]> {
return await (this.isDevScenario() ? this.getMCPServerConfigsFromManifest() : this.getMCPServerConfigsFromToolingGateway(agenticAppId, authToken));
async listToolServers(agenticAppId: string, authToken: string, channelId?: string, subChannelId?: string): Promise<MCPServerConfig[]> {
Comment thread
fpfp100 marked this conversation as resolved.
Outdated
return await (this.isDevScenario()
? this.getMCPServerConfigsFromManifest()
: this.getMCPServerConfigsFromToolingGateway(agenticAppId, authToken, channelId, subChannelId));
}

/**
Expand Down Expand Up @@ -70,25 +74,28 @@ export class McpToolServerConfigurationService {

/**
* Query the tooling gateway for MCP servers for the specified agent and normalize each entry's mcpServerUniqueName into a full URL using Utility.BuildMcpServerUrl.
* Includes optional channel context headers and supports optional bearer token.
* Throws an error if the gateway call fails.
*
* @param agenticAppId The agentic app id used by the tooling gateway to scope results.
* @param authToken Optional Bearer token to include in the Authorization header when calling the gateway.
* @param channelId Optional channel identifier header used for routing.
* @param subChannelId Optional sub-channel identifier header used for routing.
* @returns Array of MCP server configs from the gateway (empty on no data).
* @throws Error when the gateway call fails or returns an unexpected payload.
*/
private async getMCPServerConfigsFromToolingGateway(agenticAppId: string, authToken: string): Promise<MCPServerConfig[]> {
private async getMCPServerConfigsFromToolingGateway(agenticAppId: string, authToken: string, channelId?: string, subChannelId?: string): Promise<MCPServerConfig[]> {
// Validate the authentication token
Utility.ValidateAuthToken(authToken);

const configEndpoint = Utility.GetToolingGatewayForDigitalWorker(agenticAppId);

try {
const headers = Utility.GetToolRequestHeaders(authToken, channelId, subChannelId);
const response = await axios.get(
configEndpoint,
{
headers: {
'Authorization': authToken ? `Bearer ${authToken}` : undefined,
},
headers,
timeout: 10000 // 10 seconds timeout
}
);
Expand Down
36 changes: 35 additions & 1 deletion packages/agents-a365-tooling/src/Utility.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,40 @@
const MCP_PLATFORM_PROD_BASE_URL = 'https://agent365.svc.cloud.microsoft';

export class Utility {
public static readonly HEADER_CHANNEL_ID = 'x-ms-channel-id';
public static readonly HEADER_SUBCHANNEL_ID = 'x-ms-subchannel-id';

/**
* Compose standard headers for MCP tooling requests.
* Includes Authorization bearer token when provided, and optionally includes channel and subchannel identifiers for routing.
Comment thread
fpfp100 marked this conversation as resolved.
Outdated
*
* @param authToken Bearer token.
* @param channelId Optional channel identifier.
* @param subChannelId Optional sub-channel identifier.
Comment thread
fpfp100 marked this conversation as resolved.
Outdated
* @returns A headers record suitable for HTTP requests.
*/
public static GetToolRequestHeaders(
Comment thread
fpfp100 marked this conversation as resolved.
authToken: string,
channelId?: string,
Comment thread
fpfp100 marked this conversation as resolved.
Outdated
subChannelId?: string
Comment thread
fpfp100 marked this conversation as resolved.
Outdated
): Record<string, string> {
const headers: Record<string, string> = {};

if (authToken) {
headers['Authorization'] = `Bearer ${authToken}`;
}

if (channelId) {
headers[Utility.HEADER_CHANNEL_ID] = channelId;
}

if (subChannelId) {
headers[Utility.HEADER_SUBCHANNEL_ID] = subChannelId;
}

return headers;
}
Comment thread
fpfp100 marked this conversation as resolved.

/**
* Validates a JWT authentication token.
* Checks that the token is a valid JWT and is not expired.
Expand Down Expand Up @@ -132,4 +166,4 @@ export class Utility {

return MCP_PLATFORM_PROD_BASE_URL;
}
}
}