Skip to content
Merged
Show file tree
Hide file tree
Changes from 5 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 @@ -51,11 +51,8 @@ export class McpToolRegistrationService {
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, turnContext);

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

agentOptions.mcpServers = Object.assign(agentOptions.mcpServers ?? {}, mcpServers);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -54,10 +54,7 @@ export class McpToolRegistrationService {

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, turnContext);

// Create Connection instance for LangChain agents
mcpServers[server.mcpServerName] = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,10 +53,7 @@ export class McpToolRegistrationService {

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, turnContext);

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

return agent;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import path from 'path';
import axios from 'axios';
import { MCPServerConfig, McpClientTool } from './contracts';
import { Utility } from './Utility';

import { StreamableHTTPClientTransport } from '@modelcontextprotocol/sdk/client/streamableHttp.js';
import { Client } from '@modelcontextprotocol/sdk/client/index.js';

Expand Down Expand Up @@ -70,13 +69,15 @@ 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.
* @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): Promise<MCPServerConfig[]> {
// Validate the authentication token
Utility.ValidateAuthToken(authToken);

Expand Down
39 changes: 38 additions & 1 deletion packages/agents-a365-tooling/src/Utility.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,47 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

import { TurnContext } from '@microsoft/agents-hosting';

// Constant for MCP Platform base URL in production
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.
*
* @param authToken Bearer token for Authorization header.
* @param turnContext Optional TurnContext object from which channel and subchannel IDs are extracted.
* @returns A headers record suitable for HTTP requests.
*/
public static GetToolRequestHeaders(
Comment thread
fpfp100 marked this conversation as resolved.
authToken?: string,
turnContext?: TurnContext
): Record<string, string> {
const headers: Record<string, string> = {};

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

const channelId = turnContext?.activity?.channelId as string | undefined;
const subChannelId = turnContext?.activity?.channelIdSubChannel as string | undefined;

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 +169,4 @@ export class Utility {

return MCP_PLATFORM_PROD_BASE_URL;
}
}
}