A developer studies a workflow diagram connecting cloud code, automation, and an AI chatbot on a large screen.
Azure Functions has a new way to put an AI agent inside an ordinary Python function without handing the function over to the agent. Microsoft's Azure SDK Blog announced Agent bindings for Python function apps (preview) on October 6, 2026. The feature adds a Microsoft Agent Framework Agent to the existing Python v2 programming model. Your trigger, validation and response logic stay in your code.

This article covers what the preview does, how to wire it up, how it works with Durable Functions, and where it falls short.

What an agent binding is​

When the function runs, the extension builds an Agent from Markdown instructions and injects it into your handler as a typed parameter. Your code decides when and how to invoke the agent alongside your deterministic application logic.

The preview's limits are firm:

  • Preview status. Agent bindings are in preview, and features, package names and configuration can change before general availability.
  • One provider. Microsoft Agent Framework is the only agent SDK supported in the current preview. The architecture is provider-neutral on paper, but in practice there is one provider today.
  • Python version. Microsoft's walkthrough requires Python 3.13 or later.

Don't confuse it with the serverless agents runtime​

Microsoft has another preview in this area. The Azure Functions serverless agents runtime is a markdown-first model. It offers a built-in chat UI, HTTP API and MCP server endpoint with no extra code. There, the runtime owns the agent loop.

Agent bindings work the other way round. Your function is the coordinator, and the agent is a bounded reasoning step it calls. Pick the runtime when you want an agent to be the application. Pick bindings when you have an existing function that needs a bit of judgment.

Project layout​

An agent-enabled app is a normal Python v2 function app with a few extra files:

  • function_app.py holds triggers, deterministic logic, the client factory and the agent call.
  • order-fulfillment.agent.md holds raw UTF-8 instructions for one agent.
  • requirements.txt selects the provider and client packages.
  • local.settings.json holds storage, Foundry project and model settings. Don't commit it.
  • Optional skills/ and mcp.json provide file-based Agent Skills and remote MCP servers.

An agent name must resolve to exactly one instruction file. Microsoft's example resolves order-fulfillment to either order-fulfillment.agent.md in the app root or the same file under agents/. If both exist, startup fails. Names can't contain absolute paths, path separators or traversal components.

Setup walkthrough​

Prerequisites​

You need:

  • Python 3.13 or later
  • an Azure subscription
  • a Microsoft Foundry project with a deployed model
  • Azure Functions Core Tools
  • Azurite or an Azure Storage account
  • the Azure CLI
  • a local identity that can access the Foundry project

Packages​

Microsoft's example requirements.txt lists azure-functions, azurefunctions-agents-extensions-agent-framework, agent-framework-foundry and azure-identity. The mcp extra adds remote MCP discovery. The durable extra adds Durable Functions support. The extension package connects the binding to Agent Framework, but it doesn't pick your model. The provider package leaves model provider selection to your client factory.

Local settings​

local.settings.json carries four values:

  • AzureWebJobsStorage, set to UseDevelopmentStorage=true for Azurite
  • FUNCTIONS_WORKER_RUNTIME, set to python
  • FOUNDRY_PROJECT_ENDPOINT, in the form https://<resource-name>.services.ai.azure.com/api/projects/<project-name>
  • FOUNDRY_MODEL, the name of your model deployment

Instructions file​

The .agent.md file is plain instructions. The extension passes the whole file through. It doesn't parse YAML front matter, model settings or tool declarations from it. Model choice lives in the client factory. Python tools stay explicit application configuration.

Client factory and decorator​

AgentFunctionApp takes a zero-argument client factory. Microsoft's sample builds a FoundryChatClient from the two environment variables and authenticates with DefaultAzureCredential. You then apply @app.markdown_agent(arg_name="order_agent", agent_name="order-fulfillment") to a function.

  • arg_name must match the handler parameter that receives the agent.
  • agent_name is the instruction file name without the .agent.md suffix.

The agent does not run on its own when the function starts. The handler calls await order_agent.run(...) explicitly. That is the design's best feature, because the reasoning step is visible and testable in your code.

What happens on each invocation​

For every invocation, the extension:

  1. loads the instruction file
  2. calls your factory to create a client
  3. combines the instructions with configured tools, skills and MCP servers
  4. builds the Agent and injects it
  5. closes its resources afterwards

Microsoft says compiled definitions and provider discovery may be cached. Live clients and credentials are not reused across invocations.

Deterministic code first​

Microsoft's order-processing example shows the intended pattern. Ordinary Python selects the fields the model needs: order ID, customer ID, currency, shipping destination and method, and items. The agent then assesses fulfillment risk and flags missing context. The function builds the HTTP response.

Data minimization is a real benefit here, because the model sees less. But treat the sample as a pattern, not a security control:

  • The sample helper selects fields. It doesn't amount to full validation or authorization.
  • The blog's sample instructions tell the model to treat the supplied fields as trusted facts.
  • The Durable quickstart takes a more defensive line. It tells the agent to use order fields only as data and not to follow instructions inside them.

