
349 – Back to basics: Managed identities vs. Service Principals vs. App Registrations
July 2, 2026Introducing kars – an Agent Reference Stack for Kubernetes
July 2, 2026As AI systems move from single agents to multi-agent workflows, one challenge becomes obvious: how do agents built in different frameworks discover each other, communicate, and collaborate reliably? This post walks through a practical Agent-to-Agent (A2A) integration between Microsoft Foundry and LangGraph, showing how a Foundry agent can call a LangGraph agent hosted on Azure Container Apps.
Prerequisites for the Tutorial:
- Azure Subscription
- Microsoft Foundry resource deployed in a resource group. Deploy any model (such as gpt-4.1-mini) in the Foundry project.
We will create a LangGraph agent and host it on Azure Container Apps. This will act as our A2A server. Our Foundry agent will be the A2A client.
The repository structure should be:
A2A/
├── agent.py
├── app.py
├── requirements.txt
├── Dockerfile
├── .dockerignore
└── README.md
Let’s walk through each file and its purpose:
agent.py: This file has code for the LangGraph agent.
import os
from langgraph.graph import StateGraph
from openai import AzureOpenAI
from azure.identity import DefaultAzureCredential, get_bearer_token_provider
api_version = “2024-12-01-preview”
model_name = “gpt-4.1-mini”
deployment = “gpt-4.1-mini”
endpoint = os.getenv(
“AZURE_OPENAI_ENDPOINT”,
“https://.cognitiveservices.azure.com/”,
)
token_provider = get_bearer_token_provider(
DefaultAzureCredential(), “https://cognitiveservices.azure.com/.default”
)
client = AzureOpenAI(
api_version=api_version,
azure_endpoint=endpoint,
azure_ad_token_provider=token_provider,
)
def process_node(state):
user_input = state.get(“input”, “”)
prompt = f””” You are an AI assistant that summarizes user input. Please provide a concise summary of the following text: {user_input} “””
response = client.chat.completions.create(
messages=[
{
“role”: “system”,
“content”: “You are a helpful assistant.”,
},
{
“role”: “user”,
“content”: prompt,
}
],
model=deployment
)
return {
“output”: response.choices[0].message.content.strip()
}
graph = StateGraph(dict)
graph.add_node(“process_node”, process_node)
graph.set_entry_point(“process_node”)
graph.set_finish_point(“process_node”)
agent = graph.compile()
app.py: This file exposes the LangGraph agent as an A2A server
import os
from a2a.server.agent_execution import AgentExecutor, RequestContext
from a2a.server.apps import A2AStarletteApplication
from a2a.server.events import EventQueue
from a2a.server.request_handlers import DefaultRequestHandler
from a2a.server.tasks import InMemoryTaskStore
from a2a.types import AgentCapabilities, AgentCard, AgentSkill
from a2a.utils import new_agent_text_message
from agent import agent
class Executor(AgentExecutor):
async def execute(self, context: RequestContext, event_queue: EventQueue):
result = agent.invoke({“input”: context.get_user_input()})
await event_queue.enqueue_event(
new_agent_text_message(result.get(“output”, “”))
)
async def cancel(self, context: RequestContext, event_queue: EventQueue):
raise Exception(“not supported”)
card = AgentCard(
name=”LangGraph Agent”,
description=”Summarises article”,
url=os.getenv(“PUBLIC_URL”, “http://localhost:8000/”),
version=”1.0.0″,
default_input_modes=[“text”],
default_output_modes=[“text”],
capabilities=AgentCapabilities(streaming=False),
skills=[
AgentSkill(
id=”summarise”,
name=”Summarise article”,
description=”Summarises a user-provided article or text”,
tags=[“summarise”],
)
],
)
app = A2AStarletteApplication(
agent_card=card,
http_handler=DefaultRequestHandler(
agent_executor=Executor(),
task_store=InMemoryTaskStore(),
),
).build()
- The Executor runs the agent for each request. It pulls the incoming user text, runs the LangGraph summarizer, and puts the summary back on the event queue as the response.
- card: This is the Agent Card that holds the agent metadata
- app: This ASGI (Asynchronous Server Gateway Interface) application serves the agent card (GET /.well-known/agent-card.json) and handles the JSON-RPC calls between client and server.
Dockerfile: For deploying the LangGraph agent to Azure Container Apps
FROM python:3.12-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install –no-cache-dir -r requirements.txt
COPY . .
EXPOSE 8000
CMD [“uvicorn”, “app:app”, “–host”, “0.0.0.0”, “–port”, “8000”]
requirements.txt
fastapi==0.138.0
uvicorn
langgraph==1.2.6
pydantic==2.13.4
openai azure-identity
a2a-sdk[http-server]>=0.3.0,<0.4
We run the following commands to deploy our agent (Ensure you have done az login before running this command):
az containerapp up –name langgraph-agent –resource-group –location –source . –target-port 8000 –ingress external$fqdn = az containerapp show -n langgraph-agent -g a2a –query properties.configuration.ingress.fqdn -o tsv az containerapp update -n langgraph-agent -g a2a –set-env-vars “PUBLIC_URL=https://$fqdn/”
This creates the Azure Container Apps (ACA) resource and related resources, then deploys the agent.
In the Container App resource, go to the ‘Overview’ tab and copy the Application Url (also called the FQDN – Fully Qualified Domain Name). This is the endpoint of our A2A server.
Once done, navigate to the Microsoft Foundry portal. Make sure you’re on the New Foundry portal.
- Go to ‘Build’ from the top navbar and click on ‘Agents’
- Create an agent – give it a suitable name (E.g. foundry-agent)
- You can use the model we deployed in Foundry for the agent.
- Go to the agent’s playground and click on ‘Add’ in the ‘Tools’ section. Choose ‘Browse all tools’
Go to the ‘Custom’ tab in the pop-up and select ‘Agent2agent (A2A)’
Fill out the parameters:
Name: my-a2a-connection (or any name)
A2A Agent Endpoint: Paste the Azure Container Apps Application Uri here
Agent Card Path: Leave it as it is (i.e. /.well-known/agent.json)
Authentication: Select an auth method from the dropdown menu.
Click on ‘Connect’
Go back to the foundry agent’s playground, and add the following prompt to the ‘Instructions’ field:
When the user asks to summarize text, you MUST call the my-a2a-connection tool to produce the summary. Do not summarize on your own.
Go ahead and give the agent a prompt! For e.g.:
The Foundry agent uses the A2A protocol to call the LangGraph agent! 🎉
Next Steps:
- Try it yourself – Clone the GitHub Repo to get started!
- Connect multiple A2A agents to create a multi-agent workflow!
- Add authentication to secure your A2A endpoint
- Enable streaming responses for real-time output
Related Resources:
- Reference Used in the Blog: Agent-to-Agent Communication: Connecting Foundry and LangGraph Agents via A2A | Microsoft Community Hub
- Learn More About A2A: A2A Protocol
- Microsoft Foundry Agent Documentation: Microsoft Foundry documentation | Microsoft Learn