|
| 1 | +--- |
| 2 | +title: A2A Integration |
| 3 | +description: Learn how to expose Microsoft Agent Framework agents using the Agent-to-Agent (A2A) protocol for inter-agent communication. |
| 4 | +author: dmkorolev |
| 5 | +ms.service: agent-framework |
| 6 | +ms.topic: tutorial |
| 7 | +ms.date: 11/11/2025 |
| 8 | +ms.author: dmkorolev |
| 9 | +--- |
| 10 | + |
| 11 | +# A2A Integration |
| 12 | + |
| 13 | +> [!NOTE] |
| 14 | +> This tutorial describes A2A integration in .NET apps; Python integration is in the works... |
| 15 | +
|
| 16 | +The Agent-to-Agent (A2A) protocol enables standardized communication between agents, allowing agents built with different frameworks and technologies to communicate seamlessly. The `Microsoft.Agents.AI.Hosting.A2A.AspNetCore` library provides ASP.NET Core integration for exposing your agents via the A2A protocol. |
| 17 | + |
| 18 | +**NuGet Packages:** |
| 19 | +- [Microsoft.Agents.AI.Hosting.A2A](https://www.nuget.org/packages/Microsoft.Agents.AI.Hosting.A2A) |
| 20 | +- [Microsoft.Agents.AI.Hosting.A2A.AspNetCore](https://www.nuget.org/packages/Microsoft.Agents.AI.Hosting.A2A.AspNetCore) |
| 21 | + |
| 22 | +## What is A2A? |
| 23 | + |
| 24 | +A2A is a standardized protocol that supports: |
| 25 | + |
| 26 | +- **Agent discovery** through agent cards |
| 27 | +- **Message-based communication** between agents |
| 28 | +- **Long-running agentic processes** via tasks |
| 29 | +- **Cross-platform interoperability** between different agent frameworks |
| 30 | + |
| 31 | +For more information, see the [A2A protocol specification](https://a2a-protocol.org/latest/). |
| 32 | + |
| 33 | +## Example |
| 34 | + |
| 35 | +This minimal example shows how to expose an agent via A2A. The sample includes OpenAPI and Swagger dependencies to simplify testing. |
| 36 | + |
| 37 | +#### 1. Create an ASP.NET Core Web API project |
| 38 | + |
| 39 | +Create a new ASP.NET Core Web API project or use an existing one. |
| 40 | + |
| 41 | +#### 2. Install required dependencies |
| 42 | + |
| 43 | +Install the following packages: |
| 44 | + |
| 45 | + ## [.NET CLI](#tab/dotnet-cli) |
| 46 | + |
| 47 | + Run the following commands in your project directory to install the required NuGet packages: |
| 48 | + |
| 49 | + ```bash |
| 50 | + # Hosting.A2A.AspNetCore for A2A protocol integration |
| 51 | + dotnet add package Microsoft.Agents.AI.Hosting.A2A.AspNetCore --prerelease |
| 52 | + |
| 53 | + # Libraries to connect to Azure OpenAI |
| 54 | + dotnet add package Azure.AI.OpenAI --prerelease |
| 55 | + dotnet add package Azure.Identity |
| 56 | + dotnet add package Microsoft.Extensions.AI |
| 57 | + dotnet add package Microsoft.Extensions.AI.OpenAI --prerelease |
| 58 | + |
| 59 | + # Swagger to test app |
| 60 | + dotnet add package Microsoft.AspNetCore.OpenApi |
| 61 | + dotnet add package Swashbuckle.AspNetCore |
| 62 | + ``` |
| 63 | + ## [Package Reference](#tab/package-reference) |
| 64 | + |
| 65 | + Add the following `<PackageReference>` elements to your `.csproj` file within an `<ItemGroup>`: |
| 66 | + |
| 67 | + ```xml |
| 68 | + <ItemGroup> |
| 69 | + <!-- Hosting.A2A.AspNetCore for A2A protocol integration --> |
| 70 | + <PackageReference Include="Microsoft.Agents.AI.Hosting.A2A.AspNetCore" Version="1.0.0-preview.251110.2" /> |
| 71 | + |
| 72 | + <!-- Libraries to connect to Azure OpenAI --> |
| 73 | + <PackageReference Include="Azure.AI.OpenAI" Version="2.5.0-beta.1" /> |
| 74 | + <PackageReference Include="Azure.Identity" Version="1.17.0" /> |
| 75 | + <PackageReference Include="Microsoft.Extensions.AI" Version="9.10.2" /> |
| 76 | + <PackageReference Include="Microsoft.Extensions.AI.OpenAI" Version="9.10.2-preview.1.25552.1" /> |
| 77 | + |
| 78 | + <!-- Swagger to test app --> |
| 79 | + <PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="9.0.0" /> |
| 80 | + <PackageReference Include="Swashbuckle.AspNetCore" Version="6.8.1" /> |
| 81 | + </ItemGroup> |
| 82 | + ``` |
| 83 | + |
| 84 | + --- |
| 85 | + |
| 86 | + |
| 87 | +#### 3. Configure Azure OpenAI connection |
| 88 | + |
| 89 | +The application requires an Azure OpenAI connection. Configure the endpoint and deployment name using `dotnet user-secrets` or environment variables. |
| 90 | +You can also simply edit the `appsettings.json`, but that's not recommended for the apps deployed in production since some of the data can be considered to be secret. |
| 91 | + |
| 92 | + ## [User-Secrets](#tab/user-secrets) |
| 93 | + ```bash |
| 94 | + dotnet user-secrets set "AZURE_OPENAI_ENDPOINT" "https://<your-openai-resource>.openai.azure.com/" |
| 95 | + dotnet user-secrets set "AZURE_OPENAI_DEPLOYMENT_NAME" "gpt-4o-mini" |
| 96 | + ``` |
| 97 | + ## [ENV Windows](#tab/env-windows) |
| 98 | + ```powershell |
| 99 | + $env:AZURE_OPENAI_ENDPOINT = "https://<your-openai-resource>.openai.azure.com/" |
| 100 | + $env:AZURE_OPENAI_DEPLOYMENT_NAME = "gpt-4o-mini" |
| 101 | + ``` |
| 102 | + ## [ENV unix](#tab/env-unix) |
| 103 | + ```bash |
| 104 | + export AZURE_OPENAI_ENDPOINT="https://<your-openai-resource>.openai.azure.com/" |
| 105 | + export AZURE_OPENAI_DEPLOYMENT_NAME="gpt-4o-mini" |
| 106 | + ``` |
| 107 | + ## [appsettings](#tab/appsettings) |
| 108 | + ```json |
| 109 | + "AZURE_OPENAI_ENDPOINT": "https://<your-openai-resource>.openai.azure.com/", |
| 110 | + "AZURE_OPENAI_DEPLOYMENT_NAME": "gpt-4o-mini" |
| 111 | + ``` |
| 112 | + |
| 113 | + --- |
| 114 | + |
| 115 | + |
| 116 | +#### 4. Add the code to Program.cs |
| 117 | + |
| 118 | +Replace the contents of `Program.cs` with the following code and run the application: |
| 119 | +```csharp |
| 120 | +using A2A.AspNetCore; |
| 121 | +using Azure.AI.OpenAI; |
| 122 | +using Azure.Identity; |
| 123 | +using Microsoft.Agents.AI.Hosting; |
| 124 | +using Microsoft.Extensions.AI; |
| 125 | + |
| 126 | +var builder = WebApplication.CreateBuilder(args); |
| 127 | + |
| 128 | +builder.Services.AddOpenApi(); |
| 129 | +builder.Services.AddSwaggerGen(); |
| 130 | + |
| 131 | +string endpoint = builder.Configuration["AZURE_OPENAI_ENDPOINT"] |
| 132 | + ?? throw new InvalidOperationException("AZURE_OPENAI_ENDPOINT is not set."); |
| 133 | +string deploymentName = builder.Configuration["AZURE_OPENAI_DEPLOYMENT_NAME"] |
| 134 | + ?? throw new InvalidOperationException("AZURE_OPENAI_DEPLOYMENT_NAME is not set."); |
| 135 | + |
| 136 | +// Register the chat client |
| 137 | +IChatClient chatClient = new AzureOpenAIClient( |
| 138 | + new Uri(endpoint), |
| 139 | + new DefaultAzureCredential()) |
| 140 | + .GetChatClient(deploymentName) |
| 141 | + .AsIChatClient(); |
| 142 | +builder.Services.AddSingleton(chatClient); |
| 143 | + |
| 144 | +// Register an agent |
| 145 | +var pirateAgent = builder.AddAIAgent("pirate", instructions: "You are a pirate. Speak like a pirate."); |
| 146 | + |
| 147 | +var app = builder.Build(); |
| 148 | + |
| 149 | +app.MapOpenApi(); |
| 150 | +app.UseSwagger(); |
| 151 | +app.UseSwaggerUI(); |
| 152 | + |
| 153 | +// Expose the agent via A2A protocol. You can also customize the agentCard |
| 154 | +app.MapA2A(pirateAgent, path: "/a2a/pirate", agentCard: new() |
| 155 | +{ |
| 156 | + Name = "Pirate Agent", |
| 157 | + Description = "An agent that speaks like a pirate.", |
| 158 | + Version = "1.0" |
| 159 | +}); |
| 160 | + |
| 161 | +app.Run(); |
| 162 | +``` |
| 163 | + |
| 164 | +### Testing the Agent |
| 165 | + |
| 166 | +Once the application is running, you can test the A2A agent using the following `.http` file or through Swagger UI. |
| 167 | + |
| 168 | +The input format complies with the A2A specification. You can provide values for: |
| 169 | +- `messageId` - A unique identifier for this specific message. You can create your own ID (e.g., a GUID) or set it to `null` to let the agent generate one automatically. |
| 170 | +- `contextId` - The conversation identifier. Provide your own ID to start a new conversation or continue an existing one by reusing a previous `contextId`. The agent will maintain conversation history for the same `contextId`. Agent will generate one for you as well, if none is provided. |
| 171 | + |
| 172 | +```http |
| 173 | +# Send A2A request to the pirate agent |
| 174 | +POST {{baseAddress}}/a2a/pirate/v1/message:stream |
| 175 | +Content-Type: application/json |
| 176 | +{ |
| 177 | + "message": { |
| 178 | + "kind": "message", |
| 179 | + "role": "user", |
| 180 | + "parts": [ |
| 181 | + { |
| 182 | + "kind": "text", |
| 183 | + "text": "Hey pirate! Tell me where have you been", |
| 184 | + "metadata": {} |
| 185 | + } |
| 186 | + ], |
| 187 | + "messageId": null, |
| 188 | + "contextId": "foo" |
| 189 | + } |
| 190 | +} |
| 191 | +``` |
| 192 | +_Note: Replace `{{baseAddress}}` with your server endpoint._ |
| 193 | + |
| 194 | +This request returns the following JSON response: |
| 195 | +```json |
| 196 | +{ |
| 197 | + "kind": "message", |
| 198 | + "role": "agent", |
| 199 | + "parts": [ |
| 200 | + { |
| 201 | + "kind": "text", |
| 202 | + "text": "Arrr, ye scallywag! Ye’ll have to tell me what yer after, or be I walkin’ the plank? 🏴☠️" |
| 203 | + } |
| 204 | + ], |
| 205 | + "messageId": "chatcmpl-CXtJbisgIJCg36Z44U16etngjAKRk", |
| 206 | + "contextId": "foo" |
| 207 | +} |
| 208 | +``` |
| 209 | + |
| 210 | +The response includes the `contextId` (conversation identifier), `messageId` (message identifier), and the actual content from the pirate agent. |
| 211 | + |
| 212 | +## AgentCard Configuration |
| 213 | + |
| 214 | +The `AgentCard` provides metadata about your agent for discovery and integration: |
| 215 | +```csharp |
| 216 | +app.MapA2A(agent, "/a2a/my-agent", agentCard: new() |
| 217 | +{ |
| 218 | + Name = "My Agent", |
| 219 | + Description = "A helpful agent that assists with tasks.", |
| 220 | + Version = "1.0", |
| 221 | +}); |
| 222 | +``` |
| 223 | + |
| 224 | +You can access the agent card by sending this request: |
| 225 | +```http |
| 226 | +# Send A2A request to the pirate agent |
| 227 | +GET {{baseAddress}}/a2a/pirate/v1/card |
| 228 | +``` |
| 229 | +_Note: Replace `{{baseAddress}}` with your server endpoint._ |
| 230 | + |
| 231 | +### AgentCard Properties |
| 232 | + |
| 233 | +- **Name**: Display name of the agent |
| 234 | +- **Description**: Brief description of the agent |
| 235 | +- **Version**: Version string for the agent |
| 236 | +- **Url**: Endpoint URL (automatically assigned if not specified) |
| 237 | +- **Capabilities**: Optional metadata about streaming, push notifications, and other features |
| 238 | + |
| 239 | +## Exposing Multiple Agents |
| 240 | + |
| 241 | +You can expose multiple agents in a single application, as long as their endpoints don't collide. Here's an example: |
| 242 | + |
| 243 | +```csharp |
| 244 | +var mathAgent = builder.AddAIAgent("math", instructions: "You are a math expert."); |
| 245 | +var scienceAgent = builder.AddAIAgent("science", instructions: "You are a science expert."); |
| 246 | + |
| 247 | +app.MapA2A(mathAgent, "/a2a/math"); |
| 248 | +app.MapA2A(scienceAgent, "/a2a/science"); |
| 249 | +``` |
| 250 | + |
| 251 | +## See Also |
| 252 | + |
| 253 | +- [Hosting Overview](index.md) |
| 254 | +- [OpenAI Integration](openai-integration.md) |
| 255 | +- [A2A Protocol Specification](https://a2a-protocol.org/latest/) |
| 256 | +- [Agent Discovery](https://github.com/a2aproject/A2A/blob/main/docs/topics/agent-discovery.md) |
0 commit comments