01 — Your First Hosted Agent
Deploy a containerized agent to the Foundry hosting platform using Microsoft Agent Framework (MAF). By the end of this lesson your agent will be running in the cloud and responding to prompts.
What is a hosted agent?
A hosted agent is a containerized application that Foundry runs and manages for you. You write the agent logic in Python, package it in a Docker container, and deploy it with azd. Foundry provisions the infrastructure, handles scaling, injects credentials via managed identity, and exposes the agent through a standard Responses API endpoint.
flowchart LR
Dev["Developer (local)"] -->|azd deploy| ACR["Azure Container Registry"]
ACR -->|image pull| Host["Foundry Hosted Runtime"]
Host -->|Responses API| Client["Foundry Portal / SDK"]
Key characteristics:
| Feature | Detail |
|---|---|
| Runtime | Container on Foundry-managed infrastructure |
| Auth | Managed identity injected at deploy time |
| Protocol | Responses API v1.0 |
| Port | 8088 (fixed) |
| GPU | Not required for inference (model calls go to your deployment) |
Alternative scaffolding
You can also create the project structure interactively with azd ai agent init. In this workshop we use pre-built files so you can see every piece explicitly.
Project structure
examples/01-first-hosted-agent/
├── main.py ← agent logic
├── agent.yaml ← hosting metadata
├── azure.yaml ← azd project manifest
├── Dockerfile ← container definition
└── requirements.txt ← Python dependencies
The code
examples/01-first-hosted-agent/main.py
"""Lesson 01 — Your First Hosted Agent."""
import os
from azure.identity import DefaultAzureCredential
from dotenv import load_dotenv
from agent_framework import Agent
from agent_framework.foundry import FoundryChatClient
from agent_framework_foundry_hosting import ResponsesHostServer
load_dotenv()
credential = DefaultAzureCredential()
client = FoundryChatClient(
project_endpoint=os.environ["AZURE_AI_PROJECT_ENDPOINT"],
model=os.environ["AZURE_AI_MODEL_DEPLOYMENT_NAME"],
credential=credential,
)
agent = Agent(
client=client,
instructions=(
"You are a helpful healthcare assistant. "
"You answer questions about general health, wellness, and medical terminology. "
"Always remind the user that your answers are for informational purposes only "
"and not a substitute for professional medical advice."
),
default_options={"store": False},
)
server = ResponsesHostServer(agent)
server.run()
Step-by-step walkthrough
1. Authenticate with DefaultAzureCredential
Locally this uses your az login session. When deployed, Foundry injects a managed identity automatically — no code change needed.
2. Create a FoundryChatClient
client = FoundryChatClient(
project_endpoint=os.environ["AZURE_AI_PROJECT_ENDPOINT"],
model=os.environ["AZURE_AI_MODEL_DEPLOYMENT_NAME"],
credential=credential,
)
The client connects your agent to a specific Foundry project and model deployment. The project_endpoint is the full URL from your Foundry project settings (format: https://<account>.services.ai.azure.com/api/projects/<project>).
3. Define the Agent
instructions— the system prompt that shapes the agent's behaviour.default_options={"store": False}— disables server-side conversation storage. Useful during development.
4. Wrap in a ResponsesHostServer
ResponsesHostServer exposes the agent via the Responses API protocol on port 8088. This is the interface the Foundry runtime expects.
5. agent.yaml — hosting metadata
kind: hosted
name: my-hosted-agent1
protocols:
- protocol: responses
version: 1.0.0
environment_variables:
- name: AZURE_AI_MODEL_DEPLOYMENT_NAME
value: ${AZURE_AI_MODEL_DEPLOYMENT_NAME}
- name: AZURE_AI_PROJECT_ENDPOINT
value: ${AZURE_AI_PROJECT_ENDPOINT}
kind: hostedtells Foundry to manage this agent.protocolsdeclares which API the agent speaks.environment_variablesmaps values from your Foundry project environment.
6. Dockerfile
FROM python:3.12-slim
WORKDIR /app
COPY . user_agent/
WORKDIR /app/user_agent
RUN if [ -f requirements.txt ]; then pip install -r requirements.txt; fi
EXPOSE 8088
CMD ["python", "main.py"]
This is the standard Dockerfile pattern for hosted agents. Foundry expects port 8088.
Try it
Initialize the azd environment
This connects your local project to your Azure resources (subscription, project, ACR). You only need to do this once per machine.
Prerequisites
This assumes you've already provisioned resources using infra/main.bicep as described in the Prerequisites. The Bicep template creates the Foundry account, project, model deployment, ACR, and role assignments (AcrPull + Foundry User for the project identity).
cd examples/01-first-hosted-agent
# Initialize — the wizard will ask you to:
# 1. "Use the code in the current directory"
# 2. Allow agent.yaml overwrite
# 3. Choose "Container Image (Docker)"
# 4. Select your subscription and Foundry project
# 5. Enter your ACR login server (e.g. <your-acr>.azurecr.io)
# 6. Select your existing model deployment
azd ai agent init
Fix agent.yaml after init
azd ai agent init overwrites agent.yaml and may remove custom environment variables. After running init, ensure your agent.yaml includes all env vars your code needs:
environment_variables:
- name: AZURE_AI_MODEL_DEPLOYMENT_NAME
value: ${AZURE_AI_MODEL_DEPLOYMENT_NAME}
- name: AZURE_AI_PROJECT_ENDPOINT
value: ${AZURE_AI_PROJECT_ENDPOINT}
Without AZURE_AI_PROJECT_ENDPOINT, the container will crash on startup and you'll see a session_not_ready error when invoking.
Run the agent locally
Start the agent using your local az login credentials — no Docker or cloud resources needed:
Stale azd environment
azd ai agent run reads environment variables from .azure/<env-name>/.env, not from the workspace .env file. If you previously deployed to a different Foundry account/project and then changed your target environment, the cached values will be stale.
To fix, either:
- Delete the
.azure/folder and re-runazd ai agent init, or - Manually update
AZURE_AI_PROJECT_ENDPOINTin.azure/<env-name>/.envto match your current endpoint.
After updating, stop the agent (Ctrl+C) and restart with azd ai agent run.
Invoke the agent locally
In a separate terminal, from the same directory:
cd examples/01-first-hosted-agent
azd ai agent invoke --local "What are the symptoms of vitamin D deficiency?"
Expected output:
Common symptoms of vitamin D deficiency include fatigue, bone pain, muscle
weakness, and mood changes. However, many people have no symptoms at all.
Please note: this information is for educational purposes only and is not
a substitute for professional medical advice.
Quick test loop
After making changes to main.py, stop the agent (Ctrl+C), then run azd ai agent run again.
Deploy to the cloud
# Deploy (builds container remotely, pushes to ACR, deploys to Foundry)
azd deploy first-hosted-agent
Assign Foundry User role to the agent identity
Required post-deploy step
When you deploy a hosted agent, the platform creates a ServiceIdentity for it. This identity needs the Foundry User role on your Foundry account so the agent can access project storage and invoke models at runtime.
After the first deploy, find the agent identity and assign the role:
# Re-use variables from the prereqs (or set them if not already exported)
# export BASE_NAME=<your-unique-name>
# export RESOURCE_GROUP=rg-foundry-advanced-workshop
ACCOUNT_ID=$(az cognitiveservices account show \
--name $BASE_NAME --resource-group $RESOURCE_GROUP --query id -o tsv)
# The agent name comes from your agent.yaml
AGENT_NAME=first-hosted-agent
PROJECT_NAME=${BASE_NAME}-project
# Find the agent's ServiceIdentity (created by the platform)
AGENT_IDENTITY=$(az ad sp list \
--display-name "${BASE_NAME}-${PROJECT_NAME}-${AGENT_NAME}-AgentIdentity" \
--query "[0].id" -o tsv)
echo "Agent identity: $AGENT_IDENTITY"
# Assign Foundry User role
az role assignment create \
--assignee-object-id "$AGENT_IDENTITY" \
--assignee-principal-type ServicePrincipal \
--role "53ca6127-db72-4b80-b1b0-d745d6d5456d" \
--scope "$ACCOUNT_ID"
Role propagation
RBAC assignments can take 1–2 minutes to propagate. If you get a PermissionDenied error immediately after assigning the role, wait a moment and try again.
Why can't this be in Bicep?
The agent's ServiceIdentity is auto-created by the Foundry platform at deploy time — it doesn't exist before azd deploy runs. The Bicep template does assign Foundry User to the project's managed identity (which covers most operations), but the agent identity needs its own assignment.
After deployment, invoke without --local:
You can also check agent status and view logs:
Key takeaways
- A hosted agent is a Python application packaged in a container.
agent.yamldescribes the hosting configuration.ResponsesHostServerwraps yourAgentto speak the Responses API.DefaultAzureCredentialworks both locally and in the cloud.azd ai agent runstarts the agent locally for fast iteration.azd ai agent init+azd provision+azd deployhandles cloud deployment.