← Blog

Claude Agent SDK: Tool Loops, MCP, and Agentic Patterns

July 25, 2026

How the Claude Agent SDK structures agentic work: tool runner, Managed Agents, MCP integration, and the pause_turn behavior that trips up most builders.

The Claude Agent SDK is not a separate library — agentic features ship in the standard Anthropic SDK. Three surfaces cover the spectrum: a beta Tool Runner for in-process loops, Managed Agents for Anthropic-hosted sessions with sandboxed containers, and Model Context Protocol integration for third-party tools. All install via pip install anthropic or npm install @anthropic-ai/sdk.

The Claude Agent SDK is not a separate package — it refers to agentic patterns built on the official Anthropic Claude API SDK (anthropic for Python, @anthropic-ai/sdk for TypeScript) across three surfaces: a beta Tool Runner that manages loops in your process, Managed Agents that run sessions on Anthropic's infrastructure, and Model Context Protocol server integration for standardized third-party tools. Knowing which surface to use — and how each handles tool-use iteration limits — is a recurring theme in CCA-F (Claude Certified Architect — Foundations) exam questions.

What is the Claude Agent SDK?

Anthropic does not publish a separate "agent SDK." What practitioners call the Claude Agent SDK is the same package used for single API calls, applied in agentic patterns. All agent features — the beta Tool Runner, Managed Agents, and MCP integration — ship in the standard install:

pip install anthropic          # Python
npm install @anthropic-ai/sdk  # TypeScript

Three surfaces cover the full range of complexity:

  • Messages API + manual tool loop — You define tools, write the loop, and manage state. Maximum control over approval gates, logging, and conditional execution.
  • Tool Runner (beta) — The SDK handles the call → execute → loop cycle automatically. Available in Python, TypeScript, Java, Go, Ruby, C#, and PHP.
  • Managed Agents (beta) — Anthropic runs the agent loop on its own orchestration layer and provisions a sandboxed container per session for tool execution. Supports bash, file operations, code execution, MCP servers, and memory stores.

The right choice depends on whether you need to host compute yourself, how much per-call control you need, and whether the task genuinely requires persistent, multi-turn agent behavior.

How does the Claude API Tool Runner work?

The Tool Runner eliminates the boilerplate of detecting stop_reason: "tool_use", executing your function, and feeding results back. In Python, the @beta_tool decorator generates the JSON schema from type annotations and the docstring automatically:

from anthropic import beta_tool, Anthropic

client = Anthropic()

@beta_tool
def search_docs(query: str) -> str:
    """Search the knowledge base for relevant documents.

    Args:
        query: The search query string.
    """
    return f"Found results for: {query}"

runner = client.beta.messages.tool_runner(
    model="claude-opus-4-8",
    max_tokens=16000,
    tools=[search_docs],
    messages=[{"role": "user", "content": "Find docs on rate limiting"}],
)

for message in runner:
    for block in message.content:
        if block.type == "text":
            print(block.text)

In TypeScript, betaZodTool from @anthropic-ai/sdk/helpers/beta/zod serves the same role, deriving the input schema from a Zod definition. The runner iterates until Claude stops calling tools, then stops.

Use the manual loop instead when you need approval gates before each execution, per-call logging, or conditional logic that depends on intermediate results. In that case, check stop_reason == "tool_use", execute, append results as a user message, and repeat until stop_reason == "end_turn".

What does "Claude reached its tool-use limit for this turn" mean?

When using server-side tools — web search, code execution, web fetch — the Anthropic Claude API runs an internal sampling loop on its own infrastructure. That loop is capped at 10 iterations by default. When the cap is reached, the response arrives with stop_reason: "pause_turn" instead of "end_turn".

This is the mechanism behind what builders commonly encounter as "Claude reached its tool-use limit." The model has paused, not stopped — it can continue. The correct handling is to append the assistant response and re-send the original conversation without adding a new user message:

