CLAUDE LABJP
2.1.278 — The auto mode classifier now runs server-side by default on the Claude API, Enterprise, Bedrock, Vertex and Foundry. You are not billed for the classifier, and /status gained an Auto mode server lineTASKOUT — The TaskOutput tool is gone. taskOutputMaxChars and TASK_MAX_OUTPUT_LENGTH no longer do anything, and background output is read with Read instead10/07 — The old management-configuration key spellings are accepted until noon PT on October 7, seventeen days from now. After that, entries that still use them stop working until you rewrite themBUNPANIC — Reports are coming in of the newest build crashing on launch alone. Earlier builds still run on the same machine, which points at the release rather than the environmentNEW — Deciding what belongs in Cowork and what belongs in Claude Code, using the approval boundary as the lineSONNET4.5 — A date in a deprecation table is a floor, not an end date. Sonnet 4.5 is still active and no deprecation notice has been posted2.1.278 — The auto mode classifier now runs server-side by default on the Claude API, Enterprise, Bedrock, Vertex and Foundry. You are not billed for the classifier, and /status gained an Auto mode server lineTASKOUT — The TaskOutput tool is gone. taskOutputMaxChars and TASK_MAX_OUTPUT_LENGTH no longer do anything, and background output is read with Read instead10/07 — The old management-configuration key spellings are accepted until noon PT on October 7, seventeen days from now. After that, entries that still use them stop working until you rewrite themBUNPANIC — Reports are coming in of the newest build crashing on launch alone. Earlier builds still run on the same machine, which points at the release rather than the environmentNEW — Deciding what belongs in Cowork and what belongs in Claude Code, using the approval boundary as the lineSONNET4.5 — A date in a deprecation table is a floor, not an end date. Sonnet 4.5 is still active and no deprecation notice has been posted
Articles/Claude.ai
Claude.ai/2026-04-11Advanced

Four Places My MCP Agent Broke — Measuring Aggregation Tools, Fake Parallelism, and Input Validation

The implementation holes I hit while running MCP servers and agent workflows as a solo developer, with numbers measured on my own machine: boundary values in aggregation tools, parallelism that quietly runs serially, brittle JSON parsing, and the limits of blocklist-style input validation.

MCP53agents8workflow40automation110Claude Code255API28

Premium Article

I remember the day I finished writing my first MCP server as an indie developer. Restarting Claude Desktop, watching my own aggregation tool appear in the tool list — a quiet, particular kind of satisfaction.

That feeling lasted about five minutes, until I handed it a real CSV from my own project. The tool was being called. It just wasn't returning anything useful.

The Model Context Protocol itself is a remarkably plain spec. What trips you up almost always lives outside the protocol: how you write your schemas, how you handle async, and what your code assumes about the shape of a model's output.

This article walks through designing MCP servers and agent workflows, but it keeps returning to four holes I fell into personally — each one paired with numbers I measured on my own machine. I'd rather share the failure conditions up front than leave you with clean architecture diagrams alone.


How Much Does MCP Actually Take Off Your Hands?

The Model Context Protocol (MCP) is an open standard protocol introduced by Anthropic in November 2024. It defines a shared interface for connecting AI models to external tools and data sources — often described as the "USB-C of AI applications."

The Problem MCP Solves

Before MCP, every external tool integration required custom adapter code written specifically for each AI model. Connecting the same tool to a different model meant rewriting the integration from scratch, driving up maintenance costs considerably.

MCP changes this. Implement a tool once as an MCP server, and it works with Claude — or any other MCP-compatible client — right away.

MCP's Three Core Components

MCP is built around three key components.

MCP Host: The environment that runs the AI model, such as Claude Desktop or Claude Code. It provides the user interface and acts as an MCP client to communicate with servers.

MCP Client: The component inside the host that manages connections to MCP servers. It establishes connections and retrieves available resources, tools, and prompts.

MCP Server: The program that provides actual functionality. File system access, database queries, web searches — any capability can be wrapped in an MCP server.

Three MCP Primitives

MCP servers can expose three types of primitives.

Tools: Functions that Claude can call — file reads and writes, API calls, computation. These are "actions" that Claude decides when to invoke based on the task at hand.

Resources: Access to static or dynamic data — files, database records, documents — identified by URI and loaded into the context window.

Prompts: Reusable prompt templates, ideal for slash-command-style interactions that users can invoke directly.


Agent Architecture Design Patterns

Before building with MCP, it helps to understand the major patterns for structuring agent systems.

Single-Agent Pattern

The simplest setup: one Claude instance completes a task using multiple MCP tools.

User
  ↓
Claude (orchestrator)
  ├── MCP: File System
  ├── MCP: Database
  ├── MCP: Web Search
  └── MCP: Email Delivery

