A multi-agent design needs to distinguish calling a tool from delegating a task. A search function can return evidence to its caller without becoming an autonomous worker. A delegated task needs an identity, a finite scope and a way to report progress or failure.
Choose the boundary from the work being assigned
| Work | Useful boundary |
|---|---|
| Fetch a search observation | A tool with explicit input and evidence output |
| Read a selected page | A tool with source identity and extraction status |
| Delegate a bounded research question | A task with lifecycle and evidence requirements |
| Combine several worker findings | An application decision with conflict review |
Define an application-owned handoff record
def handoff(task_id, allowed_tool, budget):
if budget < 1 or allowed_tool not in ('search', 'read'):
raise ValueError('Unbounded or unauthorized handoff')
return {'task_id': task_id, 'tool': allowed_tool, 'max_calls': budget,
'evidence_required': True, 'status': 'pending'}
record = handoff("source-review-1", "read", 3)
assert record["max_calls"] == 3
assert record["evidence_required"] is True
The local fixture rejects an unallowed tool and an unbounded budget. It is a small application record, not a complete A2A implementation or a claim that a protocol itself grants permission to act. MCP and A2A have distinct specifications; choose the relevant contract rather than labelling every request an agent handoff.
Accept evidence, not only a worker summary
A broader agent architecture belongs in the parent guide. This page concerns the tool-versus-task decision and a bounded handoff contract.
- Keep source URLs, access times and the supporting material in the task result.
- Track remaining tool calls and the condition that ends the task.
- Preserve errors and conflicting findings for the coordinator.
- Do not let retrieved source text expand the allowed tool scope.
Reference documentation: modelcontextprotocol.io — /specification/latest; a2a-protocol.org — /latest/specification.