if response.stop_reason == "pause_turn":
    messages.append({"role": "assistant", "content": response.content})
    # Do NOT add a new user "continue" message — the API resumes automatically
    response = client.messages.create(
        model="claude-opus-4-8",
        max_tokens=16000,
        tools=tools,
        messages=messages,
    )

The API detects the trailing server-tool block and resumes from where it left off. Always add a max_continuations counter in production to prevent infinite loops.

The CCA-F exam tests the distinction between pause_turn and max_tokens: max_tokens is a hard output ceiling you set that the model cannot see — truncation is permanent without increasing the limit or switching to streaming. pause_turn is a resumable pause the model is aware of. They require fundamentally different handling.

How do Managed Agents work?

Managed Agents is the highest-abstraction surface in the Claude agent SDK. Anthropic runs the agent loop on its orchestration layer; a sandboxed container is provisioned per session for tool execution. You never manage compute directly — only the event stream in and out.

The mandatory flow: create an Agent once, reference it in every Session. The model, system, and tools fields belong on the Agent object — never the session.

# ONE-TIME SETUP — run once, persist agent.id
agent = client.beta.agents.create(
    name="Research Agent",
    model="claude-opus-4-8",
    system="You are a thorough research assistant.",
    tools=[{"type": "agent_toolset_20260401"}],
)

# PER-TASK — open the stream BEFORE sending the message
session = client.beta.sessions.create(
    agent=agent.id,
    environment_id=environment.id,
)

with client.beta.sessions.events.stream(session.id) as stream:
    client.beta.sessions.events.send(
        session_id=session.id,
        events=[{"type": "user.message",
                 "content": [{"type": "text", "text": "Research AI regulation in the EU"}]}],
    )
    for event in stream:
        if event.type == "agent.message":
            for block in event.content:
                if block.type == "text":
                    print(block.text, end="", flush=True)
        elif event.type == "session.status_terminated":
            break

The stream only delivers events emitted after it opens — opening the stream after sending the message means early events arrive in a single buffered batch or are missed entirely. Stream-first is not optional.

Managed Agents is available on the first-party Anthropic Claude API and on Claude Platform on AWS. It is not available on Amazon Bedrock or Google Vertex AI.

How does Model Context Protocol integrate with Claude agents?

A Model Context Protocol server exposes standardized third-party capabilities — GitHub, Linear, Asana, Notion, and others — that the agent invokes via mcp_toolset. The Agent definition declares which servers to connect; credentials live in a Vault, not inline in the config.

agent = client.beta.agents.create(
    name="GitHub Agent",
    model="claude-opus-4-8",
    mcp_servers=[{
        "type": "url",
        "name": "github",
        "url": "https://api.githubcopilot.com/mcp/"
    }],
    tools=[
        {"type": "agent_toolset_20260401"},
        {"type": "mcp_toolset", "mcp_server_name": "github"},
    ],
)

session = client.beta.sessions.create(
    agent=agent.id,
    environment_id=environment.id,
    vault_ids=[vault.id],  # vault holds the OAuth credential
)

A critical detail the exam covers: MCP servers require OAuth bearer tokens, not a service's native API key. A Notion integration token authenticates against the Notion REST API but will not work for the Notion MCP server — they are separate auth systems. Vault credentials auto-refresh via a standard OAuth refresh-token grant. The session container never sees the credential directly; Anthropic injects it into outbound MCP calls only after the request leaves the sandbox, which prevents exfiltration even under prompt injection attacks.

Which API parameters matter most for agentic Claude API usage?