This pattern works well when the task is clearly defined and coordination between tools is relatively straightforward. Standard Claude Desktop usage maps directly to this pattern.

Orchestrator + Sub-Agent Pattern

For more complex tasks, a parent agent (orchestrator) breaks work into pieces and delegates to specialized sub-agents.

User
  ↓
Orchestrator (Claude)
  ├── Sub-Agent 1 (Research)
  │     └── MCP: Web Search, Wikipedia
  ├── Sub-Agent 2 (Analysis)
  │     └── MCP: Database, Calculation Tools
  └── Sub-Agent 3 (Output)
        └── MCP: File Generation, Email Delivery

Anthropic's Claude Agent SDK, released in 2025, natively supports this pattern. You define each agent's role using the Agent class, while the orchestrator coordinates everything through the orchestrate() method.

Parallel Agent Pattern

When tasks are independent of each other, running multiple agents simultaneously cuts processing time. This is also where I made the mistake that's hardest to notice.

Wrap the call in async def, hand it to asyncio.gather, and the shape is unmistakably parallel. But if what you're calling inside is a synchronous client, the event loop blocks for the entire duration of each call. It looks concurrent and runs in single file.

I measured it. Four blocking operations of 0.5 seconds each, handed to asyncio.gather (Python 3.10.12):

ApproachMeasured time for 4 × 0.5s tasks
Synchronous call inside async def2.00s
Wrapped in asyncio.to_thread0.50s

A clean 4×. Code I believed was parallel had been running serially the whole time — and not a single exception was raised to tell me. Scale to eight agents and you simply wait eight times as long.

There are two fixes. The direct one is to use the async client. If you need to keep existing synchronous code, push it onto a worker thread with asyncio.to_thread.

import asyncio
from anthropic import Anthropic
 
client = Anthropic()
 
async def run_agent(task: str, tools: list) -> str:
    """Run a single agent"""
    response = client.messages.create(
        model="claude-opus-4-6",
        max_tokens=4096,
        tools=tools,
        messages=[{"role": "user", "content": task}]
    )
    return response.content[0].text
 
async def parallel_workflow(tasks: list[dict]) -> list[str]:
    """Execute multiple tasks in parallel"""
    coroutines = [run_agent(t["task"], t["tools"]) for t in tasks]
    results = await asyncio.gather(*coroutines)
    return results

When using the parallel pattern, make sure each agent's tasks are truly independent. Concurrent writes to shared resources will cause data integrity issues.

Sequential Pattern with Checkpoints

For long-running workflows, saving state after each step is crucial. If something fails midway, you won't have to start over from scratch.


Thank you for reading this far.

Continue Reading

What follows includes implementation code, benchmarks, and practical content we hope you'll find useful. This site runs without ads — server and development costs are supported entirely by members like you. If it's been helpful, we'd be truly grateful for your support.

WHAT YOU'LL LEARN
Why a strict zod schema can reject your entire real-world dataset — and how to fix it
Calling a sync SDK inside async def turns parallel work serial: 2.00s vs 0.50s, measured
How a tool returning -Infinity or NaN becomes indistinguishable from an empty result on Claude's side
Secure payment via Stripe · Cancel anytime

Unlock This Article

Get full access to the rest of this article. Buy once, read anytime. This site is ad-free — your support goes directly toward keeping it running.

or
Unlock all articles with Membership →
Share

Thank You for Reading

Claude Lab is ad-free, supported entirely by members like you. We publish practical guides daily with implementation code, benchmarks, and production-ready patterns. If you've found it useful, we'd love to have you on board.

  • Copy-paste ready implementation code
  • New advanced guides published daily
  • $5/mo or $15 for lifetime access
View Membership →

Related Articles

Claude Code2026-03-20
Implementation Patterns for Custom Claude Code Skills — SKILL.md Design, Testing, and Distribution
A hands-on tutorial for building three production custom Claude Code skills from scratch. Covers SKILL.md structure, agent types, context injection, testing, and team distribution.
Claude.ai2026-07-11
When a Connector Starts Slowing Down at Night: A Health-Aware Circuit Breaker for Solo Automation
Seeing connector errors and latency is only half the job — the other half is deciding when to route around them. This is my implementation of a circuit breaker that opens on error rate and p95, with runnable Python and notes on wiring it into nightly jobs.
Claude.ai2026-07-07
A connector failed for two nights and I never noticed — instrumenting my solo setup after observability went to public beta
The week connector observability hit public beta, I realized my one-person operation had no view into errors or latency. Here is how I wrapped my MCP connector calls in a thin meter and started reviewing it weekly.
📚RECOMMENDED BOOKS
Build a Large Language Model (From Scratch)
Sebastian Raschka
LLM Dev
Prompt Engineering for LLMs
Berryman & Ziegler
Prompting
AI Engineering
Chip Huyen
AI Eng
* Contains affiliate links