Skip to content
Open
Show file tree
Hide file tree
Changes from all 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
9 changes: 5 additions & 4 deletions dotnet/agent-framework/sample-agent/Agent/MyAgent.cs
Original file line number Diff line number Diff line change
Expand Up @@ -361,14 +361,15 @@ await A365OtelWrapper.InvokeObservedAgentOperation(
{
await context.StreamingResponse.QueueInformativeUpdateAsync("Loading tools...");

// For the bearer token (development) flow, pass the token as an override and
// use OboAuthHandlerName (or fall back to AgenticAuthHandlerName) as the handler.
// The SDK's token provider (AgenticMcpTokenProvider in production,
// DevMcpTokenProvider in dev) resolves per-server tokens automatically:
// - Dev: reads BEARER_TOKEN_<SERVER_NAME> (V2) or BEARER_TOKEN (V1 fallback)
// - Prod: performs per-audience OBO exchange for each V2 server
var handlerForMcp = !string.IsNullOrEmpty(authHandlerName)
? authHandlerName
: OboAuthHandlerName ?? AgenticAuthHandlerName ?? string.Empty;
var tokenOverride = string.IsNullOrEmpty(authHandlerName) ? accessToken : null;

var a365Tools = await toolService.GetMcpToolsAsync(agentId, UserAuthorization, handlerForMcp, context, tokenOverride).ConfigureAwait(false);
var a365Tools = await toolService.GetMcpToolsAsync(agentId, UserAuthorization, handlerForMcp, context).ConfigureAwait(false);
Comment on lines 368 to +372
Copy link

Copilot AI Apr 16, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Now that tokenOverride was removed from GetMcpToolsAsync(...), MCP tool loading depends on agentId being non-null. But agentId is still only resolved via authHandlerName or BEARER_TOKEN, so a dev setup that only provides V2 BEARER_TOKEN_<SERVER_NAME> values will never reach this call. Consider resolving agentId from agentic context when available (e.g., IsAgenticRequest()/GetAgenticInstanceId()), or otherwise handle/document the token requirement for agentId.

Copilot uses AI. Check for mistakes.

if (a365Tools != null && a365Tools.Count > 0)
{
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
{
"profiles": {
"Sample Agent": {
"commandName": "Project",
"launchBrowser": false,
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development",
"SKIP_TOOLING_ON_ERRORS": "true"
},
"applicationUrl": "http://localhost:3978"
},
"Sample Agent with Bearer Token Support": {
"commandName": "Project",
"launchBrowser": false,
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development",
"BEARER_TOKEN": "",
"SKIP_TOOLING_ON_ERRORS": "true"
},
"applicationUrl": "http://localhost:3978"
},
"Sample Agent with V2 Bearer Token Support": {
"commandName": "Project",
"launchBrowser": false,
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development",
"BEARER_TOKEN": "",
Copy link

Copilot AI Apr 16, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The “Sample Agent with Bearer Token Support” and “Sample Agent with V2 Bearer Token Support” profiles currently set the same env vars (BEARER_TOKEN + SKIP_TOOLING_ON_ERRORS). This makes the V2 profile misleading/redundant; either remove one, or update the V2 profile to include BEARER_TOKEN_<SERVER_NAME> placeholders (and optionally omit BEARER_TOKEN to avoid masking V2 issues).

Suggested change
"BEARER_TOKEN": "",
"BEARER_TOKEN_YOUR_SERVER_NAME": "",

Copilot uses AI. Check for mistakes.
"SKIP_TOOLING_ON_ERRORS": "true"
},
"applicationUrl": "http://localhost:3978"
}
}
}
5 changes: 5 additions & 0 deletions dotnet/agent-framework/sample-agent/appsettings.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,9 @@
{
// V2 MCP per-server dev tokens: set BEARER_TOKEN_<UPPERCASE_SERVER_NAME> environment variables.
// Run: a365 develop get-token (writes these automatically for all configured servers)
// The SDK reads BEARER_TOKEN_<SERVER_NAME> for each V2 server and falls back to BEARER_TOKEN for V1.
Copy link

Copilot AI Apr 16, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The comments reference BEARER_TOKEN_<UPPERCASE_SERVER_NAME> but also say the SDK reads BEARER_TOKEN_<SERVER_NAME>. Please align these (and clarify case-normalization), otherwise users may set the wrong env var (especially on case-sensitive environments).

Suggested change
// The SDK reads BEARER_TOKEN_<SERVER_NAME> for each V2 server and falls back to BEARER_TOKEN for V1.
// The SDK reads BEARER_TOKEN_<UPPERCASE_SERVER_NAME> for each V2 server, using the server name normalized to uppercase, and falls back to BEARER_TOKEN for V1.

Copilot uses AI. Check for mistakes.
// Example for a server named "MailTools": BEARER_TOKEN_MAILTOOLS=<token>

"AgentApplication": {
"StartTypingTimer": false,
"RemoveRecipientMention": false,
Expand Down
21 changes: 5 additions & 16 deletions dotnet/semantic-kernel/sample-agent/Agents/Agent365Agent.cs
Original file line number Diff line number Diff line change
Expand Up @@ -56,12 +56,6 @@ public static async Task<Agent365Agent> CreateA365AgentWrapper(Kernel kernel, IS
return _agent;
}

public static bool TryGetBearerTokenForDevelopment(out string? bearerToken)
{
bearerToken = Environment.GetEnvironmentVariable("BEARER_TOKEN");
return !string.IsNullOrEmpty(bearerToken);
}

/// <summary>
/// Checks if graceful fallback to bare LLM mode is enabled when MCP tools fail to load.
/// This is only allowed in Development environment AND when SKIP_TOOLING_ON_ERRORS is explicitly set to "true".
Expand Down Expand Up @@ -103,16 +97,11 @@ public async Task InitializeAgent365Agent(Kernel kernel, IServiceProvider servic

try
{
if (TryGetBearerTokenForDevelopment(out var bearerToken))
{
// Development mode: Use bearer token from environment variable for simplified local testing
await toolService.AddToolServersToAgentAsync(kernel, userAuthorization, authHandlerName, turnContext, bearerToken);
}
else
{
// Production mode: Use standard authentication flow (Client Credentials, Managed Identity, or Federated Credentials)
await toolService.AddToolServersToAgentAsync(kernel, userAuthorization, authHandlerName, turnContext);
}
// The SDK's token provider (AgenticMcpTokenProvider in production,
// DevMcpTokenProvider in dev) resolves per-server tokens automatically:
// - Dev: reads BEARER_TOKEN_<SERVER_NAME> (V2) or BEARER_TOKEN (V1 fallback)
// - Prod: performs per-audience OBO exchange for each V2 server
await toolService.AddToolServersToAgentAsync(kernel, userAuthorization, authHandlerName, turnContext);
}
catch (Exception ex)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,16 @@
"SKIP_TOOLING_ON_ERRORS": "true"
},
"applicationUrl": "https://localhost:64896;http://localhost:64897"
},
"Sample Agent with V2 Bearer Token Support": {
"commandName": "Project",
"launchBrowser": true,
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development",
"BEARER_TOKEN": "",
Copy link

Copilot AI Apr 16, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The new profile is named “V2 Bearer Token Support” but it only sets BEARER_TOKEN (V1 fallback) and doesn’t show any BEARER_TOKEN_<SERVER_NAME> variables. Consider either renaming this profile or adding representative BEARER_TOKEN_<SERVER> placeholders so the profile actually exercises the V2 per-server convention being documented.

Suggested change
"BEARER_TOKEN": "",
"BEARER_TOKEN": "",
"BEARER_TOKEN_GITHUB": "",
"BEARER_TOKEN_AZURE": "",

Copilot uses AI. Check for mistakes.
"SKIP_TOOLING_ON_ERRORS": "true"
},
"applicationUrl": "https://localhost:64896;http://localhost:64897"
}
}
}
5 changes: 5 additions & 0 deletions dotnet/semantic-kernel/sample-agent/appsettings.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,11 @@
"TenantId": "{{TenantId}}"
},

