Microsoft Agent Framework 1.9 Puts Approval Gates and MCP Sampling Limits Into the Harness

Microsoft Agent Framework 1.9 Puts Approval Gates and MCP Sampling Limits Into the Harness

Microsoft Agent Framework Python 1.9.0 is the kind of release the agent ecosystem needs more of: fewer “look, it can call tools” demos, more policy wired into the place where tools are actually called. The headline is governance. MCP sampling is denied by default unless an approval callback exists, sampling gets token and request limits, and tool approval is now part of the harness agent instead of a convention every sample app has to remember.

That sounds dry because good safety work usually does. But for teams building internal agents, this is the boundary between a framework that can be used in production and a framework that merely hopes the developer remembered to paste in the guardrails.

Approval belongs in the harness, not the README

The release adds tool approval middleware and integrates it into the harness agent. PR #6522 says create_harness_agent now wires ToolApprovalMiddleware by default, adds a deliberate disable_tool_approval opt-out, forwards auto_approval_rules, and extends the harness console with “always approve” options for both tool-wide and tool-plus-argument approvals. The same PR’s fetched CI summary showed 7,982 Python unit tests, 34 skipped, zero failures, zero errors, and a 2 minute 4 second runtime.

The important word is “default.” Agent frameworks have historically treated approvals like UI chrome: ask before shell, ask before file writes, maybe remember a user preference, and call it safety. That is not enough once agents become programmable loops with tools, memory, MCP servers, shell access, and workflow orchestration. Approval policy has to live where it can be configured, tested, composed, logged, and intentionally bypassed only when the operator has made that decision.

Moving approval into the harness changes the review model. A team can now test approval as runtime behavior instead of auditing every agent factory for a missing callback. That is how production systems get safer: not because every developer becomes more careful, but because the dangerous omission becomes harder to make accidentally.

The “always approve” addition is useful and risky in exactly the way real operational features are. Humans cannot approve every trivial tool call in a long-running agent loop; that path trains people to click through. Standing approvals are necessary. But they should be narrow, argument-aware, logged, reviewable, and easy to revoke. Microsoft’s distinction between tool-wide and tool-plus-argument approvals points in the right direction. The practitioner move is to start with the argument-scoped form, observe traces, then widen only after the workflow becomes boring.

MCP servers are not passive libraries

The breaking MCP change is the release’s sharpest security signal. PR #6413 adds sampling_approval_callback, sampling_max_tokens, and sampling_max_requests to MCPTool and its subclasses. Server-initiated sampling/createMessage is denied by default when no callback exists. Requested token counts are clamped. Request counts are enforced per session.

This is the right default because MCP sampling flips the usual mental model. Most engineers think of MCP as “the model calls a tool.” Sampling lets the tool server ask the client/model side to generate messages. That can be legitimate. It can also cause unexpected model work, token spend, trace pollution, and data movement. Treating MCP servers as passive libraries is a category error. They are active participants in the agent loop.

Deny-by-default sampling closes the most obvious hole: a server should not be able to cause model generations unless the client side has an explicit policy for that behavior. The max-token and max-request settings add blast-radius controls. Those are not merely FinOps knobs. A compromised, buggy, or poorly designed MCP server that repeatedly requests sampling can turn one tool call into an unbounded agent bill and a debugging mess. A per-session cap creates an invariant operators can reason about: this server cannot request more than N extra generations without crossing a policy boundary.

The distinction between “no approval callback configured” and “callback explicitly denied” is also worth preserving in logs and metrics. They are different operational failures. The first is missing policy. The second is policy doing its job. If your traces collapse them into the same error, the on-call engineer has to infer intent from smoke.

The shell tool makes the governance story more urgent

Agent Framework 1.9.0 also adds shell-tool integration into the harness agent, plus AgentLoopMiddleware, telemetry for context-provider instructions, opt-in AG-UI thread snapshot persistence and hydration, and stable agent-framework-orchestrations 1.0.0. These are not separate stories. They are why approval middleware matters.

A shell tool is one of the clearest examples of agent authority. It can inspect files, run tests, modify state, exfiltrate data if misused, and burn time in ways that look like progress. Add loop middleware and persisted thread snapshots, and the agent is no longer just responding once to a prompt. It is running a process. Processes need policy at the loop boundary, tool boundary, and persistence boundary.

Telemetry for context-provider instructions belongs in the same discussion. Context providers can quietly shape what the agent sees and believes. Capturing those instructions in telemetry makes agent behavior more reviewable after the fact. If a tool call looked irrational, the answer might be in the retrieved instruction, not the model weights. Production agent teams need this because debugging agents is increasingly about reconstructing the runtime environment, not just reading the final message.

The AG-UI snapshot work is also operationally relevant. Persisting and hydrating thread state helps long-running agent experiences survive UI reloads, handoffs, and multi-step workflows. But persisted state becomes evidence. Teams should decide what is retained, who can inspect it, and how approval decisions are represented inside that state. A workflow snapshot without approval context is only half a trace.

Useful fixes, not decorative polish

The release fixes several MCP edges that practitioners will recognize. Empty-list handling for MCP allowed_tools is corrected. CallToolResult.structuredContent is parsed to avoid None tool results. OpenTelemetry usage detail attributes are fixed across Anthropic, core, and OpenAI packages.

These are the small cuts that determine whether an agent framework feels trustworthy. An empty allowlist is a policy statement; mishandling it can mean “allow nothing” becomes “maybe allow something” or vice versa. Structured tool content turning into None creates pointless retries and misleading traces. Usage attributes drifting across providers turns cost analysis into archaeology. None of these fixes are glamorous. All of them compound.

Microsoft’s own documentation frames Agent Framework as a platform for robust, future-proof agentic AI solutions across agents, tools, skills, conversations, providers, workflows, memory, and hosting. That is broad language. Version 1.9.0 earns some of it by moving safety from promise to plumbing.

What engineers should actually do

If you are using Agent Framework, do not treat this as a passive upgrade. Add approval behavior to your test suite. Verify that harness-created agents install approval middleware by default. Verify that disabling approval requires an explicit opt-out. Test auto-approval rules with arguments that should match and arguments that should not. Confirm the console’s “always approve” choices produce scoped, inspectable behavior rather than broad invisible grants.

For MCP, create a test server that calls sampling/createMessage. Confirm sampling fails closed when no callback exists. Add a callback and confirm explicit denial is observable. Request more tokens than allowed and verify clamping. Request sampling repeatedly and verify the per-session cap fires before the server can turn a single interaction into an accidental loop. This is the kind of test that looks excessive until it catches the exact bug that would have been expensive in production.

For shell access, pair policy with telemetry. A shell tool without traceable approval is a liability. A loop without max-iteration or approval checks is just a polite infinite loop. A persisted AG-UI thread without approval history is a replay problem waiting to happen.

The broader industry lesson is simple: approval gates are not UX. MCP servers are not inert tools. Agent loops are not chat messages with ambition. They are runtime systems, and runtime systems need enforceable contracts. Microsoft Agent Framework 1.9.0 is valuable because it puts more of that contract in code instead of asking teams to enforce it through vibes and documentation.

That is not the most exciting release note. It is the one senior engineers should approve first.

Sources: Microsoft Agent Framework Python 1.9.0 release, PR #6413, PR #6414, PR #6522, Microsoft Agent Framework docs