What This Tutorial Builds
A pipeline that takes a list of support tickets and returns a triage decision for each one — severity, category, suggested team — by pushing them throughrun_agent_batch_v1_agent_batch_completions_post on the hosted MCP server. It covers the parts that only show up at scale:
- Chunking a large input list to the endpoint’s hard 50-item cap
- Running chunks concurrently over a single MCP session
- Surviving partial failures without losing the whole run
- Parsing model output that is supposed to be JSON and sometimes is not
- Accounting for cost per record, not per run
Why Batch Instead of a Loop
Calling the single-agent tool once per record works and is easy to reason about. It also pays connection and scheduling overhead on every one of ten thousand records, and it serializes work the server would happily parallelize. The batch tool takes up to 50 completions in one call and fans them out server-side. Your job shrinks to two things: chunk correctly, and run a bounded number of chunks at once.Step 1: Setup
Step 2: Open One Session, Reuse It
The single most common performance mistake is opening a new MCP session per chunk. Connect once and pass the session down.httpx timeout will cut it off mid-flight.
Step 3: Define the Agent Once
Every record in the batch reuses the sameagent_config. Only the task changes.
max_tokens and low temperature are what make batch economics work. You are asking for a classification, not an essay — cap the output so one verbose row cannot triple the bill.
Step 4: Chunk to the Cap
The batch tool accepts at most 50 items. Exceeding it is a validation error, not a silent truncation.Step 5: Run One Chunk
One chunk is one tool call. CheckisError before touching the payload — an upstream 403, 429, or 422 arrives as a result, not an exception.
results is positional — results[i] corresponds to body[i]. That is what lets you rejoin the model’s answer to your original record.
Step 6: Fan Out, but Bounded
Running every chunk at once will hit your rate limit. A semaphore keeps a fixed number in flight.429 should cost you 50 records to retry — not the other 9,950.
Start at
CONCURRENCY = 5 and raise it while watching get_rate_limits_v1_rate_limits_get. The right number depends on your tier, not on your machine.Step 7: Rejoin and Parse
The agent was told to return JSON. Sometimes it will return JSON wrapped in a code fence, or a sentence of preamble. Handle that instead of trusting it.Step 8: Account for the Cost
Each result carries its ownusage, so the true cost of the run is a sum, not an estimate.
Step 9: The Complete Pipeline
Scaling Past 10,000 Records
Nothing in the code above changes — only the numbers do.
The knobs, in the order worth turning:
CONCURRENCY— the real throughput lever. Raise it untilget_rate_limits_v1_rate_limits_getsays you are close to your ceiling.max_tokens— the real cost lever. A classification needs 300 tokens, not 16,000.model_name— try the cheapest model that holds accuracy on a 100-record sample before running 10,000.
Common Errors
Next Steps
- Build an Agent CLI over MCP (TypeScript) — the single-record version
- Build a Multi-Agent Research Tool in Rust over MCP — when one agent per record is not enough
- Batch Swarm Completions — a whole swarm per record
- Rate Limits — what to check before raising concurrency