Azure AI Foundry
Semantic Kernel Blueprint That Makes .NET Multi-Agent Collaboration Effortless
Screenshot showing A2A communication betweeen Travel Planning and Flight booking Agent
Imagine this: You’re building a travel app. A Trip Planner agent figures out where and when you want to go, while a Flight Booking agent handles seat selection, ticket pricing, and booking confirmations.
Now imagine these two agents talking to each other — no human in the loop — to get you from “I want to go to Paris” to “Here’s your boarding pass.”
That’s the magic of agent-to-agent (A2A) communication.
In my last post, we built this exact setup in Python using Google’s A2A and Microsoft’s Semantic Kernel. This time, we’re bringing it into the .NET world with the Semantic Kernel C
In this guide, you’ll learn:
The high-level architecture behind multi-agent systems in Semantic Kernel
How to stand up an A2A Server for the Flight Booking Agent
How to build a A2A Client for the Trip Planner Agent
How to orchestrate them in real time — with .NET doing the heavy lifting.
By the end, you’ll have a working, modular multi-agent system you can adapt to finance, healthcare, or any other domain.
[Step-by-Step Guide to Create a Multi-Agent System with Microsoft Semantic Kernel and Google A2A \
Learn How to Connect and Orchestrate Agents Using Semantic Kernel and Google’s A2A Protocol\
TLDR;
Define Agent — Create agent in Azure AI Foundry
Create Agent Card — Explains the capability definition process
A2AHostAgent
abstraction provided by Semantic Kernel SDKRun Server — Shows how to expose the agent via ASP.NET Core
Create A2A Helper — Agent discovery and communication setup
Initialize A2A Client — HTTP-based communication setup
Register as SK Plugin — Converting A2A agents to Semantic Kernel functions
Integrate with Semantic Kernel — Plugin registration process with kernel.
Orchestrate Agents — SK automatically invokes A2A agents by automatic tool calling (remember in step 3, we converted A2A Invok function into tool)
┌─────────────────────┐ A2A Protocol ┌─────────────────────┐
│ TravelBookingAgent │ ◄──────────────────► │ FlightBookingAgent │
│ (Client) │ │ (Server) │
│ │ │ │
│ ┌─────────────────┐ │ │ ┌─────────────────┐ │
│ │ Web UI │ │ │ │ Azure AI │ │
│ │ (HTML/JS) │ │ │ │ Foundry Agent │ │
│ └─────────────────┘ │ │ └─────────────────┘ │
│ ┌─────────────────┐ │ │ ┌─────────────────┐ │
│ │ ChatCompletion │ │ │ │ A2A Host Agent │ │
│ │ Agent │ │ │ │ │ │
│ └─────────────────┘ │ │ └─────────────────┘ │
└─────────────────────┘ └─────────────────────┘
Software Requirements
Visual Studio 2022 or Visual Studio Code
Git for version control
Azure CLI (optional, but recommended)
Azure AI Foundry Project
In this example, I am using Azure Foundry to create my flight booking agent
Create a new project
Navigate to “Agents” section
Create a new agent with:
Name: FlightBookingAgent
Model: GPT-4o
Instructions: “You are a specialized flight booking agent. Help users search for flights, compare prices, and book tickets. Always ask for departure city, destination, travel dates, and passenger count.”
asst_E8h9axBS1S4CX7rZ551SxYT3
)Join Medium for free to get updates from this writer.
Subscribe
Subscribe
https://ai-foundary-akshay.services.ai.azure.com/api/projects/firstProject
Press enter or click to view image in full size
Screenshot of Agent created in Azure AI Foundry
AgentCardHelper
method to create Agent Card for our Flight Booking agent.
using SharpA2A.Core;
namespace A2AServer.Agents
public class AgentCardHelper
public static AgentCard GetFlightBookingAgentCard()
return new AgentCard
Name = "FlightBookingAgent",
Description = "Specialized agent for flight booking and search operations",
Version = "1.0.0",
Capabilities = new List<string>
"flight_search",
"price_comparison",
"booking_assistance"
ChatCompletionAgent
CreateFoundryHostAgentAsync
-\Helps with defining the connection with Agent Foundry and retrieve the created agent based onassistantId
using Azure.AI.Agents.Persistent;
using Azure.Identity;
using Microsoft.SemanticKernel;
using Microsoft.SemanticKernel.Agents.A2A;
using Microsoft.SemanticKernel.Agents.AzureAI;
using SharpA2A.Core;
namespace A2AServer.Agents
public class AgentHelper
internal static async Task<A2AHostAgent> CreateFoundryHostAgentAsync(
string agentType,
string modelId = null,
string endpoint = null,
string assistantId = null,
IEnumerable<KernelPlugin>? plugins = null)
// Create Azure AI client
var agentsClient = new PersistentAgentsClient(endpoint, new AzureCliCredential());
PersistentAgent definition = await agentsClient.Administration.GetAgentAsync(assistantId);
// Create Azure AI Agent
var agent = new AzureAIAgent(definition, agentsClient, plugins);
// Get agent card based on type
AgentCard agentCard = agentType.ToUpperInvariant() switch
"FLIGHTBOOKINGAGENT" =
> AgentCardHelper.GetFlightBookingAgentCard(),
_ =
> throw new ArgumentException($"Unsupported agent type: {agentType}"),
return new A2AHostAgent(agent, agentCard);
A2AHostAgent
is initated with the agent that we created in previous step, and app.MapA2A(hostAgent!.TaskManager!, “”);
maps the task manager, which is backbone of event managent in A2A is mapped with the server.
using A2AServer.Agents;
using Microsoft.SemanticKernel.Agents.A2A;
using SharpA2A.AspNetCore;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddHttpClient().AddLogging();
builder.Services.AddOpenApi();
var app = builder.Build();
// Get agent type from command line arguments
var agentType = GetAgentTypeFromArgs(args);
A2AHostAgent? hostAgent = null;
switch (agentType.ToLowerInvariant())
case "flightbookingagent":
hostAgent = await AgentHelper.CreateFoundryHostAgentAsync(
agentType: "FlightBookingAgent",
modelId: "gpt-4o",
endpoint: "YOUR_AZURE_AI_FOUNDRY_ENDPOINT",
assistantId: "YOUR_ASSISTANT_ID",
plugins: null);
break;
default:
Console.WriteLine($"Unknown agent type: {agentType}");
Console.WriteLine("Available agents: FlightBookingAgent");
Environment.Exit(1);
return;
// Map A2A endpoints
app.MapA2A(hostAgent!.TaskManager!, "");
app.UseHttpsRedirection();
app.Run();
Run your application and if everything work correctly, agent is exposed throw A2A.
I believe Semantic Kernel abstracts the official A2A .NET library: https://github.com/a2aproject/a2a-dotnet. While it’s not strictly required, I highly recommend reading the README file — it helped me better understand and correlate the Python and .NET implementations.
Press enter or click to view image in full size
AgentKernelFunctionFactory.CreateFromAgent(agent)).ToList();
KernelFunction
using AgentKernelFunctionFactory
, and bundles them into a plugin via KernelPluginFactory
.a2aAgents
list. The helper method GetA2AAgent
handles HTTP communication to retrieve each agent's card and initialize an A2AAgent
instance. This setup allows seamless integration of multiple A2A agents into the Semantic Kernel runtime.
public static async Task CreatePluginFromA2AAgent(List<KernelFunction> a2aAgents, string[] agentUrls)
var createAgentTasks = agentUrls.Select(agentUrl =
> GetA2AAgent(agentUrl));
var agents = await Task.WhenAll(createAgentTasks);
var agentFunctions = agents.Select(agent =
> AgentKernelFunctionFactory.CreateFromAgent(agent)).ToList();
var agentPlugin = KernelPluginFactory.CreateFromFunctions("AgentPlugin", agentFunctions);
a2aAgents.AddRange(agentPlugin);
Console.WriteLine($"A2A Plugin created with {a2aAgents.Count} functions");
#pragma warning restore SKEXP0110 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed.
public static async Task<A2AAgent> GetA2AAgent(string agentUri)
var httpClient = new HttpClient
BaseAddress = new Uri(agentUri),
Timeout = TimeSpan.FromSeconds(60)
var client = new A2AClient(httpClient);
var cardResolver = new A2ACardResolver(httpClient);
AgentCard agentCard = await cardResolver.GetAgentCardAsync();
if (agentCard == null)
throw new InvalidOperationException($"No agent card found at {agentUri}");
Console.WriteLine($"A2A Agent '{agentCard}' found at {agentUri}");
return new A2AAgent(client, agentCard!);
This step shows how to register A2A agents as plugins in the Semantic Kernel runtime.
KernelFunction
and calls CreatePluginFromA2AAgent
, which populates the list by fetching the agent from a local URL."A2AAgents"
.Finally, the kernel is built and ready to use the A2A agent as a callable tool within the Semantic Kernel workflow.
List<KernelFunction> a2aAgents = new List<KernelFunction>();
A2AHelper.CreatePluginFromA2AAgent(a2aAgents, new string[] { "http://localhost:5237" }).Wait();
// Create Semantic Kernel with Azure OpenAI
var kernelBuilder = Kernel.CreateBuilder()
.AddAzureOpenAIChatCompletion(deploymentName, endpoint, apiKey);
if (a2aAgents.Any())
// register fetched A2A agent as tool/plugin to Kernel
kernelBuilder.Plugins.AddFromFunctions("A2AAgents", a2aAgents);
var kernel = kernelBuilder.Build();
http://localhost:5237/
is the port where my A2A Server is exposed.
_travelPlanningAgent = new ChatCompletionAgent()
Instructions = "You are a helpful travel planning assistant. You can help users plan their trips by coordinating with specialized agents for flights, hotels, and other travel services. When users ask about flights, use the available FlightBookingAgent to get flight information.",
Name = "TravelPlanner",
Kernel = kernel,
Arguments = new KernelArguments(new PromptExecutionSettings() { FunctionChoiceBehavior = FunctionChoiceBehavior.Auto() }),
PromptExecutionSettings
configured with FunctionChoiceBehavior.Auto()
, allowing the system to automatically decide when to invoke available functions like flight booking during conversation.
public async Task<string> GetAgentResponseAsync(string userInput, ChatHistory chatHistory)
try
_logger.LogInformation("Processing user input: {UserInput}", userInput);
var response = new StringBuilder();
await foreach (var content in _travelPlanningAgent.InvokeAsync(chatHistory))
response.Append(content.Content);
return response.ToString();
catch (Exception ex)
_logger.LogError(ex, "Error processing agent response");
return "Sorry, I encountered an error while processing your request. Please try again.";
cd "FlightBookingAgent -A2AServer/A2AServer"
dotnet run -- --agent FlightBookingAgent
cd "TravelBookingAgent
- A2AClient/A2AClient"
dotnet run
http://localhost:5223
The travel planning interface will be available
Press enter or click to view image in full size
Demo
By combining Azure OpenAI, Semantic Kernel, and the A2A protocol, we’ve created a powerful and extensible multi-agent system capable of simulating real-world scenarios like travel planning. This blog demonstrated how to integrate external agents (like a FlightBookingAgent) into Semantic Kernel using the A2A standard, wrap them as plugins, and orchestrate them through a central ChatCompletionAgent. This modular approach allows developers to build intelligent, task-oriented agents that can collaborate seamlessly — paving the way for more dynamic, interoperable, and scalable AI-powered applications. Whether you’re building travel bots, enterprise assistants, or custom agent networks, this architecture gives you a flexible foundation to innovate and expand.
Developer SDKs, repos, connectors, and infrastructure helpers. APIs, development tools, and integration resources.