That difference is worth copying. Order fields can contain customer-supplied text, and prompt injection through data fields is a known risk class. Use the more defensive wording if any of your input originates outside your organization. Validate the model's output before it drives anything consequential.

Skills and MCP: the sharing caveat​

The extension discovers file-based skills in skills/<name>/SKILL.md or Skills/<name>/SKILL.md. It reads remote MCP servers from a root mcp.json.

The preview has a significant limitation. Every agent binding in the function app receives all discovered agent skills and MCP servers. Microsoft's documentation says the preview can't select a subset for an app or for an individual binding. Skills and MCP tools can perform privileged operations. The guidance is to include only capabilities every agent in the app may use, and to split agents into separate function apps when their capability boundaries differ.

Other MCP details from Microsoft's documentation:

  • Remote HTTP and streamable-HTTP servers are supported.
  • Local-process and stdio servers are not.
  • mcp.json can reference environment variables for URLs, headers, authentication scopes and client IDs. Microsoft says not to put secrets directly in a source-controlled file.

Python tools are scoped more tightly. You can pass them at the app level or on a single binding. Microsoft's example gives a lookup_inventory tool to just one agent.

Durable Functions​

For work that outlives one request, install the durable extra. The Durable quickstart has three parts:

  • HTTP starter. It checks the body is JSON and calls start_new. It returns 202 Accepted with management URLs, including statusQueryGetUri, plus Location and Retry-After headers.
  • Preparation activity. An ordinary activity validates and selects fields.
  • Orchestrator. A synchronous generator yields context.call_activity(...) and then context.call_agent("order-fulfillment", {...}).

Orchestrators replay, so they can't do model or network work directly. Microsoft says call_agent() schedules a hidden activity instead. That activity resolves the agent definition and performs the file, credential, model, tool and network operations. The orchestrator only builds a deterministic, JSON-serializable request. On replay, the recorded result is reused and the model isn't called again.

"Replay-safe" has a narrow meaning. The orchestrator doesn't repeat the model call on replay. That says nothing about the model giving the same answer twice, and it doesn't make the whole workflow exactly-once. Inputs and outputs must be JSON-serializable.

Running it locally​

  1. Run az login so DefaultAzureCredential can use your Azure CLI identity.
  2. Start Azurite with azurite --silent --location .azurite.
  3. In a second terminal, run func start.
  4. POST an order to /orders/orchestrations. The Durable sample puts order_id in the body, because the starter has no route parameter for it.
  5. Poll statusQueryGetUri until runtimeStatus is Completed, then read risk_assessment from the output.

Failure points​

Microsoft's troubleshooting list covers the usual local problems:

SymptomSuggested check
Agent definition can't be foundRun func start from the app root and confirm the .agent.md file is there
Foundry authentication failsRun az login, then verify the tenant, subscription and project access
Durable extension won't loadConfirm the durable extra is in requirements.txt and the extension bundle can download
Orchestration stays PendingConfirm Azurite is running and AzureWebJobsStorage points at the right storage
Failure in the preparation activityConfirm the order has order_id, a customer ID, shipping info and at least one item
Agent activity failsCheck host logs and instance status for authentication, model or quota errors

Malformed JSON returns HTTP 400 and never starts an orchestration. Valid JSON with a missing required field does start one, and it then fails in the preparation activity. Callers who only look at the 202 will miss that. You need status polling or alerting.

Don't lean on breakpoints inside the orchestrator to run only once. Replay means they won't.

Which path to choose​

  • Call the agent directly when the answer belongs in the current HTTP response or trigger invocation.
  • Use Durable Functions when you need persisted progress, several steps, waiting on external systems, or work that continues after the original request ends.

Microsoft also lists queue, Event Grid and timer triggers as places to use bindings, for example classifying or enriching event payloads. The published walkthroughs only demonstrate HTTP.

Practical takeaways​

  • Treat this as a preview. Microsoft's documentation warns that package names and configuration may change.
  • Keep the agent's work narrow: classify, summarize or recommend. Leave authorization and writes to code.
  • Because bindings share all discovered skills and MCP servers, separate function apps are the way to isolate capabilities.
  • Use the more defensive instruction wording from the Durable quickstart when inputs are untrusted.
  • Expect a Foundry project, a deployed model and a configured identity before anything runs.

Microsoft says it wants feedback and points to the Agent Extension repository for issues and feature requests.

 

References

  1. Bring agentic reasoning to Python function apps with Azure Functions Agent bindings (preview) Azure SDK Blog 2026-10-06T15:00:10+00:00
  2. Use a Microsoft Agent Framework agent binding in a Durable orchestration | Microsoft Learn learn.microsoft.com
  3. Agent bindings for Python in Azure Functions learn.microsoft.com