Note
Access to this page requires authorization. You can try signing in or changing directories.
Access to this page requires authorization. You can try changing directories.
Agent Framework Python 1.23.0 introduces three changes that can require code updates:
- MCP integrations move to the MCP SDK 2.x high-level client lifecycle.
- AG-UI endpoint registration requires an explicit authorization ownership mode.
DockerShellTool.extra_run_argsis renamed tounsafe_extra_run_args.
The release also adds allowlisted A2A run-context forwarding, an opt-in provider compatibility option for sequential agents, and broader Python 3.15 support.
Upgrade the package cohort together
If you use the standard metapackage, upgrade it directly:
python -m pip install --upgrade "agent-framework==1.23.0"
If you install individual packages, upgrade the packages used by the
application in one operation. Agent Framework packages don't all share the
same numeric version, so don't force every integration package to 1.23.0.
Keep --pre only when the command includes an alpha or beta package.
Avoid running old and new workers against the same persisted sessions,
histories, snapshots, or checkpoints during the upgrade. Python 1.22 introduced
serialized hosted and merge_mode fields that older runtimes can't read.
Migrate MCP connections
Agent Framework 1.23 uses mcp>=2.2.0,<3 and treats the MCP SDK's high-level
Client as the primary connection.
Keep simple framework-owned connections
For most applications, continue to pass a URL or command to an Agent Framework MCP tool. Agent Framework creates, enters, reconnects, and closes the MCP client:
from agent_framework import MCPStreamableHTTPTool
mcp_tool = MCPStreamableHTTPTool(
name="microsoft-learn",
url="https://learn.microsoft.com/api/mcp",
)
Use the tool as an async context manager when your application controls its
lifetime, or attach it to an Agent whose lifetime is managed with
async with.
Use a caller-owned high-level client
Use this pattern when the application must configure or reuse the MCP SDK client:
from agent_framework import MCPStreamableHTTPTool
from mcp import Client
async with (
Client(server="https://learn.microsoft.com/api/mcp") as mcp_client,
MCPStreamableHTTPTool(
name="microsoft-learn",
mcp_client=mcp_client,
) as mcp_tool,
):
result = await agent.run("Find the relevant documentation.", tools=mcp_tool)
The caller must enter the Client before the MCP tool connects and keep it
entered for the complete agent or workflow run. Agent Framework doesn't close
or replace a caller-owned client.
Don't combine mcp_client= with transport configuration such as url=,
command=, headers, or a caller-owned HTTP client. These combinations mix
ownership modes and fail early.
Replace low-level session access
Caller-supplied ClientSession support remains as a deprecated compatibility
path. It doesn't receive the high-level client's response caching, automatic
multi-round-trip handling, or modern subscription behavior.
Replace code that reads MCPTool.session or passes a ClientSession with a
caller-owned mcp.Client. For high-level connections, MCPTool.session
returns None.
Remove unsupported MCP features
- Replace
MCPWebsocketToolwithMCPStreamableHTTPTool. The compatibility symbol raises when used. - Remove
MCPTaskOptionsandtask_options. MCP Tasks aren't currently supported by the Python SDK runtime used by Agent Framework. - Don't build new integrations around
sampling_callback. Server-initiated MCP sampling is deprecated; servers should call model-provider APIs directly. - Replace MCP hosting examples based on
FastMCPwith the MCP SDK 2.xMCPServerAPI.
For detailed lifecycle behavior, see Local MCP tools.
Declare AG-UI authorization ownership
Every AG-UI endpoint must now declare who owns server-side state.
Local or single-user application
Use single_user=True only when every caller belongs to the same trust
boundary and process-local scope is sufficient:
add_agent_framework_fastapi_endpoint(
app,
agent,
"/agent",
single_user=True,
)
The generated scope changes when the endpoint is registered again. For durable
single-user snapshots, checkpoints, or provider state, return an
application-owned constant from authorization_scope_resolver instead.
Authenticated or shared application
Resolve a stable scope from authenticated request context:
import os
from fastapi import HTTPException, Security
from fastapi.security import APIKeyHeader
api_key_header = APIKeyHeader(name="X-API-Key", auto_error=False)
expected_api_key = os.environ["AG_UI_API_KEY"]
async def resolve_authorization_scope(
api_key: str | None = Security(api_key_header),
) -> str:
if api_key != expected_api_key:
raise HTTPException(status_code=403, detail="Invalid API key.")
return "tenant:contoso:user:alice"
add_agent_framework_fastapi_endpoint(
app,
agent,
"/agent",
authorization_scope_resolver=resolve_authorization_scope,
)
The resolver can use FastAPI Depends, Security, headers, cookies, or
Request. It must return a stable, nonempty scope for the principal or
collaboration boundary that can access the same snapshots, sessions,
checkpoints, detached runs, and approval state.
Authentication-only dependencies don't provide this scoping. Don't combine
them with single_user=True when different authenticated callers can reach the
endpoint.
For more information, see AG-UI security considerations.
Rename Docker shell extra arguments
Rename the constructor argument:
Before:
DockerShellTool(extra_run_args=["--some-runtime-option"])
After:
DockerShellTool(
unsafe_extra_run_args=["--some-runtime-option"],
)
These values are appended verbatim to the Docker or Podman command. They can weaken or bypass the tool's isolation defaults. Keep them developer-controlled, never populate them from user or model output, and prefer a dedicated constructor option when one exists.
Review optional behavior changes
A2A forwarded context
Configure independent allow lists on both sides:
from agent_framework.a2a import A2AAgent, A2AExecutor
client_agent = A2AAgent(
name="remote",
url="https://a2a-agent.example.com",
forwarded_kwargs=["tenant_id", "trace"],
)
executor = A2AExecutor(
local_agent,
accepted_function_invocation_kwargs=["tenant_id"],
accepted_client_kwargs=["trace"],
)
The default is to send and accept nothing. Forwarded values must be JSON-compatible and aren't credentials or authorization by themselves.
Sequential provider compatibility
Some chat-completions providers return an empty response when the input ends with an assistant message. Opt in only for those providers:
workflow = SequentialBuilder(
participants=[writer, reviewer],
ensure_trailing_user_turn=True,
).build()
The synthetic user continuation is added only to the invocation copy and isn't stored in the workflow conversation.
Review Python version behavior
Python 1.24 supports Python 3.11 through 3.15. Package metadata still permits Python 3.10 installation, but that version is no longer supported or tested. The remaining Python 3.15 standard-install limitations are:
- Redis isn't installed because RedisVL requires Python earlier than 3.15.
- Declarative Power Fx expressions aren't evaluated on Python 3.14 or 3.15.
Migration checklist
- Upgrade the complete package cohort in one operation.
- Replace low-level MCP sessions with entered high-level
mcp.Clientinstances where the application owns the connection. - Remove MCP WebSocket and
task_optionsusage. Tools that require the Tasks extension are skipped, while tools that declare Tasks as optional continue through ordinarytools/callrequests. - Remove new server-initiated sampling usage.
- Add an authorization resolver or
single_user=Trueto every AG-UI endpoint. - Rename
extra_run_argstounsafe_extra_run_args. - Review A2A forwarded context and sequential provider compatibility only when those opt-in behaviors are needed.
- Test persisted-state, approval, workflow, and hosting paths before a rolling deployment.
For the complete release summary, see Python 2026 significant changes.