portfolio-optimiser/docs/research/2026-06-24-maf-vs-claude-agent-sdk.md
Kjell Tore Guttormsen 25bb07a46e docs(research): MAF vs Claude Agent SDK comparison + D7 sibling-impl decision
Verified comparison of Microsoft Agent Framework (ground-truth introspection of
installed agent-framework-core 1.9.0 + Microsoft Learn) and Claude Agent SDK
(Anthropic docs + npm/PyPI). Grounds decision D7: rebuild the same method on
Claude Agent SDK as a separate sibling repo, in sequence, sharing only the
spec + golden/conformance suite — not orchestration code.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Fif1r1En5W542HbZV88yMH
2026-06-24 06:51:24 +02:00

12 KiB
Raw Blame History

Microsoft Agent Framework (MAF) vs. Claude Agent SDK — a practitioner's comparison

Date: 2026-06-24 · Audience: people who know agent frameworks but not these two specifically. Why this exists: portfolio-optimiser is built on MAF; the same method will be rebuilt on Claude Agent SDK as a separate sibling repo (decision D7). This doc grounds that work and is a standalone reference.

Verification status: MAF facts were ground-truth-introspected against the installed agent-framework-core==1.9.0 in this repo + Microsoft Learn. Claude Agent SDK facts were verified against Anthropic docs (code.claude.com) + npm/PyPI. Items the research could not confirm are marked (unverified) and must not be repeated as fact.


TL;DR — they are two different kinds of thing

  • MAF is a multi-agent orchestration framework. You declare the topology. It ships named, first-class collaboration patterns (Sequential, Concurrent, GroupChat, Handoff, Magentic) and an explicit, deterministic graph workflow engine. The control plane is explicit and yours. It is model-agnostic (provider abstraction), Azure/enterprise heritage (the merger of Semantic Kernel

    • AutoGen), with OpenTelemetry observability built in.
  • Claude Agent SDK is a single autonomous agent harness. It exposes the same agentic loop that powers Claude Code (gather context → act → verify → repeat). You steer one capable agent with tools, hooks, permissions, and the ability to delegate to subagents. The control plane is implicit — Claude decides the sequence; you constrain it with hooks. It is Claude-only (but multi-cloud), coding/ops heritage, observability is DIY.

Mental model: MAF = you are the conductor writing the score; the agents are players executing your composition. Claude Agent SDK = you hire one very capable generalist, give it tools and guardrails, and let it decide how to get the job done — delegating to specialists (subagents) when it judges it useful.

The single sharpest axis: MAF makes orchestration explicit and declarative; Claude Agent SDK makes it implicit and emergent, bounded by hooks.


Side-by-side

