Written by Sergey Menshykh, Adam Sitnik, and Brandon H, this article introduces the A2A .NET SDK, demonstrating how developers can build collaborative AI agents leveraging the Agent2Agent protocol within the Azure AI Foundry environment.

Building Collaborative AI Agents with the A2A .NET SDK

Authors: Sergey Menshykh, Adam Sitnik, Brandon H

The evolution of AI has led to the proliferation of autonomous agents handling various specialized tasks, from customer service bots to workflow orchestration. However, enabling these agents to communicate and collaborate effectively is a challenge tackled by the Agent2Agent (A2A) protocol and its new .NET SDK implementation.

Introduction: Agent Collaboration Challenges

AI agents are becoming increasingly sophisticated, yet many operate as isolated systems. There is a growing need for a standardized protocol that allows independent agents to discover, communicate, and collaborate, regardless of their underlying framework or vendor. The A2A protocol solves this by providing a common language for agent interoperability.

What Is the Agent2Agent (A2A) Protocol?

The Agent2Agent (A2A) Protocol is an open standard enabling AI agents to:

  • Discover each other’s capabilities
  • Negotiate communication modalities (text, forms, media)
  • Collaborate securely on long-running tasks
  • Operate without exposing internal state, memory, or tools

A2A bridges vendor and technology divides, making agent ecosystems extensible and collaborative.

Announcing the A2A .NET SDK

The newly released A2A .NET SDK lets .NET developers build A2A servers and clients, allowing agents written in .NET (or any technology that supports the protocol) to participate in the agent ecosystem. The SDK strengthens the AI ecosystem, particularly in conjunction with Azure AI Foundry and Microsoft’s Semantic Kernel, both of which are adding and evolving their A2A capabilities.

Note: The SDK is in preview, so APIs may change as feedback is incorporated.

Key Features of the A2A .NET SDK

🔍 Agent Capability Discovery

  • Retrieve agent capabilities via standardized Agent Cards using the A2ACardResolver class
  • Agent Cards describe host URLs, supported modalities, streaming support, notifications, and more

Example:

A2ACardResolver cardResolver = new A2ACardResolver(new Uri("http://localhost:5100/"));
AgentCard agentCard = await cardResolver.GetAgentCardAsync();

💬 Flexible Communication Patterns

  • Message-based: Synchronous messaging for immediate responses
  • Task-based: Asynchronous tasks for longer-running operations

Message Example:

A2AClient client = new A2AClient(new Uri(agentCard.Url));
Message response = (Message)await client.SendMessageAsync(new MessageSendParams {
  Message = new Message {
    Role = MessageRole.User,
    Parts = [new TextPart { Text = "What is the current weather in Settle" }]
  }
});
Console.WriteLine($"Received: {((TextPart)response.Parts[0]).Text}");

Task Example:

AgentTask agentTask = (AgentTask)await client.SendMessageAsync(new MessageSendParams {
  Message = new Message {
    Role = MessageRole.User,
    Parts = [new TextPart { Text = "Generate an image of a sunset over the mountains" }]
  }
});
// Poll for task completion and handle result

For more, see Message or a Task.

🌊 Real-time Streaming Support

  • Supports Server-Sent Events (SSE) for real-time update scenarios

Example:

await foreach (SseItem<A2AEvent> sseItem in client.SendMessageStreamAsync(new MessageSendParams { Message = userMessage })) {
  Message agentResponse = (Message)sseItem.Data;
  Console.WriteLine($"Received: {((TextPart)agentResponse.Parts[0]).Text}");
}

🏗️ ASP.NET Core Integration

Enables rapid development of A2A agents using ASP.NET Core extensions.

Example:

WebApplicationBuilder builder = WebApplication.CreateBuilder(args);
WebApplication app = builder.Build();
TaskManager taskManager = new TaskManager();
agent.Attach(taskManager);
app.MapA2A(taskManager, "/agent");
app.Run();

Tutorial: Building a Simple Echo Agent