// V2 MCP per-server dev tokens: set BEARER_TOKEN_<UPPERCASE_SERVER_NAME> environment variables.
// Run: a365 develop get-token (writes these automatically for all configured servers)
// The SDK reads BEARER_TOKEN_<SERVER_NAME> for each V2 server and falls back to BEARER_TOKEN for V1.
Copy link

Copilot AI Apr 16, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The new guidance mixes BEARER_TOKEN_<UPPERCASE_SERVER_NAME> (line 17) with BEARER_TOKEN_<SERVER_NAME> (line 19). Please make the env-var naming rule explicit and consistent (including whether the SDK normalizes case), since env var names are case-sensitive on Linux and a mismatch can make dev tokens appear to “not work.”

Suggested change
// The SDK reads BEARER_TOKEN_<SERVER_NAME> for each V2 server and falls back to BEARER_TOKEN for V1.
// For each V2 server, the SDK uppercases the configured server name and reads BEARER_TOKEN_<UPPERCASE_SERVER_NAME>; it falls back to BEARER_TOKEN for V1.

Copilot uses AI. Check for mistakes.
// Example for a server named "MailTools": BEARER_TOKEN_MAILTOOLS=<token>

"AgentApplication": {
"StartTypingTimer": false,
"RemoveRecipientMention": false,
Expand Down
Loading