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==1.0 python-dotenv. Drop the credentials in a .env:
AOAI_ENDPOINT=https://... AOAI_DEPLOYMENT=gpt-4o-mini AOAI_API_KEY=... AOAI_API_VERSION=2024-10-21
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
from dotenv import load_dotenv
from agent_framework import (
ChatClientAgent,
)
from agent_framework.azure import (
AzureOpenAIChatClient,
)
load_dotenv()
E = os.environ
client = AzureOpenAIChatClient(
endpoint=E["AOAI_ENDPOINT"],
api_key=E["AOAI_API_KEY"],
deployment_name=E["AOAI_DEPLOYMENT"],
api_version=E["AOAI_API_VERSION"],
)
agent = ChatClientAgent(
chat_client=client,
instructions=(
"Terse release-notes "
"summarizer. One sentence."
),
)
prompt = (
"Summarize: Azure VPN P2S "
"now supports user-group "
"IP pools, GA 2026-05-21."
)
print(agent.run(prompt).content)
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 = ChatClientAgent(
chat_client=client,
instructions=(
"Portfolio assistant. "
"Use the tool for prices."
),
tools=[get_price],
)
q = "MSFT price? PGEN above $1?"
print(agent.run(q).content)
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.mcp import (
MCPStreamableHTTPClient,
)
URL = (
"https://learn.microsoft.com"
"/api/mcp"
)
async def main():
mcp = MCPStreamableHTTPClient(
url=URL,
)
async with mcp:
tools = await mcp.list_tools()
agent = ChatClientAgent(
chat_client=client,
instructions=(
"MS Learn assistant. "
"Use the MCP tools."
),
tools=tools,
)
q = (
"Front Door Standard "
"vs Premium tiers?"
)
r = await agent.run_async(q)
print(r.content)
asyncio.run(main())
Swap the URL for GitHub’s, Atlassian’s, or your own private one – the rest of the code is unchanged.
Two gotchas worth knowing: agent-framework==1.0 moved instructions to the ChatClientAgent constructor, so preview code that set it on ChatClientAgentOptions will break. And if a model deployment rejects parallel tool calls, pass parallel_tool_calls=False on the agent constructor.

