StackA2A
enterprisesemantic-kernelcsharp

A2A Semantic Kernel Dotnet

27

by SiddyHub

A2A protocol integration leveraging dynamic Semantic Kernel functions and an Agent Card Repository for adaptive workflows.

1 starsUpdated 2025-11-27
Quality Score27/100
Community
7
Freshness
51
Official
30
Skills
10
Protocol
30
🔒 Security
20

Getting Started

1Clone the repository
$ git clone https://github.com/SiddyHub/a2a-semantic-kernel-dotnet
2Navigate to the project
$ cd a2a-semantic-kernel-dotnet
3Install dependencies
$ dotnet restore
4Run the agent
$ dotnet run

README

Agentic Semantic Kernel Orchestrator (A2A)

Agentic multi‑agent orchestration on Semantic Kernel (.NET) with A2A (Agent‑to‑Agent) protocol, dynamic function routing, and an Agent Card Repository for adaptive, hierarchical workflows.

📖 Overview

This project demonstrates a sophisticated multi-agent architecture using the A2A protocol for agent communication, Semantic Kernel for AI orchestration, and a dynamic plugin system based on agent card registries. The system supports hierarchical agent communication with root agents, parent orchestrators, and specialized child agents.

This hybrid architecture leverages A2A (Agent-to-Agent) protocols for foundational plumbing and dynamic agent discovery, while Semantic Kernel (SK) provides advanced intelligence and orchestrated routing. The combination ensures seamless integration and intelligent coordination among enterprise AI agents, eliminating manual intervention and static configuration for onboarding new capabilities.

📺 Demo

▶ Watch the demo video

🏗️ Architecture

The architecture follows a hierarchical multi-agent pattern with dynamic plugin discovery:

Client → Root Agent (Semantic Kernel)
 ├─ Dynamic Plugins (from CardDetails.json)
    ├─ Echo Orchestrator (A2A Client)
    └─ Shipping Order Orchestrator (A2A Client)
       └─ Dynamic Plugins (from ChildCardDetails.json)
          ├─ Order Child Agent (A2A Client)
  └─ Logistics Shipping Child Agent (A2A Client)

Below is the sample Architecture Diagram to understand this project.

Architecture

Key Components

  1. Root Agent (DynamicSKConsoleApp)

    • Console application with Semantic Kernel-powered chat completion agent
    • Dynamically loads agent plugins from CardDetails.json registry
    • Routes queries to appropriate orchestrator agents via A2A protocol
    • Provides user interaction layer with animated loading indicators
  2. Orchestrator Agents

    • Echo Agent Server (DynamicSKEchoAgentServer) - Simple echo demonstration
    • Shipping Agent Server (DynamicSKInventoryAgentServer) - Complex routing orchestrator
      • Routes between order and logistics domains
      • Dynamically loads child agent plugins from ChildCardDetails.json
      • Uses Semantic Kernel for intelligent query classification
  3. Child Agents

    • Order Child Agent (DynamicSKInventoryChildServer) - Order processing and inventory
    • Logistics Shipping Agent (DynamicSKInventoryChildServer2) - Shipping and logistics details
    • Each powered by Semantic Kernel with specialized plugins
  4. Agent Card Registry (A2A Registry)

  • JSON-based agent discovery and registration
    • Defines agent capabilities, endpoints, and skill schemas
    • Enables dynamic plugin generation at runtime
    • Note: In production scenarios, the agent registry can be backed by any database system (SQL Server, PostgreSQL, MongoDB, Cosmos DB, etc.). This implementation uses JSON files stored in the file system for demonstration and educational purposes to keep the setup simple and focus on the A2A protocol concepts.
  1. Other Components
    • The Client can be a Web App or any Consumer App like Azure Functions, Console App etc.
    • We can also have a Power App to Register or POST New Agent / GET Agents to / from the Agent Registry.
    • As part of Child Agents we can also use / have MCP Servers added as Plugins / Tools, but in our sample we are using Semantic Kernel Functions.

✨ Key Features

Dynamic Plugin System

  • Runtime Plugin Generation: Agents are discovered and loaded dynamically from JSON card registries
  • JSON Schema-based: Input/output schemas define agent capabilities
  • Zero Code Changes: Add new agents without modifying existing code
  • Hierarchical Discovery: Root and parent agents maintain their own registries

A2A Protocol Integration

  • Agent Card Resolution: Automatic discovery of agent capabilities
  • Streaming Support: Real-time streaming responses via Server-Sent Events (SSE)
  • HTTP/A2A Protocols: Flexible communication protocols
  • Metadata Passing: Rich context propagation between agents

Semantic Kernel Features

  • Function Calling: Automatic tool selection by LLM
  • Auto Function Choice: AI determines which agent to invoke
  • Chat Completion Agents: Conversational AI with context management
  • Kernel Plugins: Modular function organization

📁 Project Structure

