Microsoft Agent Framework 1.0: three runnable Python examples

Microsoft Agent Framework reached 1.0 GA on May 21, 2026 for both .NET and Python. It consolidates the previous Semantic Kernel and AutoGen SDKs into one supported codebase with a stable API surface and a long-term support commitment.

To see what zero-to-agent actually looks like against my own Azure OpenAI deployment, I wrote three small Python examples that progressively add capability: a hello-world agent, an agent with local Python tools, and an agent that connects to a remote MCP server. All three are real files I ran.

You need Python 3.10 or newer, an Azure OpenAI deployment (I used gpt-4o-mini, which is gpt-4.1-mini behind the alias), the endpoint URL and an API key, and pip install agent-framework-core agent-framework-openai python-dotenv mcp. Drop the credentials in a .env:

AOAI_ENDPOINT=https://...
AOAI_DEPLOYMENT=gpt-4o-mini
AOAI_API_KEY=...
AOAI_API_VERSION=2025-01-01-preview

The first example is a single agent that takes one prompt and returns one response. No tools, no state, no MCP. If it returns a sentence, the SDK and the deployment are both working:

import os
import asyncio
from dotenv import load_dotenv
from agent_framework import Agent
from agent_framework.openai import (
    OpenAIChatCompletionClient,
)

load_dotenv()
E = os.environ

client = OpenAIChatCompletionClient(
    azure_endpoint=E["AOAI_ENDPOINT"],
    api_key=E["AOAI_API_KEY"],
    model=E["AOAI_DEPLOYMENT"],
    api_version=E["AOAI_API_VERSION"],
)

agent = Agent(
    client,
    instructions=(
        "Terse release-notes "
        "summarizer. One sentence."
    ),
)

prompt = (
    "Summarize: Azure VPN P2S "
    "now supports user-group "
    "IP pools, GA 2026-05-21."
)
print(asyncio.run(agent.run(prompt)).text)

Adding a tool is one more parameter. The Annotated[..., "description"] pattern feeds each parameter description into the tool schema the model sees; the function docstring becomes the tool description:

from typing import Annotated

PRICES = {
    "MSFT": 412.10,
    "TSLA": 178.42,
    "PGEN": 1.23,
}

def get_price(
    sym: Annotated[
        str, "Ticker, uppercase"
    ],
) -> str:
    "Mock price for a ticker."
    p = PRICES.get(sym.upper())
    if p is None:
        return f"unknown {sym}"
    return f"{sym}: ${p:.2f}"

agent = Agent(
    client,
    instructions=(
        "Portfolio assistant. "
        "Use the tool for prices."
    ),
    tools=[get_price],
)

q = "MSFT price? PGEN above $1?"
print(asyncio.run(agent.run(q)).text)

With two questions in one prompt the agent calls the tool twice and summarizes both results.

The third example skips local tools entirely and pulls them from a remote MCP server. Agent Framework ships an MCP client, so any compliant server is a tool source with no glue code. The Microsoft Learn MCP server at learn.microsoft.com/api/mcp is public and Streamable-HTTP:

import asyncio
from agent_framework import (
    Agent,
    MCPStreamableHTTPTool,
)

URL = (
    "https://learn.microsoft.com"
    "/api/mcp"
)

async def main():
    async with MCPStreamableHTTPTool(
        name="mslearn",
        url=URL,
    ) as mcp:
        agent = Agent(
            client,
            instructions=(
                "MS Learn assistant. "
                "Use the MCP tools."
            ),
            tools=mcp,
        )
        q = (
            "Front Door Standard "
            "vs Premium tiers?"
        )
        r = await agent.run(q)
        print(r.text)

asyncio.run(main())

Swap the URL for GitHub’s, Atlassian’s, or your own private one – the rest of the code is unchanged.

A few things changed between the preview and GA and will bite you. The Azure client is OpenAIChatCompletionClient from agent_framework.openai, not AzureOpenAIChatClient; the newer OpenAIChatClient defaults to the /responses endpoint, which rejects the classic api-version with a 400, so use the ChatCompletion client for Azure OpenAI. The agent class is now Agent (the preview ChatClientAgent is gone), and it takes the client as its first positional argument with instructions= as a keyword. And agent.run(...) is async: wrap it in asyncio.run(...) and read the reply text off .text, not .content.


Posted

in

by

Tags: