Monday, September 21, 2026

Microsoft Agent Framework: Hosted Agents in Microsoft Foundry with .NET

In this post, let's see how we can take an agent written with Microsoft Agent Framework and let Microsoft Foundry host it, as a hosted agent.

A while back I blogged about Microsoft Agent Framework: Agents on Azure Functions with .NET, where we hosted the agent ourselves. And in the last post, Microsoft Agent Framework: Prompt Agents in Microsoft Foundry with .NET, we looked at prompt agents, where Foundry stores the agent definition but our code still runs the tools.

A hosted agent is the other end of that. We write the agent in code as usual, and Foundry runs it for us as a container with a managed endpoint, its own Microsoft Entra identity, scaling, versions, and a playground. Our tools run inside that container, not in our application.

The agent

The agent itself is the same weekend planner from the earlier posts. The only difference is that instead of running it, we serve it over the Responses protocol.
// Foundry injects these when the agent is hosted, locally they come from launchSettings.json
string endpoint = Environment.GetEnvironmentVariable("FOUNDRY_PROJECT_ENDPOINT")!;
string deploymentName = Environment.GetEnvironmentVariable("AZURE_AI_MODEL_DEPLOYMENT_NAME")!;

// Locally this is the developer, in Foundry it is the agent's own managed identity
var credential = new DefaultAzureCredential();

AIAgent agent = new AIProjectClient(new Uri(endpoint), credential)
    .AsAIAgent(
        model: deploymentName,
        name: "weekend-planner",
        instructions: """
            You help users plan their weekends and choose the best activities for the given weather.
            If an activity would be unpleasant in weather, don't suggest it.
            Include date of the weekend in response.
            """,
        tools: [
            AIFunctionFactory.Create(GetWeather, nameof(GetWeather)),
            AIFunctionFactory.Create(GetActivities, nameof(GetActivities)),
            AIFunctionFactory.Create(GetCurrentDate, nameof(GetCurrentDate))
        ]);

// Serve the agent over the Responses protocol, on port 8088 by default
AgentHostBuilder builder = AgentHost.CreateBuilder(args);
builder.Services.AddFoundryResponses(agent);
builder.RegisterProtocol("responses", endpoints => endpoints.MapFoundryResponses());

AgentHostApp app = builder.Build();
app.Run();
A couple of things to note. DefaultAzureCredential is used on purpose here, so the same code works locally as ourselves, and in Foundry as the agent's identity.

The project targets net10.0, because that's the runtime Foundry hosted agents run on (latest package as of today, it will change).
<PropertyGroup>
  <TargetFramework>net10.0</TargetFramework>
</PropertyGroup>

<ItemGroup>
  <PackageReference Include="Microsoft.Agents.AI.Foundry.Hosting" Version="1.22.0-preview.260918.1" />
</ItemGroup>

Running it locally first

Before deploying anything, the agent is just a web app. dotnet run and it listens on port 8088.
@host = http://localhost:8088

### Invoke the agent running locally
POST {{host}}/responses
Content-Type: application/json

{
  "input": "What should I do this weekend in Auckland?",
  "stream": false
}
The response contains the function_call items for the tools and the final message, so we can see the agent working before it goes anywhere near Azure.
Running Locally

Deploying

Deployment is done with Azure Developer CLI and the Foundry extension.
azd extension install microsoft.foundry
azd auth login
Then, from the agent's folder, initialize it against an existing Foundry project. The project id is the ARM resource id of the Foundry project.
azd ai agent init `
--no-prompt ` --src . ` --agent-name weekend-planner ` --project-id "/subscriptions/<subscription>/resourceGroups/<resource-group>/providers/Microsoft.CognitiveServices/accounts/<account>/projects/<project>" ` --deploy-mode code ` --runtime dotnet_10 ` --entry-point HostedAgent.dll ` --model-deployment <DeploymentId> ` --protocol responses ` --environment weekend-planner
That writes an azure.yaml, an .agentignore, and a .gitignore that keeps the .azure environment folder out of source control.
# yaml-language-server: $schema=https://raw.githubusercontent.com/Azure/azure-dev/main/schemas/v1.0/azure.yaml.json