DynamicSKConsoleApp/
├─ DynamicSKConsoleApp/       # Root agent console app
│   ├─ Program.cs    # Main entry point
│   ├─ Program.GetKernel.cs   # Kernel configuration & dynamic plugin loading
│   ├─ CardDetails.json  # Root agent registry (Echo, Shipping)
│   └─ appsettings.json       # Azure OpenAI configuration
│
├─ DynamicSKEchoAgentServer/  # Simple echo orchestrator
│   ├─ EchoAgent.cs           # Echo agent implementation
│   ├─ Program.cs   # ASP.NET Core host
│   └─ appsettings.json
│
├─ DynamicSKInventoryAgentServer/    # Shipping orchestrator (parent)
│   ├─ ShippingOrderAgent.cs  # Routing orchestrator with dynamic plugins
│   ├─ ChildCardDetails.json  # Child agent registry (Order, Logistics)
│   ├─ AgentDetails.cs        # Agent card models
│   ├─ Program.cs          # ASP.NET Core host
│   └─ appsettings.json
│
├─ DynamicSKInventoryChildServer/  # Order child agent
│   ├─ OrderChildAgent.cs     # Order processing agent
│   ├─ Plugins/OrderPlugin.cs # Order-specific functions
│   ├─ Program.cs
│   └─ appsettings.json
│
├─ DynamicSKInventoryChildServer2/   # Logistics child agent
│   ├─ ShippingAgent.cs       # Shipping logistics agent
│   ├─ Plugins/ShippingPlugin.cs # Shipping-specific functions
│   ├─ Program.cs
│   └─ appsettings.json
│
└─ DynamicSKConsoleApp.sln    # Solution file

🚀 Getting Started

Prerequisites

  • .NET 9.0 SDK
  • Azure OpenAI Service account
  • Visual Studio 2022 or VS Code

Configuration

Each Project (Except for DynamicSKEchoAgentServer) requires Azure OpenAI configuration in appsettings.json:

{
  "AzureOpenAI": {
    "ChatDeploymentName": "gpt-5-mini",
    "Endpoint": "https://your-resource.openai.azure.com/",
    "ApiKey": "your-api-key-here"
  }
}

Running the Solution

  1. Start all agent servers (order matters for registry population):

    # Terminal 1 - Child Agent (Order)
    cd DynamicSKInventoryChildServer
    dotnet run
    # Runs on: https://localhost:7277
    
    # Terminal 2 - Child Agent (Logistics)
    cd DynamicSKInventoryChildServer2
    dotnet run
    # Runs on: https://localhost:7071
    
    # Terminal 3 - Parent Agent (Shipping Orchestrator)
    cd DynamicSKInventoryAgentServer
    dotnet run
    # Runs on: https://localhost:7026
    
    # Terminal 4 - Echo Agent
    cd DynamicSKEchoAgentServer
    dotnet run
    # Runs on: https://localhost:7131
    
  2. Run the root agent console:

    # Terminal 5 - Root Agent
    cd DynamicSKConsoleApp
    dotnet run
    

Note : If you do not want to run above bash commands, we can also use Visual Studio to run each project simultaneously. In Project Properties, set multiple startup projects and select Apply.

Right Click Solution -> Select Properties Select Start Action for All Projects

Once multiple startup is configured, simply press F5 to launch all Agents & Console App or click the ▶️ Start button.

  1. Interact with the system:
    Enter Your Question: What is the status of order 12345?
    agent working | [█████████░░░░░]
    
    Order Processing Child Artifact: Order 12345 is shipped and will arrive tomorrow.
    
    Press X to exit or any other key to ask another question.
    

📋 Agent Card Registry Format

Root Registry (CardDetails.json)

Defines orchestrator agents accessible from the root:

{
  "id": "shipping-agent-123",
  "name": "Shipping",
  "description": "Calls Shipping Agent",
  "endpoint": "https://localhost:7026",
  "protocol": "http",
  "tags": ["Order", "Shipping", "Logistics"],
  "skills": [
    {
      "name": "shipping_details",
      "description": "Get order, inventory, or logistics information",
      "inputSchema": {
        "type": "object",
     "properties": {
          "userQuestion": { "type": "string" },
          "location": { "type": "string" }
        }
      },
      "outputSchema": {
        "type": "object",
        "properties": {
     "response": { "type": "string" }
        }
   }
    }
  ]
}

Child Registry (ChildCardDetails.json)

Defines specialized child agents for the parent orchestrator:

{
  "id": "order_inventory_agent",
  "name": "Order",
  "description": "Call Order Child Agent",
  "endpoint": "https://localhost:7277",
  "protocol": "http",
  "tags": ["Order", "Inventory"],
  "skills": [
 {
      "name": "order_details",
      "description": "Gets order details",
      "inputSchema": {
        "type": "object",
        "properties": {
          "userQuestion": { "type": "string" },
          "orderId": { "type": "int" }
        }
    }
    }
  ]
}