Dimension Microsoft Agent Framework (MAF) Claude Agent SDK
What it is Orchestration framework for agents + workflows Programmatic harness over the Claude Code agent loop
Lineage Successor to & merger of Semantic Kernel + AutoGen Renamed from "Claude Code SDK"; evolved beyond coding
Maturity GA 1.0.0 (Python, 2026-04-02); installed here: core 1.9.0 Pre-1.0, very fast cadence (TS at 0.3.x, 225+ npm releases)
Languages Python ≥3.10 and .NET (C#) — not full parity Python ≥3.10 and TypeScript — TS slightly richer
Models Model-agnostic via provider packages (Azure OpenAI, Foundry, OpenAI, Ollama, Anthropic*, Gemini*, Bedrock*) Claude only, but multi-cloud: Anthropic API / Bedrock / Vertex / Azure Foundry
Core primitive Agent (LLM loop) + WorkflowBuilder (graph of Executor nodes) query() async generator + ClaudeSDKClient (persistent)
Multi-agent Named patterns: Sequential, Concurrent, GroupChat, Handoff, Magentic No named patterns — compose yourself via subagents / N calls
Determinism Native: FunctionExecutor node + conditional edges in the graph Via PreToolUse hook that denies until a step has run
Tools / MCP MCP client (stdio/HTTP/WS) + agent can be exposed as MCP server Built-in tools + custom tools via in-process MCP server; MCP client
HITL ToolApprovalMiddleware, RunContext.request_info(), Magentic plan-review permission_mode, allowed_tools, PreToolUse/PermissionRequest hooks
Observability Built-in OpenTelemetry (GenAI semantic conventions, metrics, evals) DIY via PostToolUse/SubagentStop hooks; no built-in OTel (unverified)
State / memory Sessions, file/Redis history, workflow checkpointing, compaction strategies Session resume (JSONL on your FS), auto-compaction, PreCompact hook
License MIT "SEE LICENSE IN README" + Anthropic Commercial ToS (FOSS license unverified)
Runs where Your process; Azure/Foundry-first for hosted tools Your process / filesystem; bundles a Claude Code binary

* beta provider packages — require --pre, not production-ready.


The dimensions that matter most

1. Multi-agent orchestration — the biggest divide

MAF gives you the topology as a first-class, named object. All five live in a separate package, agent-framework-orchestrations (GA 1.0.0; not bundled with core):

Pattern Builder Behaviour
Sequential SequentialBuilder A → B → C, output chained
Concurrent ConcurrentBuilder Same input fan-out, results aggregated
GroupChat GroupChatBuilder Star topology; an orchestrator picks the next speaker (round-robin / prompt / custom selection fn)
Handoff HandoffBuilder Point-to-point control transfer between agents
Magentic MagenticBuilder Magentic-One manager that plans, tracks a progress ledger, and coordinates specialists dynamically

Note: Microsoft itself warns Magentic is "untested … outside of the original Magentic-One design." Treat as beta for novel use cases.

Claude Agent SDK has no equivalent. The multi-agent mechanism is subagents: your main agent spawns separate agent instances (via the Agent tool) defined programmatically through AgentDefinition (or .claude/agents/*.md). Key properties:

  • The main agent decides when to delegate, from each subagent's description. You can also ask explicitly ("use the X agent").
  • A subagent does not inherit the parent's history; the only channel in is the spawn prompt, and it returns only its final answer (not intermediate steps).
  • Subagents can run in parallel and nest (up to 5 levels, since Claude Code 2.1.172).
  • There is no built-in coordination protocol between peer agents — no debate loop, no consensus, no voting. To coordinate N peers you run N query() calls and aggregate yourself, or have one orchestrator agent fan out to subagents. (A Workflow tool for 10100-agent scale exists in the TypeScript SDK; availability in Python is unverified.)

So: if your design is a named multi-agent topology (a maker-checker debate, a planner-manager), MAF hands it to you. On Claude Agent SDK you hand-roll it from subagents + your own glue.

2. Determinism / forcing a blocking step

This is MAF's headline differentiator and directly relevant to a "mandatory deterministic validator."

  • MAF: add a FunctionExecutor — a pure Python function, no LLM — as a node in WorkflowBuilder, with conditional edges (EdgeCondition, SwitchCaseEdgeGroup). It blocks the graph until it returns. The sequence is declared in code; the validator is a graph node by construction.
  • Claude Agent SDK: there is no declarative graph. You force a sequence with a PreToolUse hook that returns permissionDecision: "deny" for any tool until your validator tool has run. You can also rewrite tool input (updatedInput), inject context, or replace tool output before the model sees it. Powerful, but the determinism is enforced by interception, not expressed as structure.

Net: stronger, more legible deterministic control → MAF. More flexible autonomy with guardrails → Claude Agent SDK.

3. Model coupling

  • MAF abstracts the provider behind BaseChatClient; you swap Azure OpenAI ↔ OpenAI ↔ Foundry ↔ local OpenAI-compatible endpoints ↔ (beta) Anthropic/Gemini/Bedrock. Instructions, tools, and middleware are portable; provider-specific run-options (OpenAIChatOptions, FoundryChatOptions) are not.
  • Claude Agent SDK runs Claude only — but across Anthropic API, Amazon Bedrock, Google Vertex, and Azure AI Foundry via env vars (CLAUDE_CODE_USE_BEDROCK/VERTEX/FOUNDRY), with no code change. Model aliases (opus/sonnet/haiku/fable/inherit) or full IDs in ClaudeAgentOptions / AgentDefinition.

4. Tools, MCP, and data access

Both are MCP clients. The difference is symmetry:

  • MAF: MCP client over three transports (MCPStdioTool, MCPStreamableHTTPTool, MCPWebsocketTool); and crucially agent.as_mcp_server() exposes an agent as an MCP server for other clients. Function tools via @tool/FunctionTool.
  • Claude Agent SDK: built-in tools (Read/Write/Edit/Bash/Grep/Glob/WebSearch/ WebFetch/Agent/AskUserQuestion); custom tools via @tool + create_sdk_mcp_server running in-process (exposed as mcp__{server}__{tool}); external MCP servers via mcp_servers.

5. Observability

  • MAF: OpenTelemetry is built in (agent_framework.observability, GenAI semantic conventions, token-usage histograms, workflow/edge/MCP spans) plus an experimental eval harness (evaluate_agent, evaluate_workflow).
  • Claude Agent SDK: you build it from hooks (PostToolUse, SubagentStop, parent_tool_use_id), asynchronously if you want non-blocking logging. No first-class OTel integration found (unverified).

What each is best at

MAF wins when you need explicit, auditable orchestration; a blocking deterministic step between LLM turns expressed as structure; named multi-agent debate/handoff patterns out of the box; model portability; built-in telemetry from day one; or you are migrating from Semantic Kernel / AutoGen.

Claude Agent SDK wins when you want one strong agent that lives on your infrastructure (your filesystem, your secrets, no vendor sandbox); coding/DevOps automation (its native turf); fast prototype → production with query(); rich MCP-client integration; and you are happy to be on Claude models across multiple clouds. Its orchestration is emergent, not declared — great for open-ended autonomy, weaker for "prove the exact sequence ran."


Implication for portfolio-optimiser (decision D7)

The product is a maker-checker debate that generates candidate measures, gated by a mandatory, blocking deterministic validator, with a HITL learning loop.

  • On MAF (this repo): debate = GroupChatBuilder; validator = a FunctionExecutor graph node — blocking by construction. Direct fit; this is why MAF was chosen.
  • On Claude Agent SDK (sibling repo, D7): debate = an orchestrator agent fanning out to maker / checker subagents (or N query() calls + your aggregation); the validator is enforced by a PreToolUse hook that denies any action until the validator tool has run. Fully possible, but you hand-roll the orchestration and the "blocking" is interception, not a declared edge.

Because the two paradigms differ this much, a single shared runtime abstraction is the wrong move. The portable, framework-neutral asset is the method, not the orchestration code: the Agent Skill, the IR contract, the validator rules, the synthetic reference domain, and — most valuable for a fair comparison — a shared golden/conformance suite (synthetic domain inputs → expected validator verdicts) that both implementations must pass. That is what makes "the same method on two frameworks" a measurable claim rather than two vaguely similar projects.


Open / unverified items (do not repeat as fact)

  • Exact date of the Claude Code SDK → Claude Agent SDK rename (secondary sources say ~Sept 2025).
  • The code's FOSS license (npm says "SEE LICENSE IN README").
  • canUseTool callback details; Workflow tool availability in the Python Claude Agent SDK.
  • Claude Agent SDK built-in OpenTelemetry support (none found, not definitively absent).
  • MAF beta Anthropic provider package name (agent-framework-claude assumed, not confirmed).

Sources

  • Microsoft Agent Framework: learn.microsoft.com/agent-framework, github.com/microsoft/agent-framework,
    • ground-truth introspection of installed agent-framework-core 1.9.0.
  • Claude Agent SDK: code.claude.com/docs/en/agent-sdk (overview, migration-guide, subagents, hooks, custom-tools), github.com/anthropics/claude-agent-sdk-{python,typescript}, npm/PyPI version checks.