name: 07-hosted-agent
services:
    ai-project:
        host: azure.ai.project
        endpoint: ${FOUNDRY_PROJECT_ENDPOINT}
    weekend-planner:
        project: .
        host: azure.ai.agent
        language: csharp
        uses:
            - ai-project
        env:
            AZURE_AI_MODEL_DEPLOYMENT_NAME: ${AZURE_AI_MODEL_DEPLOYMENT_NAME}
        codeConfiguration:
            dependencyResolution: remote_build
            entryPoint: HostedAgent.dll
            runtime: dotnet_10
        container:
            resources:
                cpu: "0.5"
                memory: 1Gi
        kind: hosted
        name: weekend-planner
        protocols:
            - protocol: responses
              version: 2.0.0
infra:
    provider: microsoft.foundry

One thing in there worth a second look is version: 2.0.0 under protocols. The SDK and REST examples in the docs still show 1.0.0, and the manifest and the hosting package have to agree, so copying the version out of those examples while referencing Microsoft.Agents.AI.Foundry.Hosting 1.22.0 will not work.

And then deploy. Note that there is no azd provision here, because the Foundry project and the model deployment already exist.
azd deploy
azd deploy
One thing worth knowing about remote_build: only the agent's own folder is zipped and uploaded, and Foundry restores and builds it there. So the project needs to stand on its own. If your agent references another project in your solution, switch to dependencyResolution: bundled instead, where the zip holds dotnet publish output rather than sources. With azd you can see it doing the publish in the deploy output.

Invoking the deployed agent

azd ai agent invoke weekend-planner "What should I do this weekend in Auckland?"
Invoking the deployed agent
Note the tools ran inside the container this time, not in our process. The agent also shows up in the Foundry portal with a playground, and that is the part worth trying. With the prompt agent it stopped at the first tool call and asked us to enter the function output as JSON, because there was nothing up there to run the tools. Here they are in the container, so the playground answers on its own.
Invoking in Foundry Playground
Every azd deploy creates a new version, and container logs are available too.
azd ai agent show weekend-planner
azd ai agent monitor weekend-planner --session-id <session-id>

Calling it from code

That is fine for a quick check, but an application would call the agent from code.
string endpoint = Environment.GetEnvironmentVariable("AZURE_AI_PROJECT_ENDPOINT")!;
const string agentName = "weekend-planner";

// For local development, using AzureCliCredential
var credential = new AzureCliCredential();

AIProjectClient projectClient = new(new Uri(endpoint), credential);

// A hosted agent is called through its own endpoint, not the project one
ProjectResponsesClient responsesClient = projectClient.ProjectOpenAIClient
    .GetProjectResponsesClientForAgentEndpoint(agentName);

string userInput = "What should I do this weekend in Auckland?";

Console.WriteLine("--- User ---");
Console.WriteLine(userInput);

ResponseResult response = responsesClient.CreateResponse(userInput);

Console.WriteLine();
Console.WriteLine("--- Agent Response ---");
Console.WriteLine(response.GetOutputText());

Cleaning up

Worth knowing that azd down is not the thing to reach for here. That removes the environment azd provisioned, and we didn't provision one, we deployed into a project that already existed. What we want is to delete the agent itself, from the portal or over REST.
@agent = weekend-planner

# For the deployed agent, get a token with:
# az account get-access-token --scope https://ai.azure.com/.default --query accessToken --output tsv
@endpoint = https://<resource>.services.ai.azure.com/api/projects/<projectId>
@token = <token>

### Delete the agent, its versions, and any active sessions
DELETE {{endpoint}}/agents/{{agent}}?api-version=v1&force=true
Authorization: Bearer {{token}}
Deleting an agent removes all of its versions and terminates any active sessions, and it can't be undone. The force=true is what cascades to the sessions, without it a deletion with sessions still open comes back as a 409.

So where does this leave us

With prompt agents, Foundry holds the definition and our application runs the tools. With hosted agents, Foundry runs the whole thing, code and tools, and gives us an endpoint, an identity, versions and a playground. And if we want to host it ourselves, Azure Functions is still there, which is what the earlier posts covered.

The complete sample is here.

More read:

Hope this helps.

Happy Coding.

Regards,
Jaliya

No comments:

Post a Comment