🔄 Communication Flow

Example: Order Status Query

  1. User asks: "What's the status of order 12345?"

  2. Root Agent (Semantic Kernel):

  • Analyzes query intent
    • Selects shipping_details function from dynamic plugins
    • Invokes via A2A protocol
  1. Shipping Orchestrator receives query:

    • Routes to appropriate child (order vs. logistics)
    • Loads child plugins dynamically
    • Classifies as order-related
  2. Order Child Agent:

    • Processes order lookup via OrderPlugin
  • Returns structured response
  1. Response flows back:
    • Child → Orchestrator → Root → User
    • Streaming via SSE for real-time updates

⚙️ Technical Implementation

Dynamic Plugin Loading

The system uses a sophisticated plugin factory pattern:

// Load agent cards from registry
var localCards = JsonSerializer.Deserialize<List<AgentCard>>(
    File.ReadAllText("CardDetails.json"));

// Create kernel functions dynamically
foreach (var card in localCards)
{
    foreach (var skill in card.Skills)
    {
     try
     {
         var function = await CreateSkillFunctionAsync(effectiveCard, skill);
         if (function != null)
             functions.Add(function);
     }
     catch (Exception ex)
     {
         Console.WriteLine($"Failed to create function for skill '{skill.Name}': {ex.Message}");
     }    
    }
if (functions.Count == 0) return;

var plugin = KernelPluginFactory.CreateFromFunctions("ShippingAgentChildSkills", functions);
kernel.Plugins.Add(plugin);
}

A2A Protocol Usage

// Resolve agent capabilities
A2ACardResolver resolver = new(new Uri(endpoint));
A2A.AgentCard card = await resolver.GetAgentCardAsync();

// Create client for communication
A2AClient client = new(new Uri(card.Url));

// Send message with metadata
AgentMessage message = new()
{
    Role = MessageRole.User,
    MessageId = Guid.NewGuid().ToString(),
    Parts = [new TextPart { Text = userQuery }],
    Metadata = parameters
};

// Streaming response
await foreach (var sseItem in client.SendMessageStreamingAsync(
    new MessageSendParams { Message = message }, ct))
{
  AgentMessage response = (AgentMessage)sseItem.Data;
    var text = response.Parts.OfType<TextPart>().FirstOrDefault()?.Text;
    Console.WriteLine(text);
}

🎨 User Experience Features

  • Animated Loading: Cyan progress bar with spinner during agent processing
  • Color-coded Output: Yellow responses for easy readability
  • Streaming Responses: Real-time output as agents process
  • Interactive Loop: Continue conversations without restarting

📦 NuGet Packages

Core Dependencies

  • Microsoft.SemanticKernel (1.66.0) - AI orchestration framework
  • Microsoft.SemanticKernel.Agents.Core (1.66.0) - Agent patterns
  • A2A (0.3.3-preview) - A2A protocol implementation
  • A2A.AspNetCore (0.3.3-preview) - ASP.NET Core integration
  • System.Net.ServerSentEvents (10.0.0-rc.2) - SSE streaming

🔒 Security Considerations

  • API keys should be stored in Azure Key Vault or user secrets
  • HTTPS enforced for all agent communication
  • Authentication tokens supported in agent card registry
  • Consider implementing rate limiting for production

🔧 Extensibility

Adding a New Agent

  1. Create agent server project (ASP.NET Core)
  2. Implement agent class with Attach(ITaskManager) method
  3. Register in parent registry (CardDetails.json or ChildCardDetails.json)
  4. Define skills with JSON schemas
  5. No code changes required in existing agents!

Adding a New Skill

  1. Update agent card registry with new skill definition
  2. Implement function in agent's kernel or plugin
  3. Dynamic loading handles the rest automatically

🐛 Troubleshooting

  • Connection errors: Verify all agent servers are running on correct ports
  • API errors: Check Azure OpenAI endpoint and API key configuration
  • Plugin not found: Ensure registry JSON files are copied to output directory
  • Namespace conflicts: Use fully qualified names (e.g., A2A.AgentCard)

📚 Learn More

🤝 Contributing

Contributions are welcome! Please follow these guidelines:

  1. Fork the repository
  2. Create a feature branch
  3. Add tests for new functionality
  4. Submit a pull request

📄 License

This project is provided as-is for educational and demonstration purposes.

🙏 Acknowledgments

  • Microsoft Semantic Kernel team
  • A2A Protocol contributors
  • .NET community

Built with ❤️ using .NET 9, Semantic Kernel, and the A2A Protocol

Capabilities

StreamingPush NotificationsMulti-TurnAuth: none
agentic-aiai-agentsazure-openaifunction-callingmulti-agentorchestration-frameworksemantic-kernelworkflow

Part of these stacks

View on GitHub