Prerequisites

  • .NET 8.0 SDK or later
  • Visual Studio/VS Code (or other .NET-compatible editor)
  • Basic C# and ASP.NET Core knowledge

Verify .NET SDK installation:

dotnet --version

Set Up the Agent Project

Initialize a new ASP.NET Core web app and add required A2A packages:

dotnet new webapp -n A2AAgent -f net9.0
cd A2AAgent
dotnet add package A2A --prerelease

# For ASP.NET Core integration

dotnet add package A2A.AspNetCore --prerelease

Implement the Echo Agent

Create EchoAgent.cs:

using A2A;
namespace A2AAgent;

public class EchoAgent {
  public void Attach(ITaskManager taskManager) {
    taskManager.OnMessageReceived = ProcessMessageAsync;
    taskManager.OnAgentCardQuery = GetAgentCardAsync;
  }

  private async Task<Message> ProcessMessageAsync(MessageSendParams messageSendParams, CancellationToken ct) {
    string request = messageSendParams.Message.Parts.OfType<TextPart>().First().Text;
    return new Message() {
      Role = MessageRole.Agent,
      MessageId = Guid.NewGuid().ToString(),
      ContextId = messageSendParams.Message.ContextId,
      Parts = [new TextPart() { Text = $"Echo: {request}" }]
    };
  }

  private async Task<AgentCard> GetAgentCardAsync(string agentUrl, CancellationToken cancellationToken) {
    return new AgentCard() {
      Name = "Echo Agent",
      Description = "An agent that will echo every message it receives.",
      Url = agentUrl,
      Version = "1.0.0",
      DefaultInputModes = ["text"],
      DefaultOutputModes = ["text"],
      Capabilities = new AgentCapabilities() { Streaming = true },
      Skills = [],
    };
  }
}

Hosting the Agent

Update Program.cs to connect and expose the agent:

using A2A;
using A2A.AspNetCore;
using A2AAgent;

WebApplicationBuilder builder = WebApplication.CreateBuilder(args);
WebApplication app = builder.Build();
EchoAgent agent = new EchoAgent();
TaskManager taskManager = new TaskManager();
agent.Attach(taskManager);
app.MapA2A(taskManager, "/agent");
await app.RunAsync();

Once running, your agent is discoverable and accessible at http://localhost:5000/agent.

Testing the Agent With a Client

Set up a new client console app:

dotnet new console -n A2AClient -f net9.0
cd A2AClient
dotnet add package A2A --prerelease
dotnet add package System.Net.ServerSentEvents --prerelease

Create the client to discover and message the agent:

A2ACardResolver cardResolver = new(new Uri("http://localhost:5000/"));
AgentCard echoAgentCard = await cardResolver.GetAgentCardAsync();
Console.WriteLine($"Connected to agent: {echoAgentCard.Name}");
Console.WriteLine($"Description: {echoAgentCard.Description}");
Console.WriteLine($"Streaming support: {echoAgentCard.Capabilities?.Streaming}");
A2AClient agentClient = new(new Uri(echoAgentCard.Url));
Message userMessage = new() {
  Role = MessageRole.User,
  MessageId = Guid.NewGuid().ToString(),
  Parts = [new TextPart { Text = "Hello from the A2A client!" }]
};
Console.WriteLine("\n=== Non-Streaming Communication ===");
Message agentResponse = (Message)await agentClient.SendMessageAsync(new MessageSendParams { Message = userMessage });
Console.WriteLine($"Received response: {((TextPart)agentResponse.Parts[0]).Text}");
Console.WriteLine("\n=== Streaming Communication ===");
await foreach (SseItem<A2AEvent> sseItem in agentClient.SendMessageStreamAsync(new MessageSendParams { Message = userMessage })) {
  Message streamingResponse = (Message)sseItem.Data;
  Console.WriteLine($"Received streaming chunk: {((TextPart)streamingResponse.Parts[0]).Text}");
}

Explore Further


The A2A .NET SDK is open source (Apache 2.0). Community participation is encouraged.

This post appeared first on “Microsoft DevBlog”. Read the entire article here