Third in the 6-part CCA-F scenario series — full source for every scenario: aicert-labs.
The scenario, as written in the exam guide
A coordinator agent delegates to specialized subagents — search, document analysis, synthesis, report generation — to produce cited, comprehensive reports.
| Domain | Weight | Where it shows up in this scenario |
|---|---|---|
| Agentic Architecture & Orchestration | 27% | The coordinator plans subtopics, runs one subagent per subtopic, then synthesizes |
| Tool Design & MCP Integration | 18% | An MCP server with two tools, not one — the split is deliberate |
| Context Management & Reliability | 15% | What the coordinator is — and isn't — allowed to see once a subagent finishes |
Delegation is the easy part
It's tempting to think the hard problem in "coordinator delegates to subagents" is the delegation itself — deciding to split work up. It isn't. The hard problem, and the one CCA-F scenario questions are built to probe, is what crosses the boundary between a subagent and the coordinator.
The naive version has the coordinator hold one long-running conversation and call every tool itself, subtopic after subtopic. Its context grows with everything: every search query, every document it read that turned out irrelevant, for every subtopic, all in the same conversation. By the third subtopic, the coordinator's context is mostly search noise, and — because everything is competing for the same context window — that noise is exactly what pushes out the actually-relevant findings from subtopic one.
aicert-labs's researchSubtopic() fixes this by giving each subtopic its own disposable conversation. It returns exactly one thing to the coordinator: { subtopic, findings: [{ claim, documentId, source }] }. Not the transcript. Not which documents it rejected. A handful of structured facts. The coordinator's context grows with the number of subtopics, not with how much searching each one took.
Two tools, not one
The MCP server exposes search_documents (cheap, returns compact hits) and get_document (fetches one document's full text) as separate tools, instead of one tool that searches and returns full text in a single call. That split forces the subagent to decide what's worth reading in full — everything doesn't land in context by default just because it matched a keyword. get_document's own description tells the subagent that snippets aren't safe to cite, which is the same pattern as Scenario 1's process_refund: put the rule in the tool's contract, not in a system-prompt aside that's easy to forget three tool calls later.
Run it yourself
git clone https://github.com/AICERT-STUDY/aicert-labs
cd aicert-labs/cca-f/scenario-3-multi-agent-research
npm install
cp .env.example .env # add your ANTHROPIC_API_KEY
npm run research -- "Does a 4-day work week actually work?"
The mock corpus (six sources on 4-day work week research) deliberately includes documents that disagree — a manufacturing study finds no productivity gain where knowledge-work studies do — so synthesis actually has to reconcile sources, not just concatenate them.
Test yourself
1. Why does researchSubtopic() return only { subtopic, findings } instead of the subagent's full message history?
Answer: so the coordinator's context grows with the number of subtopics, not with how much searching and reading each subagent needed to do.
If the coordinator held every subagent's full transcript, its context would fill with search noise proportional to effort, not to what's actually relevant to the final report — and that noise crowds out the findings that matter.
2. What's the architectural reason for splitting search_documents and get_document into two tools instead of one that returns full text directly?
Answer: it forces the subagent to decide what's worth reading in full, instead of every search hit's complete text landing in context by default.
A single search-and-return-everything tool optimizes for fewer tool calls at the cost of unreviewed context growth. Splitting the decision point into its own call is a deliberate trade: one extra round trip in exchange for the subagent only pulling in what it actually judges relevant.
3. The research subagent has a record_finding tool instead of just answering with a findings list in its final text message. Why?
Answer: a dedicated tool gives the coordinator a structured, parseable result instead of depending on the model formatting free text correctly and consistently.
This is the same principle behind typed tool results elsewhere in this series: a tool call is something calling code can rely on structurally; a paragraph of prose requires the caller to correctly parse it every time, with no guarantee of consistency across runs.
4. If two documents give conflicting answers to the same subtopic, at what stage of this architecture does that get reconciled?
Answer: synthesis — the individual research subagents don't compare notes with each other; only the coordinator's synthesis step sees findings from every subtopic at once.
Each research subagent works on one subtopic in isolation and has no visibility into what other subagents found. Reconciling contradictions requires a vantage point that can see everything at once, which by design only the synthesis step has.
5. The coordinator runs research subagents sequentially in a for loop rather than in parallel. What would have to be true for switching to Promise.all to be safe?
Answer: the subagents would need to be independent of each other, with no shared mutable state and no subtopic depending on another subtopic's findings — which is already the case here.
Since each researchSubtopic() call only reads from the shared MCP corpus and writes to its own local findings array, nothing about the architecture actually requires sequential execution — it's a console-log readability choice, not a correctness one.
Free CCA-F practice exam, covering all 5 domains: aicert.study/certifications/ccaf.