These parameters appear frequently in CCA-F exam questions and in every production agentic system:

  • thinking: {"type": "adaptive"} — Lets Claude decide when and how deeply to reason before acting. Use on Opus 4.6, 4.7, and 4.8. On Opus 4.7 and 4.8, budget_tokens is fully removed — sending it returns a 400 error. Adaptive is the only supported thinking mode on those models.
  • output_config.effort — Controls thinking depth and token spend. Values: low, medium, high, xhigh (Opus 4.7 and 4.8 only), max (Opus-tier only). This goes inside output_config, not at the top level. For most agentic work, high or xhigh is the right starting point.
  • tool_choice{"type": "auto"} lets Claude decide; {"type": "any"} forces at least one tool call per turn; {"type": "tool", "name": "X"} forces a specific tool. Use any when the model must always act on data rather than respond in prose.
  • max_tokens — Give agentic calls generous headroom. With streaming, Opus 4.6, 4.7, and 4.8 support up to 128,000 output tokens; Sonnet 4.6 and Haiku 4.5 support up to 64,000.
  • Task Budgets (beta, Opus 4.7 and later)output_config: {"task_budget": {"type": "tokens", "total": N}} tells the model how many tokens it has for the full agentic loop. The model sees a running countdown and self-moderates. Minimum is 20,000 tokens. Requires the beta header task-budgets-2026-03-13.

The CCA-F exam distinguishes task_budget from max_tokens directly: task_budget is a model-visible budget for the entire loop; max_tokens is a hard per-response ceiling the model cannot see and has no awareness of. Using task_budget for multi-step work lets Claude self-pace; using only max_tokens can truncate mid-thought with no graceful wrap-up.

Plinth Practice Item

The following is Plinth Prep–authored practice material and is not an actual CCA-F exam question.

A developer using Managed Agents opens an SSE event stream, then sends a user message, and finds the first few agent events are consistently missing from the stream. Which single change most directly resolves this?

  1. Increase max_tokens on the Agent definition
  2. Open the event stream before sending the user message
  3. Replace agent_toolset_20260401 with custom tools only
  4. Move the MCP server declaration from the Agent to the Session

Answer: B. The SSE stream delivers only events emitted after it opens. Sending the message first means early events — including fast status transitions and the first agent.message block — arrive in one buffered batch or are lost entirely. Opening the stream before sending is a non-negotiable ordering requirement in the Managed Agents API.

Frequently asked questions

What is the Claude Agent SDK?
The Claude Agent SDK is not a separate library — agentic features are built on the official Anthropic SDK. Three surfaces cover the range: a beta Tool Runner that handles the call-execute loop in your process, Managed Agents where Anthropic runs the loop server-side in a sandboxed container, and Model Context Protocol integration for third-party tools.
What does 'Claude reached its tool-use limit for this turn' mean?
This occurs when the Anthropic Claude API's internal server-side loop for tools like web search and code execution reaches its default cap of 10 iterations. The response returns stop_reason: pause_turn. To continue, append the assistant response to the messages array and re-send the original request without adding a new user message — the API resumes automatically.
How do Managed Agents differ from the Claude API Tool Runner?
The Tool Runner runs in your application process: the SDK loops through API call → local function execute → repeat until Claude stops. Managed Agents run Anthropic-side with a container provisioned per session for bash, file operations, and code execution; they support MCP servers and memory stores but are unavailable on Bedrock or Vertex AI.
How do you connect a Model Context Protocol server to a Claude agent?
Declare the MCP server on the Agent definition with an mcp_servers entry (type url, a name, and the server URL), then add an mcp_toolset entry in tools referencing that name. Store OAuth credentials in a Vault and pass vault_ids at session creation — Anthropic injects them into outbound MCP calls only after requests leave the sandbox, preventing credential exfiltration.
What is the difference between pause_turn and max_tokens as Claude API stop reasons?
max_tokens is a hard per-response output ceiling the model cannot see — truncation is permanent. pause_turn means Anthropic's internal server-side tool loop hit its iteration limit; the model can resume. Re-append the assistant response and re-send the original request without a new user message; the API resumes automatically. Add a max_continuations counter in production to prevent infinite loops.

Share this post

Plinth Prep is an independent study resource and is not affiliated with, endorsed by, or sponsored by Anthropic. Practice material is written by Plinth Prep and does not reproduce real exam content.